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