root/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mxm_match_tmds_partner
  2. mxm_match_dcb
  3. mxm_dcb_sanitise_entry
  4. mxm_show_unmatched
  5. mxm_dcb_sanitise
  6. nv50_mxm_new

   1 /*
   2  * Copyright 2011 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 "mxms.h"
  25 
  26 #include <subdev/bios.h>
  27 #include <subdev/bios/conn.h>
  28 #include <subdev/bios/dcb.h>
  29 #include <subdev/bios/mxm.h>
  30 
  31 struct context {
  32         u32 *outp;
  33         struct mxms_odev desc;
  34 };
  35 
  36 static bool
  37 mxm_match_tmds_partner(struct nvkm_mxm *mxm, u8 *data, void *info)
  38 {
  39         struct context *ctx = info;
  40         struct mxms_odev desc;
  41 
  42         mxms_output_device(mxm, data, &desc);
  43         if (desc.outp_type == 2 &&
  44             desc.dig_conn == ctx->desc.dig_conn)
  45                 return false;
  46         return true;
  47 }
  48 
  49 static bool
  50 mxm_match_dcb(struct nvkm_mxm *mxm, u8 *data, void *info)
  51 {
  52         struct nvkm_bios *bios = mxm->subdev.device->bios;
  53         struct context *ctx = info;
  54         u64 desc = *(u64 *)data;
  55 
  56         mxms_output_device(mxm, data, &ctx->desc);
  57 
  58         /* match dcb encoder type to mxm-ods device type */
  59         if ((ctx->outp[0] & 0x0000000f) != ctx->desc.outp_type)
  60                 return true;
  61 
  62         /* digital output, have some extra stuff to match here, there's a
  63          * table in the vbios that provides a mapping from the mxm digital
  64          * connection enum values to SOR/link
  65          */
  66         if ((desc & 0x00000000000000f0) >= 0x20) {
  67                 /* check against sor index */
  68                 u8 link = mxm_sor_map(bios, ctx->desc.dig_conn);
  69                 if ((ctx->outp[0] & 0x0f000000) != (link & 0x0f) << 24)
  70                         return true;
  71 
  72                 /* check dcb entry has a compatible link field */
  73                 link = (link & 0x30) >> 4;
  74                 if ((link & ((ctx->outp[1] & 0x00000030) >> 4)) != link)
  75                         return true;
  76         }
  77 
  78         /* mark this descriptor accounted for by setting invalid device type,
  79          * except of course some manufactures don't follow specs properly and
  80          * we need to avoid killing off the TMDS function on DP connectors
  81          * if MXM-SIS is missing an entry for it.
  82          */
  83         data[0] &= ~0xf0;
  84         if (ctx->desc.outp_type == 6 && ctx->desc.conn_type == 6 &&
  85             mxms_foreach(mxm, 0x01, mxm_match_tmds_partner, ctx)) {
  86                 data[0] |= 0x20; /* modify descriptor to match TMDS now */
  87         } else {
  88                 data[0] |= 0xf0;
  89         }
  90 
  91         return false;
  92 }
  93 
  94 static int
  95 mxm_dcb_sanitise_entry(struct nvkm_bios *bios, void *data, int idx, u16 pdcb)
  96 {
  97         struct nvkm_mxm *mxm = data;
  98         struct context ctx = { .outp = (u32 *)(bios->data + pdcb) };
  99         u8 type, i2cidx, link, ver, len;
 100         u8 *conn;
 101 
 102         /* look for an output device structure that matches this dcb entry.
 103          * if one isn't found, disable it.
 104          */
 105         if (mxms_foreach(mxm, 0x01, mxm_match_dcb, &ctx)) {
 106                 nvkm_debug(&mxm->subdev, "disable %d: %08x %08x\n",
 107                            idx, ctx.outp[0], ctx.outp[1]);
 108                 ctx.outp[0] |= 0x0000000f;
 109                 return 0;
 110         }
 111 
 112         /* modify the output's ddc/aux port, there's a pointer to a table
 113          * with the mapping from mxm ddc/aux port to dcb i2c_index in the
 114          * vbios mxm table
 115          */
 116         i2cidx = mxm_ddc_map(bios, ctx.desc.ddc_port);
 117         if ((ctx.outp[0] & 0x0000000f) != DCB_OUTPUT_DP)
 118                 i2cidx = (i2cidx & 0x0f) << 4;
 119         else
 120                 i2cidx = (i2cidx & 0xf0);
 121 
 122         if (i2cidx != 0xf0) {
 123                 ctx.outp[0] &= ~0x000000f0;
 124                 ctx.outp[0] |= i2cidx;
 125         }
 126 
 127         /* override dcb sorconf.link, based on what mxm data says */
 128         switch (ctx.desc.outp_type) {
 129         case 0x00: /* Analog CRT */
 130         case 0x01: /* Analog TV/HDTV */
 131                 break;
 132         default:
 133                 link = mxm_sor_map(bios, ctx.desc.dig_conn) & 0x30;
 134                 ctx.outp[1] &= ~0x00000030;
 135                 ctx.outp[1] |= link;
 136                 break;
 137         }
 138 
 139         /* we may need to fixup various other vbios tables based on what
 140          * the descriptor says the connector type should be.
 141          *
 142          * in a lot of cases, the vbios tables will claim DVI-I is possible,
 143          * and the mxm data says the connector is really HDMI.  another
 144          * common example is DP->eDP.
 145          */
 146         conn  = bios->data;
 147         conn += nvbios_connEe(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len);
 148         type  = conn[0];
 149         switch (ctx.desc.conn_type) {
 150         case 0x01: /* LVDS */
 151                 ctx.outp[1] |= 0x00000004; /* use_power_scripts */
 152                 /* XXX: modify default link width in LVDS table */
 153                 break;
 154         case 0x02: /* HDMI */
 155                 type = DCB_CONNECTOR_HDMI_1;
 156                 break;
 157         case 0x03: /* DVI-D */
 158                 type = DCB_CONNECTOR_DVI_D;
 159                 break;
 160         case 0x0e: /* eDP, falls through to DPint */
 161                 ctx.outp[1] |= 0x00010000;
 162                 /* fall through */
 163         case 0x07: /* DP internal, wtf is this?? HP8670w */
 164                 ctx.outp[1] |= 0x00000004; /* use_power_scripts? */
 165                 type = DCB_CONNECTOR_eDP;
 166                 break;
 167         default:
 168                 break;
 169         }
 170 
 171         if (mxms_version(mxm) >= 0x0300)
 172                 conn[0] = type;
 173 
 174         return 0;
 175 }
 176 
 177 static bool
 178 mxm_show_unmatched(struct nvkm_mxm *mxm, u8 *data, void *info)
 179 {
 180         struct nvkm_subdev *subdev = &mxm->subdev;
 181         u64 desc = *(u64 *)data;
 182         if ((desc & 0xf0) != 0xf0)
 183                 nvkm_info(subdev, "unmatched output device %016llx\n", desc);
 184         return true;
 185 }
 186 
 187 static void
 188 mxm_dcb_sanitise(struct nvkm_mxm *mxm)
 189 {
 190         struct nvkm_subdev *subdev = &mxm->subdev;
 191         struct nvkm_bios *bios = subdev->device->bios;
 192         u8  ver, hdr, cnt, len;
 193         u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len);
 194         if (dcb == 0x0000 || (ver != 0x40 && ver != 0x41)) {
 195                 nvkm_warn(subdev, "unsupported DCB version\n");
 196                 return;
 197         }
 198 
 199         dcb_outp_foreach(bios, mxm, mxm_dcb_sanitise_entry);
 200         mxms_foreach(mxm, 0x01, mxm_show_unmatched, NULL);
 201 }
 202 
 203 int
 204 nv50_mxm_new(struct nvkm_device *device, int index, struct nvkm_subdev **pmxm)
 205 {
 206         struct nvkm_mxm *mxm;
 207         int ret;
 208 
 209         ret = nvkm_mxm_new_(device, index, &mxm);
 210         if (mxm)
 211                 *pmxm = &mxm->subdev;
 212         if (ret)
 213                 return ret;
 214 
 215         if (mxm->action & MXM_SANITISE_DCB)
 216                 mxm_dcb_sanitise(mxm);
 217 
 218         return 0;
 219 }

/* [<][>][^][v][top][bottom][index][help] */