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