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