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 int old_bus = i2c_get_bus_num(); 293 bool pixclock_present = false; 294 bool output_driver_present = false; 295 296 FPGA_GET_REG(0, osd.version, &version); 297 FPGA_GET_REG(0, osd.features, &features); 298 299 base_width = ((features & 0x3f00) >> 8) + 1; 300 base_height = (features & 0x001f) + 1; 301 bufsize = base_width * base_height; 302 buf = malloc(sizeof(u16) * bufsize); 303 if (!buf) 304 return -1; 305 306 printf("OSD%d: Digital-OSD version %01d.%02d, %d" "x%d characters\n", 307 screen, version/100, version%100, base_width, base_height); 308 309 /* setup pixclock */ 310 311 #ifdef CONFIG_SYS_MPC92469AC 312 pixclock_present = true; 313 mpc92469ac_set(screen, PIXCLK_640_480_60); 314 #endif 315 316 #ifdef CONFIG_SYS_ICS8N3QV01_I2C 317 i2c_set_bus_num(ics8n3qv01_i2c[screen]); 318 if (!i2c_probe(ICS8N3QV01_I2C_ADDR)) { 319 ics8n3qv01_set(PIXCLK_640_480_60); 320 pixclock_present = true; 321 } 322 #endif 323 324 if (!pixclock_present) 325 printf(" no pixelclock found\n"); 326 327 /* setup output driver */ 328 329 #ifdef CONFIG_SYS_CH7301_I2C 330 i2c_set_bus_num(ch7301_i2c[screen]); 331 if (!i2c_probe(CH7301_I2C_ADDR)) { 332 u8 value = i2c_reg_read(CH7301_I2C_ADDR, CH7301_DID); 333 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 if (i2c_reg_read(SIL1178_SLAVE_I2C_ADDRESS, 0x02) == 0x06) { 349 /* 350 * magic initialization sequence, 351 * adapted from datasheet 352 */ 353 i2c_reg_write(SIL1178_SLAVE_I2C_ADDRESS, 0x08, 0x36); 354 i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x44); 355 i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x4c); 356 i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0e, 0x10); 357 i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0a, 0x80); 358 i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x09, 0x30); 359 i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0c, 0x89); 360 i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0d, 0x60); 361 i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x36); 362 i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x37); 363 output_driver_present = true; 364 } 365 } 366 #endif 367 368 #ifdef CONFIG_SYS_DP501_I2C 369 i2c_set_bus_num(dp501_i2c[screen]); 370 if (!i2c_probe(DP501_I2C_ADDR)) { 371 dp501_powerup(DP501_I2C_ADDR); 372 output_driver_present = true; 373 } 374 #endif 375 376 if (!output_driver_present) 377 printf(" no output driver found\n"); 378 379 FPGA_SET_REG(screen, osd.control, 0x0049); 380 381 FPGA_SET_REG(screen, osd.xy_size, ((32 - 1) << 8) | (16 - 1)); 382 FPGA_SET_REG(screen, osd.x_pos, 0x007f); 383 FPGA_SET_REG(screen, osd.y_pos, 0x005f); 384 385 if (screen > max_osd_screen) 386 max_osd_screen = screen; 387 388 i2c_set_bus_num(old_bus); 389 390 return 0; 391 } 392 393 int osd_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 394 { 395 unsigned screen; 396 397 for (screen = 0; screen <= max_osd_screen; ++screen) { 398 unsigned x; 399 unsigned y; 400 unsigned k; 401 u16 buffer[base_width]; 402 char *rp; 403 u16 *wp = buffer; 404 unsigned count = (argc > 4) ? 405 simple_strtoul(argv[4], NULL, 16) : 1; 406 407 if ((argc < 4) || (strlen(argv[3]) % 4)) { 408 cmd_usage(cmdtp); 409 return 1; 410 } 411 412 x = simple_strtoul(argv[1], NULL, 16); 413 y = simple_strtoul(argv[2], NULL, 16); 414 rp = argv[3]; 415 416 417 while (*rp) { 418 char substr[5]; 419 420 memcpy(substr, rp, 4); 421 substr[4] = 0; 422 *wp = simple_strtoul(substr, NULL, 16); 423 424 rp += 4; 425 wp++; 426 if (wp - buffer > base_width) 427 break; 428 } 429 430 for (k = 0; k < count; ++k) { 431 unsigned offset = 432 y * base_width + x + k * (wp - buffer); 433 osd_write_videomem(screen, offset, buffer, 434 wp - buffer); 435 } 436 } 437 438 return 0; 439 } 440 441 U_BOOT_CMD( 442 osdw, 5, 0, osd_write, 443 "write 16-bit hex encoded buffer to osd memory", 444 "pos_x pos_y buffer count\n" 445 ); 446 447 U_BOOT_CMD( 448 osdp, 5, 0, osd_print, 449 "write ASCII buffer to osd memory", 450 "pos_x pos_y color text\n" 451 ); 452