1b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs/*
2b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * Copyright 2011 Red Hat Inc.
3b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs *
4b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
5b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * copy of this software and associated documentation files (the "Software"),
6b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * to deal in the Software without restriction, including without limitation
7b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * and/or sell copies of the Software, and to permit persons to whom the
9b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * Software is furnished to do so, subject to the following conditions:
10b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs *
11b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * The above copyright notice and this permission notice shall be included in
12b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * all copies or substantial portions of the Software.
13b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs *
14b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * OTHER DEALINGS IN THE SOFTWARE.
21b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs *
22b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * Authors: Ben Skeggs
23b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs */
24b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
2593d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs#include <linux/acpi.h>
2693d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs
27b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs#include "drmP.h"
28b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs#include "nouveau_drv.h"
29b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
30b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs#define MXM_DBG(dev, fmt, args...) NV_DEBUG((dev), "MXM: " fmt, ##args)
31b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs#define MXM_MSG(dev, fmt, args...) NV_INFO((dev), "MXM: " fmt, ##args)
32b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
33b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic u8 *
34b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxms_data(struct drm_device *dev)
35b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
36b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
37b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return dev_priv->mxms;
38b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
39b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
40b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
41b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic u16
42b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxms_version(struct drm_device *dev)
43b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
44b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 *mxms = mxms_data(dev);
45b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u16 version = (mxms[4] << 8) | mxms[5];
46b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	switch (version ) {
47b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	case 0x0200:
48b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	case 0x0201:
49b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	case 0x0300:
50b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return version;
51b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	default:
52b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		break;
53b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
54b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
55b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	MXM_DBG(dev, "unknown version %d.%d\n", mxms[4], mxms[5]);
56b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return 0x0000;
57b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
58b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
59b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic u16
60b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxms_headerlen(struct drm_device *dev)
61b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
62b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return 8;
63b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
64b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
65b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic u16
66b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxms_structlen(struct drm_device *dev)
67b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
68b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return *(u16 *)&mxms_data(dev)[6];
69b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
70b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
71b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic bool
72b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxms_checksum(struct drm_device *dev)
73b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
74b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u16 size = mxms_headerlen(dev) + mxms_structlen(dev);
75b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 *mxms = mxms_data(dev), sum = 0;
76b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	while (size--)
77b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		sum += *mxms++;
78b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (sum) {
79b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		MXM_DBG(dev, "checksum invalid\n");
80b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return false;
81b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
82b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return true;
83b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
84b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
85b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic bool
86b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxms_valid(struct drm_device *dev)
87b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
88b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 *mxms = mxms_data(dev);
89b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (*(u32 *)mxms != 0x5f4d584d) {
90b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		MXM_DBG(dev, "signature invalid\n");
91b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return false;
92b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
93b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
94b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (!mxms_version(dev) || !mxms_checksum(dev))
95b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return false;
96b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
97b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return true;
98b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
99b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
100b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic bool
101b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxms_foreach(struct drm_device *dev, u8 types,
102b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	     bool (*exec)(struct drm_device *, u8 *, void *), void *info)
103b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
104b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 *mxms = mxms_data(dev);
105b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 *desc = mxms + mxms_headerlen(dev);
106b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 *fini = desc + mxms_structlen(dev) - 1;
107b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	while (desc < fini) {
108b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		u8 type = desc[0] & 0x0f;
109b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		u8 headerlen = 0;
110b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		u8 recordlen = 0;
111b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		u8 entries = 0;
112b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
113b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		switch (type) {
114b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		case 0: /* Output Device Structure */
115b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			if (mxms_version(dev) >= 0x0300)
116b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				headerlen = 8;
117b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			else
118b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				headerlen = 6;
119b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			break;
120b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		case 1: /* System Cooling Capability Structure */
121b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		case 2: /* Thermal Structure */
122b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		case 3: /* Input Power Structure */
123b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			headerlen = 4;
124b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			break;
125b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		case 4: /* GPIO Device Structure */
126b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			headerlen = 4;
127b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			recordlen = 2;
128b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			entries   = (ROM32(desc[0]) & 0x01f00000) >> 20;
129b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			break;
130b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		case 5: /* Vendor Specific Structure */
131b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			headerlen = 8;
132b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			break;
133b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		case 6: /* Backlight Control Structure */
134b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			if (mxms_version(dev) >= 0x0300) {
135b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				headerlen = 4;
136b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				recordlen = 8;
137b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				entries   = (desc[1] & 0xf0) >> 4;
138b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			} else {
139b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				headerlen = 8;
140b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			}
141b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			break;
142b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		case 7: /* Fan Control Structure */
143b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			headerlen = 8;
144b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			recordlen = 4;
145b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			entries   = desc[1] & 0x07;
146b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			break;
147b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		default:
148b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			MXM_DBG(dev, "unknown descriptor type %d\n", type);
149b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			return false;
150b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		}
151b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
152b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		if ((drm_debug & DRM_UT_DRIVER) && (exec == NULL)) {
153b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			static const char * mxms_desc_name[] = {
154b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				"ODS", "SCCS", "TS", "IPS",
155b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				"GSD", "VSS", "BCS", "FCS",
156b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			};
157b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			u8 *dump = desc;
158b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			int i, j;
159b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
160b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			MXM_DBG(dev, "%4s: ", mxms_desc_name[type]);
161b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			for (j = headerlen - 1; j >= 0; j--)
162b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				printk("%02x", dump[j]);
163b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			printk("\n");
164b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			dump += headerlen;
165b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
166b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			for (i = 0; i < entries; i++, dump += recordlen) {
167b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				MXM_DBG(dev, "      ");
168b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				for (j = recordlen - 1; j >= 0; j--)
169b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs					printk("%02x", dump[j]);
170b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				printk("\n");
171b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			}
172b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		}
173b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
174b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		if (types & (1 << type)) {
175b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			if (!exec(dev, desc, info))
176b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				return false;
177b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		}
178b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
179b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		desc += headerlen + (entries * recordlen);
180b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
181b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
182b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return true;
183b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
184b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
185b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic u8 *
186b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxm_table(struct drm_device *dev, u8 *size)
187b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
188b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	struct bit_entry x;
189b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
190b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (bit_table(dev, 'x', &x)) {
191b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		MXM_DBG(dev, "BIT 'x' table not present\n");
192b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return NULL;
193b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
194b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
195b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (x.version != 1 || x.length < 3) {
196b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		MXM_MSG(dev, "BIT x table %d/%d unknown\n",
197b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			x.version, x.length);
198b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return NULL;
199b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
200b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
201b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	*size = x.length;
202b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return x.data;
203b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
204b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
205b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs/* These map MXM v2.x digital connection values to the appropriate SOR/link,
206b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * hopefully they're correct for all boards within the same chipset...
207b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs *
208b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs * MXM v3.x VBIOS are nicer and provide pointers to these tables.
209b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs */
210b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic u8 nv84_sor_map[16] = {
211b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31,
212b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
213b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs};
214b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
215b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic u8 nv92_sor_map[16] = {
216b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31,
217b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
218b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs};
219b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
220b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic u8 nv94_sor_map[16] = {
221b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	0x00, 0x14, 0x24, 0x11, 0x34, 0x31, 0x11, 0x31,
222b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	0x11, 0x31, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00
223b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs};
224b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
225b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic u8 nv96_sor_map[16] = {
226b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	0x00, 0x14, 0x24, 0x00, 0x34, 0x00, 0x11, 0x31,
227b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	0x11, 0x31, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00
228b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs};
229b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
230b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic u8 nv98_sor_map[16] = {
231b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	0x00, 0x14, 0x12, 0x11, 0x00, 0x31, 0x11, 0x31,
232b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
233b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs};
234b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
235b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic u8
236b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxm_sor_map(struct drm_device *dev, u8 conn)
237b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
238b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
239b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 len, *mxm = mxm_table(dev, &len);
240b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (mxm && len >= 6) {
241b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		u8 *map = ROMPTR(dev, mxm[4]);
242b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		if (map) {
243b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			if (map[0] == 0x10) {
244b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				if (conn < map[3])
245b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs					return map[map[1] + conn];
246b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				return 0x00;
247b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			}
248b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
249b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			MXM_MSG(dev, "unknown sor map 0x%02x\n", map[0]);
250b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		}
251b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
252b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
253b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (dev_priv->chipset == 0x84 || dev_priv->chipset == 0x86)
254b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return nv84_sor_map[conn];
255b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (dev_priv->chipset == 0x92)
256b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return nv92_sor_map[conn];
257b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (dev_priv->chipset == 0x94)
258b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return nv94_sor_map[conn];
259b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (dev_priv->chipset == 0x96)
260b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return nv96_sor_map[conn];
261b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (dev_priv->chipset == 0x98)
262b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return nv98_sor_map[conn];
263b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
264b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	MXM_MSG(dev, "missing sor map\n");
265b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return 0x00;
266b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
267b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
268b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic u8
269b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxm_ddc_map(struct drm_device *dev, u8 port)
270b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
271b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 len, *mxm = mxm_table(dev, &len);
272b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (mxm && len >= 8) {
273b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		u8 *map = ROMPTR(dev, mxm[6]);
274b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		if (map) {
275b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			if (map[0] == 0x10) {
276b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				if (port < map[3])
277b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs					return map[map[1] + port];
278b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				return 0x00;
279b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			}
280b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
281b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			MXM_MSG(dev, "unknown ddc map 0x%02x\n", map[0]);
282b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		}
283b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
284b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
285b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	/* v2.x: directly write port as dcb i2cidx */
286b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return (port << 4) | port;
287b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
288b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
289b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstruct mxms_odev {
290b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 outp_type;
291b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 conn_type;
292b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 ddc_port;
293b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 dig_conn;
294b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs};
295b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
296b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic void
297b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxms_output_device(struct drm_device *dev, u8 *pdata, struct mxms_odev *desc)
298b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
299b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u64 data = ROM32(pdata[0]);
300b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (mxms_version(dev) >= 0x0300)
301b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		data |= (u64)ROM16(pdata[4]) << 32;
302b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
303b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	desc->outp_type = (data & 0x00000000000000f0ULL) >> 4;
304b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	desc->ddc_port  = (data & 0x0000000000000f00ULL) >> 8;
305b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	desc->conn_type = (data & 0x000000000001f000ULL) >> 12;
306b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	desc->dig_conn  = (data & 0x0000000000780000ULL) >> 19;
307b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
308b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
309b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstruct context {
310b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u32 *outp;
311b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	struct mxms_odev desc;
312b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs};
313b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
314b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic bool
315b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxm_match_tmds_partner(struct drm_device *dev, u8 *data, void *info)
316b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
317b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	struct context *ctx = info;
318b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	struct mxms_odev desc;
319b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
320b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	mxms_output_device(dev, data, &desc);
321b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (desc.outp_type == 2 &&
322b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	    desc.dig_conn == ctx->desc.dig_conn)
323b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return false;
324b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return true;
325b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
326b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
327b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic bool
328b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxm_match_dcb(struct drm_device *dev, u8 *data, void *info)
329b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
330b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	struct context *ctx = info;
331b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u64 desc = *(u64 *)data;
332b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
333b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	mxms_output_device(dev, data, &ctx->desc);
334b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
335b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	/* match dcb encoder type to mxm-ods device type */
336b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if ((ctx->outp[0] & 0x0000000f) != ctx->desc.outp_type)
337b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return true;
338b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
339b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	/* digital output, have some extra stuff to match here, there's a
340b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 * table in the vbios that provides a mapping from the mxm digital
341b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 * connection enum values to SOR/link
342b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 */
343b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if ((desc & 0x00000000000000f0) >= 0x20) {
344b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		/* check against sor index */
345b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		u8 link = mxm_sor_map(dev, ctx->desc.dig_conn);
346b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		if ((ctx->outp[0] & 0x0f000000) != (link & 0x0f) << 24)
347b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			return true;
348b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
349b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		/* check dcb entry has a compatible link field */
350b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		link = (link & 0x30) >> 4;
351b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		if ((link & ((ctx->outp[1] & 0x00000030) >> 4)) != link)
352b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			return true;
353b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
354b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
355b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	/* mark this descriptor accounted for by setting invalid device type,
356b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 * except of course some manufactures don't follow specs properly and
357b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 * we need to avoid killing off the TMDS function on DP connectors
358b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 * if MXM-SIS is missing an entry for it.
359b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 */
360b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	data[0] &= ~0xf0;
361b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (ctx->desc.outp_type == 6 && ctx->desc.conn_type == 6 &&
362b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	    mxms_foreach(dev, 0x01, mxm_match_tmds_partner, ctx)) {
363b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		data[0] |= 0x20; /* modify descriptor to match TMDS now */
364b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	} else {
365b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		data[0] |= 0xf0;
366b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
367b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
368b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return false;
369b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
370b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
371b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic int
372b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxm_dcb_sanitise_entry(struct drm_device *dev, void *data, int idx, u8 *dcbe)
373b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
374b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	struct context ctx = { .outp = (u32 *)dcbe };
375b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 type, i2cidx, link;
376b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 *conn;
377b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
378b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	/* look for an output device structure that matches this dcb entry.
379b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 * if one isn't found, disable it.
380b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 */
381b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (mxms_foreach(dev, 0x01, mxm_match_dcb, &ctx)) {
382b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		MXM_DBG(dev, "disable %d: 0x%08x 0x%08x\n",
383b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			idx, ctx.outp[0], ctx.outp[1]);
384b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		ctx.outp[0] |= 0x0000000f;
385b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return 0;
386b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
387b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
388b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	/* modify the output's ddc/aux port, there's a pointer to a table
389b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 * with the mapping from mxm ddc/aux port to dcb i2c_index in the
390b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 * vbios mxm table
391b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 */
392b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	i2cidx = mxm_ddc_map(dev, ctx.desc.ddc_port);
393b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if ((ctx.outp[0] & 0x0000000f) != OUTPUT_DP)
394b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		i2cidx = (i2cidx & 0x0f) << 4;
395b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	else
396b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		i2cidx = (i2cidx & 0xf0);
397b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
398b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (i2cidx != 0xf0) {
399b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		ctx.outp[0] &= ~0x000000f0;
400b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		ctx.outp[0] |= i2cidx;
401b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
402b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
403b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	/* override dcb sorconf.link, based on what mxm data says */
404b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	switch (ctx.desc.outp_type) {
405b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	case 0x00: /* Analog CRT */
406b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	case 0x01: /* Analog TV/HDTV */
407b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		break;
408b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	default:
409b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		link = mxm_sor_map(dev, ctx.desc.dig_conn) & 0x30;
410b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		ctx.outp[1] &= ~0x00000030;
411b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		ctx.outp[1] |= link;
412b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		break;
413b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
414b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
415b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	/* we may need to fixup various other vbios tables based on what
416b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 * the descriptor says the connector type should be.
417b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 *
418b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 * in a lot of cases, the vbios tables will claim DVI-I is possible,
419b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 * and the mxm data says the connector is really HDMI.  another
420b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 * common example is DP->eDP.
421b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	 */
422b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	conn = dcb_conn(dev, (ctx.outp[0] & 0x0000f000) >> 12);
423b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	type = conn[0];
424b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	switch (ctx.desc.conn_type) {
425b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	case 0x01: /* LVDS */
426b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		ctx.outp[1] |= 0x00000004; /* use_power_scripts */
427b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		/* XXX: modify default link width in LVDS table */
428b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		break;
429b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	case 0x02: /* HDMI */
430b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		type = DCB_CONNECTOR_HDMI_1;
431b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		break;
432b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	case 0x03: /* DVI-D */
433b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		type = DCB_CONNECTOR_DVI_D;
434b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		break;
435b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	case 0x0e: /* eDP, falls through to DPint */
436b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		ctx.outp[1] |= 0x00010000;
437b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	case 0x07: /* DP internal, wtf is this?? HP8670w */
438b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		ctx.outp[1] |= 0x00000004; /* use_power_scripts? */
439b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		type = DCB_CONNECTOR_eDP;
440b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		break;
441b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	default:
442b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		break;
443b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
444b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
445b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (mxms_version(dev) >= 0x0300)
446b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		conn[0] = type;
447b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
448b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return 0;
449b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
450b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
451b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic bool
452b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxm_show_unmatched(struct drm_device *dev, u8 *data, void *info)
453b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
454b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u64 desc = *(u64 *)data;
455b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if ((desc & 0xf0) != 0xf0)
456b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		MXM_MSG(dev, "unmatched output device 0x%016llx\n", desc);
457b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return true;
458b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
459b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
460b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic void
461b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsmxm_dcb_sanitise(struct drm_device *dev)
462b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
463b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 *dcb = dcb_table(dev);
464b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (!dcb || dcb[0] != 0x40) {
465b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		MXM_DBG(dev, "unsupported DCB version\n");
466b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return;
467b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
468b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
469b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	dcb_outp_foreach(dev, NULL, mxm_dcb_sanitise_entry);
470b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	mxms_foreach(dev, 0x01, mxm_show_unmatched, NULL);
471b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
472b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
473b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic bool
474c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggsmxm_shadow_rom_fetch(struct nouveau_i2c_chan *i2c, u8 addr,
475c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs		     u8 offset, u8 size, u8 *data)
476c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs{
477c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	struct i2c_msg msgs[] = {
478c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs		{ .addr = addr, .flags = 0, .len = 1, .buf = &offset },
479c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs		{ .addr = addr, .flags = I2C_M_RD, .len = size, .buf = data, },
480c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	};
481c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs
482c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	return i2c_transfer(&i2c->adapter, msgs, 2) == 2;
483c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs}
484c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs
485c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggsstatic bool
48693d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggsmxm_shadow_rom(struct drm_device *dev, u8 version)
487b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
488c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
489c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	struct nouveau_i2c_chan *i2c = NULL;
490c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	u8 i2cidx, mxms[6], addr, size;
491c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs
492c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	i2cidx = mxm_ddc_map(dev, 1 /* LVDS_DDC */) & 0x0f;
493c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	if (i2cidx < 0x0f)
494c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs		i2c = nouveau_i2c_find(dev, i2cidx);
495c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	if (!i2c)
496c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs		return false;
497c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs
498c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	addr = 0x54;
499c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	if (!mxm_shadow_rom_fetch(i2c, addr, 0, 6, mxms)) {
500c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs		addr = 0x56;
501c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs		if (!mxm_shadow_rom_fetch(i2c, addr, 0, 6, mxms))
502c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs			return false;
503c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	}
504c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs
505c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	dev_priv->mxms = mxms;
506c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	size = mxms_headerlen(dev) + mxms_structlen(dev);
507c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	dev_priv->mxms = kmalloc(size, GFP_KERNEL);
508c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs
509c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	if (dev_priv->mxms &&
510c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	    mxm_shadow_rom_fetch(i2c, addr, 0, size, dev_priv->mxms))
511c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs		return true;
512c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs
513c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	kfree(dev_priv->mxms);
514c37e99050c84c40441e614bd41474e12b6cc2079Ben Skeggs	dev_priv->mxms = NULL;
515b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return false;
516b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
517b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
5183952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs#if defined(CONFIG_ACPI)
519b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic bool
52093d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggsmxm_shadow_dsm(struct drm_device *dev, u8 version)
521b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
5223952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
5233952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	static char muid[] = {
5243952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		0x00, 0xA4, 0x04, 0x40, 0x7D, 0x91, 0xF2, 0x4C,
5253952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65
5263952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	};
5273952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	u32 mxms_args[] = { 0x00000000 };
5283952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	union acpi_object args[4] = {
5293952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		/* _DSM MUID */
5303952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		{ .buffer.type = 3,
5313952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		  .buffer.length = sizeof(muid),
5323952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		  .buffer.pointer = muid,
5333952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		},
5343952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		/* spec says this can be zero to mean "highest revision", but
5353952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		 * of course there's at least one bios out there which fails
5363952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		 * unless you pass in exactly the version it supports..
5373952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		 */
5383952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		{ .integer.type = ACPI_TYPE_INTEGER,
5393952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		  .integer.value = (version & 0xf0) << 4 | (version & 0x0f),
5403952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		},
5413952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		/* MXMS function */
5423952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		{ .integer.type = ACPI_TYPE_INTEGER,
5433952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		  .integer.value = 0x00000010,
5443952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		},
5453952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		/* Pointer to MXMS arguments */
5463952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		{ .buffer.type = ACPI_TYPE_BUFFER,
5473952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		  .buffer.length = sizeof(mxms_args),
5483952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		  .buffer.pointer = (char *)mxms_args,
5493952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		},
5503952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	};
5513952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	struct acpi_object_list list = { ARRAY_SIZE(args), args };
5523952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
5533952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	union acpi_object *obj;
5543952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	acpi_handle handle;
5553952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	int ret;
5563952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs
5573952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
5583952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	if (!handle)
5593952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		return false;
5603952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs
5613952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	ret = acpi_evaluate_object(handle, "_DSM", &list, &retn);
5623952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	if (ret) {
5633952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		MXM_DBG(dev, "DSM MXMS failed: %d\n", ret);
5643952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		return false;
5653952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	}
5663952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs
5673952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	obj = retn.pointer;
5683952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	if (obj->type == ACPI_TYPE_BUFFER) {
5693952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		dev_priv->mxms = kmemdup(obj->buffer.pointer,
5703952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs					 obj->buffer.length, GFP_KERNEL);
5713952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	} else
5723952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	if (obj->type == ACPI_TYPE_INTEGER) {
5733952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs		MXM_DBG(dev, "DSM MXMS returned 0x%llx\n", obj->integer.value);
5743952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	}
5753952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs
5763952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	kfree(obj);
5773952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs	return dev_priv->mxms != NULL;
578b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
5793952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs#endif
580b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
58193d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
58293d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs
58393d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs#define WMI_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
58493d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs
58584ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggsstatic u8
58684ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggswmi_wmmx_mxmi(struct drm_device *dev, u8 version)
58784ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs{
58884ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	u32 mxmi_args[] = { 0x494D584D /* MXMI */, version, 0 };
58984ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	struct acpi_buffer args = { sizeof(mxmi_args), mxmi_args };
59084ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
59184ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	union acpi_object *obj;
59284ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	acpi_status status;
59384ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs
59484ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
59584ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	if (ACPI_FAILURE(status)) {
59684ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs		MXM_DBG(dev, "WMMX MXMI returned %d\n", status);
59784ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs		return 0x00;
59884ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	}
59984ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs
60084ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	obj = retn.pointer;
60184ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	if (obj->type == ACPI_TYPE_INTEGER) {
60284ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs		version = obj->integer.value;
60384ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs		MXM_DBG(dev, "WMMX MXMI version %d.%d\n",
60484ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs			     (version >> 4), version & 0x0f);
60584ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	} else {
60684ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs		version = 0;
60784ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs		MXM_DBG(dev, "WMMX MXMI returned non-integer\n");
60884ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	}
60984ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs
61084ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	kfree(obj);
61184ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	return version;
61284ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs}
61384ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs
61493d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggsstatic bool
61593d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggsmxm_shadow_wmi(struct drm_device *dev, u8 version)
61693d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs{
61793d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
61893d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	u32 mxms_args[] = { 0x534D584D /* MXMS */, version, 0 };
61993d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	struct acpi_buffer args = { sizeof(mxms_args), mxms_args };
62093d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
62193d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	union acpi_object *obj;
62293d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	acpi_status status;
62393d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs
62484ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	if (!wmi_has_guid(WMI_WMMX_GUID)) {
62584ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs		MXM_DBG(dev, "WMMX GUID not found\n");
62684ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs		return false;
62784ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	}
62884ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs
62984ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	mxms_args[1] = wmi_wmmx_mxmi(dev, 0x00);
63084ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	if (!mxms_args[1])
63184ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs		mxms_args[1] = wmi_wmmx_mxmi(dev, version);
63284ddfda6d4765e410981edeef81c9b5a5a1ce87bBen Skeggs	if (!mxms_args[1])
63393d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs		return false;
63493d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs
63593d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
63693d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	if (ACPI_FAILURE(status)) {
63793d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs		MXM_DBG(dev, "WMMX MXMS returned %d\n", status);
63893d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs		return false;
63993d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	}
64093d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs
64193d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	obj = retn.pointer;
64293d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	if (obj->type == ACPI_TYPE_BUFFER) {
64393d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs		dev_priv->mxms = kmemdup(obj->buffer.pointer,
64493d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs					 obj->buffer.length, GFP_KERNEL);
64593d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	}
64693d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs
64793d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	kfree(obj);
64893d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	return dev_priv->mxms != NULL;
64993d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs}
65093d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs#endif
65193d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs
652b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstruct mxm_shadow_h {
653b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	const char *name;
65493d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	bool (*exec)(struct drm_device *, u8 version);
655b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs} _mxm_shadow[] = {
656b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	{ "ROM", mxm_shadow_rom },
6573952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs#if defined(CONFIG_ACPI)
658b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	{ "DSM", mxm_shadow_dsm },
6593952315b9d20fb04d43d184f9c1475327811c5aaBen Skeggs#endif
66093d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
66193d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	{ "WMI", mxm_shadow_wmi },
66293d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs#endif
663b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	{}
664b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs};
665b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
666b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsstatic int
66793d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggsmxm_shadow(struct drm_device *dev, u8 version)
668b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
669b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
670b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	struct mxm_shadow_h *shadow = _mxm_shadow;
671b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	do {
672b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		MXM_DBG(dev, "checking %s\n", shadow->name);
67393d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs		if (shadow->exec(dev, version)) {
674b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			if (mxms_valid(dev))
675b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs				return 0;
676b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			kfree(dev_priv->mxms);
677b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs			dev_priv->mxms = NULL;
678b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		}
679b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	} while ((++shadow)->name);
680b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return -ENOENT;
681b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
682b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
683b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsint
684b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsnouveau_mxm_init(struct drm_device *dev)
685b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
686b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	u8 mxm_size, *mxm = mxm_table(dev, &mxm_size);
687b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (!mxm || !mxm[0]) {
688b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		MXM_MSG(dev, "no VBIOS data, nothing to do\n");
689b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return 0;
690b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
691b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
692b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	MXM_MSG(dev, "BIOS version %d.%d\n", mxm[0] >> 4, mxm[0] & 0x0f);
693b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
69493d9206d08dd18e3aaeed90a3e076b8c323fdd72Ben Skeggs	if (mxm_shadow(dev, mxm[0])) {
695b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		MXM_MSG(dev, "failed to locate valid SIS\n");
696ce2e7895faba8fabaa917f52293126e5f4174fa9Ben Skeggs#if 0
697ce2e7895faba8fabaa917f52293126e5f4174fa9Ben Skeggs		/* we should, perhaps, fall back to some kind of limited
698ce2e7895faba8fabaa917f52293126e5f4174fa9Ben Skeggs		 * mode here if the x86 vbios hasn't already done the
699ce2e7895faba8fabaa917f52293126e5f4174fa9Ben Skeggs		 * work for us (so we prevent loading with completely
700ce2e7895faba8fabaa917f52293126e5f4174fa9Ben Skeggs		 * whacked vbios tables).
701ce2e7895faba8fabaa917f52293126e5f4174fa9Ben Skeggs		 */
702b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		return -EINVAL;
703ce2e7895faba8fabaa917f52293126e5f4174fa9Ben Skeggs#else
704ce2e7895faba8fabaa917f52293126e5f4174fa9Ben Skeggs		return 0;
705ce2e7895faba8fabaa917f52293126e5f4174fa9Ben Skeggs#endif
706b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	}
707b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
708b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	MXM_MSG(dev, "MXMS Version %d.%d\n",
709b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		mxms_version(dev) >> 8, mxms_version(dev) & 0xff);
710b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	mxms_foreach(dev, 0, NULL, NULL);
711b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
712b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	if (nouveau_mxmdcb)
713b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs		mxm_dcb_sanitise(dev);
714b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	return 0;
715b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
716b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs
717b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsvoid
718b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggsnouveau_mxm_fini(struct drm_device *dev)
719b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs{
720b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
721b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	kfree(dev_priv->mxms);
722b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs	dev_priv->mxms = NULL;
723b4c26818aeb4159dd537eff6453ae5ebf7a69723Ben Skeggs}
724