These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / nouveau / nvkm / subdev / mxm / nv50.c
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         case 0x07: /* DP internal, wtf is this?? HP8670w */
163                 ctx.outp[1] |= 0x00000004; /* use_power_scripts? */
164                 type = DCB_CONNECTOR_eDP;
165                 break;
166         default:
167                 break;
168         }
169
170         if (mxms_version(mxm) >= 0x0300)
171                 conn[0] = type;
172
173         return 0;
174 }
175
176 static bool
177 mxm_show_unmatched(struct nvkm_mxm *mxm, u8 *data, void *info)
178 {
179         struct nvkm_subdev *subdev = &mxm->subdev;
180         u64 desc = *(u64 *)data;
181         if ((desc & 0xf0) != 0xf0)
182                 nvkm_info(subdev, "unmatched output device %016llx\n", desc);
183         return true;
184 }
185
186 static void
187 mxm_dcb_sanitise(struct nvkm_mxm *mxm)
188 {
189         struct nvkm_subdev *subdev = &mxm->subdev;
190         struct nvkm_bios *bios = subdev->device->bios;
191         u8  ver, hdr, cnt, len;
192         u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len);
193         if (dcb == 0x0000 || ver != 0x40) {
194                 nvkm_debug(subdev, "unsupported DCB version\n");
195                 return;
196         }
197
198         dcb_outp_foreach(bios, mxm, mxm_dcb_sanitise_entry);
199         mxms_foreach(mxm, 0x01, mxm_show_unmatched, NULL);
200 }
201
202 int
203 nv50_mxm_new(struct nvkm_device *device, int index, struct nvkm_subdev **pmxm)
204 {
205         struct nvkm_mxm *mxm;
206         int ret;
207
208         ret = nvkm_mxm_new_(device, index, &mxm);
209         if (mxm)
210                 *pmxm = &mxm->subdev;
211         if (ret)
212                 return ret;
213
214         if (mxm->action & MXM_SANITISE_DCB)
215                 mxm_dcb_sanitise(mxm);
216
217         return 0;
218 }