diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c | 163 |
1 files changed, 83 insertions, 80 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index 6c532eadba17..99b3b9050635 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -21,111 +21,114 @@ * * Authors: Ben Skeggs */ -#include "outpdp.h" -#include "nv50.h" +#include "ior.h" +#include "head.h" -#include <core/client.h> #include <subdev/i2c.h> #include <subdev/timer.h> -#include <nvif/cl5070.h> -#include <nvif/unpack.h> - -int -nv50_pior_power(NV50_DISP_MTHD_V1) +static void +nv50_pior_clock(struct nvkm_ior *pior) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = outp->or * 0x800; - union { - struct nv50_disp_pior_pwr_v0 v0; - } *args = data; - u32 ctrl, type; - int ret = -ENOSYS; + struct nvkm_device *device = pior->disp->engine.subdev.device; + const u32 poff = nv50_ior_base(pior); + nvkm_mask(device, 0x614380 + poff, 0x00000707, 0x00000001); +} - nvif_ioctl(object, "disp pior pwr size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n", - args->v0.version, args->v0.state, args->v0.type); - if (args->v0.type > 0x0f) - return -EINVAL; - ctrl = !!args->v0.state; - type = args->v0.type; - } else +static int +nv50_pior_dp_links(struct nvkm_ior *pior, struct nvkm_i2c_aux *aux) +{ + int ret = nvkm_i2c_aux_lnk_ctl(aux, pior->dp.nr, pior->dp.bw, + pior->dp.ef); + if (ret) return ret; + return 1; +} +static void +nv50_pior_power_wait(struct nvkm_device *device, u32 poff) +{ nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) - break; - ); - nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) + if (!(nvkm_rd32(device, 0x61e004 + poff) & 0x80000000)) break; ); - disp->pior.type[outp->or] = type; - return 0; } -/****************************************************************************** - * TMDS - *****************************************************************************/ -static const struct nvkm_output_func -nv50_pior_output_func = { -}; - -int -nv50_pior_output_new(struct nvkm_disp *disp, int index, - struct dcb_output *dcbE, struct nvkm_output **poutp) +static void +nv50_pior_power(struct nvkm_ior *pior, bool normal, bool pu, + bool data, bool vsync, bool hsync) { - return nvkm_output_new_(&nv50_pior_output_func, disp, - index, dcbE, poutp); -} + struct nvkm_device *device = pior->disp->engine.subdev.device; + const u32 poff = nv50_ior_base(pior); + const u32 shift = normal ? 0 : 16; + const u32 state = 0x80000000 | (0x00000001 * !!pu) << shift; + const u32 field = 0x80000000 | (0x00000101 << shift); -/****************************************************************************** - * DisplayPort - *****************************************************************************/ -static int -nv50_pior_output_dp_pattern(struct nvkm_output_dp *outp, int pattern) -{ - return 0; + nv50_pior_power_wait(device, poff); + nvkm_mask(device, 0x61e004 + poff, field, state); + nv50_pior_power_wait(device, poff); } -static int -nv50_pior_output_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) +void +nv50_pior_depth(struct nvkm_ior *ior, struct nvkm_ior_state *state, u32 ctrl) { - return 0; + /* GF119 moves this information to per-head methods, which is + * a lot more convenient, and where our shared code expect it. + */ + if (state->head && state == &ior->asy) { + struct nvkm_head *head = + nvkm_head_find(ior->disp, __ffs(state->head)); + if (!WARN_ON(!head)) { + struct nvkm_head_state *state = &head->asy; + switch ((ctrl & 0x000f0000) >> 16) { + case 6: state->or.depth = 30; break; + case 5: state->or.depth = 24; break; + case 2: state->or.depth = 18; break; + case 0: state->or.depth = 18; break; /*XXX*/ + default: + state->or.depth = 18; + WARN_ON(1); + break; + } + } + } } -static int -nv50_pior_output_dp_lnk_ctl(struct nvkm_output_dp *outp, - int nr, int bw, bool ef) +static void +nv50_pior_state(struct nvkm_ior *pior, struct nvkm_ior_state *state) { - int ret = nvkm_i2c_aux_lnk_ctl(outp->aux, nr, bw, ef); - if (ret) - return ret; - return 1; + struct nvkm_device *device = pior->disp->engine.subdev.device; + const u32 coff = pior->id * 8 + (state == &pior->arm) * 4; + u32 ctrl = nvkm_rd32(device, 0x610b80 + coff); + + state->proto_evo = (ctrl & 0x00000f00) >> 8; + state->rgdiv = 1; + switch (state->proto_evo) { + case 0: state->proto = TMDS; break; + default: + state->proto = UNKNOWN; + break; + } + + state->head = ctrl & 0x00000003; + nv50_pior_depth(pior, state, ctrl); } -static const struct nvkm_output_dp_func -nv50_pior_output_dp_func = { - .pattern = nv50_pior_output_dp_pattern, - .lnk_pwr = nv50_pior_output_dp_lnk_pwr, - .lnk_ctl = nv50_pior_output_dp_lnk_ctl, +static const struct nvkm_ior_func +nv50_pior = { + .state = nv50_pior_state, + .power = nv50_pior_power, + .clock = nv50_pior_clock, + .dp = { + .links = nv50_pior_dp_links, + }, }; int -nv50_pior_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, - struct nvkm_output **poutp) +nv50_pior_new(struct nvkm_disp *disp, int id) { - struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; - struct nvkm_i2c_aux *aux = - nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbE->extdev)); - struct nvkm_output_dp *outp; - - if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL))) - return -ENOMEM; - *poutp = &outp->base; - - return nvkm_output_dp_ctor(&nv50_pior_output_dp_func, disp, - index, dcbE, aux, outp); + struct nvkm_device *device = disp->engine.subdev.device; + if (!(nvkm_rd32(device, 0x610184) & (0x10000000 << id))) + return 0; + return nvkm_ior_new_(&nv50_pior, disp, PIOR, id); } |