1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
283c6620bSDave Airlie
3fbbbd160SSam Ravnborg #include <linux/delay.h>
483c6620bSDave Airlie #include <linux/firmware.h>
5fbbbd160SSam Ravnborg #include <linux/module.h>
6fbbbd160SSam Ravnborg
783c6620bSDave Airlie #include "ast_drv.h"
8fbbbd160SSam Ravnborg
983c6620bSDave Airlie MODULE_FIRMWARE("ast_dp501_fw.bin");
1083c6620bSDave Airlie
ast_release_firmware(void * data)112c0b6566SThomas Zimmermann static void ast_release_firmware(void *data)
122c0b6566SThomas Zimmermann {
1337b42cf9SThomas Zimmermann struct ast_device *ast = data;
142c0b6566SThomas Zimmermann
152c0b6566SThomas Zimmermann release_firmware(ast->dp501_fw);
162c0b6566SThomas Zimmermann ast->dp501_fw = NULL;
172c0b6566SThomas Zimmermann }
182c0b6566SThomas Zimmermann
ast_load_dp501_microcode(struct drm_device * dev)1912f8030eSEgbert Eich static int ast_load_dp501_microcode(struct drm_device *dev)
2083c6620bSDave Airlie {
215abaa683SThomas Zimmermann struct ast_device *ast = to_ast_device(dev);
222c0b6566SThomas Zimmermann int ret;
2383c6620bSDave Airlie
242c0b6566SThomas Zimmermann ret = request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev);
252c0b6566SThomas Zimmermann if (ret)
262c0b6566SThomas Zimmermann return ret;
272c0b6566SThomas Zimmermann
282c0b6566SThomas Zimmermann return devm_add_action_or_reset(dev->dev, ast_release_firmware, ast);
2983c6620bSDave Airlie }
3083c6620bSDave Airlie
send_ack(struct ast_device * ast)3137b42cf9SThomas Zimmermann static void send_ack(struct ast_device *ast)
3283c6620bSDave Airlie {
3383c6620bSDave Airlie u8 sendack;
3483c6620bSDave Airlie sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff);
3583c6620bSDave Airlie sendack |= 0x80;
3683c6620bSDave Airlie ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack);
3783c6620bSDave Airlie }
3883c6620bSDave Airlie
send_nack(struct ast_device * ast)3937b42cf9SThomas Zimmermann static void send_nack(struct ast_device *ast)
4083c6620bSDave Airlie {
4183c6620bSDave Airlie u8 sendack;
4283c6620bSDave Airlie sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff);
4383c6620bSDave Airlie sendack &= ~0x80;
4483c6620bSDave Airlie ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack);
4583c6620bSDave Airlie }
4683c6620bSDave Airlie
wait_ack(struct ast_device * ast)4737b42cf9SThomas Zimmermann static bool wait_ack(struct ast_device *ast)
4883c6620bSDave Airlie {
4983c6620bSDave Airlie u8 waitack;
5083c6620bSDave Airlie u32 retry = 0;
5183c6620bSDave Airlie do {
5283c6620bSDave Airlie waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 0xff);
5383c6620bSDave Airlie waitack &= 0x80;
5483c6620bSDave Airlie udelay(100);
5583c6620bSDave Airlie } while ((!waitack) && (retry++ < 1000));
5683c6620bSDave Airlie
5783c6620bSDave Airlie if (retry < 1000)
5883c6620bSDave Airlie return true;
5983c6620bSDave Airlie else
6083c6620bSDave Airlie return false;
6183c6620bSDave Airlie }
6283c6620bSDave Airlie
wait_nack(struct ast_device * ast)6337b42cf9SThomas Zimmermann static bool wait_nack(struct ast_device *ast)
6483c6620bSDave Airlie {
6583c6620bSDave Airlie u8 waitack;
6683c6620bSDave Airlie u32 retry = 0;
6783c6620bSDave Airlie do {
6883c6620bSDave Airlie waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 0xff);
6983c6620bSDave Airlie waitack &= 0x80;
7083c6620bSDave Airlie udelay(100);
7183c6620bSDave Airlie } while ((waitack) && (retry++ < 1000));
7283c6620bSDave Airlie
7383c6620bSDave Airlie if (retry < 1000)
7483c6620bSDave Airlie return true;
7583c6620bSDave Airlie else
7683c6620bSDave Airlie return false;
7783c6620bSDave Airlie }
7883c6620bSDave Airlie
set_cmd_trigger(struct ast_device * ast)7937b42cf9SThomas Zimmermann static void set_cmd_trigger(struct ast_device *ast)
8083c6620bSDave Airlie {
8183c6620bSDave Airlie ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x40);
8283c6620bSDave Airlie }
8383c6620bSDave Airlie
clear_cmd_trigger(struct ast_device * ast)8437b42cf9SThomas Zimmermann static void clear_cmd_trigger(struct ast_device *ast)
8583c6620bSDave Airlie {
8683c6620bSDave Airlie ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x00);
8783c6620bSDave Airlie }
8883c6620bSDave Airlie
8983c6620bSDave Airlie #if 0
9037b42cf9SThomas Zimmermann static bool wait_fw_ready(struct ast_device *ast)
9183c6620bSDave Airlie {
9283c6620bSDave Airlie u8 waitready;
9383c6620bSDave Airlie u32 retry = 0;
9483c6620bSDave Airlie do {
9583c6620bSDave Airlie waitready = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 0xff);
9683c6620bSDave Airlie waitready &= 0x40;
9783c6620bSDave Airlie udelay(100);
9883c6620bSDave Airlie } while ((!waitready) && (retry++ < 1000));
9983c6620bSDave Airlie
10083c6620bSDave Airlie if (retry < 1000)
10183c6620bSDave Airlie return true;
10283c6620bSDave Airlie else
10383c6620bSDave Airlie return false;
10483c6620bSDave Airlie }
10583c6620bSDave Airlie #endif
10683c6620bSDave Airlie
ast_write_cmd(struct drm_device * dev,u8 data)10783c6620bSDave Airlie static bool ast_write_cmd(struct drm_device *dev, u8 data)
10883c6620bSDave Airlie {
1095abaa683SThomas Zimmermann struct ast_device *ast = to_ast_device(dev);
11083c6620bSDave Airlie int retry = 0;
11183c6620bSDave Airlie if (wait_nack(ast)) {
11283c6620bSDave Airlie send_nack(ast);
11383c6620bSDave Airlie ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data);
11483c6620bSDave Airlie send_ack(ast);
11583c6620bSDave Airlie set_cmd_trigger(ast);
11683c6620bSDave Airlie do {
11783c6620bSDave Airlie if (wait_ack(ast)) {
11883c6620bSDave Airlie clear_cmd_trigger(ast);
11983c6620bSDave Airlie send_nack(ast);
12083c6620bSDave Airlie return true;
12183c6620bSDave Airlie }
12283c6620bSDave Airlie } while (retry++ < 100);
12383c6620bSDave Airlie }
12483c6620bSDave Airlie clear_cmd_trigger(ast);
12583c6620bSDave Airlie send_nack(ast);
12683c6620bSDave Airlie return false;
12783c6620bSDave Airlie }
12883c6620bSDave Airlie
ast_write_data(struct drm_device * dev,u8 data)12983c6620bSDave Airlie static bool ast_write_data(struct drm_device *dev, u8 data)
13083c6620bSDave Airlie {
1315abaa683SThomas Zimmermann struct ast_device *ast = to_ast_device(dev);
13283c6620bSDave Airlie
13383c6620bSDave Airlie if (wait_nack(ast)) {
13483c6620bSDave Airlie send_nack(ast);
13583c6620bSDave Airlie ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data);
13683c6620bSDave Airlie send_ack(ast);
13783c6620bSDave Airlie if (wait_ack(ast)) {
13883c6620bSDave Airlie send_nack(ast);
13983c6620bSDave Airlie return true;
14083c6620bSDave Airlie }
14183c6620bSDave Airlie }
14283c6620bSDave Airlie send_nack(ast);
14383c6620bSDave Airlie return false;
14483c6620bSDave Airlie }
14583c6620bSDave Airlie
14683c6620bSDave Airlie #if 0
14783c6620bSDave Airlie static bool ast_read_data(struct drm_device *dev, u8 *data)
14883c6620bSDave Airlie {
1495abaa683SThomas Zimmermann struct ast_device *ast = to_ast_device(dev);
15083c6620bSDave Airlie u8 tmp;
15183c6620bSDave Airlie
15283c6620bSDave Airlie *data = 0;
15383c6620bSDave Airlie
15483c6620bSDave Airlie if (wait_ack(ast) == false)
15583c6620bSDave Airlie return false;
15683c6620bSDave Airlie tmp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd3, 0xff);
15783c6620bSDave Airlie *data = tmp;
15883c6620bSDave Airlie if (wait_nack(ast) == false) {
15983c6620bSDave Airlie send_nack(ast);
16083c6620bSDave Airlie return false;
16183c6620bSDave Airlie }
16283c6620bSDave Airlie send_nack(ast);
16383c6620bSDave Airlie return true;
16483c6620bSDave Airlie }
16583c6620bSDave Airlie
16637b42cf9SThomas Zimmermann static void clear_cmd(struct ast_device *ast)
16783c6620bSDave Airlie {
16883c6620bSDave Airlie send_nack(ast);
16983c6620bSDave Airlie ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, 0x00);
17083c6620bSDave Airlie }
17183c6620bSDave Airlie #endif
17283c6620bSDave Airlie
ast_set_dp501_video_output(struct drm_device * dev,u8 mode)17383c6620bSDave Airlie void ast_set_dp501_video_output(struct drm_device *dev, u8 mode)
17483c6620bSDave Airlie {
17583c6620bSDave Airlie ast_write_cmd(dev, 0x40);
17683c6620bSDave Airlie ast_write_data(dev, mode);
17783c6620bSDave Airlie
17883c6620bSDave Airlie msleep(10);
17983c6620bSDave Airlie }
18083c6620bSDave Airlie
get_fw_base(struct ast_device * ast)18137b42cf9SThomas Zimmermann static u32 get_fw_base(struct ast_device *ast)
18283c6620bSDave Airlie {
18383c6620bSDave Airlie return ast_mindwm(ast, 0x1e6e2104) & 0x7fffffff;
18483c6620bSDave Airlie }
18583c6620bSDave Airlie
ast_backup_fw(struct drm_device * dev,u8 * addr,u32 size)18683c6620bSDave Airlie bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size)
18783c6620bSDave Airlie {
1885abaa683SThomas Zimmermann struct ast_device *ast = to_ast_device(dev);
18983c6620bSDave Airlie u32 i, data;
19083c6620bSDave Airlie u32 boot_address;
19183c6620bSDave Airlie
192ba4e0339SKuoHsiang Chou if (ast->config_mode != ast_use_p2a)
193ba4e0339SKuoHsiang Chou return false;
194ba4e0339SKuoHsiang Chou
19583c6620bSDave Airlie data = ast_mindwm(ast, 0x1e6e2100) & 0x01;
19683c6620bSDave Airlie if (data) {
19783c6620bSDave Airlie boot_address = get_fw_base(ast);
19883c6620bSDave Airlie for (i = 0; i < size; i += 4)
19983c6620bSDave Airlie *(u32 *)(addr + i) = ast_mindwm(ast, boot_address + i);
20083c6620bSDave Airlie return true;
20183c6620bSDave Airlie }
20283c6620bSDave Airlie return false;
20383c6620bSDave Airlie }
20483c6620bSDave Airlie
ast_launch_m68k(struct drm_device * dev)20512f8030eSEgbert Eich static bool ast_launch_m68k(struct drm_device *dev)
20683c6620bSDave Airlie {
2075abaa683SThomas Zimmermann struct ast_device *ast = to_ast_device(dev);
20883c6620bSDave Airlie u32 i, data, len = 0;
20983c6620bSDave Airlie u32 boot_address;
21083c6620bSDave Airlie u8 *fw_addr = NULL;
21183c6620bSDave Airlie u8 jreg;
21283c6620bSDave Airlie
213ba4e0339SKuoHsiang Chou if (ast->config_mode != ast_use_p2a)
214ba4e0339SKuoHsiang Chou return false;
215ba4e0339SKuoHsiang Chou
21683c6620bSDave Airlie data = ast_mindwm(ast, 0x1e6e2100) & 0x01;
21783c6620bSDave Airlie if (!data) {
21883c6620bSDave Airlie
21983c6620bSDave Airlie if (ast->dp501_fw_addr) {
22083c6620bSDave Airlie fw_addr = ast->dp501_fw_addr;
22183c6620bSDave Airlie len = 32*1024;
22212f8030eSEgbert Eich } else {
22312f8030eSEgbert Eich if (!ast->dp501_fw &&
22412f8030eSEgbert Eich ast_load_dp501_microcode(dev) < 0)
22512f8030eSEgbert Eich return false;
22612f8030eSEgbert Eich
22783c6620bSDave Airlie fw_addr = (u8 *)ast->dp501_fw->data;
22883c6620bSDave Airlie len = ast->dp501_fw->size;
22983c6620bSDave Airlie }
23083c6620bSDave Airlie /* Get BootAddress */
23183c6620bSDave Airlie ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);
23283c6620bSDave Airlie data = ast_mindwm(ast, 0x1e6e0004);
23383c6620bSDave Airlie switch (data & 0x03) {
23483c6620bSDave Airlie case 0:
23583c6620bSDave Airlie boot_address = 0x44000000;
23683c6620bSDave Airlie break;
23783c6620bSDave Airlie default:
23883c6620bSDave Airlie case 1:
23983c6620bSDave Airlie boot_address = 0x48000000;
24083c6620bSDave Airlie break;
24183c6620bSDave Airlie case 2:
24283c6620bSDave Airlie boot_address = 0x50000000;
24383c6620bSDave Airlie break;
24483c6620bSDave Airlie case 3:
24583c6620bSDave Airlie boot_address = 0x60000000;
24683c6620bSDave Airlie break;
24783c6620bSDave Airlie }
24883c6620bSDave Airlie boot_address -= 0x200000; /* -2MB */
24983c6620bSDave Airlie
25083c6620bSDave Airlie /* copy image to buffer */
25183c6620bSDave Airlie for (i = 0; i < len; i += 4) {
25283c6620bSDave Airlie data = *(u32 *)(fw_addr + i);
25383c6620bSDave Airlie ast_moutdwm(ast, boot_address + i, data);
25483c6620bSDave Airlie }
25583c6620bSDave Airlie
25683c6620bSDave Airlie /* Init SCU */
25783c6620bSDave Airlie ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);
25883c6620bSDave Airlie
25983c6620bSDave Airlie /* Launch FW */
26083c6620bSDave Airlie ast_moutdwm(ast, 0x1e6e2104, 0x80000000 + boot_address);
26183c6620bSDave Airlie ast_moutdwm(ast, 0x1e6e2100, 1);
26283c6620bSDave Airlie
26383c6620bSDave Airlie /* Update Scratch */
26483c6620bSDave Airlie data = ast_mindwm(ast, 0x1e6e2040) & 0xfffff1ff; /* D[11:9] = 100b: UEFI handling */
26583c6620bSDave Airlie data |= 0x800;
26683c6620bSDave Airlie ast_moutdwm(ast, 0x1e6e2040, data);
26783c6620bSDave Airlie
26883c6620bSDave Airlie jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x99, 0xfc); /* D[1:0]: Reserved Video Buffer */
26983c6620bSDave Airlie jreg |= 0x02;
27083c6620bSDave Airlie ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x99, jreg);
27183c6620bSDave Airlie }
27283c6620bSDave Airlie return true;
27383c6620bSDave Airlie }
27483c6620bSDave Airlie
ast_dp501_is_connected(struct ast_device * ast)275*f81bb0acSJocelyn Falempe bool ast_dp501_is_connected(struct ast_device *ast)
27683c6620bSDave Airlie {
277*f81bb0acSJocelyn Falempe u32 boot_address, offset, data;
27883c6620bSDave Airlie
279ba4e0339SKuoHsiang Chou if (ast->config_mode == ast_use_p2a) {
28083c6620bSDave Airlie boot_address = get_fw_base(ast);
28183c6620bSDave Airlie
28283c6620bSDave Airlie /* validate FW version */
283ba4e0339SKuoHsiang Chou offset = AST_DP501_GBL_VERSION;
28483c6620bSDave Airlie data = ast_mindwm(ast, boot_address + offset);
285ba4e0339SKuoHsiang Chou if ((data & AST_DP501_FW_VERSION_MASK) != AST_DP501_FW_VERSION_1)
28683c6620bSDave Airlie return false;
28783c6620bSDave Airlie
28883c6620bSDave Airlie /* validate PnP Monitor */
289ba4e0339SKuoHsiang Chou offset = AST_DP501_PNPMONITOR;
29083c6620bSDave Airlie data = ast_mindwm(ast, boot_address + offset);
291ba4e0339SKuoHsiang Chou if (!(data & AST_DP501_PNP_CONNECTED))
29283c6620bSDave Airlie return false;
293ba4e0339SKuoHsiang Chou } else {
294ba4e0339SKuoHsiang Chou if (!ast->dp501_fw_buf)
295ba4e0339SKuoHsiang Chou return false;
296ba4e0339SKuoHsiang Chou
297ba4e0339SKuoHsiang Chou /* dummy read */
298ba4e0339SKuoHsiang Chou offset = 0x0000;
299ba4e0339SKuoHsiang Chou data = readl(ast->dp501_fw_buf + offset);
300ba4e0339SKuoHsiang Chou
301ba4e0339SKuoHsiang Chou /* validate FW version */
302ba4e0339SKuoHsiang Chou offset = AST_DP501_GBL_VERSION;
303ba4e0339SKuoHsiang Chou data = readl(ast->dp501_fw_buf + offset);
304ba4e0339SKuoHsiang Chou if ((data & AST_DP501_FW_VERSION_MASK) != AST_DP501_FW_VERSION_1)
305ba4e0339SKuoHsiang Chou return false;
306ba4e0339SKuoHsiang Chou
307ba4e0339SKuoHsiang Chou /* validate PnP Monitor */
308ba4e0339SKuoHsiang Chou offset = AST_DP501_PNPMONITOR;
309ba4e0339SKuoHsiang Chou data = readl(ast->dp501_fw_buf + offset);
310ba4e0339SKuoHsiang Chou if (!(data & AST_DP501_PNP_CONNECTED))
311ba4e0339SKuoHsiang Chou return false;
312*f81bb0acSJocelyn Falempe }
313*f81bb0acSJocelyn Falempe return true;
314*f81bb0acSJocelyn Falempe }
315ba4e0339SKuoHsiang Chou
ast_dp501_read_edid(struct drm_device * dev,u8 * ediddata)316*f81bb0acSJocelyn Falempe bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata)
317*f81bb0acSJocelyn Falempe {
318*f81bb0acSJocelyn Falempe struct ast_device *ast = to_ast_device(dev);
319*f81bb0acSJocelyn Falempe u32 i, boot_address, offset, data;
320*f81bb0acSJocelyn Falempe u32 *pEDIDidx;
321*f81bb0acSJocelyn Falempe
322*f81bb0acSJocelyn Falempe if (!ast_dp501_is_connected(ast))
323*f81bb0acSJocelyn Falempe return false;
324*f81bb0acSJocelyn Falempe
325*f81bb0acSJocelyn Falempe if (ast->config_mode == ast_use_p2a) {
326*f81bb0acSJocelyn Falempe boot_address = get_fw_base(ast);
327*f81bb0acSJocelyn Falempe
328*f81bb0acSJocelyn Falempe /* Read EDID */
329*f81bb0acSJocelyn Falempe offset = AST_DP501_EDID_DATA;
330*f81bb0acSJocelyn Falempe for (i = 0; i < 128; i += 4) {
331*f81bb0acSJocelyn Falempe data = ast_mindwm(ast, boot_address + offset + i);
332*f81bb0acSJocelyn Falempe pEDIDidx = (u32 *)(ediddata + i);
333*f81bb0acSJocelyn Falempe *pEDIDidx = data;
334*f81bb0acSJocelyn Falempe }
335*f81bb0acSJocelyn Falempe } else {
336ba4e0339SKuoHsiang Chou /* Read EDID */
337ba4e0339SKuoHsiang Chou offset = AST_DP501_EDID_DATA;
338ba4e0339SKuoHsiang Chou for (i = 0; i < 128; i += 4) {
339ba4e0339SKuoHsiang Chou data = readl(ast->dp501_fw_buf + offset + i);
340ba4e0339SKuoHsiang Chou pEDIDidx = (u32 *)(ediddata + i);
341ba4e0339SKuoHsiang Chou *pEDIDidx = data;
342ba4e0339SKuoHsiang Chou }
34383c6620bSDave Airlie }
34483c6620bSDave Airlie
34583c6620bSDave Airlie return true;
34683c6620bSDave Airlie }
34783c6620bSDave Airlie
ast_init_dvo(struct drm_device * dev)34883c6620bSDave Airlie static bool ast_init_dvo(struct drm_device *dev)
34983c6620bSDave Airlie {
3505abaa683SThomas Zimmermann struct ast_device *ast = to_ast_device(dev);
35183c6620bSDave Airlie u8 jreg;
35283c6620bSDave Airlie u32 data;
35383c6620bSDave Airlie ast_write32(ast, 0xf004, 0x1e6e0000);
35483c6620bSDave Airlie ast_write32(ast, 0xf000, 0x1);
35583c6620bSDave Airlie ast_write32(ast, 0x12000, 0x1688a8a8);
35683c6620bSDave Airlie
35783c6620bSDave Airlie jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
35883c6620bSDave Airlie if (!(jreg & 0x80)) {
35983c6620bSDave Airlie /* Init SCU DVO Settings */
36083c6620bSDave Airlie data = ast_read32(ast, 0x12008);
36183c6620bSDave Airlie /* delay phase */
36283c6620bSDave Airlie data &= 0xfffff8ff;
36383c6620bSDave Airlie data |= 0x00000500;
36483c6620bSDave Airlie ast_write32(ast, 0x12008, data);
36583c6620bSDave Airlie
366ecf64579SThomas Zimmermann if (IS_AST_GEN4(ast)) {
36783c6620bSDave Airlie data = ast_read32(ast, 0x12084);
36883c6620bSDave Airlie /* multi-pins for DVO single-edge */
36983c6620bSDave Airlie data |= 0xfffe0000;
37083c6620bSDave Airlie ast_write32(ast, 0x12084, data);
37183c6620bSDave Airlie
37283c6620bSDave Airlie data = ast_read32(ast, 0x12088);
37383c6620bSDave Airlie /* multi-pins for DVO single-edge */
37483c6620bSDave Airlie data |= 0x000fffff;
37583c6620bSDave Airlie ast_write32(ast, 0x12088, data);
37683c6620bSDave Airlie
37783c6620bSDave Airlie data = ast_read32(ast, 0x12090);
37883c6620bSDave Airlie /* multi-pins for DVO single-edge */
37983c6620bSDave Airlie data &= 0xffffffcf;
38083c6620bSDave Airlie data |= 0x00000020;
38183c6620bSDave Airlie ast_write32(ast, 0x12090, data);
382ecf64579SThomas Zimmermann } else { /* AST GEN5+ */
38383c6620bSDave Airlie data = ast_read32(ast, 0x12088);
38483c6620bSDave Airlie /* multi-pins for DVO single-edge */
38583c6620bSDave Airlie data |= 0x30000000;
38683c6620bSDave Airlie ast_write32(ast, 0x12088, data);
38783c6620bSDave Airlie
38883c6620bSDave Airlie data = ast_read32(ast, 0x1208c);
38983c6620bSDave Airlie /* multi-pins for DVO single-edge */
39083c6620bSDave Airlie data |= 0x000000cf;
39183c6620bSDave Airlie ast_write32(ast, 0x1208c, data);
39283c6620bSDave Airlie
39383c6620bSDave Airlie data = ast_read32(ast, 0x120a4);
39483c6620bSDave Airlie /* multi-pins for DVO single-edge */
39583c6620bSDave Airlie data |= 0xffff0000;
39683c6620bSDave Airlie ast_write32(ast, 0x120a4, data);
39783c6620bSDave Airlie
39883c6620bSDave Airlie data = ast_read32(ast, 0x120a8);
39983c6620bSDave Airlie /* multi-pins for DVO single-edge */
40083c6620bSDave Airlie data |= 0x0000000f;
40183c6620bSDave Airlie ast_write32(ast, 0x120a8, data);
40283c6620bSDave Airlie
40383c6620bSDave Airlie data = ast_read32(ast, 0x12094);
40483c6620bSDave Airlie /* multi-pins for DVO single-edge */
40583c6620bSDave Airlie data |= 0x00000002;
40683c6620bSDave Airlie ast_write32(ast, 0x12094, data);
40783c6620bSDave Airlie }
40883c6620bSDave Airlie }
40983c6620bSDave Airlie
41083c6620bSDave Airlie /* Force to DVO */
41183c6620bSDave Airlie data = ast_read32(ast, 0x1202c);
41283c6620bSDave Airlie data &= 0xfffbffff;
41383c6620bSDave Airlie ast_write32(ast, 0x1202c, data);
41483c6620bSDave Airlie
41583c6620bSDave Airlie /* Init VGA DVO Settings */
41683c6620bSDave Airlie ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80);
41783c6620bSDave Airlie return true;
41883c6620bSDave Airlie }
41983c6620bSDave Airlie
42037b9b81fSBenjamin Herrenschmidt
ast_init_analog(struct drm_device * dev)42137b9b81fSBenjamin Herrenschmidt static void ast_init_analog(struct drm_device *dev)
42237b9b81fSBenjamin Herrenschmidt {
4235abaa683SThomas Zimmermann struct ast_device *ast = to_ast_device(dev);
42437b9b81fSBenjamin Herrenschmidt u32 data;
42537b9b81fSBenjamin Herrenschmidt
42637b9b81fSBenjamin Herrenschmidt /*
42737b9b81fSBenjamin Herrenschmidt * Set DAC source to VGA mode in SCU2C via the P2A
42837b9b81fSBenjamin Herrenschmidt * bridge. First configure the P2U to target the SCU
42937b9b81fSBenjamin Herrenschmidt * in case it isn't at this stage.
43037b9b81fSBenjamin Herrenschmidt */
43137b9b81fSBenjamin Herrenschmidt ast_write32(ast, 0xf004, 0x1e6e0000);
43237b9b81fSBenjamin Herrenschmidt ast_write32(ast, 0xf000, 0x1);
43337b9b81fSBenjamin Herrenschmidt
43437b9b81fSBenjamin Herrenschmidt /* Then unlock the SCU with the magic password */
43537b9b81fSBenjamin Herrenschmidt ast_write32(ast, 0x12000, 0x1688a8a8);
43637b9b81fSBenjamin Herrenschmidt ast_write32(ast, 0x12000, 0x1688a8a8);
43737b9b81fSBenjamin Herrenschmidt ast_write32(ast, 0x12000, 0x1688a8a8);
43837b9b81fSBenjamin Herrenschmidt
43937b9b81fSBenjamin Herrenschmidt /* Finally, clear bits [17:16] of SCU2c */
44037b9b81fSBenjamin Herrenschmidt data = ast_read32(ast, 0x1202c);
44137b9b81fSBenjamin Herrenschmidt data &= 0xfffcffff;
44237b9b81fSBenjamin Herrenschmidt ast_write32(ast, 0, data);
44337b9b81fSBenjamin Herrenschmidt
44437b9b81fSBenjamin Herrenschmidt /* Disable DVO */
44537b9b81fSBenjamin Herrenschmidt ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x00);
44637b9b81fSBenjamin Herrenschmidt }
44737b9b81fSBenjamin Herrenschmidt
ast_init_3rdtx(struct drm_device * dev)44883c6620bSDave Airlie void ast_init_3rdtx(struct drm_device *dev)
44983c6620bSDave Airlie {
4505abaa683SThomas Zimmermann struct ast_device *ast = to_ast_device(dev);
45183c6620bSDave Airlie u8 jreg;
45237b9b81fSBenjamin Herrenschmidt
453ecf64579SThomas Zimmermann if (IS_AST_GEN4(ast) || IS_AST_GEN5(ast)) {
45483c6620bSDave Airlie jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff);
45583c6620bSDave Airlie switch (jreg & 0x0e) {
45683c6620bSDave Airlie case 0x04:
45783c6620bSDave Airlie ast_init_dvo(dev);
45883c6620bSDave Airlie break;
45983c6620bSDave Airlie case 0x08:
46083c6620bSDave Airlie ast_launch_m68k(dev);
46183c6620bSDave Airlie break;
46283c6620bSDave Airlie case 0x0c:
46383c6620bSDave Airlie ast_init_dvo(dev);
46483c6620bSDave Airlie break;
46583c6620bSDave Airlie default:
4667f35680aSThomas Zimmermann if (ast->tx_chip_types & BIT(AST_TX_SIL164))
46783c6620bSDave Airlie ast_init_dvo(dev);
46837b9b81fSBenjamin Herrenschmidt else
46937b9b81fSBenjamin Herrenschmidt ast_init_analog(dev);
47083c6620bSDave Airlie }
47183c6620bSDave Airlie }
47283c6620bSDave Airlie }
473