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