diff options
Diffstat (limited to 'board/gdsys/common/osd.c')
-rw-r--r-- | board/gdsys/common/osd.c | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/board/gdsys/common/osd.c b/board/gdsys/common/osd.c new file mode 100644 index 0000000..05800ff --- /dev/null +++ b/board/gdsys/common/osd.c @@ -0,0 +1,247 @@ +/* + * (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 + */ + +#include <common.h> +#include <i2c.h> +#include <asm/io.h> + +#include "fpga.h" + +#define CH7301_I2C_ADDR 0x75 + +#define PIXCLK_640_480_60 25180000 + +#define BASE_WIDTH 32 +#define BASE_HEIGHT 16 +#define BUFSIZE (BASE_WIDTH * BASE_HEIGHT) + +enum { + REG_CONTROL = 0x0010, + REG_MPC3W_CONTROL = 0x001a, + REG_VIDEOCONTROL = 0x0042, + REG_OSDVERSION = 0x0100, + REG_OSDFEATURES = 0x0102, + REG_OSDCONTROL = 0x0104, + REG_XY_SIZE = 0x0106, + REG_VIDEOMEM = 0x0800, +}; + +enum { + CH7301_CM = 0x1c, /* Clock Mode Register */ + CH7301_IC = 0x1d, /* Input Clock Register */ + CH7301_GPIO = 0x1e, /* GPIO Control Register */ + CH7301_IDF = 0x1f, /* Input Data Format Register */ + CH7301_CD = 0x20, /* Connection Detect Register */ + CH7301_DC = 0x21, /* DAC Control Register */ + CH7301_HPD = 0x23, /* Hot Plug Detection Register */ + CH7301_TCTL = 0x31, /* DVI Control Input Register */ + CH7301_TPCP = 0x33, /* DVI PLL Charge Pump Ctrl Register */ + CH7301_TPD = 0x34, /* DVI PLL Divide Register */ + CH7301_TPVT = 0x35, /* DVI PLL Supply Control Register */ + CH7301_TPF = 0x36, /* DVI PLL Filter Register */ + CH7301_TCT = 0x37, /* DVI Clock Test Register */ + CH7301_TSTP = 0x48, /* Test Pattern Register */ + CH7301_PM = 0x49, /* Power Management register */ + CH7301_VID = 0x4a, /* Version ID Register */ + CH7301_DID = 0x4b, /* Device ID Register */ + CH7301_DSP = 0x56, /* DVI Sync polarity Register */ +}; + +static void mpc92469ac_calc_parameters(unsigned int fout, + unsigned int *post_div, unsigned int *feedback_div) +{ + unsigned int n = *post_div; + unsigned int m = *feedback_div; + unsigned int a; + unsigned int b = 14745600 / 16; + + if (fout < 50169600) + n = 8; + else if (fout < 100339199) + n = 4; + else if (fout < 200678399) + n = 2; + else + n = 1; + + a = fout * n + (b / 2); /* add b/2 for proper rounding */ + + m = a / b; + + *post_div = n; + *feedback_div = m; +} + +static void mpc92469ac_set(unsigned int fout) +{ + unsigned int n; + unsigned int m; + unsigned int bitval = 0; + mpc92469ac_calc_parameters(fout, &n, &m); + + switch (n) { + case 1: + bitval = 0x00; + break; + case 2: + bitval = 0x01; + break; + case 4: + bitval = 0x02; + break; + case 8: + bitval = 0x03; + break; + } + + fpga_set_reg(REG_MPC3W_CONTROL, (bitval << 9) | m); +} + +static int osd_write_videomem(unsigned offset, u16 *data, size_t charcount) +{ + unsigned int k; + + for (k = 0; k < charcount; ++k) { + if (offset + k >= BUFSIZE) + return -1; + fpga_set_reg(REG_VIDEOMEM + 2 * (offset + k), data[k]); + } + + return charcount; +} + +static int osd_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned x; + unsigned y; + unsigned charcount; + unsigned len; + u8 color; + unsigned int k; + u16 buf[BUFSIZE]; + char *text; + + if (argc < 5) { + cmd_usage(cmdtp); + return 1; + } + + x = simple_strtoul(argv[1], NULL, 16); + y = simple_strtoul(argv[2], NULL, 16); + color = simple_strtoul(argv[3], NULL, 16); + text = argv[4]; + charcount = strlen(text); + len = (charcount > BUFSIZE) ? BUFSIZE : charcount; + + for (k = 0; k < len; ++k) + buf[k] = (text[k] << 8) | color; + + return osd_write_videomem(y * BASE_WIDTH + x, buf, len); +} + +int osd_probe(void) +{ + u8 value; + u16 version = fpga_get_reg(REG_OSDVERSION); + u16 features = fpga_get_reg(REG_OSDFEATURES); + unsigned width; + unsigned height; + + width = ((features & 0x3f00) >> 8) + 1; + height = (features & 0x001f) + 1; + + printf("OSD: Digital-OSD version %01d.%02d, %d" "x%d characters\n", + version/100, version%100, width, height); + + 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); + + mpc92469ac_set(PIXCLK_640_480_60); + fpga_set_reg(REG_VIDEOCONTROL, 0x0002); + fpga_set_reg(REG_OSDCONTROL, 0x0049); + + fpga_set_reg(REG_XY_SIZE, ((32 - 1) << 8) | (16 - 1)); + + return 0; +} + +int osd_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned x; + unsigned y; + unsigned k; + u16 buffer[BASE_WIDTH]; + char *rp; + u16 *wp = buffer; + unsigned count = (argc > 4) ? simple_strtoul(argv[4], NULL, 16) : 1; + + if ((argc < 4) || (strlen(argv[3]) % 4)) { + cmd_usage(cmdtp); + return 1; + } + + x = simple_strtoul(argv[1], NULL, 16); + y = simple_strtoul(argv[2], NULL, 16); + rp = argv[3]; + + + while (*rp) { + char substr[5]; + + memcpy(substr, rp, 4); + substr[4] = 0; + *wp = simple_strtoul(substr, NULL, 16); + + rp += 4; + wp++; + if (wp - buffer > BASE_WIDTH) + break; + } + + for (k = 0; k < count; ++k) { + unsigned offset = y * BASE_WIDTH + x + k * (wp - buffer); + osd_write_videomem(offset, buffer, wp - buffer); + } + + return 0; +} + +U_BOOT_CMD( + osdw, 5, 0, osd_write, + "write 16-bit hex encoded buffer to osd memory", + "pos_x pos_y buffer count\n" +); + +U_BOOT_CMD( + osdp, 5, 0, osd_print, + "write ASCII buffer to osd memory", + "pos_x pos_y color text\n" +); |