1296548Sdumbbell/*
2296548Sdumbbell *
3296548Sdumbbell * Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter
4296548Sdumbbell *
5296548Sdumbbell * All Rights Reserved.
6296548Sdumbbell *
7296548Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a
8296548Sdumbbell * copy of this software and associated documentation files (the
9296548Sdumbbell * "Software"), to deal in the Software without restriction, including
10296548Sdumbbell * without limitation the rights to use, copy, modify, merge, publish,
11296548Sdumbbell * distribute, sub license, and/or sell copies of the Software, and to
12296548Sdumbbell * permit persons to whom the Software is furnished to do so, subject to
13296548Sdumbbell * the following conditions:
14296548Sdumbbell *
15296548Sdumbbell * The above copyright notice and this permission notice (including the
16296548Sdumbbell * next paragraph) shall be included in all copies or substantial portions
17296548Sdumbbell * of the Software.
18296548Sdumbbell *
19296548Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20296548Sdumbbell * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21296548Sdumbbell * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22296548Sdumbbell * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
23296548Sdumbbell * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24296548Sdumbbell * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25296548Sdumbbell * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26296548Sdumbbell *
27296548Sdumbbell */
28296548Sdumbbell
29296548Sdumbbell#include <sys/cdefs.h>
30296548Sdumbbell__FBSDID("$FreeBSD$");
31296548Sdumbbell
32296548Sdumbbell#include "dvo.h"
33296548Sdumbbell#include "i915_reg.h"
34296548Sdumbbell#include "i915_drv.h"
35296548Sdumbbell
36296548Sdumbbell#define NS2501_VID 0x1305
37296548Sdumbbell#define NS2501_DID 0x6726
38296548Sdumbbell
39296548Sdumbbell#define NS2501_VID_LO 0x00
40296548Sdumbbell#define NS2501_VID_HI 0x01
41296548Sdumbbell#define NS2501_DID_LO 0x02
42296548Sdumbbell#define NS2501_DID_HI 0x03
43296548Sdumbbell#define NS2501_REV 0x04
44296548Sdumbbell#define NS2501_RSVD 0x05
45296548Sdumbbell#define NS2501_FREQ_LO 0x06
46296548Sdumbbell#define NS2501_FREQ_HI 0x07
47296548Sdumbbell
48296548Sdumbbell#define NS2501_REG8 0x08
49296548Sdumbbell#define NS2501_8_VEN (1<<5)
50296548Sdumbbell#define NS2501_8_HEN (1<<4)
51296548Sdumbbell#define NS2501_8_DSEL (1<<3)
52296548Sdumbbell#define NS2501_8_BPAS (1<<2)
53296548Sdumbbell#define NS2501_8_RSVD (1<<1)
54296548Sdumbbell#define NS2501_8_PD (1<<0)
55296548Sdumbbell
56296548Sdumbbell#define NS2501_REG9 0x09
57296548Sdumbbell#define NS2501_9_VLOW (1<<7)
58296548Sdumbbell#define NS2501_9_MSEL_MASK (0x7<<4)
59296548Sdumbbell#define NS2501_9_TSEL (1<<3)
60296548Sdumbbell#define NS2501_9_RSEN (1<<2)
61296548Sdumbbell#define NS2501_9_RSVD (1<<1)
62296548Sdumbbell#define NS2501_9_MDI (1<<0)
63296548Sdumbbell
64296548Sdumbbell#define NS2501_REGC 0x0c
65296548Sdumbbell
66296548Sdumbbellstruct ns2501_priv {
67296548Sdumbbell	//I2CDevRec d;
68296548Sdumbbell	bool quiet;
69296548Sdumbbell	int reg_8_shadow;
70296548Sdumbbell	int reg_8_set;
71296548Sdumbbell	// Shadow registers for i915
72296548Sdumbbell	int dvoc;
73296548Sdumbbell	int pll_a;
74296548Sdumbbell	int srcdim;
75296548Sdumbbell	int fw_blc;
76296548Sdumbbell};
77296548Sdumbbell
78296548Sdumbbell#define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr))
79296548Sdumbbell
80296548Sdumbbell/*
81296548Sdumbbell * For reasons unclear to me, the ns2501 at least on the Fujitsu/Siemens
82296548Sdumbbell * laptops does not react on the i2c bus unless
83296548Sdumbbell * both the PLL is running and the display is configured in its native
84296548Sdumbbell * resolution.
85296548Sdumbbell * This function forces the DVO on, and stores the registers it touches.
86296548Sdumbbell * Afterwards, registers are restored to regular values.
87296548Sdumbbell *
88296548Sdumbbell * This is pretty much a hack, though it works.
89296548Sdumbbell * Without that, ns2501_readb and ns2501_writeb fail
90296548Sdumbbell * when switching the resolution.
91296548Sdumbbell */
92296548Sdumbbell
93296548Sdumbbellstatic void enable_dvo(struct intel_dvo_device *dvo)
94296548Sdumbbell{
95296548Sdumbbell	struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
96296548Sdumbbell	device_t adapter = dvo->i2c_bus;
97296548Sdumbbell	/*
98296548Sdumbbell	 * FIXME Linux<->FreeBSD: device_get_softc() returns a struct
99296548Sdumbbell	 * intel_iic_softc in reality, where struct intel_gmbus is
100296548Sdumbbell	 * the first member. struct intel_iic_softc is defined in
101296548Sdumbbell	 * intel_iic.c.
102296548Sdumbbell	 */
103296548Sdumbbell	struct intel_gmbus *bus =
104296548Sdumbbell	    (struct intel_gmbus *)device_get_softc(adapter);
105296548Sdumbbell	struct drm_i915_private *dev_priv = bus->dev_priv;
106296548Sdumbbell
107296548Sdumbbell	DRM_DEBUG_KMS("%s: Trying to re-enable the DVO\n", __FUNCTION__);
108296548Sdumbbell
109296548Sdumbbell	ns->dvoc = I915_READ(DVO_C);
110296548Sdumbbell	ns->pll_a = I915_READ(_DPLL_A);
111296548Sdumbbell	ns->srcdim = I915_READ(DVOC_SRCDIM);
112296548Sdumbbell	ns->fw_blc = I915_READ(FW_BLC);
113296548Sdumbbell
114296548Sdumbbell	I915_WRITE(DVOC, 0x10004084);
115296548Sdumbbell	I915_WRITE(_DPLL_A, 0xd0820000);
116296548Sdumbbell	I915_WRITE(DVOC_SRCDIM, 0x400300);	// 1024x768
117296548Sdumbbell	I915_WRITE(FW_BLC, 0x1080304);
118296548Sdumbbell
119296548Sdumbbell	I915_WRITE(DVOC, 0x90004084);
120296548Sdumbbell}
121296548Sdumbbell
122296548Sdumbbell/*
123296548Sdumbbell * Restore the I915 registers modified by the above
124296548Sdumbbell * trigger function.
125296548Sdumbbell */
126296548Sdumbbellstatic void restore_dvo(struct intel_dvo_device *dvo)
127296548Sdumbbell{
128296548Sdumbbell	device_t adapter = dvo->i2c_bus;
129296548Sdumbbell	/*
130296548Sdumbbell	 * FIXME Linux<->FreeBSD: device_get_softc() returns a struct
131296548Sdumbbell	 * intel_iic_softc in reality, where struct intel_gmbus is
132296548Sdumbbell	 * the first member. struct intel_iic_softc is defined in
133296548Sdumbbell	 * intel_iic.c.
134296548Sdumbbell	 */
135296548Sdumbbell	struct intel_gmbus *bus =
136296548Sdumbbell	    (struct intel_gmbus *)device_get_softc(adapter);
137296548Sdumbbell	struct drm_i915_private *dev_priv = bus->dev_priv;
138296548Sdumbbell	struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
139296548Sdumbbell
140296548Sdumbbell	I915_WRITE(DVOC, ns->dvoc);
141296548Sdumbbell	I915_WRITE(_DPLL_A, ns->pll_a);
142296548Sdumbbell	I915_WRITE(DVOC_SRCDIM, ns->srcdim);
143296548Sdumbbell	I915_WRITE(FW_BLC, ns->fw_blc);
144296548Sdumbbell}
145296548Sdumbbell
146296548Sdumbbell/*
147296548Sdumbbell** Read a register from the ns2501.
148296548Sdumbbell** Returns true if successful, false otherwise.
149296548Sdumbbell** If it returns false, it might be wise to enable the
150296548Sdumbbell** DVO with the above function.
151296548Sdumbbell*/
152296548Sdumbbellstatic bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch)
153296548Sdumbbell{
154296548Sdumbbell	struct ns2501_priv *ns = dvo->dev_priv;
155296548Sdumbbell	device_t adapter = dvo->i2c_bus;
156296548Sdumbbell	u8 out_buf[2];
157296548Sdumbbell	u8 in_buf[2];
158296548Sdumbbell
159296548Sdumbbell	struct iic_msg msgs[] = {
160296548Sdumbbell		{
161296548Sdumbbell		 .slave = dvo->slave_addr << 1,
162296548Sdumbbell		 .flags = 0,
163296548Sdumbbell		 .len = 1,
164296548Sdumbbell		 .buf = out_buf,
165296548Sdumbbell		 },
166296548Sdumbbell		{
167296548Sdumbbell		 .slave = dvo->slave_addr << 1,
168296548Sdumbbell		 .flags = I2C_M_RD,
169296548Sdumbbell		 .len = 1,
170296548Sdumbbell		 .buf = in_buf,
171296548Sdumbbell		 }
172296548Sdumbbell	};
173296548Sdumbbell
174296548Sdumbbell	out_buf[0] = addr;
175296548Sdumbbell	out_buf[1] = 0;
176296548Sdumbbell
177296548Sdumbbell	if (-iicbus_transfer(adapter, msgs, 2) == 0) {
178296548Sdumbbell		*ch = in_buf[0];
179296548Sdumbbell		return true;
180296548Sdumbbell	}
181296548Sdumbbell
182296548Sdumbbell	if (!ns->quiet) {
183296548Sdumbbell		DRM_DEBUG_KMS
184296548Sdumbbell		    ("Unable to read register 0x%02x from %s:0x%02x.\n", addr,
185296548Sdumbbell		     device_get_nameunit(adapter), dvo->slave_addr);
186296548Sdumbbell	}
187296548Sdumbbell
188296548Sdumbbell	return false;
189296548Sdumbbell}
190296548Sdumbbell
191296548Sdumbbell/*
192296548Sdumbbell** Write a register to the ns2501.
193296548Sdumbbell** Returns true if successful, false otherwise.
194296548Sdumbbell** If it returns false, it might be wise to enable the
195296548Sdumbbell** DVO with the above function.
196296548Sdumbbell*/
197296548Sdumbbellstatic bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
198296548Sdumbbell{
199296548Sdumbbell	struct ns2501_priv *ns = dvo->dev_priv;
200296548Sdumbbell	device_t adapter = dvo->i2c_bus;
201296548Sdumbbell	uint8_t out_buf[2];
202296548Sdumbbell
203296548Sdumbbell	struct iic_msg msg = {
204296548Sdumbbell		.slave = dvo->slave_addr << 1,
205296548Sdumbbell		.flags = 0,
206296548Sdumbbell		.len = 2,
207296548Sdumbbell		.buf = out_buf,
208296548Sdumbbell	};
209296548Sdumbbell
210296548Sdumbbell	out_buf[0] = addr;
211296548Sdumbbell	out_buf[1] = ch;
212296548Sdumbbell
213296548Sdumbbell	if (-iicbus_transfer(adapter, &msg, 1) == 0) {
214296548Sdumbbell		return true;
215296548Sdumbbell	}
216296548Sdumbbell
217296548Sdumbbell	if (!ns->quiet) {
218296548Sdumbbell		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n",
219296548Sdumbbell			      addr, device_get_nameunit(adapter), dvo->slave_addr);
220296548Sdumbbell	}
221296548Sdumbbell
222296548Sdumbbell	return false;
223296548Sdumbbell}
224296548Sdumbbell
225296548Sdumbbell/* National Semiconductor 2501 driver for chip on i2c bus
226296548Sdumbbell * scan for the chip on the bus.
227296548Sdumbbell * Hope the VBIOS initialized the PLL correctly so we can
228296548Sdumbbell * talk to it. If not, it will not be seen and not detected.
229296548Sdumbbell * Bummer!
230296548Sdumbbell */
231296548Sdumbbellstatic bool ns2501_init(struct intel_dvo_device *dvo,
232296548Sdumbbell			device_t adapter)
233296548Sdumbbell{
234296548Sdumbbell	/* this will detect the NS2501 chip on the specified i2c bus */
235296548Sdumbbell	struct ns2501_priv *ns;
236296548Sdumbbell	unsigned char ch;
237296548Sdumbbell
238296548Sdumbbell	ns = malloc(sizeof(struct ns2501_priv), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
239296548Sdumbbell	if (ns == NULL)
240296548Sdumbbell		return false;
241296548Sdumbbell
242296548Sdumbbell	dvo->i2c_bus = adapter;
243296548Sdumbbell	dvo->dev_priv = ns;
244296548Sdumbbell	ns->quiet = true;
245296548Sdumbbell
246296548Sdumbbell	if (!ns2501_readb(dvo, NS2501_VID_LO, &ch))
247296548Sdumbbell		goto out;
248296548Sdumbbell
249296548Sdumbbell	if (ch != (NS2501_VID & 0xff)) {
250296548Sdumbbell		DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
251296548Sdumbbell			      ch, device_get_nameunit(adapter), dvo->slave_addr);
252296548Sdumbbell		goto out;
253296548Sdumbbell	}
254296548Sdumbbell
255296548Sdumbbell	if (!ns2501_readb(dvo, NS2501_DID_LO, &ch))
256296548Sdumbbell		goto out;
257296548Sdumbbell
258296548Sdumbbell	if (ch != (NS2501_DID & 0xff)) {
259296548Sdumbbell		DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
260296548Sdumbbell			      ch, device_get_nameunit(adapter), dvo->slave_addr);
261296548Sdumbbell		goto out;
262296548Sdumbbell	}
263296548Sdumbbell	ns->quiet = false;
264296548Sdumbbell	ns->reg_8_set = 0;
265296548Sdumbbell	ns->reg_8_shadow =
266296548Sdumbbell	    NS2501_8_PD | NS2501_8_BPAS | NS2501_8_VEN | NS2501_8_HEN;
267296548Sdumbbell
268296548Sdumbbell	DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n");
269296548Sdumbbell	return true;
270296548Sdumbbell
271296548Sdumbbellout:
272296548Sdumbbell	free(ns, DRM_MEM_KMS);
273296548Sdumbbell	return false;
274296548Sdumbbell}
275296548Sdumbbell
276296548Sdumbbellstatic enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo)
277296548Sdumbbell{
278296548Sdumbbell	/*
279296548Sdumbbell	 * This is a Laptop display, it doesn't have hotplugging.
280296548Sdumbbell	 * Even if not, the detection bit of the 2501 is unreliable as
281296548Sdumbbell	 * it only works for some display types.
282296548Sdumbbell	 * It is even more unreliable as the PLL must be active for
283296548Sdumbbell	 * allowing reading from the chiop.
284296548Sdumbbell	 */
285296548Sdumbbell	return connector_status_connected;
286296548Sdumbbell}
287296548Sdumbbell
288296548Sdumbbellstatic enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
289296548Sdumbbell					      struct drm_display_mode *mode)
290296548Sdumbbell{
291296548Sdumbbell	DRM_DEBUG_KMS
292296548Sdumbbell	    ("%s: is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n",
293296548Sdumbbell	     __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay,
294296548Sdumbbell	     mode->vtotal);
295296548Sdumbbell
296296548Sdumbbell	/*
297296548Sdumbbell	 * Currently, these are all the modes I have data from.
298296548Sdumbbell	 * More might exist. Unclear how to find the native resolution
299296548Sdumbbell	 * of the panel in here so we could always accept it
300296548Sdumbbell	 * by disabling the scaler.
301296548Sdumbbell	 */
302296548Sdumbbell	if ((mode->hdisplay == 800 && mode->vdisplay == 600) ||
303296548Sdumbbell	    (mode->hdisplay == 640 && mode->vdisplay == 480) ||
304296548Sdumbbell	    (mode->hdisplay == 1024 && mode->vdisplay == 768)) {
305296548Sdumbbell		return MODE_OK;
306296548Sdumbbell	} else {
307296548Sdumbbell		return MODE_ONE_SIZE;	/* Is this a reasonable error? */
308296548Sdumbbell	}
309296548Sdumbbell}
310296548Sdumbbell
311296548Sdumbbellstatic void ns2501_mode_set(struct intel_dvo_device *dvo,
312296548Sdumbbell			    struct drm_display_mode *mode,
313296548Sdumbbell			    struct drm_display_mode *adjusted_mode)
314296548Sdumbbell{
315296548Sdumbbell	bool ok;
316296548Sdumbbell	bool restore = false;
317296548Sdumbbell	struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
318296548Sdumbbell
319296548Sdumbbell	DRM_DEBUG_KMS
320296548Sdumbbell	    ("%s: set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
321296548Sdumbbell	     __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay,
322296548Sdumbbell	     mode->vtotal);
323296548Sdumbbell
324296548Sdumbbell	/*
325296548Sdumbbell	 * Where do I find the native resolution for which scaling is not required???
326296548Sdumbbell	 *
327296548Sdumbbell	 * First trigger the DVO on as otherwise the chip does not appear on the i2c
328296548Sdumbbell	 * bus.
329296548Sdumbbell	 */
330296548Sdumbbell	do {
331296548Sdumbbell		ok = true;
332296548Sdumbbell
333296548Sdumbbell		if (mode->hdisplay == 800 && mode->vdisplay == 600) {
334296548Sdumbbell			/* mode 277 */
335296548Sdumbbell			ns->reg_8_shadow &= ~NS2501_8_BPAS;
336296548Sdumbbell			DRM_DEBUG_KMS("%s: switching to 800x600\n",
337296548Sdumbbell				      __FUNCTION__);
338296548Sdumbbell
339296548Sdumbbell			/*
340296548Sdumbbell			 * No, I do not know where this data comes from.
341296548Sdumbbell			 * It is just what the video bios left in the DVO, so
342296548Sdumbbell			 * I'm just copying it here over.
343296548Sdumbbell			 * This also means that I cannot support any other modes
344296548Sdumbbell			 * except the ones supported by the bios.
345296548Sdumbbell			 */
346296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x11, 0xc8);	// 0xc7 also works.
347296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x1b, 0x19);
348296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x1c, 0x62);	// VBIOS left 0x64 here, but 0x62 works nicer
349296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x1d, 0x02);
350296548Sdumbbell
351296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x34, 0x03);
352296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x35, 0xff);
353296548Sdumbbell
354296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x80, 0x27);
355296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x81, 0x03);
356296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x82, 0x41);
357296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x83, 0x05);
358296548Sdumbbell
359296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x8d, 0x02);
360296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x8e, 0x04);
361296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x8f, 0x00);
362296548Sdumbbell
363296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x90, 0xfe);	/* vertical. VBIOS left 0xff here, but 0xfe works better */
364296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x91, 0x07);
365296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x94, 0x00);
366296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x95, 0x00);
367296548Sdumbbell
368296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x96, 0x00);
369296548Sdumbbell
370296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x99, 0x00);
371296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x9a, 0x88);
372296548Sdumbbell
373296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x9c, 0x23);	/* Looks like first and last line of the image. */
374296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x9d, 0x00);
375296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x9e, 0x25);
376296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x9f, 0x03);
377296548Sdumbbell
378296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xa4, 0x80);
379296548Sdumbbell
380296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xb6, 0x00);
381296548Sdumbbell
382296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xb9, 0xc8);	/* horizontal? */
383296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xba, 0x00);	/* horizontal? */
384296548Sdumbbell
385296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc0, 0x05);	/* horizontal? */
386296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc1, 0xd7);
387296548Sdumbbell
388296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc2, 0x00);
389296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc3, 0xf8);
390296548Sdumbbell
391296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc4, 0x03);
392296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc5, 0x1a);
393296548Sdumbbell
394296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc6, 0x00);
395296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc7, 0x73);
396296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc8, 0x02);
397296548Sdumbbell
398296548Sdumbbell		} else if (mode->hdisplay == 640 && mode->vdisplay == 480) {
399296548Sdumbbell			/* mode 274 */
400296548Sdumbbell			DRM_DEBUG_KMS("%s: switching to 640x480\n",
401296548Sdumbbell				      __FUNCTION__);
402296548Sdumbbell			/*
403296548Sdumbbell			 * No, I do not know where this data comes from.
404296548Sdumbbell			 * It is just what the video bios left in the DVO, so
405296548Sdumbbell			 * I'm just copying it here over.
406296548Sdumbbell			 * This also means that I cannot support any other modes
407296548Sdumbbell			 * except the ones supported by the bios.
408296548Sdumbbell			 */
409296548Sdumbbell			ns->reg_8_shadow &= ~NS2501_8_BPAS;
410296548Sdumbbell
411296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x11, 0xa0);
412296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x1b, 0x11);
413296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x1c, 0x54);
414296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x1d, 0x03);
415296548Sdumbbell
416296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x34, 0x03);
417296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x35, 0xff);
418296548Sdumbbell
419296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x80, 0xff);
420296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x81, 0x07);
421296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x82, 0x3d);
422296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x83, 0x05);
423296548Sdumbbell
424296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x8d, 0x02);
425296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x8e, 0x10);
426296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x8f, 0x00);
427296548Sdumbbell
428296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x90, 0xff);	/* vertical */
429296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x91, 0x07);
430296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x94, 0x00);
431296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x95, 0x00);
432296548Sdumbbell
433296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x96, 0x05);
434296548Sdumbbell
435296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x99, 0x00);
436296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x9a, 0x88);
437296548Sdumbbell
438296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x9c, 0x24);
439296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x9d, 0x00);
440296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x9e, 0x25);
441296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x9f, 0x03);
442296548Sdumbbell
443296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xa4, 0x84);
444296548Sdumbbell
445296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xb6, 0x09);
446296548Sdumbbell
447296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xb9, 0xa0);	/* horizontal? */
448296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xba, 0x00);	/* horizontal? */
449296548Sdumbbell
450296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc0, 0x05);	/* horizontal? */
451296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc1, 0x90);
452296548Sdumbbell
453296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc2, 0x00);
454296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc3, 0x0f);
455296548Sdumbbell
456296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc4, 0x03);
457296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc5, 0x16);
458296548Sdumbbell
459296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc6, 0x00);
460296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc7, 0x02);
461296548Sdumbbell			ok &= ns2501_writeb(dvo, 0xc8, 0x02);
462296548Sdumbbell
463296548Sdumbbell		} else if (mode->hdisplay == 1024 && mode->vdisplay == 768) {
464296548Sdumbbell			/* mode 280 */
465296548Sdumbbell			DRM_DEBUG_KMS("%s: switching to 1024x768\n",
466296548Sdumbbell				      __FUNCTION__);
467296548Sdumbbell			/*
468296548Sdumbbell			 * This might or might not work, actually. I'm silently
469296548Sdumbbell			 * assuming here that the native panel resolution is
470296548Sdumbbell			 * 1024x768. If not, then this leaves the scaler disabled
471296548Sdumbbell			 * generating a picture that is likely not the expected.
472296548Sdumbbell			 *
473296548Sdumbbell			 * Problem is that I do not know where to take the panel
474296548Sdumbbell			 * dimensions from.
475296548Sdumbbell			 *
476296548Sdumbbell			 * Enable the bypass, scaling not required.
477296548Sdumbbell			 *
478296548Sdumbbell			 * The scaler registers are irrelevant here....
479296548Sdumbbell			 *
480296548Sdumbbell			 */
481296548Sdumbbell			ns->reg_8_shadow |= NS2501_8_BPAS;
482296548Sdumbbell			ok &= ns2501_writeb(dvo, 0x37, 0x44);
483296548Sdumbbell		} else {
484296548Sdumbbell			/*
485296548Sdumbbell			 * Data not known. Bummer!
486296548Sdumbbell			 * Hopefully, the code should not go here
487296548Sdumbbell			 * as mode_OK delivered no other modes.
488296548Sdumbbell			 */
489296548Sdumbbell			ns->reg_8_shadow |= NS2501_8_BPAS;
490296548Sdumbbell		}
491296548Sdumbbell		ok &= ns2501_writeb(dvo, NS2501_REG8, ns->reg_8_shadow);
492296548Sdumbbell
493296548Sdumbbell		if (!ok) {
494296548Sdumbbell			if (restore)
495296548Sdumbbell				restore_dvo(dvo);
496296548Sdumbbell			enable_dvo(dvo);
497296548Sdumbbell			restore = true;
498296548Sdumbbell		}
499296548Sdumbbell	} while (!ok);
500296548Sdumbbell	/*
501296548Sdumbbell	 * Restore the old i915 registers before
502296548Sdumbbell	 * forcing the ns2501 on.
503296548Sdumbbell	 */
504296548Sdumbbell	if (restore)
505296548Sdumbbell		restore_dvo(dvo);
506296548Sdumbbell}
507296548Sdumbbell
508296548Sdumbbell/* set the NS2501 power state */
509296548Sdumbbellstatic bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
510296548Sdumbbell{
511296548Sdumbbell	unsigned char ch;
512296548Sdumbbell
513296548Sdumbbell	if (!ns2501_readb(dvo, NS2501_REG8, &ch))
514296548Sdumbbell		return false;
515296548Sdumbbell
516296548Sdumbbell	if (ch & NS2501_8_PD)
517296548Sdumbbell		return true;
518296548Sdumbbell	else
519296548Sdumbbell		return false;
520296548Sdumbbell}
521296548Sdumbbell
522296548Sdumbbell/* set the NS2501 power state */
523296548Sdumbbellstatic void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
524296548Sdumbbell{
525296548Sdumbbell	bool ok;
526296548Sdumbbell	bool restore = false;
527296548Sdumbbell	struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
528296548Sdumbbell	unsigned char ch;
529296548Sdumbbell
530296548Sdumbbell	DRM_DEBUG_KMS("%s: Trying set the dpms of the DVO to %i\n",
531296548Sdumbbell		      __FUNCTION__, enable);
532296548Sdumbbell
533296548Sdumbbell	ch = ns->reg_8_shadow;
534296548Sdumbbell
535296548Sdumbbell	if (enable)
536296548Sdumbbell		ch |= NS2501_8_PD;
537296548Sdumbbell	else
538296548Sdumbbell		ch &= ~NS2501_8_PD;
539296548Sdumbbell
540296548Sdumbbell	if (ns->reg_8_set == 0 || ns->reg_8_shadow != ch) {
541296548Sdumbbell		ns->reg_8_set = 1;
542296548Sdumbbell		ns->reg_8_shadow = ch;
543296548Sdumbbell
544296548Sdumbbell		do {
545296548Sdumbbell			ok = true;
546296548Sdumbbell			ok &= ns2501_writeb(dvo, NS2501_REG8, ch);
547296548Sdumbbell			ok &=
548296548Sdumbbell			    ns2501_writeb(dvo, 0x34,
549296548Sdumbbell					  enable ? 0x03 : 0x00);
550296548Sdumbbell			ok &=
551296548Sdumbbell			    ns2501_writeb(dvo, 0x35,
552296548Sdumbbell					  enable ? 0xff : 0x00);
553296548Sdumbbell			if (!ok) {
554296548Sdumbbell				if (restore)
555296548Sdumbbell					restore_dvo(dvo);
556296548Sdumbbell				enable_dvo(dvo);
557296548Sdumbbell				restore = true;
558296548Sdumbbell			}
559296548Sdumbbell		} while (!ok);
560296548Sdumbbell
561296548Sdumbbell		if (restore)
562296548Sdumbbell			restore_dvo(dvo);
563296548Sdumbbell	}
564296548Sdumbbell}
565296548Sdumbbell
566296548Sdumbbellstatic void ns2501_dump_regs(struct intel_dvo_device *dvo)
567296548Sdumbbell{
568296548Sdumbbell	uint8_t val;
569296548Sdumbbell
570296548Sdumbbell	ns2501_readb(dvo, NS2501_FREQ_LO, &val);
571296548Sdumbbell	DRM_LOG_KMS("NS2501_FREQ_LO: 0x%02x\n", val);
572296548Sdumbbell	ns2501_readb(dvo, NS2501_FREQ_HI, &val);
573296548Sdumbbell	DRM_LOG_KMS("NS2501_FREQ_HI: 0x%02x\n", val);
574296548Sdumbbell	ns2501_readb(dvo, NS2501_REG8, &val);
575296548Sdumbbell	DRM_LOG_KMS("NS2501_REG8: 0x%02x\n", val);
576296548Sdumbbell	ns2501_readb(dvo, NS2501_REG9, &val);
577296548Sdumbbell	DRM_LOG_KMS("NS2501_REG9: 0x%02x\n", val);
578296548Sdumbbell	ns2501_readb(dvo, NS2501_REGC, &val);
579296548Sdumbbell	DRM_LOG_KMS("NS2501_REGC: 0x%02x\n", val);
580296548Sdumbbell}
581296548Sdumbbell
582296548Sdumbbellstatic void ns2501_destroy(struct intel_dvo_device *dvo)
583296548Sdumbbell{
584296548Sdumbbell	struct ns2501_priv *ns = dvo->dev_priv;
585296548Sdumbbell
586296548Sdumbbell	if (ns) {
587296548Sdumbbell		free(ns, DRM_MEM_KMS);
588296548Sdumbbell		dvo->dev_priv = NULL;
589296548Sdumbbell	}
590296548Sdumbbell}
591296548Sdumbbell
592296548Sdumbbellstruct intel_dvo_dev_ops ns2501_ops = {
593296548Sdumbbell	.init = ns2501_init,
594296548Sdumbbell	.detect = ns2501_detect,
595296548Sdumbbell	.mode_valid = ns2501_mode_valid,
596296548Sdumbbell	.mode_set = ns2501_mode_set,
597296548Sdumbbell	.dpms = ns2501_dpms,
598296548Sdumbbell	.get_hw_state = ns2501_get_hw_state,
599296548Sdumbbell	.dump_regs = ns2501_dump_regs,
600296548Sdumbbell	.destroy = ns2501_destroy,
601296548Sdumbbell};
602