diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c | 100 |
1 files changed, 64 insertions, 36 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index 53596bed3c36..f3ebd0c22e7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -21,59 +21,87 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" -#include "outp.h" +#include "ior.h" -#include <core/client.h> #include <subdev/timer.h> -#include <nvif/cl5070.h> -#include <nvif/unpack.h> - -int -nv50_sor_power(NV50_DISP_MTHD_V1) +void +nv50_sor_clock(struct nvkm_ior *sor) { - struct nvkm_device *device = disp->base.engine.subdev.device; - union { - struct nv50_disp_sor_pwr_v0 v0; - } *args = data; - const u32 soff = outp->or * 0x800; - u32 stat; - int ret = -ENOSYS; - - nvif_ioctl(object, "disp sor pwr size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp sor pwr vers %d state %d\n", - args->v0.version, args->v0.state); - stat = !!args->v0.state; - } else - return ret; - + struct nvkm_device *device = sor->disp->engine.subdev.device; + const int div = sor->asy.link == 3; + const u32 soff = nv50_ior_base(sor); + nvkm_mask(device, 0x614300 + soff, 0x00000707, (div << 8) | div); +} +static void +nv50_sor_power_wait(struct nvkm_device *device, u32 soff) +{ nvkm_msec(device, 2000, if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000)) break; ); - nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000 | stat); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000)) - break; - ); +} + +void +nv50_sor_power(struct nvkm_ior *sor, bool normal, bool pu, + bool data, bool vsync, bool hsync) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); + const u32 shift = normal ? 0 : 16; + const u32 state = 0x80000000 | (0x00000001 * !!pu) << shift; + const u32 field = 0x80000000 | (0x00000001 << shift); + + nv50_sor_power_wait(device, soff); + nvkm_mask(device, 0x61c004 + soff, field, state); + nv50_sor_power_wait(device, soff); + nvkm_msec(device, 2000, if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000)) break; ); - return 0; } -static const struct nvkm_output_func -nv50_sor_output_func = { +void +nv50_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 coff = sor->id * 8 + (state == &sor->arm) * 4; + u32 ctrl = nvkm_rd32(device, 0x610b70 + coff); + + state->proto_evo = (ctrl & 0x00000f00) >> 8; + switch (state->proto_evo) { + case 0: state->proto = LVDS; state->link = 1; break; + case 1: state->proto = TMDS; state->link = 1; break; + case 2: state->proto = TMDS; state->link = 2; break; + case 5: state->proto = TMDS; state->link = 3; break; + default: + state->proto = UNKNOWN; + break; + } + + state->head = ctrl & 0x00000003; +} + +int +nv50_sor_new_(const struct nvkm_ior_func *func, struct nvkm_disp *disp, int id) +{ + struct nvkm_device *device = disp->engine.subdev.device; + if (!(nvkm_rd32(device, 0x610184) & (0x01000000 << id))) + return 0; + return nvkm_ior_new_(func, disp, SOR, id); +} + +static const struct nvkm_ior_func +nv50_sor = { + .state = nv50_sor_state, + .power = nv50_sor_power, + .clock = nv50_sor_clock, }; int -nv50_sor_output_new(struct nvkm_disp *disp, int index, - struct dcb_output *dcbE, struct nvkm_output **poutp) +nv50_sor_new(struct nvkm_disp *disp, int id) { - return nvkm_output_new_(&nv50_sor_output_func, disp, - index, dcbE, poutp); + return nv50_sor_new_(&nv50_sor, disp, id); } |