xref: /openbmc/u-boot/board/freescale/t1040qds/diu.c (revision d0e6d34d)
1 /*
2  * Copyright 2014 Freescale Semiconductor, Inc.
3  * Author: Priyanka Jain <Priyanka.Jain@freescale.com>
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 #include <command.h>
10 #include <linux/ctype.h>
11 #include <asm/io.h>
12 #include <stdio_dev.h>
13 #include <video_fb.h>
14 #include <fsl_diu_fb.h>
15 #include "../common/qixis.h"
16 #include "t1040qds.h"
17 #include "t1040qds_qixis.h"
18 #include <i2c.h>
19 
20 
21 #define I2C_DVI_INPUT_DATA_FORMAT_REG		0x1F
22 #define I2C_DVI_PLL_CHARGE_CNTL_REG		0x33
23 #define I2C_DVI_PLL_DIVIDER_REG			0x34
24 #define I2C_DVI_PLL_SUPPLY_CNTL_REG		0x35
25 #define I2C_DVI_PLL_FILTER_REG			0x36
26 #define I2C_DVI_TEST_PATTERN_REG		0x48
27 #define I2C_DVI_POWER_MGMT_REG			0x49
28 #define I2C_DVI_LOCK_STATE_REG			0x4D
29 #define I2C_DVI_SYNC_POLARITY_REG		0x56
30 
31 /*
32  * Set VSYNC/HSYNC to active high. This is polarity of sync signals
33  * from DIU->DVI. The DIU default is active igh, so DVI is set to
34  * active high.
35  */
36 #define I2C_DVI_INPUT_DATA_FORMAT_VAL		0x98
37 
38 #define I2C_DVI_PLL_CHARGE_CNTL_HIGH_SPEED_VAL	0x06
39 #define I2C_DVI_PLL_DIVIDER_HIGH_SPEED_VAL	0x26
40 #define I2C_DVI_PLL_FILTER_HIGH_SPEED_VAL	0xA0
41 #define I2C_DVI_PLL_CHARGE_CNTL_LOW_SPEED_VAL	0x08
42 #define I2C_DVI_PLL_DIVIDER_LOW_SPEED_VAL	0x16
43 #define I2C_DVI_PLL_FILTER_LOW_SPEED_VAL	0x60
44 
45 /* Clear test pattern */
46 #define I2C_DVI_TEST_PATTERN_VAL		0x18
47 /* Exit Power-down mode */
48 #define I2C_DVI_POWER_MGMT_VAL			0xC0
49 
50 /* Monitor polarity is handled via DVI Sync Polarity Register */
51 #define I2C_DVI_SYNC_POLARITY_VAL		0x00
52 
53 /*
54  * DIU Area Descriptor
55  *
56  * Note that we need to byte-swap the value before it's written to the AD
57  * register.  So even though the registers don't look like they're in the same
58  * bit positions as they are on the MPC8610, the same value is written to the
59  * AD register on the MPC8610 and on the P1022.
60  */
61 #define AD_BYTE_F		0x10000000
62 #define AD_ALPHA_C_SHIFT	25
63 #define AD_BLUE_C_SHIFT		23
64 #define AD_GREEN_C_SHIFT	21
65 #define AD_RED_C_SHIFT		19
66 #define AD_PIXEL_S_SHIFT	16
67 #define AD_COMP_3_SHIFT		12
68 #define AD_COMP_2_SHIFT		8
69 #define AD_COMP_1_SHIFT		4
70 #define AD_COMP_0_SHIFT		0
71 
72 /* Programming of HDMI Chrontel CH7301 connector */
73 int diu_set_dvi_encoder(unsigned int pixclock)
74 {
75 	int ret;
76 	u8 temp;
77 	select_i2c_ch_pca9547(I2C_MUX_CH_DIU);
78 
79 	temp = I2C_DVI_TEST_PATTERN_VAL;
80 	ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR, I2C_DVI_TEST_PATTERN_REG, 1,
81 			&temp, 1);
82 	if (ret) {
83 		puts("I2C: failed to select proper dvi test pattern\n");
84 		return ret;
85 	}
86 	temp = I2C_DVI_INPUT_DATA_FORMAT_VAL;
87 	ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR, I2C_DVI_INPUT_DATA_FORMAT_REG,
88 			1, &temp, 1);
89 	if (ret) {
90 		puts("I2C: failed to select dvi input data format\n");
91 		return ret;
92 	}
93 
94 	/* Set Sync polarity register */
95 	temp = I2C_DVI_SYNC_POLARITY_VAL;
96 	ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR, I2C_DVI_SYNC_POLARITY_REG, 1,
97 			&temp, 1);
98 	if (ret) {
99 		puts("I2C: failed to select dvi syc polarity\n");
100 		return ret;
101 	}
102 
103 	/* Set PLL registers based on pixel clock rate*/
104 	if (pixclock > 65000000) {
105 		temp = I2C_DVI_PLL_CHARGE_CNTL_HIGH_SPEED_VAL;
106 		ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
107 				I2C_DVI_PLL_CHARGE_CNTL_REG, 1,	&temp, 1);
108 		if (ret) {
109 			puts("I2C: failed to select dvi pll charge_cntl\n");
110 			return ret;
111 		}
112 		temp = I2C_DVI_PLL_DIVIDER_HIGH_SPEED_VAL;
113 		ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
114 				I2C_DVI_PLL_DIVIDER_REG, 1, &temp, 1);
115 		if (ret) {
116 			puts("I2C: failed to select dvi pll divider\n");
117 			return ret;
118 		}
119 		temp = I2C_DVI_PLL_FILTER_HIGH_SPEED_VAL;
120 		ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
121 				I2C_DVI_PLL_FILTER_REG, 1, &temp, 1);
122 		if (ret) {
123 			puts("I2C: failed to select dvi pll filter\n");
124 			return ret;
125 		}
126 	} else {
127 		temp = I2C_DVI_PLL_CHARGE_CNTL_LOW_SPEED_VAL;
128 		ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
129 				I2C_DVI_PLL_CHARGE_CNTL_REG, 1, &temp, 1);
130 		if (ret) {
131 			puts("I2C: failed to select dvi pll charge_cntl\n");
132 			return ret;
133 		}
134 		temp = I2C_DVI_PLL_DIVIDER_LOW_SPEED_VAL;
135 		ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
136 				I2C_DVI_PLL_DIVIDER_REG, 1, &temp, 1);
137 		if (ret) {
138 			puts("I2C: failed to select dvi pll divider\n");
139 			return ret;
140 		}
141 		temp = I2C_DVI_PLL_FILTER_LOW_SPEED_VAL;
142 		ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
143 				I2C_DVI_PLL_FILTER_REG, 1, &temp, 1);
144 		if (ret) {
145 			puts("I2C: failed to select dvi pll filter\n");
146 			return ret;
147 		}
148 	}
149 
150 	temp = I2C_DVI_POWER_MGMT_VAL;
151 	ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR, I2C_DVI_POWER_MGMT_REG, 1,
152 			&temp, 1);
153 	if (ret) {
154 		puts("I2C: failed to select dvi power mgmt\n");
155 		return ret;
156 	}
157 
158 	udelay(500);
159 
160 	select_i2c_ch_pca9547(I2C_MUX_CH_DEFAULT);
161 	return 0;
162 }
163 
164 void diu_set_pixel_clock(unsigned int pixclock)
165 {
166 	unsigned long speed_ccb, temp;
167 	u32 pixval;
168 	int ret = 0;
169 	speed_ccb = get_bus_freq(0);
170 	temp = 1000000000 / pixclock;
171 	temp *= 1000;
172 	pixval = speed_ccb / temp;
173 
174 	/* Program HDMI encoder */
175 	ret = diu_set_dvi_encoder(temp);
176 	if (ret) {
177 		puts("Failed to set DVI encoder\n");
178 		return;
179 	}
180 
181 	/* Program pixel clock */
182 	out_be32((unsigned *)CONFIG_SYS_FSL_SCFG_PIXCLK_ADDR,
183 		 ((pixval << PXCK_BITS_START) & PXCK_MASK));
184 	/* enable clock*/
185 	out_be32((unsigned *)CONFIG_SYS_FSL_SCFG_PIXCLK_ADDR, PXCKEN_MASK |
186 		 ((pixval << PXCK_BITS_START) & PXCK_MASK));
187 }
188 
189 int platform_diu_init(unsigned int xres, unsigned int yres, const char *port)
190 {
191 	u32 pixel_format;
192 	u8 sw;
193 
194 	/*Route I2C4 to DIU system as HSYNC/VSYNC*/
195 	sw = QIXIS_READ(brdcfg[5]);
196 	QIXIS_WRITE(brdcfg[5],
197 		    ((sw & ~(BRDCFG5_IMX_MASK)) | (BRDCFG5_IMX_DIU)));
198 
199 	/*Configure Display ouput port as HDMI*/
200 	sw = QIXIS_READ(brdcfg[15]);
201 	QIXIS_WRITE(brdcfg[15],
202 		    ((sw & ~(BRDCFG15_LCDPD_MASK | BRDCFG15_DIUSEL_MASK))
203 		      | (BRDCFG15_LCDPD_ENABLED | BRDCFG15_DIUSEL_HDMI)));
204 
205 	pixel_format = cpu_to_le32(AD_BYTE_F | (3 << AD_ALPHA_C_SHIFT) |
206 		(0 << AD_BLUE_C_SHIFT) | (1 << AD_GREEN_C_SHIFT) |
207 		(2 << AD_RED_C_SHIFT) | (8 << AD_COMP_3_SHIFT) |
208 		(8 << AD_COMP_2_SHIFT) | (8 << AD_COMP_1_SHIFT) |
209 		(8 << AD_COMP_0_SHIFT) | (3 << AD_PIXEL_S_SHIFT));
210 
211 	printf("DIU:   Switching to monitor @ %ux%u\n",  xres, yres);
212 
213 
214 	return fsl_diu_init(xres, yres, pixel_format, 0);
215 }
216