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