0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include "mxms.h"
0025
0026 #include <subdev/bios.h>
0027 #include <subdev/bios/conn.h>
0028 #include <subdev/bios/dcb.h>
0029 #include <subdev/bios/mxm.h>
0030
0031 struct context {
0032 u32 *outp;
0033 struct mxms_odev desc;
0034 };
0035
0036 static bool
0037 mxm_match_tmds_partner(struct nvkm_mxm *mxm, u8 *data, void *info)
0038 {
0039 struct context *ctx = info;
0040 struct mxms_odev desc;
0041
0042 mxms_output_device(mxm, data, &desc);
0043 if (desc.outp_type == 2 &&
0044 desc.dig_conn == ctx->desc.dig_conn)
0045 return false;
0046 return true;
0047 }
0048
0049 static bool
0050 mxm_match_dcb(struct nvkm_mxm *mxm, u8 *data, void *info)
0051 {
0052 struct nvkm_bios *bios = mxm->subdev.device->bios;
0053 struct context *ctx = info;
0054 u64 desc = *(u64 *)data;
0055
0056 mxms_output_device(mxm, data, &ctx->desc);
0057
0058
0059 if ((ctx->outp[0] & 0x0000000f) != ctx->desc.outp_type)
0060 return true;
0061
0062
0063
0064
0065
0066 if ((desc & 0x00000000000000f0) >= 0x20) {
0067
0068 u8 link = mxm_sor_map(bios, ctx->desc.dig_conn);
0069 if ((ctx->outp[0] & 0x0f000000) != (link & 0x0f) << 24)
0070 return true;
0071
0072
0073 link = (link & 0x30) >> 4;
0074 if ((link & ((ctx->outp[1] & 0x00000030) >> 4)) != link)
0075 return true;
0076 }
0077
0078
0079
0080
0081
0082
0083 data[0] &= ~0xf0;
0084 if (ctx->desc.outp_type == 6 && ctx->desc.conn_type == 6 &&
0085 mxms_foreach(mxm, 0x01, mxm_match_tmds_partner, ctx)) {
0086 data[0] |= 0x20;
0087 } else {
0088 data[0] |= 0xf0;
0089 }
0090
0091 return false;
0092 }
0093
0094 static int
0095 mxm_dcb_sanitise_entry(struct nvkm_bios *bios, void *data, int idx, u16 pdcb)
0096 {
0097 struct nvkm_mxm *mxm = data;
0098 struct context ctx = { .outp = (u32 *)(bios->data + pdcb) };
0099 u8 type, i2cidx, link, ver, len;
0100 u8 *conn;
0101
0102
0103
0104
0105 if (mxms_foreach(mxm, 0x01, mxm_match_dcb, &ctx)) {
0106 nvkm_debug(&mxm->subdev, "disable %d: %08x %08x\n",
0107 idx, ctx.outp[0], ctx.outp[1]);
0108 ctx.outp[0] |= 0x0000000f;
0109 return 0;
0110 }
0111
0112
0113
0114
0115
0116 i2cidx = mxm_ddc_map(bios, ctx.desc.ddc_port);
0117 if ((ctx.outp[0] & 0x0000000f) != DCB_OUTPUT_DP)
0118 i2cidx = (i2cidx & 0x0f) << 4;
0119 else
0120 i2cidx = (i2cidx & 0xf0);
0121
0122 if (i2cidx != 0xf0) {
0123 ctx.outp[0] &= ~0x000000f0;
0124 ctx.outp[0] |= i2cidx;
0125 }
0126
0127
0128 switch (ctx.desc.outp_type) {
0129 case 0x00:
0130 case 0x01:
0131 break;
0132 default:
0133 link = mxm_sor_map(bios, ctx.desc.dig_conn) & 0x30;
0134 ctx.outp[1] &= ~0x00000030;
0135 ctx.outp[1] |= link;
0136 break;
0137 }
0138
0139
0140
0141
0142
0143
0144
0145
0146 conn = bios->data;
0147 conn += nvbios_connEe(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len);
0148 type = conn[0];
0149 switch (ctx.desc.conn_type) {
0150 case 0x01:
0151 ctx.outp[1] |= 0x00000004;
0152
0153 break;
0154 case 0x02:
0155 type = DCB_CONNECTOR_HDMI_1;
0156 break;
0157 case 0x03:
0158 type = DCB_CONNECTOR_DVI_D;
0159 break;
0160 case 0x0e:
0161 ctx.outp[1] |= 0x00010000;
0162 fallthrough;
0163 case 0x07:
0164 ctx.outp[1] |= 0x00000004;
0165 type = DCB_CONNECTOR_eDP;
0166 break;
0167 default:
0168 break;
0169 }
0170
0171 if (mxms_version(mxm) >= 0x0300)
0172 conn[0] = type;
0173
0174 return 0;
0175 }
0176
0177 static bool
0178 mxm_show_unmatched(struct nvkm_mxm *mxm, u8 *data, void *info)
0179 {
0180 struct nvkm_subdev *subdev = &mxm->subdev;
0181 u64 desc = *(u64 *)data;
0182 if ((desc & 0xf0) != 0xf0)
0183 nvkm_info(subdev, "unmatched output device %016llx\n", desc);
0184 return true;
0185 }
0186
0187 static void
0188 mxm_dcb_sanitise(struct nvkm_mxm *mxm)
0189 {
0190 struct nvkm_subdev *subdev = &mxm->subdev;
0191 struct nvkm_bios *bios = subdev->device->bios;
0192 u8 ver, hdr, cnt, len;
0193 u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len);
0194 if (dcb == 0x0000 || (ver != 0x40 && ver != 0x41)) {
0195 nvkm_warn(subdev, "unsupported DCB version\n");
0196 return;
0197 }
0198
0199 dcb_outp_foreach(bios, mxm, mxm_dcb_sanitise_entry);
0200 mxms_foreach(mxm, 0x01, mxm_show_unmatched, NULL);
0201 }
0202
0203 int
0204 nv50_mxm_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
0205 struct nvkm_subdev **pmxm)
0206 {
0207 struct nvkm_mxm *mxm;
0208 int ret;
0209
0210 ret = nvkm_mxm_new_(device, type, inst, &mxm);
0211 if (mxm)
0212 *pmxm = &mxm->subdev;
0213 if (ret)
0214 return ret;
0215
0216 if (mxm->action & MXM_SANITISE_DCB)
0217 mxm_dcb_sanitise(mxm);
0218
0219 return 0;
0220 }