brintos

brintos / linux-shallow public Read only

0
0
Text · 6.2 KiB · f316790 Raw
221 lines · c
1/*2 * Copyright 2011 Red Hat Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * 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 OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: Ben Skeggs23 */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 31struct context {32	u32 *outp;33	struct mxms_odev desc;34};35 36static bool37mxm_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 49static bool50mxm_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 a63	 * table in the vbios that provides a mapping from the mxm digital64	 * connection enum values to SOR/link65	 */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 and80	 * we need to avoid killing off the TMDS function on DP connectors81	 * 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 94static int95mxm_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 table113	 * with the mapping from mxm ddc/aux port to dcb i2c_index in the114	 * vbios mxm table115	 */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	else120		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 what140	 * 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.  another144	 * 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		fallthrough;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 177static bool178mxm_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 187static void188mxm_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 203int204nv50_mxm_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,205	     struct nvkm_subdev **pmxm)206{207	struct nvkm_mxm *mxm;208	int ret;209 210	ret = nvkm_mxm_new_(device, type, inst, &mxm);211	if (mxm)212		*pmxm = &mxm->subdev;213	if (ret)214		return ret;215 216	if (mxm->action & MXM_SANITISE_DCB)217		mxm_dcb_sanitise(mxm);218 219	return 0;220}221