X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;ds=sidebyside;f=board%2Fgdsys%2Fcommon%2Fosd.c;h=55ecdf10127ed6e976e7906dd2707d89381e0835;hb=fc9b0b80435cda721fbdbe507c9e4f388b0ea62b;hp=4d8c046a8ab14ca2c90d026bdc1d1e0840b2f71a;hpb=494a7d215bfba17f1a94736df40c332c8713c30e;p=karo-tx-uboot.git diff --git a/board/gdsys/common/osd.c b/board/gdsys/common/osd.c index 4d8c046a8a..55ecdf1012 100644 --- a/board/gdsys/common/osd.c +++ b/board/gdsys/common/osd.c @@ -2,44 +2,32 @@ * (C) Copyright 2010 * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0+ */ #include #include -#include +#include +#include "dp501.h" #include #define CH7301_I2C_ADDR 0x75 #define ICS8N3QV01_I2C_ADDR 0x6E -#define ICS8N3QV01_FREF 114285 +#define ICS8N3QV01_FREF 114285000 +#define ICS8N3QV01_FREF_LL 114285000LL +#define ICS8N3QV01_F_DEFAULT_0 156250000LL +#define ICS8N3QV01_F_DEFAULT_1 125000000LL +#define ICS8N3QV01_F_DEFAULT_2 100000000LL +#define ICS8N3QV01_F_DEFAULT_3 25175000LL #define SIL1178_MASTER_I2C_ADDRESS 0x38 #define SIL1178_SLAVE_I2C_ADDRESS 0x39 -#define PIXCLK_640_480_60 25180000 +#define DP501_I2C_ADDR 0x08 -#define BASE_WIDTH 32 -#define BASE_HEIGHT 16 -#define BUFSIZE (BASE_WIDTH * BASE_HEIGHT) +#define PIXCLK_640_480_60 25180000 enum { CH7301_CM = 0x1c, /* Clock Mode Register */ @@ -62,40 +50,30 @@ enum { CH7301_DSP = 0x56, /* DVI Sync polarity Register */ }; -#if defined(CONFIG_SYS_ICS8N3QV01) || defined(CONFIG_SYS_SIL1178) -static void fpga_iic_write(unsigned screen, u8 slave, u8 reg, u8 data) -{ - ihs_fpga_t *fpga = (ihs_fpga_t *) CONFIG_SYS_FPGA_BASE(screen); - ihs_i2c_t *i2c = &fpga->i2c; +unsigned int base_width; +unsigned int base_height; +size_t bufsize; +u16 *buf; - while (in_le16(&fpga->extended_interrupt) & (1 << 12)) - ; - out_le16(&i2c->write_mailbox_ext, reg | (data << 8)); - out_le16(&i2c->write_mailbox, 0xc400 | (slave << 1)); -} +unsigned int max_osd_screen = CONFIG_SYS_OSD_SCREENS - 1; -static u8 fpga_iic_read(unsigned screen, u8 slave, u8 reg) -{ - ihs_fpga_t *fpga = (ihs_fpga_t *) CONFIG_SYS_FPGA_BASE(screen); - ihs_i2c_t *i2c = &fpga->i2c; - unsigned int ctr = 0; - - while (in_le16(&fpga->extended_interrupt) & (1 << 12)) - ; - out_le16(&fpga->extended_interrupt, 1 << 14); - out_le16(&i2c->write_mailbox_ext, reg); - out_le16(&i2c->write_mailbox, 0xc000 | (slave << 1)); - while (!(in_le16(&fpga->extended_interrupt) & (1 << 14))) { - udelay(100000); - if (ctr++ > 5) { - printf("iic receive timeout\n"); - break; - } - } - return in_le16(&i2c->read_mailbox_ext) >> 8; -} +#ifdef CONFIG_SYS_ICS8N3QV01_I2C +int ics8n3qv01_i2c[] = CONFIG_SYS_ICS8N3QV01_I2C; #endif +#ifdef CONFIG_SYS_CH7301_I2C +int ch7301_i2c[] = CONFIG_SYS_CH7301_I2C; +#endif + +#ifdef CONFIG_SYS_SIL1178_I2C +int sil1178_i2c[] = CONFIG_SYS_SIL1178_I2C; +#endif + +#ifdef CONFIG_SYS_DP501_I2C +int dp501_i2c[] = CONFIG_SYS_DP501_I2C; +#endif + + #ifdef CONFIG_SYS_MPC92469AC static void mpc92469ac_calc_parameters(unsigned int fout, unsigned int *post_div, unsigned int *feedback_div) @@ -124,7 +102,6 @@ static void mpc92469ac_calc_parameters(unsigned int fout, static void mpc92469ac_set(unsigned screen, unsigned int fout) { - ihs_fpga_t *fpga = (ihs_fpga_t *) CONFIG_SYS_FPGA_BASE(screen); unsigned int n; unsigned int m; unsigned int bitval = 0; @@ -145,11 +122,46 @@ static void mpc92469ac_set(unsigned screen, unsigned int fout) break; } - out_le16(&fpga->mpc3w_control, (bitval << 9) | m); + FPGA_SET_REG(screen, mpc3w_control, (bitval << 9) | m); } #endif -#ifdef CONFIG_SYS_ICS8N3QV01 +#ifdef CONFIG_SYS_ICS8N3QV01_I2C + +static unsigned int ics8n3qv01_get_fout_calc(unsigned index) +{ + unsigned long long n; + unsigned long long mint; + unsigned long long mfrac; + u8 reg_a, reg_b, reg_c, reg_d, reg_f; + unsigned long long fout_calc; + + if (index > 3) + return 0; + + reg_a = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 0 + index); + reg_b = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 4 + index); + reg_c = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 8 + index); + reg_d = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 12 + index); + reg_f = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 20 + index); + + mint = ((reg_a >> 1) & 0x1f) | (reg_f & 0x20); + mfrac = ((reg_a & 0x01) << 17) | (reg_b << 9) | (reg_c << 1) + | (reg_d >> 7); + n = reg_d & 0x7f; + + fout_calc = (mint * ICS8N3QV01_FREF_LL + + mfrac * ICS8N3QV01_FREF_LL / 262144LL + + ICS8N3QV01_FREF_LL / 524288LL + + n / 2) + / n + * 1000000 + / (1000000 - 100); + + return fout_calc; +} + + static void ics8n3qv01_calc_parameters(unsigned int fout, unsigned int *_mint, unsigned int *_mfrac, unsigned int *_n) @@ -160,7 +172,7 @@ static void ics8n3qv01_calc_parameters(unsigned int fout, unsigned int mint; unsigned long long mfrac; - n = 2550000000U / fout; + n = (2215000000U + fout / 2) / fout; if ((n & 1) && (n > 5)) n -= 1; @@ -179,51 +191,58 @@ static void ics8n3qv01_calc_parameters(unsigned int fout, *_n = n; } -static void ics8n3qv01_set(unsigned screen, unsigned int fout) +static void ics8n3qv01_set(unsigned int fout) { unsigned int n; unsigned int mint; unsigned int mfrac; + unsigned int fout_calc; + unsigned long long fout_prog; + long long off_ppm; u8 reg0, reg4, reg8, reg12, reg18, reg20; - ics8n3qv01_calc_parameters(fout, &mint, &mfrac, &n); + fout_calc = ics8n3qv01_get_fout_calc(1); + off_ppm = (fout_calc - ICS8N3QV01_F_DEFAULT_1) * 1000000 + / ICS8N3QV01_F_DEFAULT_1; + printf(" PLL is off by %lld ppm\n", off_ppm); + fout_prog = (unsigned long long)fout * (unsigned long long)fout_calc + / ICS8N3QV01_F_DEFAULT_1; + ics8n3qv01_calc_parameters(fout_prog, &mint, &mfrac, &n); - reg0 = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 0) & 0xc0; + reg0 = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 0) & 0xc0; reg0 |= (mint & 0x1f) << 1; reg0 |= (mfrac >> 17) & 0x01; - fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 0, reg0); + i2c_reg_write(ICS8N3QV01_I2C_ADDR, 0, reg0); reg4 = mfrac >> 9; - fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 4, reg4); + i2c_reg_write(ICS8N3QV01_I2C_ADDR, 4, reg4); reg8 = mfrac >> 1; - fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 8, reg8); + i2c_reg_write(ICS8N3QV01_I2C_ADDR, 8, reg8); reg12 = mfrac << 7; reg12 |= n & 0x7f; - fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 12, reg12); + i2c_reg_write(ICS8N3QV01_I2C_ADDR, 12, reg12); - reg18 = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 18) & 0x03; + reg18 = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 18) & 0x03; reg18 |= 0x20; - fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 18, reg18); + i2c_reg_write(ICS8N3QV01_I2C_ADDR, 18, reg18); - reg20 = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 20) & 0x1f; + reg20 = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 20) & 0x1f; reg20 |= mint & (1 << 5); - fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 20, reg20); + i2c_reg_write(ICS8N3QV01_I2C_ADDR, 20, reg20); } #endif static int osd_write_videomem(unsigned screen, unsigned offset, u16 *data, size_t charcount) { - ihs_fpga_t *fpga = - (ihs_fpga_t *) CONFIG_SYS_FPGA_BASE(screen); unsigned int k; for (k = 0; k < charcount; ++k) { - if (offset + k >= BUFSIZE) + if (offset + k >= bufsize) return -1; - out_le16(&fpga->videomem + offset + k, data[k]); + FPGA_SET_REG(screen, videomem[offset + k], data[k]); } return charcount; @@ -233,14 +252,13 @@ static int osd_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { unsigned screen; - for (screen = 0; screen < CONFIG_SYS_OSD_SCREENS; ++screen) { + for (screen = 0; screen <= max_osd_screen; ++screen) { unsigned x; unsigned y; unsigned charcount; unsigned len; u8 color; unsigned int k; - u16 buf[BUFSIZE]; char *text; int res; @@ -254,12 +272,12 @@ static int osd_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) color = simple_strtoul(argv[3], NULL, 16); text = argv[4]; charcount = strlen(text); - len = (charcount > BUFSIZE) ? BUFSIZE : charcount; + len = (charcount > bufsize) ? bufsize : charcount; for (k = 0; k < len; ++k) buf[k] = (text[k] << 8) | color; - res = osd_write_videomem(screen, y * BASE_WIDTH + x, buf, len); + res = osd_write_videomem(screen, y * base_width + x, buf, len); if (res < 0) return res; } @@ -269,64 +287,105 @@ static int osd_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) int osd_probe(unsigned screen) { - ihs_fpga_t *fpga = (ihs_fpga_t *) CONFIG_SYS_FPGA_BASE(screen); - ihs_osd_t *osd = &fpga->osd; - u16 version = in_le16(&osd->version); - u16 features = in_le16(&osd->features); - unsigned width; - unsigned height; - u8 value; - - width = ((features & 0x3f00) >> 8) + 1; - height = (features & 0x001f) + 1; + u16 version; + u16 features; + int old_bus = i2c_get_bus_num(); + bool pixclock_present = false; + bool output_driver_present = false; + + FPGA_GET_REG(0, osd.version, &version); + FPGA_GET_REG(0, osd.features, &features); + + base_width = ((features & 0x3f00) >> 8) + 1; + base_height = (features & 0x001f) + 1; + bufsize = base_width * base_height; + buf = malloc(sizeof(u16) * bufsize); + if (!buf) + return -1; printf("OSD%d: Digital-OSD version %01d.%02d, %d" "x%d characters\n", - screen, version/100, version%100, width, height); + screen, version/100, version%100, base_width, base_height); -#ifdef CONFIG_SYS_CH7301 - value = i2c_reg_read(CH7301_I2C_ADDR, CH7301_DID); - if (value != 0x17) { - printf(" Probing CH7301 failed, DID %02x\n", value); - return -1; - } - i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPCP, 0x08); - i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPD, 0x16); - i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPF, 0x60); - i2c_reg_write(CH7301_I2C_ADDR, CH7301_DC, 0x09); - i2c_reg_write(CH7301_I2C_ADDR, CH7301_PM, 0xc0); -#endif + /* setup pixclock */ #ifdef CONFIG_SYS_MPC92469AC + pixclock_present = true; mpc92469ac_set(screen, PIXCLK_640_480_60); #endif -#ifdef CONFIG_SYS_ICS8N3QV01 - ics8n3qv01_set(screen, PIXCLK_640_480_60); +#ifdef CONFIG_SYS_ICS8N3QV01_I2C + i2c_set_bus_num(ics8n3qv01_i2c[screen]); + if (!i2c_probe(ICS8N3QV01_I2C_ADDR)) { + ics8n3qv01_set(PIXCLK_640_480_60); + pixclock_present = true; + } #endif -#ifdef CONFIG_SYS_SIL1178 - value = fpga_iic_read(screen, SIL1178_SLAVE_I2C_ADDRESS, 0x02); - if (value != 0x06) { - printf(" Probing CH7301 SIL1178, DEV_IDL %02x\n", value); - return -1; + if (!pixclock_present) + printf(" no pixelclock found\n"); + + /* setup output driver */ + +#ifdef CONFIG_SYS_CH7301_I2C + i2c_set_bus_num(ch7301_i2c[screen]); + if (!i2c_probe(CH7301_I2C_ADDR)) { + u8 value = i2c_reg_read(CH7301_I2C_ADDR, CH7301_DID); + + if (value == 0x17) { + i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPCP, 0x08); + i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPD, 0x16); + i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPF, 0x60); + i2c_reg_write(CH7301_I2C_ADDR, CH7301_DC, 0x09); + i2c_reg_write(CH7301_I2C_ADDR, CH7301_PM, 0xc0); + output_driver_present = true; + } + } +#endif + +#ifdef CONFIG_SYS_SIL1178_I2C + i2c_set_bus_num(sil1178_i2c[screen]); + if (!i2c_probe(SIL1178_SLAVE_I2C_ADDRESS)) { + if (i2c_reg_read(SIL1178_SLAVE_I2C_ADDRESS, 0x02) == 0x06) { + /* + * magic initialization sequence, + * adapted from datasheet + */ + i2c_reg_write(SIL1178_SLAVE_I2C_ADDRESS, 0x08, 0x36); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x44); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x4c); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0e, 0x10); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0a, 0x80); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x09, 0x30); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0c, 0x89); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0d, 0x60); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x36); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x37); + output_driver_present = true; + } } - /* magic initialization sequence adapted from datasheet */ - fpga_iic_write(screen, SIL1178_SLAVE_I2C_ADDRESS, 0x08, 0x36); - fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x44); - fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x4c); - fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0e, 0x10); - fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0a, 0x80); - fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x09, 0x30); - fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0c, 0x89); - fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0d, 0x60); - fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x36); - fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x37); #endif - out_le16(&fpga->videocontrol, 0x0002); - out_le16(&osd->control, 0x0049); +#ifdef CONFIG_SYS_DP501_I2C + i2c_set_bus_num(dp501_i2c[screen]); + if (!i2c_probe(DP501_I2C_ADDR)) { + dp501_powerup(DP501_I2C_ADDR); + output_driver_present = true; + } +#endif + + if (!output_driver_present) + printf(" no output driver found\n"); + + FPGA_SET_REG(screen, osd.control, 0x0049); + + FPGA_SET_REG(screen, osd.xy_size, ((32 - 1) << 8) | (16 - 1)); + FPGA_SET_REG(screen, osd.x_pos, 0x007f); + FPGA_SET_REG(screen, osd.y_pos, 0x005f); + + if (screen > max_osd_screen) + max_osd_screen = screen; - out_le16(&osd->xy_size, ((32 - 1) << 8) | (16 - 1)); + i2c_set_bus_num(old_bus); return 0; } @@ -335,11 +394,11 @@ int osd_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { unsigned screen; - for (screen = 0; screen < CONFIG_SYS_OSD_SCREENS; ++screen) { + for (screen = 0; screen <= max_osd_screen; ++screen) { unsigned x; unsigned y; unsigned k; - u16 buffer[BASE_WIDTH]; + u16 buffer[base_width]; char *rp; u16 *wp = buffer; unsigned count = (argc > 4) ? @@ -364,13 +423,13 @@ int osd_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) rp += 4; wp++; - if (wp - buffer > BASE_WIDTH) + if (wp - buffer > base_width) break; } for (k = 0; k < count; ++k) { unsigned offset = - y * BASE_WIDTH + x + k * (wp - buffer); + y * base_width + x + k * (wp - buffer); osd_write_videomem(screen, offset, buffer, wp - buffer); }