xref: /OK3568_Linux_fs/u-boot/board/gdsys/common/osd.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2010
3*4882a593Smuzhiyun  * Dirk Eibach,  Guntermann & Drunck GmbH, eibach@gdsys.de
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <i2c.h>
10*4882a593Smuzhiyun #include <malloc.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include "ch7301.h"
13*4882a593Smuzhiyun #include "dp501.h"
14*4882a593Smuzhiyun #include <gdsys_fpga.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define ICS8N3QV01_I2C_ADDR 0x6E
17*4882a593Smuzhiyun #define ICS8N3QV01_FREF 114285000
18*4882a593Smuzhiyun #define ICS8N3QV01_FREF_LL 114285000LL
19*4882a593Smuzhiyun #define ICS8N3QV01_F_DEFAULT_0 156250000LL
20*4882a593Smuzhiyun #define ICS8N3QV01_F_DEFAULT_1 125000000LL
21*4882a593Smuzhiyun #define ICS8N3QV01_F_DEFAULT_2 100000000LL
22*4882a593Smuzhiyun #define ICS8N3QV01_F_DEFAULT_3  25175000LL
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define SIL1178_MASTER_I2C_ADDRESS 0x38
25*4882a593Smuzhiyun #define SIL1178_SLAVE_I2C_ADDRESS 0x39
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #define PIXCLK_640_480_60 25180000
28*4882a593Smuzhiyun #define MAX_X_CHARS 53
29*4882a593Smuzhiyun #define MAX_Y_CHARS 26
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #ifdef CONFIG_SYS_OSD_DH
32*4882a593Smuzhiyun #define MAX_OSD_SCREEN 8
33*4882a593Smuzhiyun #define OSD_DH_BASE 4
34*4882a593Smuzhiyun #else
35*4882a593Smuzhiyun #define MAX_OSD_SCREEN 4
36*4882a593Smuzhiyun #endif
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #ifdef CONFIG_SYS_OSD_DH
39*4882a593Smuzhiyun #define OSD_SET_REG(screen, fld, val) \
40*4882a593Smuzhiyun 	do { \
41*4882a593Smuzhiyun 		if (screen >= OSD_DH_BASE) \
42*4882a593Smuzhiyun 			FPGA_SET_REG(screen - OSD_DH_BASE, osd1.fld, val); \
43*4882a593Smuzhiyun 		else \
44*4882a593Smuzhiyun 			FPGA_SET_REG(screen, osd0.fld, val); \
45*4882a593Smuzhiyun 	} while (0)
46*4882a593Smuzhiyun #else
47*4882a593Smuzhiyun #define OSD_SET_REG(screen, fld, val) \
48*4882a593Smuzhiyun 		FPGA_SET_REG(screen, osd0.fld, val)
49*4882a593Smuzhiyun #endif
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun #ifdef CONFIG_SYS_OSD_DH
52*4882a593Smuzhiyun #define OSD_GET_REG(screen, fld, val) \
53*4882a593Smuzhiyun 	do {					\
54*4882a593Smuzhiyun 		if (screen >= OSD_DH_BASE) \
55*4882a593Smuzhiyun 			FPGA_GET_REG(screen - OSD_DH_BASE, osd1.fld, val); \
56*4882a593Smuzhiyun 		else \
57*4882a593Smuzhiyun 			FPGA_GET_REG(screen, osd0.fld, val); \
58*4882a593Smuzhiyun 	} while (0)
59*4882a593Smuzhiyun #else
60*4882a593Smuzhiyun #define OSD_GET_REG(screen, fld, val) \
61*4882a593Smuzhiyun 		FPGA_GET_REG(screen, osd0.fld, val)
62*4882a593Smuzhiyun #endif
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun unsigned int base_width;
65*4882a593Smuzhiyun unsigned int base_height;
66*4882a593Smuzhiyun size_t bufsize;
67*4882a593Smuzhiyun u16 *buf;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun unsigned int osd_screen_mask = 0;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun #ifdef CONFIG_SYS_ICS8N3QV01_I2C
72*4882a593Smuzhiyun int ics8n3qv01_i2c[] = CONFIG_SYS_ICS8N3QV01_I2C;
73*4882a593Smuzhiyun #endif
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun #ifdef CONFIG_SYS_SIL1178_I2C
76*4882a593Smuzhiyun int sil1178_i2c[] = CONFIG_SYS_SIL1178_I2C;
77*4882a593Smuzhiyun #endif
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #ifdef CONFIG_SYS_MPC92469AC
mpc92469ac_calc_parameters(unsigned int fout,unsigned int * post_div,unsigned int * feedback_div)80*4882a593Smuzhiyun static void mpc92469ac_calc_parameters(unsigned int fout,
81*4882a593Smuzhiyun 	unsigned int *post_div, unsigned int *feedback_div)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	unsigned int n = *post_div;
84*4882a593Smuzhiyun 	unsigned int m = *feedback_div;
85*4882a593Smuzhiyun 	unsigned int a;
86*4882a593Smuzhiyun 	unsigned int b = 14745600 / 16;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	if (fout < 50169600)
89*4882a593Smuzhiyun 		n = 8;
90*4882a593Smuzhiyun 	else if (fout < 100339199)
91*4882a593Smuzhiyun 		n = 4;
92*4882a593Smuzhiyun 	else if (fout < 200678399)
93*4882a593Smuzhiyun 		n = 2;
94*4882a593Smuzhiyun 	else
95*4882a593Smuzhiyun 		n = 1;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	a = fout * n + (b / 2); /* add b/2 for proper rounding */
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	m = a / b;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	*post_div = n;
102*4882a593Smuzhiyun 	*feedback_div = m;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
mpc92469ac_set(unsigned screen,unsigned int fout)105*4882a593Smuzhiyun static void mpc92469ac_set(unsigned screen, unsigned int fout)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	unsigned int n;
108*4882a593Smuzhiyun 	unsigned int m;
109*4882a593Smuzhiyun 	unsigned int bitval = 0;
110*4882a593Smuzhiyun 	mpc92469ac_calc_parameters(fout, &n, &m);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	switch (n) {
113*4882a593Smuzhiyun 	case 1:
114*4882a593Smuzhiyun 		bitval = 0x00;
115*4882a593Smuzhiyun 		break;
116*4882a593Smuzhiyun 	case 2:
117*4882a593Smuzhiyun 		bitval = 0x01;
118*4882a593Smuzhiyun 		break;
119*4882a593Smuzhiyun 	case 4:
120*4882a593Smuzhiyun 		bitval = 0x02;
121*4882a593Smuzhiyun 		break;
122*4882a593Smuzhiyun 	case 8:
123*4882a593Smuzhiyun 		bitval = 0x03;
124*4882a593Smuzhiyun 		break;
125*4882a593Smuzhiyun 	}
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	FPGA_SET_REG(screen, mpc3w_control, (bitval << 9) | m);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun #endif
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun #ifdef CONFIG_SYS_ICS8N3QV01_I2C
132*4882a593Smuzhiyun 
ics8n3qv01_get_fout_calc(unsigned index)133*4882a593Smuzhiyun static unsigned int ics8n3qv01_get_fout_calc(unsigned index)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	unsigned long long n;
136*4882a593Smuzhiyun 	unsigned long long mint;
137*4882a593Smuzhiyun 	unsigned long long mfrac;
138*4882a593Smuzhiyun 	u8 reg_a, reg_b, reg_c, reg_d, reg_f;
139*4882a593Smuzhiyun 	unsigned long long fout_calc;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	if (index > 3)
142*4882a593Smuzhiyun 		return 0;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	reg_a = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 0 + index);
145*4882a593Smuzhiyun 	reg_b = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 4 + index);
146*4882a593Smuzhiyun 	reg_c = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 8 + index);
147*4882a593Smuzhiyun 	reg_d = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 12 + index);
148*4882a593Smuzhiyun 	reg_f = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 20 + index);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	mint = ((reg_a >> 1) & 0x1f) | (reg_f & 0x20);
151*4882a593Smuzhiyun 	mfrac = ((reg_a & 0x01) << 17) | (reg_b << 9) | (reg_c << 1)
152*4882a593Smuzhiyun 		| (reg_d >> 7);
153*4882a593Smuzhiyun 	n = reg_d & 0x7f;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	fout_calc = (mint * ICS8N3QV01_FREF_LL
156*4882a593Smuzhiyun 		     + mfrac * ICS8N3QV01_FREF_LL / 262144LL
157*4882a593Smuzhiyun 		     + ICS8N3QV01_FREF_LL / 524288LL
158*4882a593Smuzhiyun 		     + n / 2)
159*4882a593Smuzhiyun 		    / n
160*4882a593Smuzhiyun 		    * 1000000
161*4882a593Smuzhiyun 		    / (1000000 - 100);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	return fout_calc;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 
ics8n3qv01_calc_parameters(unsigned int fout,unsigned int * _mint,unsigned int * _mfrac,unsigned int * _n)167*4882a593Smuzhiyun static void ics8n3qv01_calc_parameters(unsigned int fout,
168*4882a593Smuzhiyun 	unsigned int *_mint, unsigned int *_mfrac,
169*4882a593Smuzhiyun 	unsigned int *_n)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	unsigned int n;
172*4882a593Smuzhiyun 	unsigned int foutiic;
173*4882a593Smuzhiyun 	unsigned int fvcoiic;
174*4882a593Smuzhiyun 	unsigned int mint;
175*4882a593Smuzhiyun 	unsigned long long mfrac;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	n = (2215000000U + fout / 2) / fout;
178*4882a593Smuzhiyun 	if ((n & 1) && (n > 5))
179*4882a593Smuzhiyun 		n -= 1;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	foutiic = fout - (fout / 10000);
182*4882a593Smuzhiyun 	fvcoiic = foutiic * n;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	mint = fvcoiic / 114285000;
185*4882a593Smuzhiyun 	if ((mint < 17) || (mint > 63))
186*4882a593Smuzhiyun 		printf("ics8n3qv01_calc_parameters: cannot determine mint\n");
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	mfrac = ((unsigned long long)fvcoiic % 114285000LL) * 262144LL
189*4882a593Smuzhiyun 		/ 114285000LL;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	*_mint = mint;
192*4882a593Smuzhiyun 	*_mfrac = mfrac;
193*4882a593Smuzhiyun 	*_n = n;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
ics8n3qv01_set(unsigned int fout)196*4882a593Smuzhiyun static void ics8n3qv01_set(unsigned int fout)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	unsigned int n;
199*4882a593Smuzhiyun 	unsigned int mint;
200*4882a593Smuzhiyun 	unsigned int mfrac;
201*4882a593Smuzhiyun 	unsigned int fout_calc;
202*4882a593Smuzhiyun 	unsigned long long fout_prog;
203*4882a593Smuzhiyun 	long long off_ppm;
204*4882a593Smuzhiyun 	u8 reg0, reg4, reg8, reg12, reg18, reg20;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	fout_calc = ics8n3qv01_get_fout_calc(1);
207*4882a593Smuzhiyun 	off_ppm = (fout_calc - ICS8N3QV01_F_DEFAULT_1) * 1000000
208*4882a593Smuzhiyun 		  / ICS8N3QV01_F_DEFAULT_1;
209*4882a593Smuzhiyun 	printf("       PLL is off by %lld ppm\n", off_ppm);
210*4882a593Smuzhiyun 	fout_prog = (unsigned long long)fout * (unsigned long long)fout_calc
211*4882a593Smuzhiyun 		    / ICS8N3QV01_F_DEFAULT_1;
212*4882a593Smuzhiyun 	ics8n3qv01_calc_parameters(fout_prog, &mint, &mfrac, &n);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	reg0 = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 0) & 0xc0;
215*4882a593Smuzhiyun 	reg0 |= (mint & 0x1f) << 1;
216*4882a593Smuzhiyun 	reg0 |= (mfrac >> 17) & 0x01;
217*4882a593Smuzhiyun 	i2c_reg_write(ICS8N3QV01_I2C_ADDR, 0, reg0);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	reg4 = mfrac >> 9;
220*4882a593Smuzhiyun 	i2c_reg_write(ICS8N3QV01_I2C_ADDR, 4, reg4);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	reg8 = mfrac >> 1;
223*4882a593Smuzhiyun 	i2c_reg_write(ICS8N3QV01_I2C_ADDR, 8, reg8);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	reg12 = mfrac << 7;
226*4882a593Smuzhiyun 	reg12 |= n & 0x7f;
227*4882a593Smuzhiyun 	i2c_reg_write(ICS8N3QV01_I2C_ADDR, 12, reg12);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	reg18 = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 18) & 0x03;
230*4882a593Smuzhiyun 	reg18 |= 0x20;
231*4882a593Smuzhiyun 	i2c_reg_write(ICS8N3QV01_I2C_ADDR, 18, reg18);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	reg20 = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 20) & 0x1f;
234*4882a593Smuzhiyun 	reg20 |= mint & (1 << 5);
235*4882a593Smuzhiyun 	i2c_reg_write(ICS8N3QV01_I2C_ADDR, 20, reg20);
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun #endif
238*4882a593Smuzhiyun 
osd_write_videomem(unsigned screen,unsigned offset,u16 * data,size_t charcount)239*4882a593Smuzhiyun static int osd_write_videomem(unsigned screen, unsigned offset,
240*4882a593Smuzhiyun 	u16 *data, size_t charcount)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	unsigned int k;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	for (k = 0; k < charcount; ++k) {
245*4882a593Smuzhiyun 		if (offset + k >= bufsize)
246*4882a593Smuzhiyun 			return -1;
247*4882a593Smuzhiyun #ifdef CONFIG_SYS_OSD_DH
248*4882a593Smuzhiyun 		if (screen >= OSD_DH_BASE)
249*4882a593Smuzhiyun 			FPGA_SET_REG(screen - OSD_DH_BASE,
250*4882a593Smuzhiyun 				     videomem1[offset + k], data[k]);
251*4882a593Smuzhiyun 		else
252*4882a593Smuzhiyun 			FPGA_SET_REG(screen, videomem0[offset + k], data[k]);
253*4882a593Smuzhiyun #else
254*4882a593Smuzhiyun 		FPGA_SET_REG(screen, videomem0[offset + k], data[k]);
255*4882a593Smuzhiyun #endif
256*4882a593Smuzhiyun 	}
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	return charcount;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun 
osd_print(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])261*4882a593Smuzhiyun static int osd_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun 	unsigned screen;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	if (argc < 5) {
266*4882a593Smuzhiyun 		cmd_usage(cmdtp);
267*4882a593Smuzhiyun 		return 1;
268*4882a593Smuzhiyun 	}
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	for (screen = 0; screen < MAX_OSD_SCREEN; ++screen) {
271*4882a593Smuzhiyun 		unsigned x;
272*4882a593Smuzhiyun 		unsigned y;
273*4882a593Smuzhiyun 		unsigned charcount;
274*4882a593Smuzhiyun 		unsigned len;
275*4882a593Smuzhiyun 		u8 color;
276*4882a593Smuzhiyun 		unsigned int k;
277*4882a593Smuzhiyun 		char *text;
278*4882a593Smuzhiyun 		int res;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 		if (!(osd_screen_mask & (1 << screen)))
281*4882a593Smuzhiyun 			continue;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 		x = simple_strtoul(argv[1], NULL, 16);
284*4882a593Smuzhiyun 		y = simple_strtoul(argv[2], NULL, 16);
285*4882a593Smuzhiyun 		color = simple_strtoul(argv[3], NULL, 16);
286*4882a593Smuzhiyun 		text = argv[4];
287*4882a593Smuzhiyun 		charcount = strlen(text);
288*4882a593Smuzhiyun 		len = (charcount > bufsize) ? bufsize : charcount;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 		for (k = 0; k < len; ++k)
291*4882a593Smuzhiyun 			buf[k] = (text[k] << 8) | color;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 		res = osd_write_videomem(screen, y * base_width + x, buf, len);
294*4882a593Smuzhiyun 		if (res < 0)
295*4882a593Smuzhiyun 			return res;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 		OSD_SET_REG(screen, control, 0x0049);
298*4882a593Smuzhiyun 	}
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	return 0;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun 
osd_probe(unsigned screen)303*4882a593Smuzhiyun int osd_probe(unsigned screen)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun 	u16 version;
306*4882a593Smuzhiyun 	u16 features;
307*4882a593Smuzhiyun 	int old_bus = i2c_get_bus_num();
308*4882a593Smuzhiyun 	bool pixclock_present = false;
309*4882a593Smuzhiyun 	bool output_driver_present = false;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	OSD_GET_REG(0, version, &version);
312*4882a593Smuzhiyun 	OSD_GET_REG(0, features, &features);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	base_width = ((features & 0x3f00) >> 8) + 1;
315*4882a593Smuzhiyun 	base_height = (features & 0x001f) + 1;
316*4882a593Smuzhiyun 	bufsize = base_width * base_height;
317*4882a593Smuzhiyun 	buf = malloc(sizeof(u16) * bufsize);
318*4882a593Smuzhiyun 	if (!buf)
319*4882a593Smuzhiyun 		return -1;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun #ifdef CONFIG_SYS_OSD_DH
322*4882a593Smuzhiyun 	printf("OSD%d-%d: Digital-OSD version %01d.%02d, %d" "x%d characters\n",
323*4882a593Smuzhiyun 	       (screen >= OSD_DH_BASE) ? (screen - OSD_DH_BASE) : screen,
324*4882a593Smuzhiyun 	       (screen > 3) ? 1 : 0, version/100, version%100, base_width,
325*4882a593Smuzhiyun 	       base_height);
326*4882a593Smuzhiyun #else
327*4882a593Smuzhiyun 	printf("OSD%d:  Digital-OSD version %01d.%02d, %d" "x%d characters\n",
328*4882a593Smuzhiyun 	       screen, version/100, version%100, base_width, base_height);
329*4882a593Smuzhiyun #endif
330*4882a593Smuzhiyun 	/* setup pixclock */
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun #ifdef CONFIG_SYS_MPC92469AC
333*4882a593Smuzhiyun 	pixclock_present = true;
334*4882a593Smuzhiyun 	mpc92469ac_set(screen, PIXCLK_640_480_60);
335*4882a593Smuzhiyun #endif
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun #ifdef CONFIG_SYS_ICS8N3QV01_I2C
338*4882a593Smuzhiyun 	i2c_set_bus_num(ics8n3qv01_i2c[screen]);
339*4882a593Smuzhiyun 	if (!i2c_probe(ICS8N3QV01_I2C_ADDR)) {
340*4882a593Smuzhiyun 		ics8n3qv01_set(PIXCLK_640_480_60);
341*4882a593Smuzhiyun 		pixclock_present = true;
342*4882a593Smuzhiyun 	}
343*4882a593Smuzhiyun #endif
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	if (!pixclock_present)
346*4882a593Smuzhiyun 		printf("       no pixelclock found\n");
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	/* setup output driver */
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun #ifdef CONFIG_SYS_CH7301_I2C
351*4882a593Smuzhiyun 	if (!ch7301_probe(screen, true))
352*4882a593Smuzhiyun 		output_driver_present = true;
353*4882a593Smuzhiyun #endif
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun #ifdef CONFIG_SYS_SIL1178_I2C
356*4882a593Smuzhiyun 	i2c_set_bus_num(sil1178_i2c[screen]);
357*4882a593Smuzhiyun 	if (!i2c_probe(SIL1178_SLAVE_I2C_ADDRESS)) {
358*4882a593Smuzhiyun 		if (i2c_reg_read(SIL1178_SLAVE_I2C_ADDRESS, 0x02) == 0x06) {
359*4882a593Smuzhiyun 			/*
360*4882a593Smuzhiyun 			 * magic initialization sequence,
361*4882a593Smuzhiyun 			 * adapted from datasheet
362*4882a593Smuzhiyun 			 */
363*4882a593Smuzhiyun 			i2c_reg_write(SIL1178_SLAVE_I2C_ADDRESS, 0x08, 0x36);
364*4882a593Smuzhiyun 			i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x44);
365*4882a593Smuzhiyun 			i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x4c);
366*4882a593Smuzhiyun 			i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0e, 0x10);
367*4882a593Smuzhiyun 			i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0a, 0x80);
368*4882a593Smuzhiyun 			i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x09, 0x30);
369*4882a593Smuzhiyun 			i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0c, 0x89);
370*4882a593Smuzhiyun 			i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0d, 0x60);
371*4882a593Smuzhiyun 			i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x36);
372*4882a593Smuzhiyun 			i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x37);
373*4882a593Smuzhiyun 			output_driver_present = true;
374*4882a593Smuzhiyun 		}
375*4882a593Smuzhiyun 	}
376*4882a593Smuzhiyun #endif
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun #ifdef CONFIG_SYS_DP501_I2C
379*4882a593Smuzhiyun 	if (!dp501_probe(screen, true))
380*4882a593Smuzhiyun 		output_driver_present = true;
381*4882a593Smuzhiyun #endif
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	if (!output_driver_present)
384*4882a593Smuzhiyun 		printf("       no output driver found\n");
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	OSD_SET_REG(screen, xy_size, ((32 - 1) << 8) | (16 - 1));
387*4882a593Smuzhiyun 	OSD_SET_REG(screen, x_pos, 0x007f);
388*4882a593Smuzhiyun 	OSD_SET_REG(screen, y_pos, 0x005f);
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	if (pixclock_present && output_driver_present)
391*4882a593Smuzhiyun 		osd_screen_mask |= 1 << screen;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	i2c_set_bus_num(old_bus);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	return 0;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun 
osd_write(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])398*4882a593Smuzhiyun int osd_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun 	unsigned screen;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	if ((argc < 4) || (strlen(argv[3]) % 4)) {
403*4882a593Smuzhiyun 		cmd_usage(cmdtp);
404*4882a593Smuzhiyun 		return 1;
405*4882a593Smuzhiyun 	}
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	for (screen = 0; screen < MAX_OSD_SCREEN; ++screen) {
408*4882a593Smuzhiyun 		unsigned x;
409*4882a593Smuzhiyun 		unsigned y;
410*4882a593Smuzhiyun 		unsigned k;
411*4882a593Smuzhiyun 		u16 buffer[base_width];
412*4882a593Smuzhiyun 		char *rp;
413*4882a593Smuzhiyun 		u16 *wp = buffer;
414*4882a593Smuzhiyun 		unsigned count = (argc > 4) ?
415*4882a593Smuzhiyun 			simple_strtoul(argv[4], NULL, 16) : 1;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 		if (!(osd_screen_mask & (1 << screen)))
418*4882a593Smuzhiyun 			continue;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 		x = simple_strtoul(argv[1], NULL, 16);
421*4882a593Smuzhiyun 		y = simple_strtoul(argv[2], NULL, 16);
422*4882a593Smuzhiyun 		rp = argv[3];
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 		while (*rp) {
426*4882a593Smuzhiyun 			char substr[5];
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 			memcpy(substr, rp, 4);
429*4882a593Smuzhiyun 			substr[4] = 0;
430*4882a593Smuzhiyun 			*wp = simple_strtoul(substr, NULL, 16);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 			rp += 4;
433*4882a593Smuzhiyun 			wp++;
434*4882a593Smuzhiyun 			if (wp - buffer > base_width)
435*4882a593Smuzhiyun 				break;
436*4882a593Smuzhiyun 		}
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 		for (k = 0; k < count; ++k) {
439*4882a593Smuzhiyun 			unsigned offset =
440*4882a593Smuzhiyun 				y * base_width + x + k * (wp - buffer);
441*4882a593Smuzhiyun 			osd_write_videomem(screen, offset, buffer,
442*4882a593Smuzhiyun 				wp - buffer);
443*4882a593Smuzhiyun 		}
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 		OSD_SET_REG(screen, control, 0x0049);
446*4882a593Smuzhiyun 	}
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	return 0;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
osd_size(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])451*4882a593Smuzhiyun int osd_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun 	unsigned screen;
454*4882a593Smuzhiyun 	unsigned x;
455*4882a593Smuzhiyun 	unsigned y;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	if (argc < 3) {
458*4882a593Smuzhiyun 		cmd_usage(cmdtp);
459*4882a593Smuzhiyun 		return 1;
460*4882a593Smuzhiyun 	}
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	x = simple_strtoul(argv[1], NULL, 16);
463*4882a593Smuzhiyun 	y = simple_strtoul(argv[2], NULL, 16);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	if (!x || (x > 64) || (x > MAX_X_CHARS) ||
466*4882a593Smuzhiyun 	    !y || (y > 32) || (y > MAX_Y_CHARS)) {
467*4882a593Smuzhiyun 		cmd_usage(cmdtp);
468*4882a593Smuzhiyun 		return 1;
469*4882a593Smuzhiyun 	}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	for (screen = 0; screen < MAX_OSD_SCREEN; ++screen) {
472*4882a593Smuzhiyun 		if (!(osd_screen_mask & (1 << screen)))
473*4882a593Smuzhiyun 			continue;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 		OSD_SET_REG(screen, xy_size, ((x - 1) << 8) | (y - 1));
476*4882a593Smuzhiyun 		OSD_SET_REG(screen, x_pos, 32767 * (640 - 12 * x) / 65535);
477*4882a593Smuzhiyun 		OSD_SET_REG(screen, y_pos, 32767 * (480 - 18 * y) / 65535);
478*4882a593Smuzhiyun 	}
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	return 0;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun U_BOOT_CMD(
484*4882a593Smuzhiyun 	osdw, 5, 0, osd_write,
485*4882a593Smuzhiyun 	"write 16-bit hex encoded buffer to osd memory",
486*4882a593Smuzhiyun 	"pos_x pos_y buffer count\n"
487*4882a593Smuzhiyun );
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun U_BOOT_CMD(
490*4882a593Smuzhiyun 	osdp, 5, 0, osd_print,
491*4882a593Smuzhiyun 	"write ASCII buffer to osd memory",
492*4882a593Smuzhiyun 	"pos_x pos_y color text\n"
493*4882a593Smuzhiyun );
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun U_BOOT_CMD(
496*4882a593Smuzhiyun 	osdsize, 3, 0, osd_size,
497*4882a593Smuzhiyun 	"set OSD XY size in characters",
498*4882a593Smuzhiyun 	"size_x(max. " __stringify(MAX_X_CHARS)
499*4882a593Smuzhiyun 	") size_y(max. " __stringify(MAX_Y_CHARS) ")\n"
500*4882a593Smuzhiyun );
501