xref: /rk3399_rockchip-uboot/board/gdsys/common/osd.c (revision aba27acf6711dce0ef1507f2f9f02a80d70a45da)
1a605ea7eSDirk Eibach /*
2a605ea7eSDirk Eibach  * (C) Copyright 2010
3a605ea7eSDirk Eibach  * Dirk Eibach,  Guntermann & Drunck GmbH, eibach@gdsys.de
4a605ea7eSDirk Eibach  *
51a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
6a605ea7eSDirk Eibach  */
7a605ea7eSDirk Eibach 
8a605ea7eSDirk Eibach #include <common.h>
9a605ea7eSDirk Eibach #include <asm/io.h>
10*aba27acfSDirk Eibach #include <i2c.h>
11a605ea7eSDirk Eibach 
122da0fc0dSDirk Eibach #include <gdsys_fpga.h>
13a605ea7eSDirk Eibach 
14a605ea7eSDirk Eibach #define CH7301_I2C_ADDR 0x75
15a605ea7eSDirk Eibach 
162da0fc0dSDirk Eibach #define ICS8N3QV01_I2C_ADDR 0x6E
176853cc4bSDirk Eibach #define ICS8N3QV01_FREF 114285000
186853cc4bSDirk Eibach #define ICS8N3QV01_FREF_LL 114285000LL
196853cc4bSDirk Eibach #define ICS8N3QV01_F_DEFAULT_0 156250000LL
206853cc4bSDirk Eibach #define ICS8N3QV01_F_DEFAULT_1 125000000LL
216853cc4bSDirk Eibach #define ICS8N3QV01_F_DEFAULT_2 100000000LL
226853cc4bSDirk Eibach #define ICS8N3QV01_F_DEFAULT_3  25175000LL
232da0fc0dSDirk Eibach 
242da0fc0dSDirk Eibach #define SIL1178_MASTER_I2C_ADDRESS 0x38
252da0fc0dSDirk Eibach #define SIL1178_SLAVE_I2C_ADDRESS 0x39
262da0fc0dSDirk Eibach 
27a605ea7eSDirk Eibach #define PIXCLK_640_480_60 25180000
28a605ea7eSDirk Eibach 
29a605ea7eSDirk Eibach #define BASE_WIDTH 32
30a605ea7eSDirk Eibach #define BASE_HEIGHT 16
31a605ea7eSDirk Eibach #define BUFSIZE (BASE_WIDTH * BASE_HEIGHT)
32a605ea7eSDirk Eibach 
33a605ea7eSDirk Eibach enum {
34a605ea7eSDirk Eibach 	CH7301_CM = 0x1c,		/* Clock Mode Register */
35a605ea7eSDirk Eibach 	CH7301_IC = 0x1d,		/* Input Clock Register */
36a605ea7eSDirk Eibach 	CH7301_GPIO = 0x1e,		/* GPIO Control Register */
37a605ea7eSDirk Eibach 	CH7301_IDF = 0x1f,		/* Input Data Format Register */
38a605ea7eSDirk Eibach 	CH7301_CD = 0x20,		/* Connection Detect Register */
39a605ea7eSDirk Eibach 	CH7301_DC = 0x21,		/* DAC Control Register */
40a605ea7eSDirk Eibach 	CH7301_HPD = 0x23,		/* Hot Plug Detection Register */
41a605ea7eSDirk Eibach 	CH7301_TCTL = 0x31,		/* DVI Control Input Register */
42a605ea7eSDirk Eibach 	CH7301_TPCP = 0x33,		/* DVI PLL Charge Pump Ctrl Register */
43a605ea7eSDirk Eibach 	CH7301_TPD = 0x34,		/* DVI PLL Divide Register */
44a605ea7eSDirk Eibach 	CH7301_TPVT = 0x35,		/* DVI PLL Supply Control Register */
45a605ea7eSDirk Eibach 	CH7301_TPF = 0x36,		/* DVI PLL Filter Register */
46a605ea7eSDirk Eibach 	CH7301_TCT = 0x37,		/* DVI Clock Test Register */
47a605ea7eSDirk Eibach 	CH7301_TSTP = 0x48,		/* Test Pattern Register */
48a605ea7eSDirk Eibach 	CH7301_PM = 0x49,		/* Power Management register */
49a605ea7eSDirk Eibach 	CH7301_VID = 0x4a,		/* Version ID Register */
50a605ea7eSDirk Eibach 	CH7301_DID = 0x4b,		/* Device ID Register */
51a605ea7eSDirk Eibach 	CH7301_DSP = 0x56,		/* DVI Sync polarity Register */
52a605ea7eSDirk Eibach };
53a605ea7eSDirk Eibach 
542da0fc0dSDirk Eibach #if defined(CONFIG_SYS_ICS8N3QV01) || defined(CONFIG_SYS_SIL1178)
552da0fc0dSDirk Eibach static void fpga_iic_write(unsigned screen, u8 slave, u8 reg, u8 data)
562da0fc0dSDirk Eibach {
57*aba27acfSDirk Eibach 	u16 val;
582da0fc0dSDirk Eibach 
59*aba27acfSDirk Eibach 	do {
60*aba27acfSDirk Eibach 		FPGA_GET_REG(screen, extended_interrupt, &val);
61*aba27acfSDirk Eibach 	} while (val & (1 << 12));
62*aba27acfSDirk Eibach 
63*aba27acfSDirk Eibach 	FPGA_SET_REG(screen, i2c.write_mailbox_ext, reg | (data << 8));
64*aba27acfSDirk Eibach 	FPGA_SET_REG(screen, i2c.write_mailbox, 0xc400 | (slave << 1));
652da0fc0dSDirk Eibach }
662da0fc0dSDirk Eibach 
672da0fc0dSDirk Eibach static u8 fpga_iic_read(unsigned screen, u8 slave, u8 reg)
682da0fc0dSDirk Eibach {
692da0fc0dSDirk Eibach 	unsigned int ctr = 0;
70*aba27acfSDirk Eibach 	u16 val;
712da0fc0dSDirk Eibach 
72*aba27acfSDirk Eibach 	do {
73*aba27acfSDirk Eibach 		FPGA_GET_REG(screen, extended_interrupt, &val);
74*aba27acfSDirk Eibach 	} while (val & (1 << 12));
75*aba27acfSDirk Eibach 
76*aba27acfSDirk Eibach 	FPGA_SET_REG(screen, extended_interrupt, 1 << 14);
77*aba27acfSDirk Eibach 	FPGA_SET_REG(screen, i2c.write_mailbox_ext, reg);
78*aba27acfSDirk Eibach 	FPGA_SET_REG(screen, i2c.write_mailbox, 0xc000 | (slave << 1));
79*aba27acfSDirk Eibach 
80*aba27acfSDirk Eibach 	FPGA_GET_REG(screen, extended_interrupt, &val);
81*aba27acfSDirk Eibach 	while (!(val & (1 << 14))) {
822da0fc0dSDirk Eibach 		udelay(100000);
832da0fc0dSDirk Eibach 		if (ctr++ > 5) {
842da0fc0dSDirk Eibach 			printf("iic receive timeout\n");
852da0fc0dSDirk Eibach 			break;
862da0fc0dSDirk Eibach 		}
87*aba27acfSDirk Eibach 		FPGA_GET_REG(screen, extended_interrupt, &val);
882da0fc0dSDirk Eibach 	}
89*aba27acfSDirk Eibach 
90*aba27acfSDirk Eibach 	FPGA_GET_REG(screen, i2c.read_mailbox_ext, &val);
91*aba27acfSDirk Eibach 	return val >> 8;
922da0fc0dSDirk Eibach }
932da0fc0dSDirk Eibach #endif
942da0fc0dSDirk Eibach 
952da0fc0dSDirk Eibach #ifdef CONFIG_SYS_MPC92469AC
96a605ea7eSDirk Eibach static void mpc92469ac_calc_parameters(unsigned int fout,
97a605ea7eSDirk Eibach 	unsigned int *post_div, unsigned int *feedback_div)
98a605ea7eSDirk Eibach {
99a605ea7eSDirk Eibach 	unsigned int n = *post_div;
100a605ea7eSDirk Eibach 	unsigned int m = *feedback_div;
101a605ea7eSDirk Eibach 	unsigned int a;
102a605ea7eSDirk Eibach 	unsigned int b = 14745600 / 16;
103a605ea7eSDirk Eibach 
104a605ea7eSDirk Eibach 	if (fout < 50169600)
105a605ea7eSDirk Eibach 		n = 8;
106a605ea7eSDirk Eibach 	else if (fout < 100339199)
107a605ea7eSDirk Eibach 		n = 4;
108a605ea7eSDirk Eibach 	else if (fout < 200678399)
109a605ea7eSDirk Eibach 		n = 2;
110a605ea7eSDirk Eibach 	else
111a605ea7eSDirk Eibach 		n = 1;
112a605ea7eSDirk Eibach 
113a605ea7eSDirk Eibach 	a = fout * n + (b / 2); /* add b/2 for proper rounding */
114a605ea7eSDirk Eibach 
115a605ea7eSDirk Eibach 	m = a / b;
116a605ea7eSDirk Eibach 
117a605ea7eSDirk Eibach 	*post_div = n;
118a605ea7eSDirk Eibach 	*feedback_div = m;
119a605ea7eSDirk Eibach }
120a605ea7eSDirk Eibach 
1212da0fc0dSDirk Eibach static void mpc92469ac_set(unsigned screen, unsigned int fout)
122a605ea7eSDirk Eibach {
123a605ea7eSDirk Eibach 	unsigned int n;
124a605ea7eSDirk Eibach 	unsigned int m;
125a605ea7eSDirk Eibach 	unsigned int bitval = 0;
126a605ea7eSDirk Eibach 	mpc92469ac_calc_parameters(fout, &n, &m);
127a605ea7eSDirk Eibach 
128a605ea7eSDirk Eibach 	switch (n) {
129a605ea7eSDirk Eibach 	case 1:
130a605ea7eSDirk Eibach 		bitval = 0x00;
131a605ea7eSDirk Eibach 		break;
132a605ea7eSDirk Eibach 	case 2:
133a605ea7eSDirk Eibach 		bitval = 0x01;
134a605ea7eSDirk Eibach 		break;
135a605ea7eSDirk Eibach 	case 4:
136a605ea7eSDirk Eibach 		bitval = 0x02;
137a605ea7eSDirk Eibach 		break;
138a605ea7eSDirk Eibach 	case 8:
139a605ea7eSDirk Eibach 		bitval = 0x03;
140a605ea7eSDirk Eibach 		break;
141a605ea7eSDirk Eibach 	}
142a605ea7eSDirk Eibach 
143*aba27acfSDirk Eibach 	FPGA_SET_REG(screen, mpc3w_control, (bitval << 9) | m);
1442da0fc0dSDirk Eibach }
1452da0fc0dSDirk Eibach #endif
1462da0fc0dSDirk Eibach 
1472da0fc0dSDirk Eibach #ifdef CONFIG_SYS_ICS8N3QV01
1486853cc4bSDirk Eibach 
1496853cc4bSDirk Eibach static unsigned int ics8n3qv01_get_fout_calc(unsigned screen, unsigned index)
1506853cc4bSDirk Eibach {
1516853cc4bSDirk Eibach 	unsigned long long n;
1526853cc4bSDirk Eibach 	unsigned long long mint;
1536853cc4bSDirk Eibach 	unsigned long long mfrac;
1546853cc4bSDirk Eibach 	u8 reg_a, reg_b, reg_c, reg_d, reg_f;
1556853cc4bSDirk Eibach 	unsigned long long fout_calc;
1566853cc4bSDirk Eibach 
1576853cc4bSDirk Eibach 	if (index > 3)
1586853cc4bSDirk Eibach 		return 0;
1596853cc4bSDirk Eibach 
1606853cc4bSDirk Eibach 	reg_a = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 0 + index);
1616853cc4bSDirk Eibach 	reg_b = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 4 + index);
1626853cc4bSDirk Eibach 	reg_c = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 8 + index);
1636853cc4bSDirk Eibach 	reg_d = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 12 + index);
1646853cc4bSDirk Eibach 	reg_f = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 20 + index);
1656853cc4bSDirk Eibach 
1666853cc4bSDirk Eibach 	mint = ((reg_a >> 1) & 0x1f) | (reg_f & 0x20);
1676853cc4bSDirk Eibach 	mfrac = ((reg_a & 0x01) << 17) | (reg_b << 9) | (reg_c << 1)
1686853cc4bSDirk Eibach 		| (reg_d >> 7);
1696853cc4bSDirk Eibach 	n = reg_d & 0x7f;
1706853cc4bSDirk Eibach 
1716853cc4bSDirk Eibach 	fout_calc = (mint * ICS8N3QV01_FREF_LL
1726853cc4bSDirk Eibach 		     + mfrac * ICS8N3QV01_FREF_LL / 262144LL
1736853cc4bSDirk Eibach 		     + ICS8N3QV01_FREF_LL / 524288LL
1746853cc4bSDirk Eibach 		     + n / 2)
1756853cc4bSDirk Eibach 		    / n
1766853cc4bSDirk Eibach 		    * 1000000
1776853cc4bSDirk Eibach 		    / (1000000 - 100);
1786853cc4bSDirk Eibach 
1796853cc4bSDirk Eibach 	return fout_calc;
1806853cc4bSDirk Eibach }
1816853cc4bSDirk Eibach 
1826853cc4bSDirk Eibach 
1832da0fc0dSDirk Eibach static void ics8n3qv01_calc_parameters(unsigned int fout,
1842da0fc0dSDirk Eibach 	unsigned int *_mint, unsigned int *_mfrac,
1852da0fc0dSDirk Eibach 	unsigned int *_n)
1862da0fc0dSDirk Eibach {
1872da0fc0dSDirk Eibach 	unsigned int n;
1882da0fc0dSDirk Eibach 	unsigned int foutiic;
1892da0fc0dSDirk Eibach 	unsigned int fvcoiic;
1902da0fc0dSDirk Eibach 	unsigned int mint;
1912da0fc0dSDirk Eibach 	unsigned long long mfrac;
1922da0fc0dSDirk Eibach 
1936853cc4bSDirk Eibach 	n = (2215000000U + fout / 2) / fout;
1942da0fc0dSDirk Eibach 	if ((n & 1) && (n > 5))
1952da0fc0dSDirk Eibach 		n -= 1;
1962da0fc0dSDirk Eibach 
1972da0fc0dSDirk Eibach 	foutiic = fout - (fout / 10000);
1982da0fc0dSDirk Eibach 	fvcoiic = foutiic * n;
1992da0fc0dSDirk Eibach 
2002da0fc0dSDirk Eibach 	mint = fvcoiic / 114285000;
2012da0fc0dSDirk Eibach 	if ((mint < 17) || (mint > 63))
2022da0fc0dSDirk Eibach 		printf("ics8n3qv01_calc_parameters: cannot determine mint\n");
2032da0fc0dSDirk Eibach 
2042da0fc0dSDirk Eibach 	mfrac = ((unsigned long long)fvcoiic % 114285000LL) * 262144LL
2052da0fc0dSDirk Eibach 		/ 114285000LL;
2062da0fc0dSDirk Eibach 
2072da0fc0dSDirk Eibach 	*_mint = mint;
2082da0fc0dSDirk Eibach 	*_mfrac = mfrac;
2092da0fc0dSDirk Eibach 	*_n = n;
210a605ea7eSDirk Eibach }
211a605ea7eSDirk Eibach 
2122da0fc0dSDirk Eibach static void ics8n3qv01_set(unsigned screen, unsigned int fout)
213a605ea7eSDirk Eibach {
2142da0fc0dSDirk Eibach 	unsigned int n;
2152da0fc0dSDirk Eibach 	unsigned int mint;
2162da0fc0dSDirk Eibach 	unsigned int mfrac;
2176853cc4bSDirk Eibach 	unsigned int fout_calc;
2186853cc4bSDirk Eibach 	unsigned long long fout_prog;
2196853cc4bSDirk Eibach 	long long off_ppm;
2202da0fc0dSDirk Eibach 	u8 reg0, reg4, reg8, reg12, reg18, reg20;
2212da0fc0dSDirk Eibach 
2226853cc4bSDirk Eibach 	fout_calc = ics8n3qv01_get_fout_calc(screen, 1);
2236853cc4bSDirk Eibach 	off_ppm = (fout_calc - ICS8N3QV01_F_DEFAULT_1) * 1000000
2246853cc4bSDirk Eibach 		  / ICS8N3QV01_F_DEFAULT_1;
2256853cc4bSDirk Eibach 	printf("       PLL is off by %lld ppm\n", off_ppm);
2266853cc4bSDirk Eibach 	fout_prog = (unsigned long long)fout * (unsigned long long)fout_calc
2276853cc4bSDirk Eibach 		    / ICS8N3QV01_F_DEFAULT_1;
2286853cc4bSDirk Eibach 	ics8n3qv01_calc_parameters(fout_prog, &mint, &mfrac, &n);
2292da0fc0dSDirk Eibach 
2302da0fc0dSDirk Eibach 	reg0 = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 0) & 0xc0;
2312da0fc0dSDirk Eibach 	reg0 |= (mint & 0x1f) << 1;
2322da0fc0dSDirk Eibach 	reg0 |= (mfrac >> 17) & 0x01;
2332da0fc0dSDirk Eibach 	fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 0, reg0);
2342da0fc0dSDirk Eibach 
2352da0fc0dSDirk Eibach 	reg4 = mfrac >> 9;
2362da0fc0dSDirk Eibach 	fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 4, reg4);
2372da0fc0dSDirk Eibach 
2382da0fc0dSDirk Eibach 	reg8 = mfrac >> 1;
2392da0fc0dSDirk Eibach 	fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 8, reg8);
2402da0fc0dSDirk Eibach 
2412da0fc0dSDirk Eibach 	reg12 = mfrac << 7;
2422da0fc0dSDirk Eibach 	reg12 |= n & 0x7f;
2432da0fc0dSDirk Eibach 	fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 12, reg12);
2442da0fc0dSDirk Eibach 
2452da0fc0dSDirk Eibach 	reg18 = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 18) & 0x03;
2462da0fc0dSDirk Eibach 	reg18 |= 0x20;
2472da0fc0dSDirk Eibach 	fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 18, reg18);
2482da0fc0dSDirk Eibach 
2492da0fc0dSDirk Eibach 	reg20 = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 20) & 0x1f;
2502da0fc0dSDirk Eibach 	reg20 |= mint & (1 << 5);
2512da0fc0dSDirk Eibach 	fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 20, reg20);
2522da0fc0dSDirk Eibach }
2532da0fc0dSDirk Eibach #endif
2542da0fc0dSDirk Eibach 
2552da0fc0dSDirk Eibach static int osd_write_videomem(unsigned screen, unsigned offset,
2562da0fc0dSDirk Eibach 	u16 *data, size_t charcount)
2572da0fc0dSDirk Eibach {
258a605ea7eSDirk Eibach 	unsigned int k;
259a605ea7eSDirk Eibach 
260a605ea7eSDirk Eibach 	for (k = 0; k < charcount; ++k) {
261a605ea7eSDirk Eibach 		if (offset + k >= BUFSIZE)
262a605ea7eSDirk Eibach 			return -1;
263*aba27acfSDirk Eibach 		FPGA_SET_REG(screen, videomem[offset + k], data[k]);
264a605ea7eSDirk Eibach 	}
265a605ea7eSDirk Eibach 
266a605ea7eSDirk Eibach 	return charcount;
267a605ea7eSDirk Eibach }
268a605ea7eSDirk Eibach 
269a605ea7eSDirk Eibach static int osd_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
270a605ea7eSDirk Eibach {
2712da0fc0dSDirk Eibach 	unsigned screen;
2722da0fc0dSDirk Eibach 
2732da0fc0dSDirk Eibach 	for (screen = 0; screen < CONFIG_SYS_OSD_SCREENS; ++screen) {
274a605ea7eSDirk Eibach 		unsigned x;
275a605ea7eSDirk Eibach 		unsigned y;
276a605ea7eSDirk Eibach 		unsigned charcount;
277a605ea7eSDirk Eibach 		unsigned len;
278a605ea7eSDirk Eibach 		u8 color;
279a605ea7eSDirk Eibach 		unsigned int k;
280a605ea7eSDirk Eibach 		u16 buf[BUFSIZE];
281a605ea7eSDirk Eibach 		char *text;
2822da0fc0dSDirk Eibach 		int res;
283a605ea7eSDirk Eibach 
284a605ea7eSDirk Eibach 		if (argc < 5) {
2852da0fc0dSDirk Eibach 			cmd_usage(cmdtp);
2862da0fc0dSDirk Eibach 			return 1;
287a605ea7eSDirk Eibach 		}
288a605ea7eSDirk Eibach 
289a605ea7eSDirk Eibach 		x = simple_strtoul(argv[1], NULL, 16);
290a605ea7eSDirk Eibach 		y = simple_strtoul(argv[2], NULL, 16);
291a605ea7eSDirk Eibach 		color = simple_strtoul(argv[3], NULL, 16);
292a605ea7eSDirk Eibach 		text = argv[4];
293a605ea7eSDirk Eibach 		charcount = strlen(text);
294a605ea7eSDirk Eibach 		len = (charcount > BUFSIZE) ? BUFSIZE : charcount;
295a605ea7eSDirk Eibach 
296a605ea7eSDirk Eibach 		for (k = 0; k < len; ++k)
297a605ea7eSDirk Eibach 			buf[k] = (text[k] << 8) | color;
298a605ea7eSDirk Eibach 
2992da0fc0dSDirk Eibach 		res = osd_write_videomem(screen, y * BASE_WIDTH + x, buf, len);
3002da0fc0dSDirk Eibach 		if (res < 0)
3012da0fc0dSDirk Eibach 			return res;
302a605ea7eSDirk Eibach 	}
303a605ea7eSDirk Eibach 
3042da0fc0dSDirk Eibach 	return 0;
3052da0fc0dSDirk Eibach }
3062da0fc0dSDirk Eibach 
3072da0fc0dSDirk Eibach int osd_probe(unsigned screen)
308a605ea7eSDirk Eibach {
309*aba27acfSDirk Eibach 	u16 version;
310*aba27acfSDirk Eibach 	u16 features;
311a605ea7eSDirk Eibach 	unsigned width;
312a605ea7eSDirk Eibach 	unsigned height;
3132da0fc0dSDirk Eibach 	u8 value;
314a605ea7eSDirk Eibach 
315*aba27acfSDirk Eibach 	FPGA_GET_REG(0, osd.version, &version);
316*aba27acfSDirk Eibach 	FPGA_GET_REG(0, osd.features, &features);
317*aba27acfSDirk Eibach 
318a605ea7eSDirk Eibach 	width = ((features & 0x3f00) >> 8) + 1;
319a605ea7eSDirk Eibach 	height = (features & 0x001f) + 1;
320a605ea7eSDirk Eibach 
3212da0fc0dSDirk Eibach 	printf("OSD%d:  Digital-OSD version %01d.%02d, %d" "x%d characters\n",
3222da0fc0dSDirk Eibach 		screen, version/100, version%100, width, height);
323a605ea7eSDirk Eibach 
3242da0fc0dSDirk Eibach #ifdef CONFIG_SYS_CH7301
325a605ea7eSDirk Eibach 	value = i2c_reg_read(CH7301_I2C_ADDR, CH7301_DID);
326a605ea7eSDirk Eibach 	if (value != 0x17) {
327a605ea7eSDirk Eibach 		printf("       Probing CH7301 failed, DID %02x\n", value);
328a605ea7eSDirk Eibach 		return -1;
329a605ea7eSDirk Eibach 	}
330a605ea7eSDirk Eibach 	i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPCP, 0x08);
331a605ea7eSDirk Eibach 	i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPD, 0x16);
332a605ea7eSDirk Eibach 	i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPF, 0x60);
333a605ea7eSDirk Eibach 	i2c_reg_write(CH7301_I2C_ADDR, CH7301_DC, 0x09);
334a605ea7eSDirk Eibach 	i2c_reg_write(CH7301_I2C_ADDR, CH7301_PM, 0xc0);
3352da0fc0dSDirk Eibach #endif
336a605ea7eSDirk Eibach 
3372da0fc0dSDirk Eibach #ifdef CONFIG_SYS_MPC92469AC
3382da0fc0dSDirk Eibach 	mpc92469ac_set(screen, PIXCLK_640_480_60);
3392da0fc0dSDirk Eibach #endif
340a605ea7eSDirk Eibach 
3412da0fc0dSDirk Eibach #ifdef CONFIG_SYS_ICS8N3QV01
3422da0fc0dSDirk Eibach 	ics8n3qv01_set(screen, PIXCLK_640_480_60);
3432da0fc0dSDirk Eibach #endif
3442da0fc0dSDirk Eibach 
3452da0fc0dSDirk Eibach #ifdef CONFIG_SYS_SIL1178
3462da0fc0dSDirk Eibach 	value = fpga_iic_read(screen, SIL1178_SLAVE_I2C_ADDRESS, 0x02);
3472da0fc0dSDirk Eibach 	if (value != 0x06) {
3482da0fc0dSDirk Eibach 		printf("       Probing CH7301 SIL1178, DEV_IDL %02x\n", value);
3492da0fc0dSDirk Eibach 		return -1;
3502da0fc0dSDirk Eibach 	}
3512da0fc0dSDirk Eibach 	/* magic initialization sequence adapted from datasheet */
3522da0fc0dSDirk Eibach 	fpga_iic_write(screen, SIL1178_SLAVE_I2C_ADDRESS, 0x08, 0x36);
3532da0fc0dSDirk Eibach 	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x44);
3542da0fc0dSDirk Eibach 	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x4c);
3552da0fc0dSDirk Eibach 	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0e, 0x10);
3562da0fc0dSDirk Eibach 	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0a, 0x80);
3572da0fc0dSDirk Eibach 	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x09, 0x30);
3582da0fc0dSDirk Eibach 	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0c, 0x89);
3592da0fc0dSDirk Eibach 	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0d, 0x60);
3602da0fc0dSDirk Eibach 	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x36);
3612da0fc0dSDirk Eibach 	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x37);
3622da0fc0dSDirk Eibach #endif
3632da0fc0dSDirk Eibach 
364*aba27acfSDirk Eibach 	FPGA_SET_REG(screen, videocontrol, 0x0002);
365*aba27acfSDirk Eibach 	FPGA_SET_REG(screen, osd.control, 0x0049);
3662da0fc0dSDirk Eibach 
367*aba27acfSDirk Eibach 	FPGA_SET_REG(screen, osd.xy_size, ((32 - 1) << 8) | (16 - 1));
368*aba27acfSDirk Eibach 	FPGA_SET_REG(screen, osd.x_pos, 0x007f);
369*aba27acfSDirk Eibach 	FPGA_SET_REG(screen, osd.y_pos, 0x005f);
370*aba27acfSDirk Eibach 
371a605ea7eSDirk Eibach 
372a605ea7eSDirk Eibach 	return 0;
373a605ea7eSDirk Eibach }
374a605ea7eSDirk Eibach 
375a605ea7eSDirk Eibach int osd_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
376a605ea7eSDirk Eibach {
3772da0fc0dSDirk Eibach 	unsigned screen;
3782da0fc0dSDirk Eibach 
3792da0fc0dSDirk Eibach 	for (screen = 0; screen < CONFIG_SYS_OSD_SCREENS; ++screen) {
380a605ea7eSDirk Eibach 		unsigned x;
381a605ea7eSDirk Eibach 		unsigned y;
382a605ea7eSDirk Eibach 		unsigned k;
383a605ea7eSDirk Eibach 		u16 buffer[BASE_WIDTH];
384a605ea7eSDirk Eibach 		char *rp;
385a605ea7eSDirk Eibach 		u16 *wp = buffer;
3862da0fc0dSDirk Eibach 		unsigned count = (argc > 4) ?
3872da0fc0dSDirk Eibach 			simple_strtoul(argv[4], NULL, 16) : 1;
388a605ea7eSDirk Eibach 
389a605ea7eSDirk Eibach 		if ((argc < 4) || (strlen(argv[3]) % 4)) {
3902da0fc0dSDirk Eibach 			cmd_usage(cmdtp);
3912da0fc0dSDirk Eibach 			return 1;
392a605ea7eSDirk Eibach 		}
393a605ea7eSDirk Eibach 
394a605ea7eSDirk Eibach 		x = simple_strtoul(argv[1], NULL, 16);
395a605ea7eSDirk Eibach 		y = simple_strtoul(argv[2], NULL, 16);
396a605ea7eSDirk Eibach 		rp = argv[3];
397a605ea7eSDirk Eibach 
398a605ea7eSDirk Eibach 
399a605ea7eSDirk Eibach 		while (*rp) {
400a605ea7eSDirk Eibach 			char substr[5];
401a605ea7eSDirk Eibach 
402a605ea7eSDirk Eibach 			memcpy(substr, rp, 4);
403a605ea7eSDirk Eibach 			substr[4] = 0;
404a605ea7eSDirk Eibach 			*wp = simple_strtoul(substr, NULL, 16);
405a605ea7eSDirk Eibach 
406a605ea7eSDirk Eibach 			rp += 4;
407a605ea7eSDirk Eibach 			wp++;
408a605ea7eSDirk Eibach 			if (wp - buffer > BASE_WIDTH)
409a605ea7eSDirk Eibach 				break;
410a605ea7eSDirk Eibach 		}
411a605ea7eSDirk Eibach 
412a605ea7eSDirk Eibach 		for (k = 0; k < count; ++k) {
4132da0fc0dSDirk Eibach 			unsigned offset =
4142da0fc0dSDirk Eibach 				y * BASE_WIDTH + x + k * (wp - buffer);
4152da0fc0dSDirk Eibach 			osd_write_videomem(screen, offset, buffer,
4162da0fc0dSDirk Eibach 				wp - buffer);
4172da0fc0dSDirk Eibach 		}
418a605ea7eSDirk Eibach 	}
419a605ea7eSDirk Eibach 
420a605ea7eSDirk Eibach 	return 0;
421a605ea7eSDirk Eibach }
422a605ea7eSDirk Eibach 
423a605ea7eSDirk Eibach U_BOOT_CMD(
424a605ea7eSDirk Eibach 	osdw, 5, 0, osd_write,
425a605ea7eSDirk Eibach 	"write 16-bit hex encoded buffer to osd memory",
426a605ea7eSDirk Eibach 	"pos_x pos_y buffer count\n"
427a605ea7eSDirk Eibach );
428a605ea7eSDirk Eibach 
429a605ea7eSDirk Eibach U_BOOT_CMD(
430a605ea7eSDirk Eibach 	osdp, 5, 0, osd_print,
431a605ea7eSDirk Eibach 	"write ASCII buffer to osd memory",
432a605ea7eSDirk Eibach 	"pos_x pos_y color text\n"
433a605ea7eSDirk Eibach );
434