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