linux/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c
<<
>>
Prefs
   1/*
   2 * Copyright 2012 Red Hat Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Authors: Ben Skeggs
  23 */
  24#include "nv50.h"
  25#include "outpdp.h"
  26
  27static inline u32
  28gf119_sor_soff(struct nvkm_output_dp *outp)
  29{
  30        return (ffs(outp->base.info.or) - 1) * 0x800;
  31}
  32
  33static inline u32
  34gf119_sor_loff(struct nvkm_output_dp *outp)
  35{
  36        return gf119_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
  37}
  38
  39static int
  40gf119_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
  41{
  42        struct nvkm_device *device = outp->base.disp->engine.subdev.device;
  43        const u32 loff = gf119_sor_loff(outp);
  44        nvkm_mask(device, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
  45        return 0;
  46}
  47
  48int
  49gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
  50{
  51        struct nvkm_device *device = outp->base.disp->engine.subdev.device;
  52        const u32 soff = gf119_sor_soff(outp);
  53        const u32 loff = gf119_sor_loff(outp);
  54        u32 dpctrl = 0x00000000;
  55        u32 clksor = 0x00000000;
  56
  57        clksor |= bw << 18;
  58        dpctrl |= ((1 << nr) - 1) << 16;
  59        if (ef)
  60                dpctrl |= 0x00004000;
  61
  62        nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor);
  63        nvkm_mask(device, 0x61c10c + loff, 0x001f4000, dpctrl);
  64        return 0;
  65}
  66
  67static int
  68gf119_sor_dp_drv_ctl(struct nvkm_output_dp *outp,
  69                     int ln, int vs, int pe, int pc)
  70{
  71        struct nvkm_device *device = outp->base.disp->engine.subdev.device;
  72        struct nvkm_bios *bios = device->bios;
  73        const u32 shift = g94_sor_dp_lane_map(device, ln);
  74        const u32 loff = gf119_sor_loff(outp);
  75        u32 addr, data[4];
  76        u8  ver, hdr, cnt, len;
  77        struct nvbios_dpout info;
  78        struct nvbios_dpcfg ocfg;
  79
  80        addr = nvbios_dpout_match(bios, outp->base.info.hasht,
  81                                        outp->base.info.hashm,
  82                                  &ver, &hdr, &cnt, &len, &info);
  83        if (!addr)
  84                return -ENODEV;
  85
  86        addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
  87                                  &ver, &hdr, &cnt, &len, &ocfg);
  88        if (!addr)
  89                return -EINVAL;
  90
  91        data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift);
  92        data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift);
  93        data[2] = nvkm_rd32(device, 0x61c130 + loff);
  94        if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
  95                data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
  96        nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
  97        nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
  98        nvkm_wr32(device, 0x61c130 + loff, data[2]);
  99        data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift);
 100        nvkm_wr32(device, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
 101        return 0;
 102}
 103
 104static const struct nvkm_output_dp_func
 105gf119_sor_dp_func = {
 106        .pattern = gf119_sor_dp_pattern,
 107        .lnk_pwr = g94_sor_dp_lnk_pwr,
 108        .lnk_ctl = gf119_sor_dp_lnk_ctl,
 109        .drv_ctl = gf119_sor_dp_drv_ctl,
 110};
 111
 112int
 113gf119_sor_dp_new(struct nvkm_disp *disp, int index,
 114                 struct dcb_output *dcbE, struct nvkm_output **poutp)
 115{
 116        return nvkm_output_dp_new_(&gf119_sor_dp_func, disp, index, dcbE, poutp);
 117}
 118