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> 9aba27acfSDirk Eibach #include <i2c.h> 10e50e8968SDirk Eibach #include <malloc.h> 11a605ea7eSDirk Eibach 12*a3f9d6c7SDirk Eibach #include "ch7301.h" 133a990bfaSDirk Eibach #include "dp501.h" 142da0fc0dSDirk Eibach #include <gdsys_fpga.h> 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 273a990bfaSDirk Eibach #define DP501_I2C_ADDR 0x08 283a990bfaSDirk Eibach 29a605ea7eSDirk Eibach #define PIXCLK_640_480_60 25180000 30a605ea7eSDirk Eibach 310f0c1021SDirk Eibach unsigned int base_width; 320f0c1021SDirk Eibach unsigned int base_height; 330f0c1021SDirk Eibach size_t bufsize; 340f0c1021SDirk Eibach u16 *buf; 350f0c1021SDirk Eibach 36e50e8968SDirk Eibach unsigned int max_osd_screen = CONFIG_SYS_OSD_SCREENS - 1; 37e50e8968SDirk Eibach 383a990bfaSDirk Eibach #ifdef CONFIG_SYS_ICS8N3QV01_I2C 39edfe9feaSDirk Eibach int ics8n3qv01_i2c[] = CONFIG_SYS_ICS8N3QV01_I2C; 40edfe9feaSDirk Eibach #endif 412da0fc0dSDirk Eibach 423a990bfaSDirk Eibach #ifdef CONFIG_SYS_SIL1178_I2C 43edfe9feaSDirk Eibach int sil1178_i2c[] = CONFIG_SYS_SIL1178_I2C; 442da0fc0dSDirk Eibach #endif 452da0fc0dSDirk Eibach 463a990bfaSDirk Eibach #ifdef CONFIG_SYS_DP501_I2C 473a990bfaSDirk Eibach int dp501_i2c[] = CONFIG_SYS_DP501_I2C; 483a990bfaSDirk Eibach #endif 493a990bfaSDirk Eibach 503a990bfaSDirk Eibach 512da0fc0dSDirk Eibach #ifdef CONFIG_SYS_MPC92469AC 52a605ea7eSDirk Eibach static void mpc92469ac_calc_parameters(unsigned int fout, 53a605ea7eSDirk Eibach unsigned int *post_div, unsigned int *feedback_div) 54a605ea7eSDirk Eibach { 55a605ea7eSDirk Eibach unsigned int n = *post_div; 56a605ea7eSDirk Eibach unsigned int m = *feedback_div; 57a605ea7eSDirk Eibach unsigned int a; 58a605ea7eSDirk Eibach unsigned int b = 14745600 / 16; 59a605ea7eSDirk Eibach 60a605ea7eSDirk Eibach if (fout < 50169600) 61a605ea7eSDirk Eibach n = 8; 62a605ea7eSDirk Eibach else if (fout < 100339199) 63a605ea7eSDirk Eibach n = 4; 64a605ea7eSDirk Eibach else if (fout < 200678399) 65a605ea7eSDirk Eibach n = 2; 66a605ea7eSDirk Eibach else 67a605ea7eSDirk Eibach n = 1; 68a605ea7eSDirk Eibach 69a605ea7eSDirk Eibach a = fout * n + (b / 2); /* add b/2 for proper rounding */ 70a605ea7eSDirk Eibach 71a605ea7eSDirk Eibach m = a / b; 72a605ea7eSDirk Eibach 73a605ea7eSDirk Eibach *post_div = n; 74a605ea7eSDirk Eibach *feedback_div = m; 75a605ea7eSDirk Eibach } 76a605ea7eSDirk Eibach 772da0fc0dSDirk Eibach static void mpc92469ac_set(unsigned screen, unsigned int fout) 78a605ea7eSDirk Eibach { 79a605ea7eSDirk Eibach unsigned int n; 80a605ea7eSDirk Eibach unsigned int m; 81a605ea7eSDirk Eibach unsigned int bitval = 0; 82a605ea7eSDirk Eibach mpc92469ac_calc_parameters(fout, &n, &m); 83a605ea7eSDirk Eibach 84a605ea7eSDirk Eibach switch (n) { 85a605ea7eSDirk Eibach case 1: 86a605ea7eSDirk Eibach bitval = 0x00; 87a605ea7eSDirk Eibach break; 88a605ea7eSDirk Eibach case 2: 89a605ea7eSDirk Eibach bitval = 0x01; 90a605ea7eSDirk Eibach break; 91a605ea7eSDirk Eibach case 4: 92a605ea7eSDirk Eibach bitval = 0x02; 93a605ea7eSDirk Eibach break; 94a605ea7eSDirk Eibach case 8: 95a605ea7eSDirk Eibach bitval = 0x03; 96a605ea7eSDirk Eibach break; 97a605ea7eSDirk Eibach } 98a605ea7eSDirk Eibach 99aba27acfSDirk Eibach FPGA_SET_REG(screen, mpc3w_control, (bitval << 9) | m); 1002da0fc0dSDirk Eibach } 1012da0fc0dSDirk Eibach #endif 1022da0fc0dSDirk Eibach 1033a990bfaSDirk Eibach #ifdef CONFIG_SYS_ICS8N3QV01_I2C 1046853cc4bSDirk Eibach 105edfe9feaSDirk Eibach static unsigned int ics8n3qv01_get_fout_calc(unsigned index) 1066853cc4bSDirk Eibach { 1076853cc4bSDirk Eibach unsigned long long n; 1086853cc4bSDirk Eibach unsigned long long mint; 1096853cc4bSDirk Eibach unsigned long long mfrac; 1106853cc4bSDirk Eibach u8 reg_a, reg_b, reg_c, reg_d, reg_f; 1116853cc4bSDirk Eibach unsigned long long fout_calc; 1126853cc4bSDirk Eibach 1136853cc4bSDirk Eibach if (index > 3) 1146853cc4bSDirk Eibach return 0; 1156853cc4bSDirk Eibach 116edfe9feaSDirk Eibach reg_a = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 0 + index); 117edfe9feaSDirk Eibach reg_b = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 4 + index); 118edfe9feaSDirk Eibach reg_c = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 8 + index); 119edfe9feaSDirk Eibach reg_d = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 12 + index); 120edfe9feaSDirk Eibach reg_f = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 20 + index); 1216853cc4bSDirk Eibach 1226853cc4bSDirk Eibach mint = ((reg_a >> 1) & 0x1f) | (reg_f & 0x20); 1236853cc4bSDirk Eibach mfrac = ((reg_a & 0x01) << 17) | (reg_b << 9) | (reg_c << 1) 1246853cc4bSDirk Eibach | (reg_d >> 7); 1256853cc4bSDirk Eibach n = reg_d & 0x7f; 1266853cc4bSDirk Eibach 1276853cc4bSDirk Eibach fout_calc = (mint * ICS8N3QV01_FREF_LL 1286853cc4bSDirk Eibach + mfrac * ICS8N3QV01_FREF_LL / 262144LL 1296853cc4bSDirk Eibach + ICS8N3QV01_FREF_LL / 524288LL 1306853cc4bSDirk Eibach + n / 2) 1316853cc4bSDirk Eibach / n 1326853cc4bSDirk Eibach * 1000000 1336853cc4bSDirk Eibach / (1000000 - 100); 1346853cc4bSDirk Eibach 1356853cc4bSDirk Eibach return fout_calc; 1366853cc4bSDirk Eibach } 1376853cc4bSDirk Eibach 1386853cc4bSDirk Eibach 1392da0fc0dSDirk Eibach static void ics8n3qv01_calc_parameters(unsigned int fout, 1402da0fc0dSDirk Eibach unsigned int *_mint, unsigned int *_mfrac, 1412da0fc0dSDirk Eibach unsigned int *_n) 1422da0fc0dSDirk Eibach { 1432da0fc0dSDirk Eibach unsigned int n; 1442da0fc0dSDirk Eibach unsigned int foutiic; 1452da0fc0dSDirk Eibach unsigned int fvcoiic; 1462da0fc0dSDirk Eibach unsigned int mint; 1472da0fc0dSDirk Eibach unsigned long long mfrac; 1482da0fc0dSDirk Eibach 1496853cc4bSDirk Eibach n = (2215000000U + fout / 2) / fout; 1502da0fc0dSDirk Eibach if ((n & 1) && (n > 5)) 1512da0fc0dSDirk Eibach n -= 1; 1522da0fc0dSDirk Eibach 1532da0fc0dSDirk Eibach foutiic = fout - (fout / 10000); 1542da0fc0dSDirk Eibach fvcoiic = foutiic * n; 1552da0fc0dSDirk Eibach 1562da0fc0dSDirk Eibach mint = fvcoiic / 114285000; 1572da0fc0dSDirk Eibach if ((mint < 17) || (mint > 63)) 1582da0fc0dSDirk Eibach printf("ics8n3qv01_calc_parameters: cannot determine mint\n"); 1592da0fc0dSDirk Eibach 1602da0fc0dSDirk Eibach mfrac = ((unsigned long long)fvcoiic % 114285000LL) * 262144LL 1612da0fc0dSDirk Eibach / 114285000LL; 1622da0fc0dSDirk Eibach 1632da0fc0dSDirk Eibach *_mint = mint; 1642da0fc0dSDirk Eibach *_mfrac = mfrac; 1652da0fc0dSDirk Eibach *_n = n; 166a605ea7eSDirk Eibach } 167a605ea7eSDirk Eibach 168edfe9feaSDirk Eibach static void ics8n3qv01_set(unsigned int fout) 169a605ea7eSDirk Eibach { 1702da0fc0dSDirk Eibach unsigned int n; 1712da0fc0dSDirk Eibach unsigned int mint; 1722da0fc0dSDirk Eibach unsigned int mfrac; 1736853cc4bSDirk Eibach unsigned int fout_calc; 1746853cc4bSDirk Eibach unsigned long long fout_prog; 1756853cc4bSDirk Eibach long long off_ppm; 1762da0fc0dSDirk Eibach u8 reg0, reg4, reg8, reg12, reg18, reg20; 1772da0fc0dSDirk Eibach 178edfe9feaSDirk Eibach fout_calc = ics8n3qv01_get_fout_calc(1); 1796853cc4bSDirk Eibach off_ppm = (fout_calc - ICS8N3QV01_F_DEFAULT_1) * 1000000 1806853cc4bSDirk Eibach / ICS8N3QV01_F_DEFAULT_1; 1816853cc4bSDirk Eibach printf(" PLL is off by %lld ppm\n", off_ppm); 1826853cc4bSDirk Eibach fout_prog = (unsigned long long)fout * (unsigned long long)fout_calc 1836853cc4bSDirk Eibach / ICS8N3QV01_F_DEFAULT_1; 1846853cc4bSDirk Eibach ics8n3qv01_calc_parameters(fout_prog, &mint, &mfrac, &n); 1852da0fc0dSDirk Eibach 186edfe9feaSDirk Eibach reg0 = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 0) & 0xc0; 1872da0fc0dSDirk Eibach reg0 |= (mint & 0x1f) << 1; 1882da0fc0dSDirk Eibach reg0 |= (mfrac >> 17) & 0x01; 189edfe9feaSDirk Eibach i2c_reg_write(ICS8N3QV01_I2C_ADDR, 0, reg0); 1902da0fc0dSDirk Eibach 1912da0fc0dSDirk Eibach reg4 = mfrac >> 9; 192edfe9feaSDirk Eibach i2c_reg_write(ICS8N3QV01_I2C_ADDR, 4, reg4); 1932da0fc0dSDirk Eibach 1942da0fc0dSDirk Eibach reg8 = mfrac >> 1; 195edfe9feaSDirk Eibach i2c_reg_write(ICS8N3QV01_I2C_ADDR, 8, reg8); 1962da0fc0dSDirk Eibach 1972da0fc0dSDirk Eibach reg12 = mfrac << 7; 1982da0fc0dSDirk Eibach reg12 |= n & 0x7f; 199edfe9feaSDirk Eibach i2c_reg_write(ICS8N3QV01_I2C_ADDR, 12, reg12); 2002da0fc0dSDirk Eibach 201edfe9feaSDirk Eibach reg18 = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 18) & 0x03; 2022da0fc0dSDirk Eibach reg18 |= 0x20; 203edfe9feaSDirk Eibach i2c_reg_write(ICS8N3QV01_I2C_ADDR, 18, reg18); 2042da0fc0dSDirk Eibach 205edfe9feaSDirk Eibach reg20 = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 20) & 0x1f; 2062da0fc0dSDirk Eibach reg20 |= mint & (1 << 5); 207edfe9feaSDirk Eibach i2c_reg_write(ICS8N3QV01_I2C_ADDR, 20, reg20); 2082da0fc0dSDirk Eibach } 2092da0fc0dSDirk Eibach #endif 2102da0fc0dSDirk Eibach 2112da0fc0dSDirk Eibach static int osd_write_videomem(unsigned screen, unsigned offset, 2122da0fc0dSDirk Eibach u16 *data, size_t charcount) 2132da0fc0dSDirk Eibach { 214a605ea7eSDirk Eibach unsigned int k; 215a605ea7eSDirk Eibach 216a605ea7eSDirk Eibach for (k = 0; k < charcount; ++k) { 2170f0c1021SDirk Eibach if (offset + k >= bufsize) 218a605ea7eSDirk Eibach return -1; 219aba27acfSDirk Eibach FPGA_SET_REG(screen, videomem[offset + k], data[k]); 220a605ea7eSDirk Eibach } 221a605ea7eSDirk Eibach 222a605ea7eSDirk Eibach return charcount; 223a605ea7eSDirk Eibach } 224a605ea7eSDirk Eibach 225a605ea7eSDirk Eibach static int osd_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 226a605ea7eSDirk Eibach { 2272da0fc0dSDirk Eibach unsigned screen; 2282da0fc0dSDirk Eibach 229e50e8968SDirk Eibach for (screen = 0; screen <= max_osd_screen; ++screen) { 230a605ea7eSDirk Eibach unsigned x; 231a605ea7eSDirk Eibach unsigned y; 232a605ea7eSDirk Eibach unsigned charcount; 233a605ea7eSDirk Eibach unsigned len; 234a605ea7eSDirk Eibach u8 color; 235a605ea7eSDirk Eibach unsigned int k; 236a605ea7eSDirk Eibach char *text; 2372da0fc0dSDirk Eibach int res; 238a605ea7eSDirk Eibach 239a605ea7eSDirk Eibach if (argc < 5) { 2402da0fc0dSDirk Eibach cmd_usage(cmdtp); 2412da0fc0dSDirk Eibach return 1; 242a605ea7eSDirk Eibach } 243a605ea7eSDirk Eibach 244a605ea7eSDirk Eibach x = simple_strtoul(argv[1], NULL, 16); 245a605ea7eSDirk Eibach y = simple_strtoul(argv[2], NULL, 16); 246a605ea7eSDirk Eibach color = simple_strtoul(argv[3], NULL, 16); 247a605ea7eSDirk Eibach text = argv[4]; 248a605ea7eSDirk Eibach charcount = strlen(text); 2490f0c1021SDirk Eibach len = (charcount > bufsize) ? bufsize : charcount; 250a605ea7eSDirk Eibach 251a605ea7eSDirk Eibach for (k = 0; k < len; ++k) 252a605ea7eSDirk Eibach buf[k] = (text[k] << 8) | color; 253a605ea7eSDirk Eibach 2540f0c1021SDirk Eibach res = osd_write_videomem(screen, y * base_width + x, buf, len); 2552da0fc0dSDirk Eibach if (res < 0) 2562da0fc0dSDirk Eibach return res; 257a605ea7eSDirk Eibach } 258a605ea7eSDirk Eibach 2592da0fc0dSDirk Eibach return 0; 2602da0fc0dSDirk Eibach } 2612da0fc0dSDirk Eibach 2622da0fc0dSDirk Eibach int osd_probe(unsigned screen) 263a605ea7eSDirk Eibach { 264aba27acfSDirk Eibach u16 version; 265aba27acfSDirk Eibach u16 features; 266e50e8968SDirk Eibach int old_bus = i2c_get_bus_num(); 2673a990bfaSDirk Eibach bool pixclock_present = false; 2683a990bfaSDirk Eibach bool output_driver_present = false; 269a605ea7eSDirk Eibach 270aba27acfSDirk Eibach FPGA_GET_REG(0, osd.version, &version); 271aba27acfSDirk Eibach FPGA_GET_REG(0, osd.features, &features); 272aba27acfSDirk Eibach 2730f0c1021SDirk Eibach base_width = ((features & 0x3f00) >> 8) + 1; 2740f0c1021SDirk Eibach base_height = (features & 0x001f) + 1; 2750f0c1021SDirk Eibach bufsize = base_width * base_height; 2760f0c1021SDirk Eibach buf = malloc(sizeof(u16) * bufsize); 2770f0c1021SDirk Eibach if (!buf) 2780f0c1021SDirk Eibach return -1; 279a605ea7eSDirk Eibach 2802da0fc0dSDirk Eibach printf("OSD%d: Digital-OSD version %01d.%02d, %d" "x%d characters\n", 2810f0c1021SDirk Eibach screen, version/100, version%100, base_width, base_height); 282a605ea7eSDirk Eibach 2833a990bfaSDirk Eibach /* setup pixclock */ 2843a990bfaSDirk Eibach 2853a990bfaSDirk Eibach #ifdef CONFIG_SYS_MPC92469AC 2863a990bfaSDirk Eibach pixclock_present = true; 2873a990bfaSDirk Eibach mpc92469ac_set(screen, PIXCLK_640_480_60); 2883a990bfaSDirk Eibach #endif 2893a990bfaSDirk Eibach 2903a990bfaSDirk Eibach #ifdef CONFIG_SYS_ICS8N3QV01_I2C 2913a990bfaSDirk Eibach i2c_set_bus_num(ics8n3qv01_i2c[screen]); 2923a990bfaSDirk Eibach if (!i2c_probe(ICS8N3QV01_I2C_ADDR)) { 2933a990bfaSDirk Eibach ics8n3qv01_set(PIXCLK_640_480_60); 2943a990bfaSDirk Eibach pixclock_present = true; 295a605ea7eSDirk Eibach } 2963a990bfaSDirk Eibach #endif 2973a990bfaSDirk Eibach 2983a990bfaSDirk Eibach if (!pixclock_present) 2993a990bfaSDirk Eibach printf(" no pixelclock found\n"); 3003a990bfaSDirk Eibach 3013a990bfaSDirk Eibach /* setup output driver */ 3023a990bfaSDirk Eibach 3033a990bfaSDirk Eibach #ifdef CONFIG_SYS_CH7301_I2C 304*a3f9d6c7SDirk Eibach if (!ch7301_probe(screen, true)) 3053a990bfaSDirk Eibach output_driver_present = true; 3063a990bfaSDirk Eibach #endif 3073a990bfaSDirk Eibach 3083a990bfaSDirk Eibach #ifdef CONFIG_SYS_SIL1178_I2C 3093a990bfaSDirk Eibach i2c_set_bus_num(sil1178_i2c[screen]); 3103a990bfaSDirk Eibach if (!i2c_probe(SIL1178_SLAVE_I2C_ADDRESS)) { 311a61762d2SDirk Eibach if (i2c_reg_read(SIL1178_SLAVE_I2C_ADDRESS, 0x02) == 0x06) { 3123a990bfaSDirk Eibach /* 3133a990bfaSDirk Eibach * magic initialization sequence, 3143a990bfaSDirk Eibach * adapted from datasheet 3153a990bfaSDirk Eibach */ 316edfe9feaSDirk Eibach i2c_reg_write(SIL1178_SLAVE_I2C_ADDRESS, 0x08, 0x36); 317edfe9feaSDirk Eibach i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x44); 318edfe9feaSDirk Eibach i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x4c); 319edfe9feaSDirk Eibach i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0e, 0x10); 320edfe9feaSDirk Eibach i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0a, 0x80); 321edfe9feaSDirk Eibach i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x09, 0x30); 322edfe9feaSDirk Eibach i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0c, 0x89); 323edfe9feaSDirk Eibach i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0d, 0x60); 324edfe9feaSDirk Eibach i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x36); 325edfe9feaSDirk Eibach i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x37); 3263a990bfaSDirk Eibach output_driver_present = true; 3273a990bfaSDirk Eibach } 3283a990bfaSDirk Eibach } 3292da0fc0dSDirk Eibach #endif 3302da0fc0dSDirk Eibach 3313a990bfaSDirk Eibach #ifdef CONFIG_SYS_DP501_I2C 3323a990bfaSDirk Eibach i2c_set_bus_num(dp501_i2c[screen]); 3333a990bfaSDirk Eibach if (!i2c_probe(DP501_I2C_ADDR)) { 3343a990bfaSDirk Eibach dp501_powerup(DP501_I2C_ADDR); 3353a990bfaSDirk Eibach output_driver_present = true; 3363a990bfaSDirk Eibach } 3373a990bfaSDirk Eibach #endif 3383a990bfaSDirk Eibach 3393a990bfaSDirk Eibach if (!output_driver_present) 3403a990bfaSDirk Eibach printf(" no output driver found\n"); 3413a990bfaSDirk Eibach 342aba27acfSDirk Eibach FPGA_SET_REG(screen, osd.control, 0x0049); 3432da0fc0dSDirk Eibach 344aba27acfSDirk Eibach FPGA_SET_REG(screen, osd.xy_size, ((32 - 1) << 8) | (16 - 1)); 345aba27acfSDirk Eibach FPGA_SET_REG(screen, osd.x_pos, 0x007f); 346aba27acfSDirk Eibach FPGA_SET_REG(screen, osd.y_pos, 0x005f); 347aba27acfSDirk Eibach 348e50e8968SDirk Eibach if (screen > max_osd_screen) 349e50e8968SDirk Eibach max_osd_screen = screen; 350a605ea7eSDirk Eibach 351edfe9feaSDirk Eibach i2c_set_bus_num(old_bus); 352edfe9feaSDirk Eibach 353a605ea7eSDirk Eibach return 0; 354a605ea7eSDirk Eibach } 355a605ea7eSDirk Eibach 356a605ea7eSDirk Eibach int osd_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 357a605ea7eSDirk Eibach { 3582da0fc0dSDirk Eibach unsigned screen; 3592da0fc0dSDirk Eibach 360e50e8968SDirk Eibach for (screen = 0; screen <= max_osd_screen; ++screen) { 361a605ea7eSDirk Eibach unsigned x; 362a605ea7eSDirk Eibach unsigned y; 363a605ea7eSDirk Eibach unsigned k; 3640f0c1021SDirk Eibach u16 buffer[base_width]; 365a605ea7eSDirk Eibach char *rp; 366a605ea7eSDirk Eibach u16 *wp = buffer; 3672da0fc0dSDirk Eibach unsigned count = (argc > 4) ? 3682da0fc0dSDirk Eibach simple_strtoul(argv[4], NULL, 16) : 1; 369a605ea7eSDirk Eibach 370a605ea7eSDirk Eibach if ((argc < 4) || (strlen(argv[3]) % 4)) { 3712da0fc0dSDirk Eibach cmd_usage(cmdtp); 3722da0fc0dSDirk Eibach return 1; 373a605ea7eSDirk Eibach } 374a605ea7eSDirk Eibach 375a605ea7eSDirk Eibach x = simple_strtoul(argv[1], NULL, 16); 376a605ea7eSDirk Eibach y = simple_strtoul(argv[2], NULL, 16); 377a605ea7eSDirk Eibach rp = argv[3]; 378a605ea7eSDirk Eibach 379a605ea7eSDirk Eibach 380a605ea7eSDirk Eibach while (*rp) { 381a605ea7eSDirk Eibach char substr[5]; 382a605ea7eSDirk Eibach 383a605ea7eSDirk Eibach memcpy(substr, rp, 4); 384a605ea7eSDirk Eibach substr[4] = 0; 385a605ea7eSDirk Eibach *wp = simple_strtoul(substr, NULL, 16); 386a605ea7eSDirk Eibach 387a605ea7eSDirk Eibach rp += 4; 388a605ea7eSDirk Eibach wp++; 3890f0c1021SDirk Eibach if (wp - buffer > base_width) 390a605ea7eSDirk Eibach break; 391a605ea7eSDirk Eibach } 392a605ea7eSDirk Eibach 393a605ea7eSDirk Eibach for (k = 0; k < count; ++k) { 3942da0fc0dSDirk Eibach unsigned offset = 3950f0c1021SDirk Eibach y * base_width + x + k * (wp - buffer); 3962da0fc0dSDirk Eibach osd_write_videomem(screen, offset, buffer, 3972da0fc0dSDirk Eibach wp - buffer); 3982da0fc0dSDirk Eibach } 399a605ea7eSDirk Eibach } 400a605ea7eSDirk Eibach 401a605ea7eSDirk Eibach return 0; 402a605ea7eSDirk Eibach } 403a605ea7eSDirk Eibach 404a605ea7eSDirk Eibach U_BOOT_CMD( 405a605ea7eSDirk Eibach osdw, 5, 0, osd_write, 406a605ea7eSDirk Eibach "write 16-bit hex encoded buffer to osd memory", 407a605ea7eSDirk Eibach "pos_x pos_y buffer count\n" 408a605ea7eSDirk Eibach ); 409a605ea7eSDirk Eibach 410a605ea7eSDirk Eibach U_BOOT_CMD( 411a605ea7eSDirk Eibach osdp, 5, 0, osd_print, 412a605ea7eSDirk Eibach "write ASCII buffer to osd memory", 413a605ea7eSDirk Eibach "pos_x pos_y color text\n" 414a605ea7eSDirk Eibach ); 415