18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
48c2ecf20Sopenharmony_ci * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/via-core.h>
88c2ecf20Sopenharmony_ci#include <linux/via_i2c.h>
98c2ecf20Sopenharmony_ci#include "global.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistatic void tmds_register_write(int index, u8 data);
128c2ecf20Sopenharmony_cistatic int tmds_register_read(int index);
138c2ecf20Sopenharmony_cistatic int tmds_register_read_bytes(int index, u8 *buff, int buff_len);
148c2ecf20Sopenharmony_cistatic void dvi_get_panel_size_from_DDCv1(
158c2ecf20Sopenharmony_ci	struct tmds_chip_information *tmds_chip,
168c2ecf20Sopenharmony_ci	struct tmds_setting_information *tmds_setting);
178c2ecf20Sopenharmony_cistatic int viafb_dvi_query_EDID(void);
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic inline bool check_tmds_chip(int device_id_subaddr, int device_id)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	return tmds_register_read(device_id_subaddr) == device_id;
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_civoid viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
258c2ecf20Sopenharmony_ci			 struct tmds_setting_information *tmds_setting)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	DEBUG_MSG(KERN_INFO "viafb_init_dvi_size()\n");
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	viafb_dvi_sense();
308c2ecf20Sopenharmony_ci	if (viafb_dvi_query_EDID() == 1)
318c2ecf20Sopenharmony_ci		dvi_get_panel_size_from_DDCv1(tmds_chip, tmds_setting);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	return;
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cibool viafb_tmds_trasmitter_identify(void)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	unsigned char sr2a = 0, sr1e = 0, sr3e = 0;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* Turn on ouputting pad */
418c2ecf20Sopenharmony_ci	switch (viaparinfo->chip_info->gfx_chip_name) {
428c2ecf20Sopenharmony_ci	case UNICHROME_K8M890:
438c2ecf20Sopenharmony_ci	    /*=* DFP Low Pad on *=*/
448c2ecf20Sopenharmony_ci		sr2a = viafb_read_reg(VIASR, SR2A);
458c2ecf20Sopenharmony_ci		viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1);
468c2ecf20Sopenharmony_ci		break;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	case UNICHROME_P4M900:
498c2ecf20Sopenharmony_ci	case UNICHROME_P4M890:
508c2ecf20Sopenharmony_ci		/* DFP Low Pad on */
518c2ecf20Sopenharmony_ci		sr2a = viafb_read_reg(VIASR, SR2A);
528c2ecf20Sopenharmony_ci		viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1);
538c2ecf20Sopenharmony_ci		/* DVP0 Pad on */
548c2ecf20Sopenharmony_ci		sr1e = viafb_read_reg(VIASR, SR1E);
558c2ecf20Sopenharmony_ci		viafb_write_reg_mask(SR1E, VIASR, 0xC0, BIT6 + BIT7);
568c2ecf20Sopenharmony_ci		break;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	default:
598c2ecf20Sopenharmony_ci	    /* DVP0/DVP1 Pad on */
608c2ecf20Sopenharmony_ci		sr1e = viafb_read_reg(VIASR, SR1E);
618c2ecf20Sopenharmony_ci		viafb_write_reg_mask(SR1E, VIASR, 0xF0, BIT4 +
628c2ecf20Sopenharmony_ci			BIT5 + BIT6 + BIT7);
638c2ecf20Sopenharmony_ci	    /* SR3E[1]Multi-function selection:
648c2ecf20Sopenharmony_ci	    0 = Emulate I2C and DDC bus by GPIO2/3/4. */
658c2ecf20Sopenharmony_ci		sr3e = viafb_read_reg(VIASR, SR3E);
668c2ecf20Sopenharmony_ci		viafb_write_reg_mask(SR3E, VIASR, 0x0, BIT5);
678c2ecf20Sopenharmony_ci		break;
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	/* Check for VT1632: */
718c2ecf20Sopenharmony_ci	viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = VT1632_TMDS;
728c2ecf20Sopenharmony_ci	viaparinfo->chip_info->
738c2ecf20Sopenharmony_ci		tmds_chip_info.tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR;
748c2ecf20Sopenharmony_ci	viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_31;
758c2ecf20Sopenharmony_ci	if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID)) {
768c2ecf20Sopenharmony_ci		/*
778c2ecf20Sopenharmony_ci		 * Currently only support 12bits,dual edge,add 24bits mode later
788c2ecf20Sopenharmony_ci		 */
798c2ecf20Sopenharmony_ci		tmds_register_write(0x08, 0x3b);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci		DEBUG_MSG(KERN_INFO "\n VT1632 TMDS ! \n");
828c2ecf20Sopenharmony_ci		DEBUG_MSG(KERN_INFO "\n %2d",
838c2ecf20Sopenharmony_ci			  viaparinfo->chip_info->tmds_chip_info.tmds_chip_name);
848c2ecf20Sopenharmony_ci		DEBUG_MSG(KERN_INFO "\n %2d",
858c2ecf20Sopenharmony_ci			  viaparinfo->chip_info->tmds_chip_info.i2c_port);
868c2ecf20Sopenharmony_ci		return true;
878c2ecf20Sopenharmony_ci	} else {
888c2ecf20Sopenharmony_ci		viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_2C;
898c2ecf20Sopenharmony_ci		if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID)) {
908c2ecf20Sopenharmony_ci			tmds_register_write(0x08, 0x3b);
918c2ecf20Sopenharmony_ci			DEBUG_MSG(KERN_INFO "\n VT1632 TMDS ! \n");
928c2ecf20Sopenharmony_ci			DEBUG_MSG(KERN_INFO "\n %2d",
938c2ecf20Sopenharmony_ci				  viaparinfo->chip_info->
948c2ecf20Sopenharmony_ci				  tmds_chip_info.tmds_chip_name);
958c2ecf20Sopenharmony_ci			DEBUG_MSG(KERN_INFO "\n %2d",
968c2ecf20Sopenharmony_ci				  viaparinfo->chip_info->
978c2ecf20Sopenharmony_ci				  tmds_chip_info.i2c_port);
988c2ecf20Sopenharmony_ci			return true;
998c2ecf20Sopenharmony_ci		}
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = INTEGRATED_TMDS;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) &&
1058c2ecf20Sopenharmony_ci	    ((viafb_display_hardware_layout == HW_LAYOUT_DVI_ONLY) ||
1068c2ecf20Sopenharmony_ci	     (viafb_display_hardware_layout == HW_LAYOUT_LCD_DVI))) {
1078c2ecf20Sopenharmony_ci		DEBUG_MSG(KERN_INFO "\n Integrated TMDS ! \n");
1088c2ecf20Sopenharmony_ci		return true;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	switch (viaparinfo->chip_info->gfx_chip_name) {
1128c2ecf20Sopenharmony_ci	case UNICHROME_K8M890:
1138c2ecf20Sopenharmony_ci		viafb_write_reg(SR2A, VIASR, sr2a);
1148c2ecf20Sopenharmony_ci		break;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	case UNICHROME_P4M900:
1178c2ecf20Sopenharmony_ci	case UNICHROME_P4M890:
1188c2ecf20Sopenharmony_ci		viafb_write_reg(SR2A, VIASR, sr2a);
1198c2ecf20Sopenharmony_ci		viafb_write_reg(SR1E, VIASR, sr1e);
1208c2ecf20Sopenharmony_ci		break;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	default:
1238c2ecf20Sopenharmony_ci		viafb_write_reg(SR1E, VIASR, sr1e);
1248c2ecf20Sopenharmony_ci		viafb_write_reg(SR3E, VIASR, sr3e);
1258c2ecf20Sopenharmony_ci		break;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	viaparinfo->chip_info->
1298c2ecf20Sopenharmony_ci		tmds_chip_info.tmds_chip_name = NON_TMDS_TRANSMITTER;
1308c2ecf20Sopenharmony_ci	viaparinfo->chip_info->tmds_chip_info.
1318c2ecf20Sopenharmony_ci		tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR;
1328c2ecf20Sopenharmony_ci	return false;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic void tmds_register_write(int index, u8 data)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info.i2c_port,
1388c2ecf20Sopenharmony_ci			    viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr,
1398c2ecf20Sopenharmony_ci			    index, data);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic int tmds_register_read(int index)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	u8 data;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	viafb_i2c_readbyte(viaparinfo->chip_info->tmds_chip_info.i2c_port,
1478c2ecf20Sopenharmony_ci			   (u8) viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr,
1488c2ecf20Sopenharmony_ci			   (u8) index, &data);
1498c2ecf20Sopenharmony_ci	return data;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int tmds_register_read_bytes(int index, u8 *buff, int buff_len)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	viafb_i2c_readbytes(viaparinfo->chip_info->tmds_chip_info.i2c_port,
1558c2ecf20Sopenharmony_ci			    (u8) viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr,
1568c2ecf20Sopenharmony_ci			    (u8) index, buff, buff_len);
1578c2ecf20Sopenharmony_ci	return 0;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/* DVI Set Mode */
1618c2ecf20Sopenharmony_civoid viafb_dvi_set_mode(const struct fb_var_screeninfo *var,
1628c2ecf20Sopenharmony_ci	u16 cxres, u16 cyres, int iga)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct fb_var_screeninfo dvi_var = *var;
1658c2ecf20Sopenharmony_ci	const struct fb_videomode *rb_mode;
1668c2ecf20Sopenharmony_ci	int maxPixelClock;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	maxPixelClock = viaparinfo->shared->tmds_setting_info.max_pixel_clock;
1698c2ecf20Sopenharmony_ci	if (maxPixelClock && PICOS2KHZ(var->pixclock) / 1000 > maxPixelClock) {
1708c2ecf20Sopenharmony_ci		rb_mode = viafb_get_best_rb_mode(var->xres, var->yres, 60);
1718c2ecf20Sopenharmony_ci		if (rb_mode)
1728c2ecf20Sopenharmony_ci			viafb_fill_var_timing_info(&dvi_var, rb_mode);
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	viafb_fill_crtc_timing(&dvi_var, cxres, cyres, iga);
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci/* Sense DVI Connector */
1798c2ecf20Sopenharmony_ciint viafb_dvi_sense(void)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	u8 RegSR1E = 0, RegSR3E = 0, RegCR6B = 0, RegCR91 = 0,
1828c2ecf20Sopenharmony_ci		RegCR93 = 0, RegCR9B = 0, data;
1838c2ecf20Sopenharmony_ci	int ret = false;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	DEBUG_MSG(KERN_INFO "viafb_dvi_sense!!\n");
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
1888c2ecf20Sopenharmony_ci		/* DI1 Pad on */
1898c2ecf20Sopenharmony_ci		RegSR1E = viafb_read_reg(VIASR, SR1E);
1908c2ecf20Sopenharmony_ci		viafb_write_reg(SR1E, VIASR, RegSR1E | 0x30);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci		/* CR6B[0]VCK Input Selection: 1 = External clock. */
1938c2ecf20Sopenharmony_ci		RegCR6B = viafb_read_reg(VIACR, CR6B);
1948c2ecf20Sopenharmony_ci		viafb_write_reg(CR6B, VIACR, RegCR6B | 0x08);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci		/* CR91[4] VDD On [3] Data On [2] VEE On [1] Back Light Off
1978c2ecf20Sopenharmony_ci		   [0] Software Control Power Sequence */
1988c2ecf20Sopenharmony_ci		RegCR91 = viafb_read_reg(VIACR, CR91);
1998c2ecf20Sopenharmony_ci		viafb_write_reg(CR91, VIACR, 0x1D);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		/* CR93[7] DI1 Data Source Selection: 1 = DSP2.
2028c2ecf20Sopenharmony_ci		   CR93[5] DI1 Clock Source: 1 = internal.
2038c2ecf20Sopenharmony_ci		   CR93[4] DI1 Clock Polarity.
2048c2ecf20Sopenharmony_ci		   CR93[3:1] DI1 Clock Adjust. CR93[0] DI1 enable */
2058c2ecf20Sopenharmony_ci		RegCR93 = viafb_read_reg(VIACR, CR93);
2068c2ecf20Sopenharmony_ci		viafb_write_reg(CR93, VIACR, 0x01);
2078c2ecf20Sopenharmony_ci	} else {
2088c2ecf20Sopenharmony_ci		/* DVP0/DVP1 Pad on */
2098c2ecf20Sopenharmony_ci		RegSR1E = viafb_read_reg(VIASR, SR1E);
2108c2ecf20Sopenharmony_ci		viafb_write_reg(SR1E, VIASR, RegSR1E | 0xF0);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci		/* SR3E[1]Multi-function selection:
2138c2ecf20Sopenharmony_ci		   0 = Emulate I2C and DDC bus by GPIO2/3/4. */
2148c2ecf20Sopenharmony_ci		RegSR3E = viafb_read_reg(VIASR, SR3E);
2158c2ecf20Sopenharmony_ci		viafb_write_reg(SR3E, VIASR, RegSR3E & (~0x20));
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		/* CR91[4] VDD On [3] Data On [2] VEE On [1] Back Light Off
2188c2ecf20Sopenharmony_ci		   [0] Software Control Power Sequence */
2198c2ecf20Sopenharmony_ci		RegCR91 = viafb_read_reg(VIACR, CR91);
2208c2ecf20Sopenharmony_ci		viafb_write_reg(CR91, VIACR, 0x1D);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		/*CR9B[4] DVP1 Data Source Selection: 1 = From secondary
2238c2ecf20Sopenharmony_ci		display.CR9B[2:0] DVP1 Clock Adjust */
2248c2ecf20Sopenharmony_ci		RegCR9B = viafb_read_reg(VIACR, CR9B);
2258c2ecf20Sopenharmony_ci		viafb_write_reg(CR9B, VIACR, 0x01);
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	data = (u8) tmds_register_read(0x09);
2298c2ecf20Sopenharmony_ci	if (data & 0x04)
2308c2ecf20Sopenharmony_ci		ret = true;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (ret == false) {
2338c2ecf20Sopenharmony_ci		if (viafb_dvi_query_EDID())
2348c2ecf20Sopenharmony_ci			ret = true;
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/* Restore status */
2388c2ecf20Sopenharmony_ci	viafb_write_reg(SR1E, VIASR, RegSR1E);
2398c2ecf20Sopenharmony_ci	viafb_write_reg(CR91, VIACR, RegCR91);
2408c2ecf20Sopenharmony_ci	if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
2418c2ecf20Sopenharmony_ci		viafb_write_reg(CR6B, VIACR, RegCR6B);
2428c2ecf20Sopenharmony_ci		viafb_write_reg(CR93, VIACR, RegCR93);
2438c2ecf20Sopenharmony_ci	} else {
2448c2ecf20Sopenharmony_ci		viafb_write_reg(SR3E, VIASR, RegSR3E);
2458c2ecf20Sopenharmony_ci		viafb_write_reg(CR9B, VIACR, RegCR9B);
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	return ret;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/* Query Flat Panel's EDID Table Version Through DVI Connector */
2528c2ecf20Sopenharmony_cistatic int viafb_dvi_query_EDID(void)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	u8 data0, data1;
2558c2ecf20Sopenharmony_ci	int restore;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	DEBUG_MSG(KERN_INFO "viafb_dvi_query_EDID!!\n");
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr;
2608c2ecf20Sopenharmony_ci	viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA0;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	data0 = (u8) tmds_register_read(0x00);
2638c2ecf20Sopenharmony_ci	data1 = (u8) tmds_register_read(0x01);
2648c2ecf20Sopenharmony_ci	if ((data0 == 0) && (data1 == 0xFF)) {
2658c2ecf20Sopenharmony_ci		viaparinfo->chip_info->
2668c2ecf20Sopenharmony_ci			tmds_chip_info.tmds_chip_slave_addr = restore;
2678c2ecf20Sopenharmony_ci		return EDID_VERSION_1;	/* Found EDID1 Table */
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	return false;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci/* Get Panel Size Using EDID1 Table */
2748c2ecf20Sopenharmony_cistatic void dvi_get_panel_size_from_DDCv1(
2758c2ecf20Sopenharmony_ci	struct tmds_chip_information *tmds_chip,
2768c2ecf20Sopenharmony_ci	struct tmds_setting_information *tmds_setting)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	int i, restore;
2798c2ecf20Sopenharmony_ci	unsigned char EDID_DATA[18];
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	DEBUG_MSG(KERN_INFO "\n dvi_get_panel_size_from_DDCv1 \n");
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	restore = tmds_chip->tmds_chip_slave_addr;
2848c2ecf20Sopenharmony_ci	tmds_chip->tmds_chip_slave_addr = 0xA0;
2858c2ecf20Sopenharmony_ci	for (i = 0x25; i < 0x6D; i++) {
2868c2ecf20Sopenharmony_ci		switch (i) {
2878c2ecf20Sopenharmony_ci		case 0x36:
2888c2ecf20Sopenharmony_ci		case 0x48:
2898c2ecf20Sopenharmony_ci		case 0x5A:
2908c2ecf20Sopenharmony_ci		case 0x6C:
2918c2ecf20Sopenharmony_ci			tmds_register_read_bytes(i, EDID_DATA, 10);
2928c2ecf20Sopenharmony_ci			if (!(EDID_DATA[0] || EDID_DATA[1])) {
2938c2ecf20Sopenharmony_ci				/* The first two byte must be zero. */
2948c2ecf20Sopenharmony_ci				if (EDID_DATA[3] == 0xFD) {
2958c2ecf20Sopenharmony_ci					/* To get max pixel clock. */
2968c2ecf20Sopenharmony_ci					tmds_setting->max_pixel_clock =
2978c2ecf20Sopenharmony_ci						EDID_DATA[9] * 10;
2988c2ecf20Sopenharmony_ci				}
2998c2ecf20Sopenharmony_ci			}
3008c2ecf20Sopenharmony_ci			break;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci		default:
3038c2ecf20Sopenharmony_ci			break;
3048c2ecf20Sopenharmony_ci		}
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	DEBUG_MSG(KERN_INFO "DVI max pixelclock = %d\n",
3088c2ecf20Sopenharmony_ci		tmds_setting->max_pixel_clock);
3098c2ecf20Sopenharmony_ci	tmds_chip->tmds_chip_slave_addr = restore;
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci/* If Disable DVI, turn off pad */
3138c2ecf20Sopenharmony_civoid viafb_dvi_disable(void)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	if (viaparinfo->chip_info->
3168c2ecf20Sopenharmony_ci		tmds_chip_info.output_interface == INTERFACE_TMDS)
3178c2ecf20Sopenharmony_ci		/* Turn off TMDS power. */
3188c2ecf20Sopenharmony_ci		viafb_write_reg(CRD2, VIACR,
3198c2ecf20Sopenharmony_ci		viafb_read_reg(VIACR, CRD2) | 0x08);
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic void dvi_patch_skew_dvp0(void)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	/* Reset data driving first: */
3258c2ecf20Sopenharmony_ci	viafb_write_reg_mask(SR1B, VIASR, 0, BIT1);
3268c2ecf20Sopenharmony_ci	viafb_write_reg_mask(SR2A, VIASR, 0, BIT4);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	switch (viaparinfo->chip_info->gfx_chip_name) {
3298c2ecf20Sopenharmony_ci	case UNICHROME_P4M890:
3308c2ecf20Sopenharmony_ci		{
3318c2ecf20Sopenharmony_ci			if ((viaparinfo->tmds_setting_info->h_active == 1600) &&
3328c2ecf20Sopenharmony_ci				(viaparinfo->tmds_setting_info->v_active ==
3338c2ecf20Sopenharmony_ci				1200))
3348c2ecf20Sopenharmony_ci				viafb_write_reg_mask(CR96, VIACR, 0x03,
3358c2ecf20Sopenharmony_ci					       BIT0 + BIT1 + BIT2);
3368c2ecf20Sopenharmony_ci			else
3378c2ecf20Sopenharmony_ci				viafb_write_reg_mask(CR96, VIACR, 0x07,
3388c2ecf20Sopenharmony_ci					       BIT0 + BIT1 + BIT2);
3398c2ecf20Sopenharmony_ci			break;
3408c2ecf20Sopenharmony_ci		}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	case UNICHROME_P4M900:
3438c2ecf20Sopenharmony_ci		{
3448c2ecf20Sopenharmony_ci			viafb_write_reg_mask(CR96, VIACR, 0x07,
3458c2ecf20Sopenharmony_ci				       BIT0 + BIT1 + BIT2 + BIT3);
3468c2ecf20Sopenharmony_ci			viafb_write_reg_mask(SR1B, VIASR, 0x02, BIT1);
3478c2ecf20Sopenharmony_ci			viafb_write_reg_mask(SR2A, VIASR, 0x10, BIT4);
3488c2ecf20Sopenharmony_ci			break;
3498c2ecf20Sopenharmony_ci		}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	default:
3528c2ecf20Sopenharmony_ci		{
3538c2ecf20Sopenharmony_ci			break;
3548c2ecf20Sopenharmony_ci		}
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic void dvi_patch_skew_dvp_low(void)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	switch (viaparinfo->chip_info->gfx_chip_name) {
3618c2ecf20Sopenharmony_ci	case UNICHROME_K8M890:
3628c2ecf20Sopenharmony_ci		{
3638c2ecf20Sopenharmony_ci			viafb_write_reg_mask(CR99, VIACR, 0x03, BIT0 + BIT1);
3648c2ecf20Sopenharmony_ci			break;
3658c2ecf20Sopenharmony_ci		}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	case UNICHROME_P4M900:
3688c2ecf20Sopenharmony_ci		{
3698c2ecf20Sopenharmony_ci			viafb_write_reg_mask(CR99, VIACR, 0x08,
3708c2ecf20Sopenharmony_ci				       BIT0 + BIT1 + BIT2 + BIT3);
3718c2ecf20Sopenharmony_ci			break;
3728c2ecf20Sopenharmony_ci		}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	case UNICHROME_P4M890:
3758c2ecf20Sopenharmony_ci		{
3768c2ecf20Sopenharmony_ci			viafb_write_reg_mask(CR99, VIACR, 0x0F,
3778c2ecf20Sopenharmony_ci				       BIT0 + BIT1 + BIT2 + BIT3);
3788c2ecf20Sopenharmony_ci			break;
3798c2ecf20Sopenharmony_ci		}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	default:
3828c2ecf20Sopenharmony_ci		{
3838c2ecf20Sopenharmony_ci			break;
3848c2ecf20Sopenharmony_ci		}
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci/* If Enable DVI, turn off pad */
3898c2ecf20Sopenharmony_civoid viafb_dvi_enable(void)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	u8 data;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	switch (viaparinfo->chip_info->tmds_chip_info.output_interface) {
3948c2ecf20Sopenharmony_ci	case INTERFACE_DVP0:
3958c2ecf20Sopenharmony_ci		viafb_write_reg_mask(CR6B, VIACR, 0x01, BIT0);
3968c2ecf20Sopenharmony_ci		viafb_write_reg_mask(CR6C, VIACR, 0x21, BIT0 + BIT5);
3978c2ecf20Sopenharmony_ci		dvi_patch_skew_dvp0();
3988c2ecf20Sopenharmony_ci		if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
3998c2ecf20Sopenharmony_ci			tmds_register_write(0x88, 0x3b);
4008c2ecf20Sopenharmony_ci		else
4018c2ecf20Sopenharmony_ci			/*clear CR91[5] to direct on display period
4028c2ecf20Sopenharmony_ci			   in the secondary diplay path */
4038c2ecf20Sopenharmony_ci			via_write_reg_mask(VIACR, 0x91, 0x00, 0x20);
4048c2ecf20Sopenharmony_ci		break;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	case INTERFACE_DVP1:
4078c2ecf20Sopenharmony_ci		if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
4088c2ecf20Sopenharmony_ci			viafb_write_reg_mask(CR93, VIACR, 0x21, BIT0 + BIT5);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci		/*fix dvi cann't be enabled with MB VT5718C4 - Al Zhang */
4118c2ecf20Sopenharmony_ci		if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
4128c2ecf20Sopenharmony_ci			tmds_register_write(0x88, 0x3b);
4138c2ecf20Sopenharmony_ci		else
4148c2ecf20Sopenharmony_ci			/*clear CR91[5] to direct on display period
4158c2ecf20Sopenharmony_ci			  in the secondary diplay path */
4168c2ecf20Sopenharmony_ci			via_write_reg_mask(VIACR, 0x91, 0x00, 0x20);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci		/*fix DVI cannot enable on EPIA-M board */
4198c2ecf20Sopenharmony_ci		if (viafb_platform_epia_dvi == 1) {
4208c2ecf20Sopenharmony_ci			viafb_write_reg_mask(CR91, VIACR, 0x1f, 0x1f);
4218c2ecf20Sopenharmony_ci			viafb_write_reg_mask(CR88, VIACR, 0x00, BIT6 + BIT0);
4228c2ecf20Sopenharmony_ci			if (viafb_bus_width == 24) {
4238c2ecf20Sopenharmony_ci				if (viafb_device_lcd_dualedge == 1)
4248c2ecf20Sopenharmony_ci					data = 0x3F;
4258c2ecf20Sopenharmony_ci				else
4268c2ecf20Sopenharmony_ci					data = 0x37;
4278c2ecf20Sopenharmony_ci				viafb_i2c_writebyte(viaparinfo->chip_info->
4288c2ecf20Sopenharmony_ci					tmds_chip_info.i2c_port,
4298c2ecf20Sopenharmony_ci					viaparinfo->chip_info->
4308c2ecf20Sopenharmony_ci					tmds_chip_info.tmds_chip_slave_addr,
4318c2ecf20Sopenharmony_ci					0x08, data);
4328c2ecf20Sopenharmony_ci			}
4338c2ecf20Sopenharmony_ci		}
4348c2ecf20Sopenharmony_ci		break;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	case INTERFACE_DFP_HIGH:
4378c2ecf20Sopenharmony_ci		if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
4388c2ecf20Sopenharmony_ci			via_write_reg_mask(VIACR, CR97, 0x03, 0x03);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci		via_write_reg_mask(VIACR, 0x91, 0x00, 0x20);
4418c2ecf20Sopenharmony_ci		break;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	case INTERFACE_DFP_LOW:
4448c2ecf20Sopenharmony_ci		if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
4458c2ecf20Sopenharmony_ci			break;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci		dvi_patch_skew_dvp_low();
4488c2ecf20Sopenharmony_ci		via_write_reg_mask(VIACR, 0x91, 0x00, 0x20);
4498c2ecf20Sopenharmony_ci		break;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	case INTERFACE_TMDS:
4528c2ecf20Sopenharmony_ci		/* Turn on Display period in the panel path. */
4538c2ecf20Sopenharmony_ci		viafb_write_reg_mask(CR91, VIACR, 0, BIT7);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci		/* Turn on TMDS power. */
4568c2ecf20Sopenharmony_ci		viafb_write_reg_mask(CRD2, VIACR, 0, BIT3);
4578c2ecf20Sopenharmony_ci		break;
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (viaparinfo->tmds_setting_info->iga_path == IGA2) {
4618c2ecf20Sopenharmony_ci		/* Disable LCD Scaling */
4628c2ecf20Sopenharmony_ci		viafb_write_reg_mask(CR79, VIACR, 0x00, BIT0);
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci}
465