xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/ast/ast_dp501.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
1*41ec0267Sriastradh /*	$NetBSD: ast_dp501.c,v 1.3 2021/12/18 23:45:27 riastradh Exp $	*/
2efa246c0Sriastradh 
3*41ec0267Sriastradh // SPDX-License-Identifier: GPL-2.0
4efa246c0Sriastradh 
5efa246c0Sriastradh #include <sys/cdefs.h>
6*41ec0267Sriastradh __KERNEL_RCSID(0, "$NetBSD: ast_dp501.c,v 1.3 2021/12/18 23:45:27 riastradh Exp $");
7efa246c0Sriastradh 
8*41ec0267Sriastradh #include <linux/delay.h>
9efa246c0Sriastradh #include <linux/firmware.h>
10*41ec0267Sriastradh #include <linux/module.h>
11*41ec0267Sriastradh 
12efa246c0Sriastradh #include "ast_drv.h"
13*41ec0267Sriastradh 
14efa246c0Sriastradh MODULE_FIRMWARE("ast_dp501_fw.bin");
15efa246c0Sriastradh 
ast_load_dp501_microcode(struct drm_device * dev)16*41ec0267Sriastradh static int ast_load_dp501_microcode(struct drm_device *dev)
17efa246c0Sriastradh {
18efa246c0Sriastradh 	struct ast_private *ast = dev->dev_private;
19efa246c0Sriastradh 
20*41ec0267Sriastradh 	return request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev);
21efa246c0Sriastradh }
22efa246c0Sriastradh 
send_ack(struct ast_private * ast)23efa246c0Sriastradh static void send_ack(struct ast_private *ast)
24efa246c0Sriastradh {
25efa246c0Sriastradh 	u8 sendack;
26efa246c0Sriastradh 	sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff);
27efa246c0Sriastradh 	sendack |= 0x80;
28efa246c0Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack);
29efa246c0Sriastradh }
30efa246c0Sriastradh 
send_nack(struct ast_private * ast)31efa246c0Sriastradh static void send_nack(struct ast_private *ast)
32efa246c0Sriastradh {
33efa246c0Sriastradh 	u8 sendack;
34efa246c0Sriastradh 	sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff);
35efa246c0Sriastradh 	sendack &= ~0x80;
36efa246c0Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack);
37efa246c0Sriastradh }
38efa246c0Sriastradh 
wait_ack(struct ast_private * ast)39efa246c0Sriastradh static bool wait_ack(struct ast_private *ast)
40efa246c0Sriastradh {
41efa246c0Sriastradh 	u8 waitack;
42efa246c0Sriastradh 	u32 retry = 0;
43efa246c0Sriastradh 	do {
44efa246c0Sriastradh 		waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 0xff);
45efa246c0Sriastradh 		waitack &= 0x80;
46efa246c0Sriastradh 		udelay(100);
47efa246c0Sriastradh 	} while ((!waitack) && (retry++ < 1000));
48efa246c0Sriastradh 
49efa246c0Sriastradh 	if (retry < 1000)
50efa246c0Sriastradh 		return true;
51efa246c0Sriastradh 	else
52efa246c0Sriastradh 		return false;
53efa246c0Sriastradh }
54efa246c0Sriastradh 
wait_nack(struct ast_private * ast)55efa246c0Sriastradh static bool wait_nack(struct ast_private *ast)
56efa246c0Sriastradh {
57efa246c0Sriastradh 	u8 waitack;
58efa246c0Sriastradh 	u32 retry = 0;
59efa246c0Sriastradh 	do {
60efa246c0Sriastradh 		waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 0xff);
61efa246c0Sriastradh 		waitack &= 0x80;
62efa246c0Sriastradh 		udelay(100);
63efa246c0Sriastradh 	} while ((waitack) && (retry++ < 1000));
64efa246c0Sriastradh 
65efa246c0Sriastradh 	if (retry < 1000)
66efa246c0Sriastradh 		return true;
67efa246c0Sriastradh 	else
68efa246c0Sriastradh 		return false;
69efa246c0Sriastradh }
70efa246c0Sriastradh 
set_cmd_trigger(struct ast_private * ast)71efa246c0Sriastradh static void set_cmd_trigger(struct ast_private *ast)
72efa246c0Sriastradh {
73efa246c0Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x40);
74efa246c0Sriastradh }
75efa246c0Sriastradh 
clear_cmd_trigger(struct ast_private * ast)76efa246c0Sriastradh static void clear_cmd_trigger(struct ast_private *ast)
77efa246c0Sriastradh {
78efa246c0Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x00);
79efa246c0Sriastradh }
80efa246c0Sriastradh 
81efa246c0Sriastradh #if 0
82efa246c0Sriastradh static bool wait_fw_ready(struct ast_private *ast)
83efa246c0Sriastradh {
84efa246c0Sriastradh 	u8 waitready;
85efa246c0Sriastradh 	u32 retry = 0;
86efa246c0Sriastradh 	do {
87efa246c0Sriastradh 		waitready = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 0xff);
88efa246c0Sriastradh 		waitready &= 0x40;
89efa246c0Sriastradh 		udelay(100);
90efa246c0Sriastradh 	} while ((!waitready) && (retry++ < 1000));
91efa246c0Sriastradh 
92efa246c0Sriastradh 	if (retry < 1000)
93efa246c0Sriastradh 		return true;
94efa246c0Sriastradh 	else
95efa246c0Sriastradh 		return false;
96efa246c0Sriastradh }
97efa246c0Sriastradh #endif
98efa246c0Sriastradh 
ast_write_cmd(struct drm_device * dev,u8 data)99efa246c0Sriastradh static bool ast_write_cmd(struct drm_device *dev, u8 data)
100efa246c0Sriastradh {
101efa246c0Sriastradh 	struct ast_private *ast = dev->dev_private;
102efa246c0Sriastradh 	int retry = 0;
103efa246c0Sriastradh 	if (wait_nack(ast)) {
104efa246c0Sriastradh 		send_nack(ast);
105efa246c0Sriastradh 		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data);
106efa246c0Sriastradh 		send_ack(ast);
107efa246c0Sriastradh 		set_cmd_trigger(ast);
108efa246c0Sriastradh 		do {
109efa246c0Sriastradh 			if (wait_ack(ast)) {
110efa246c0Sriastradh 				clear_cmd_trigger(ast);
111efa246c0Sriastradh 				send_nack(ast);
112efa246c0Sriastradh 				return true;
113efa246c0Sriastradh 			}
114efa246c0Sriastradh 		} while (retry++ < 100);
115efa246c0Sriastradh 	}
116efa246c0Sriastradh 	clear_cmd_trigger(ast);
117efa246c0Sriastradh 	send_nack(ast);
118efa246c0Sriastradh 	return false;
119efa246c0Sriastradh }
120efa246c0Sriastradh 
ast_write_data(struct drm_device * dev,u8 data)121efa246c0Sriastradh static bool ast_write_data(struct drm_device *dev, u8 data)
122efa246c0Sriastradh {
123efa246c0Sriastradh 	struct ast_private *ast = dev->dev_private;
124efa246c0Sriastradh 
125efa246c0Sriastradh 	if (wait_nack(ast)) {
126efa246c0Sriastradh 		send_nack(ast);
127efa246c0Sriastradh 		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data);
128efa246c0Sriastradh 		send_ack(ast);
129efa246c0Sriastradh 		if (wait_ack(ast)) {
130efa246c0Sriastradh 			send_nack(ast);
131efa246c0Sriastradh 			return true;
132efa246c0Sriastradh 		}
133efa246c0Sriastradh 	}
134efa246c0Sriastradh 	send_nack(ast);
135efa246c0Sriastradh 	return false;
136efa246c0Sriastradh }
137efa246c0Sriastradh 
138efa246c0Sriastradh #if 0
139efa246c0Sriastradh static bool ast_read_data(struct drm_device *dev, u8 *data)
140efa246c0Sriastradh {
141efa246c0Sriastradh 	struct ast_private *ast = dev->dev_private;
142efa246c0Sriastradh 	u8 tmp;
143efa246c0Sriastradh 
144efa246c0Sriastradh 	*data = 0;
145efa246c0Sriastradh 
146efa246c0Sriastradh 	if (wait_ack(ast) == false)
147efa246c0Sriastradh 		return false;
148efa246c0Sriastradh 	tmp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd3, 0xff);
149efa246c0Sriastradh 	*data = tmp;
150efa246c0Sriastradh 	if (wait_nack(ast) == false) {
151efa246c0Sriastradh 		send_nack(ast);
152efa246c0Sriastradh 		return false;
153efa246c0Sriastradh 	}
154efa246c0Sriastradh 	send_nack(ast);
155efa246c0Sriastradh 	return true;
156efa246c0Sriastradh }
157efa246c0Sriastradh 
158efa246c0Sriastradh static void clear_cmd(struct ast_private *ast)
159efa246c0Sriastradh {
160efa246c0Sriastradh 	send_nack(ast);
161efa246c0Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, 0x00);
162efa246c0Sriastradh }
163efa246c0Sriastradh #endif
164efa246c0Sriastradh 
ast_set_dp501_video_output(struct drm_device * dev,u8 mode)165efa246c0Sriastradh void ast_set_dp501_video_output(struct drm_device *dev, u8 mode)
166efa246c0Sriastradh {
167efa246c0Sriastradh 	ast_write_cmd(dev, 0x40);
168efa246c0Sriastradh 	ast_write_data(dev, mode);
169efa246c0Sriastradh 
170efa246c0Sriastradh 	msleep(10);
171efa246c0Sriastradh }
172efa246c0Sriastradh 
get_fw_base(struct ast_private * ast)173efa246c0Sriastradh static u32 get_fw_base(struct ast_private *ast)
174efa246c0Sriastradh {
175efa246c0Sriastradh 	return ast_mindwm(ast, 0x1e6e2104) & 0x7fffffff;
176efa246c0Sriastradh }
177efa246c0Sriastradh 
ast_backup_fw(struct drm_device * dev,u8 * addr,u32 size)178efa246c0Sriastradh bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size)
179efa246c0Sriastradh {
180efa246c0Sriastradh 	struct ast_private *ast = dev->dev_private;
181efa246c0Sriastradh 	u32 i, data;
182efa246c0Sriastradh 	u32 boot_address;
183efa246c0Sriastradh 
184efa246c0Sriastradh 	data = ast_mindwm(ast, 0x1e6e2100) & 0x01;
185efa246c0Sriastradh 	if (data) {
186efa246c0Sriastradh 		boot_address = get_fw_base(ast);
187efa246c0Sriastradh 		for (i = 0; i < size; i += 4)
188efa246c0Sriastradh 			*(u32 *)(addr + i) = ast_mindwm(ast, boot_address + i);
189efa246c0Sriastradh 		return true;
190efa246c0Sriastradh 	}
191efa246c0Sriastradh 	return false;
192efa246c0Sriastradh }
193efa246c0Sriastradh 
ast_launch_m68k(struct drm_device * dev)194*41ec0267Sriastradh static bool ast_launch_m68k(struct drm_device *dev)
195efa246c0Sriastradh {
196efa246c0Sriastradh 	struct ast_private *ast = dev->dev_private;
197efa246c0Sriastradh 	u32 i, data, len = 0;
198efa246c0Sriastradh 	u32 boot_address;
199efa246c0Sriastradh 	u8 *fw_addr = NULL;
200efa246c0Sriastradh 	u8 jreg;
201efa246c0Sriastradh 
202efa246c0Sriastradh 	data = ast_mindwm(ast, 0x1e6e2100) & 0x01;
203efa246c0Sriastradh 	if (!data) {
204efa246c0Sriastradh 
205efa246c0Sriastradh 		if (ast->dp501_fw_addr) {
206efa246c0Sriastradh 			fw_addr = ast->dp501_fw_addr;
207efa246c0Sriastradh 			len = 32*1024;
208*41ec0267Sriastradh 		} else {
209*41ec0267Sriastradh 			if (!ast->dp501_fw &&
210*41ec0267Sriastradh 			    ast_load_dp501_microcode(dev) < 0)
211*41ec0267Sriastradh 				return false;
212*41ec0267Sriastradh 
213efa246c0Sriastradh 			fw_addr = (u8 *)ast->dp501_fw->data;
214efa246c0Sriastradh 			len = ast->dp501_fw->size;
215efa246c0Sriastradh 		}
216efa246c0Sriastradh 		/* Get BootAddress */
217efa246c0Sriastradh 		ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);
218efa246c0Sriastradh 		data = ast_mindwm(ast, 0x1e6e0004);
219efa246c0Sriastradh 		switch (data & 0x03) {
220efa246c0Sriastradh 		case 0:
221efa246c0Sriastradh 			boot_address = 0x44000000;
222efa246c0Sriastradh 			break;
223efa246c0Sriastradh 		default:
224efa246c0Sriastradh 		case 1:
225efa246c0Sriastradh 			boot_address = 0x48000000;
226efa246c0Sriastradh 			break;
227efa246c0Sriastradh 		case 2:
228efa246c0Sriastradh 			boot_address = 0x50000000;
229efa246c0Sriastradh 			break;
230efa246c0Sriastradh 		case 3:
231efa246c0Sriastradh 			boot_address = 0x60000000;
232efa246c0Sriastradh 			break;
233efa246c0Sriastradh 		}
234efa246c0Sriastradh 		boot_address -= 0x200000; /* -2MB */
235efa246c0Sriastradh 
236efa246c0Sriastradh 		/* copy image to buffer */
237efa246c0Sriastradh 		for (i = 0; i < len; i += 4) {
238efa246c0Sriastradh 			data = *(u32 *)(fw_addr + i);
239efa246c0Sriastradh 			ast_moutdwm(ast, boot_address + i, data);
240efa246c0Sriastradh 		}
241efa246c0Sriastradh 
242efa246c0Sriastradh 		/* Init SCU */
243efa246c0Sriastradh 		ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);
244efa246c0Sriastradh 
245efa246c0Sriastradh 		/* Launch FW */
246efa246c0Sriastradh 		ast_moutdwm(ast, 0x1e6e2104, 0x80000000 + boot_address);
247efa246c0Sriastradh 		ast_moutdwm(ast, 0x1e6e2100, 1);
248efa246c0Sriastradh 
249efa246c0Sriastradh 		/* Update Scratch */
250efa246c0Sriastradh 		data = ast_mindwm(ast, 0x1e6e2040) & 0xfffff1ff;		/* D[11:9] = 100b: UEFI handling */
251efa246c0Sriastradh 		data |= 0x800;
252efa246c0Sriastradh 		ast_moutdwm(ast, 0x1e6e2040, data);
253efa246c0Sriastradh 
254efa246c0Sriastradh 		jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x99, 0xfc); /* D[1:0]: Reserved Video Buffer */
255efa246c0Sriastradh 		jreg |= 0x02;
256efa246c0Sriastradh 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x99, jreg);
257efa246c0Sriastradh 	}
258efa246c0Sriastradh 	return true;
259efa246c0Sriastradh }
260efa246c0Sriastradh 
ast_get_dp501_max_clk(struct drm_device * dev)261efa246c0Sriastradh u8 ast_get_dp501_max_clk(struct drm_device *dev)
262efa246c0Sriastradh {
263efa246c0Sriastradh 	struct ast_private *ast = dev->dev_private;
264efa246c0Sriastradh 	u32 boot_address, offset, data;
265efa246c0Sriastradh 	u8 linkcap[4], linkrate, linklanes, maxclk = 0xff;
266efa246c0Sriastradh 
267efa246c0Sriastradh 	boot_address = get_fw_base(ast);
268efa246c0Sriastradh 
269efa246c0Sriastradh 	/* validate FW version */
270efa246c0Sriastradh 	offset = 0xf000;
271efa246c0Sriastradh 	data = ast_mindwm(ast, boot_address + offset);
272efa246c0Sriastradh 	if ((data & 0xf0) != 0x10) /* version: 1x */
273efa246c0Sriastradh 		return maxclk;
274efa246c0Sriastradh 
275efa246c0Sriastradh 	/* Read Link Capability */
276efa246c0Sriastradh 	offset  = 0xf014;
277efa246c0Sriastradh 	*(u32 *)linkcap = ast_mindwm(ast, boot_address + offset);
278efa246c0Sriastradh 	if (linkcap[2] == 0) {
279efa246c0Sriastradh 		linkrate = linkcap[0];
280efa246c0Sriastradh 		linklanes = linkcap[1];
281efa246c0Sriastradh 		data = (linkrate == 0x0a) ? (90 * linklanes) : (54 * linklanes);
282efa246c0Sriastradh 		if (data > 0xff)
283efa246c0Sriastradh 			data = 0xff;
284efa246c0Sriastradh 		maxclk = (u8)data;
285efa246c0Sriastradh 	}
286efa246c0Sriastradh 	return maxclk;
287efa246c0Sriastradh }
288efa246c0Sriastradh 
ast_dp501_read_edid(struct drm_device * dev,u8 * ediddata)289efa246c0Sriastradh bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata)
290efa246c0Sriastradh {
291efa246c0Sriastradh 	struct ast_private *ast = dev->dev_private;
292efa246c0Sriastradh 	u32 i, boot_address, offset, data;
293efa246c0Sriastradh 
294efa246c0Sriastradh 	boot_address = get_fw_base(ast);
295efa246c0Sriastradh 
296efa246c0Sriastradh 	/* validate FW version */
297efa246c0Sriastradh 	offset = 0xf000;
298efa246c0Sriastradh 	data = ast_mindwm(ast, boot_address + offset);
299efa246c0Sriastradh 	if ((data & 0xf0) != 0x10)
300efa246c0Sriastradh 		return false;
301efa246c0Sriastradh 
302efa246c0Sriastradh 	/* validate PnP Monitor */
303efa246c0Sriastradh 	offset = 0xf010;
304efa246c0Sriastradh 	data = ast_mindwm(ast, boot_address + offset);
305efa246c0Sriastradh 	if (!(data & 0x01))
306efa246c0Sriastradh 		return false;
307efa246c0Sriastradh 
308efa246c0Sriastradh 	/* Read EDID */
309efa246c0Sriastradh 	offset = 0xf020;
310efa246c0Sriastradh 	for (i = 0; i < 128; i += 4) {
311efa246c0Sriastradh 		data = ast_mindwm(ast, boot_address + offset + i);
312efa246c0Sriastradh 		*(u32 *)(ediddata + i) = data;
313efa246c0Sriastradh 	}
314efa246c0Sriastradh 
315efa246c0Sriastradh 	return true;
316efa246c0Sriastradh }
317efa246c0Sriastradh 
ast_init_dvo(struct drm_device * dev)318efa246c0Sriastradh static bool ast_init_dvo(struct drm_device *dev)
319efa246c0Sriastradh {
320efa246c0Sriastradh 	struct ast_private *ast = dev->dev_private;
321efa246c0Sriastradh 	u8 jreg;
322efa246c0Sriastradh 	u32 data;
323efa246c0Sriastradh 	ast_write32(ast, 0xf004, 0x1e6e0000);
324efa246c0Sriastradh 	ast_write32(ast, 0xf000, 0x1);
325efa246c0Sriastradh 	ast_write32(ast, 0x12000, 0x1688a8a8);
326efa246c0Sriastradh 
327efa246c0Sriastradh 	jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
328efa246c0Sriastradh 	if (!(jreg & 0x80)) {
329efa246c0Sriastradh 		/* Init SCU DVO Settings */
330efa246c0Sriastradh 		data = ast_read32(ast, 0x12008);
331efa246c0Sriastradh 		/* delay phase */
332efa246c0Sriastradh 		data &= 0xfffff8ff;
333efa246c0Sriastradh 		data |= 0x00000500;
334efa246c0Sriastradh 		ast_write32(ast, 0x12008, data);
335efa246c0Sriastradh 
336efa246c0Sriastradh 		if (ast->chip == AST2300) {
337efa246c0Sriastradh 			data = ast_read32(ast, 0x12084);
338efa246c0Sriastradh 			/* multi-pins for DVO single-edge */
339efa246c0Sriastradh 			data |= 0xfffe0000;
340efa246c0Sriastradh 			ast_write32(ast, 0x12084, data);
341efa246c0Sriastradh 
342efa246c0Sriastradh 			data = ast_read32(ast, 0x12088);
343efa246c0Sriastradh 			/* multi-pins for DVO single-edge */
344efa246c0Sriastradh 			data |= 0x000fffff;
345efa246c0Sriastradh 			ast_write32(ast, 0x12088, data);
346efa246c0Sriastradh 
347efa246c0Sriastradh 			data = ast_read32(ast, 0x12090);
348efa246c0Sriastradh 			/* multi-pins for DVO single-edge */
349efa246c0Sriastradh 			data &= 0xffffffcf;
350efa246c0Sriastradh 			data |= 0x00000020;
351efa246c0Sriastradh 			ast_write32(ast, 0x12090, data);
352efa246c0Sriastradh 		} else { /* AST2400 */
353efa246c0Sriastradh 			data = ast_read32(ast, 0x12088);
354efa246c0Sriastradh 			/* multi-pins for DVO single-edge */
355efa246c0Sriastradh 			data |= 0x30000000;
356efa246c0Sriastradh 			ast_write32(ast, 0x12088, data);
357efa246c0Sriastradh 
358efa246c0Sriastradh 			data = ast_read32(ast, 0x1208c);
359efa246c0Sriastradh 			/* multi-pins for DVO single-edge */
360efa246c0Sriastradh 			data |= 0x000000cf;
361efa246c0Sriastradh 			ast_write32(ast, 0x1208c, data);
362efa246c0Sriastradh 
363efa246c0Sriastradh 			data = ast_read32(ast, 0x120a4);
364efa246c0Sriastradh 			/* multi-pins for DVO single-edge */
365efa246c0Sriastradh 			data |= 0xffff0000;
366efa246c0Sriastradh 			ast_write32(ast, 0x120a4, data);
367efa246c0Sriastradh 
368efa246c0Sriastradh 			data = ast_read32(ast, 0x120a8);
369efa246c0Sriastradh 			/* multi-pins for DVO single-edge */
370efa246c0Sriastradh 			data |= 0x0000000f;
371efa246c0Sriastradh 			ast_write32(ast, 0x120a8, data);
372efa246c0Sriastradh 
373efa246c0Sriastradh 			data = ast_read32(ast, 0x12094);
374efa246c0Sriastradh 			/* multi-pins for DVO single-edge */
375efa246c0Sriastradh 			data |= 0x00000002;
376efa246c0Sriastradh 			ast_write32(ast, 0x12094, data);
377efa246c0Sriastradh 		}
378efa246c0Sriastradh 	}
379efa246c0Sriastradh 
380efa246c0Sriastradh 	/* Force to DVO */
381efa246c0Sriastradh 	data = ast_read32(ast, 0x1202c);
382efa246c0Sriastradh 	data &= 0xfffbffff;
383efa246c0Sriastradh 	ast_write32(ast, 0x1202c, data);
384efa246c0Sriastradh 
385efa246c0Sriastradh 	/* Init VGA DVO Settings */
386efa246c0Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80);
387efa246c0Sriastradh 	return true;
388efa246c0Sriastradh }
389efa246c0Sriastradh 
390efa246c0Sriastradh 
ast_init_analog(struct drm_device * dev)391efa246c0Sriastradh static void ast_init_analog(struct drm_device *dev)
392efa246c0Sriastradh {
393efa246c0Sriastradh 	struct ast_private *ast = dev->dev_private;
394efa246c0Sriastradh 	u32 data;
395efa246c0Sriastradh 
396efa246c0Sriastradh 	/*
397efa246c0Sriastradh 	 * Set DAC source to VGA mode in SCU2C via the P2A
398efa246c0Sriastradh 	 * bridge. First configure the P2U to target the SCU
399efa246c0Sriastradh 	 * in case it isn't at this stage.
400efa246c0Sriastradh 	 */
401efa246c0Sriastradh 	ast_write32(ast, 0xf004, 0x1e6e0000);
402efa246c0Sriastradh 	ast_write32(ast, 0xf000, 0x1);
403efa246c0Sriastradh 
404efa246c0Sriastradh 	/* Then unlock the SCU with the magic password */
405efa246c0Sriastradh 	ast_write32(ast, 0x12000, 0x1688a8a8);
406efa246c0Sriastradh 	ast_write32(ast, 0x12000, 0x1688a8a8);
407efa246c0Sriastradh 	ast_write32(ast, 0x12000, 0x1688a8a8);
408efa246c0Sriastradh 
409efa246c0Sriastradh 	/* Finally, clear bits [17:16] of SCU2c */
410efa246c0Sriastradh 	data = ast_read32(ast, 0x1202c);
411efa246c0Sriastradh 	data &= 0xfffcffff;
412efa246c0Sriastradh 	ast_write32(ast, 0, data);
413efa246c0Sriastradh 
414efa246c0Sriastradh 	/* Disable DVO */
415efa246c0Sriastradh 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x00);
416efa246c0Sriastradh }
417efa246c0Sriastradh 
ast_init_3rdtx(struct drm_device * dev)418efa246c0Sriastradh void ast_init_3rdtx(struct drm_device *dev)
419efa246c0Sriastradh {
420efa246c0Sriastradh 	struct ast_private *ast = dev->dev_private;
421efa246c0Sriastradh 	u8 jreg;
422efa246c0Sriastradh 
423efa246c0Sriastradh 	if (ast->chip == AST2300 || ast->chip == AST2400) {
424efa246c0Sriastradh 		jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff);
425efa246c0Sriastradh 		switch (jreg & 0x0e) {
426efa246c0Sriastradh 		case 0x04:
427efa246c0Sriastradh 			ast_init_dvo(dev);
428efa246c0Sriastradh 			break;
429efa246c0Sriastradh 		case 0x08:
430efa246c0Sriastradh 			ast_launch_m68k(dev);
431efa246c0Sriastradh 			break;
432efa246c0Sriastradh 		case 0x0c:
433efa246c0Sriastradh 			ast_init_dvo(dev);
434efa246c0Sriastradh 			break;
435efa246c0Sriastradh 		default:
436efa246c0Sriastradh 			if (ast->tx_chip_type == AST_TX_SIL164)
437efa246c0Sriastradh 				ast_init_dvo(dev);
438efa246c0Sriastradh 			else
439efa246c0Sriastradh 				ast_init_analog(dev);
440efa246c0Sriastradh 		}
441efa246c0Sriastradh 	}
442efa246c0Sriastradh }
443*41ec0267Sriastradh 
ast_release_firmware(struct drm_device * dev)444*41ec0267Sriastradh void ast_release_firmware(struct drm_device *dev)
445*41ec0267Sriastradh {
446*41ec0267Sriastradh 	struct ast_private *ast = dev->dev_private;
447*41ec0267Sriastradh 
448*41ec0267Sriastradh 	release_firmware(ast->dp501_fw);
449*41ec0267Sriastradh 	ast->dp501_fw = NULL;
450*41ec0267Sriastradh }
451