1 /* 2 * (C) Copyright 2010 3 * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 #include <common.h> 25 #include <i2c.h> 26 #include <asm/io.h> 27 28 #include "fpga.h" 29 30 #define CH7301_I2C_ADDR 0x75 31 32 #define PIXCLK_640_480_60 25180000 33 34 #define BASE_WIDTH 32 35 #define BASE_HEIGHT 16 36 #define BUFSIZE (BASE_WIDTH * BASE_HEIGHT) 37 38 enum { 39 REG_CONTROL = 0x0010, 40 REG_MPC3W_CONTROL = 0x001a, 41 REG_VIDEOCONTROL = 0x0042, 42 REG_OSDVERSION = 0x0100, 43 REG_OSDFEATURES = 0x0102, 44 REG_OSDCONTROL = 0x0104, 45 REG_XY_SIZE = 0x0106, 46 REG_VIDEOMEM = 0x0800, 47 }; 48 49 enum { 50 CH7301_CM = 0x1c, /* Clock Mode Register */ 51 CH7301_IC = 0x1d, /* Input Clock Register */ 52 CH7301_GPIO = 0x1e, /* GPIO Control Register */ 53 CH7301_IDF = 0x1f, /* Input Data Format Register */ 54 CH7301_CD = 0x20, /* Connection Detect Register */ 55 CH7301_DC = 0x21, /* DAC Control Register */ 56 CH7301_HPD = 0x23, /* Hot Plug Detection Register */ 57 CH7301_TCTL = 0x31, /* DVI Control Input Register */ 58 CH7301_TPCP = 0x33, /* DVI PLL Charge Pump Ctrl Register */ 59 CH7301_TPD = 0x34, /* DVI PLL Divide Register */ 60 CH7301_TPVT = 0x35, /* DVI PLL Supply Control Register */ 61 CH7301_TPF = 0x36, /* DVI PLL Filter Register */ 62 CH7301_TCT = 0x37, /* DVI Clock Test Register */ 63 CH7301_TSTP = 0x48, /* Test Pattern Register */ 64 CH7301_PM = 0x49, /* Power Management register */ 65 CH7301_VID = 0x4a, /* Version ID Register */ 66 CH7301_DID = 0x4b, /* Device ID Register */ 67 CH7301_DSP = 0x56, /* DVI Sync polarity Register */ 68 }; 69 70 static void mpc92469ac_calc_parameters(unsigned int fout, 71 unsigned int *post_div, unsigned int *feedback_div) 72 { 73 unsigned int n = *post_div; 74 unsigned int m = *feedback_div; 75 unsigned int a; 76 unsigned int b = 14745600 / 16; 77 78 if (fout < 50169600) 79 n = 8; 80 else if (fout < 100339199) 81 n = 4; 82 else if (fout < 200678399) 83 n = 2; 84 else 85 n = 1; 86 87 a = fout * n + (b / 2); /* add b/2 for proper rounding */ 88 89 m = a / b; 90 91 *post_div = n; 92 *feedback_div = m; 93 } 94 95 static void mpc92469ac_set(unsigned int fout) 96 { 97 unsigned int n; 98 unsigned int m; 99 unsigned int bitval = 0; 100 mpc92469ac_calc_parameters(fout, &n, &m); 101 102 switch (n) { 103 case 1: 104 bitval = 0x00; 105 break; 106 case 2: 107 bitval = 0x01; 108 break; 109 case 4: 110 bitval = 0x02; 111 break; 112 case 8: 113 bitval = 0x03; 114 break; 115 } 116 117 fpga_set_reg(REG_MPC3W_CONTROL, (bitval << 9) | m); 118 } 119 120 static int osd_write_videomem(unsigned offset, u16 *data, size_t charcount) 121 { 122 unsigned int k; 123 124 for (k = 0; k < charcount; ++k) { 125 if (offset + k >= BUFSIZE) 126 return -1; 127 fpga_set_reg(REG_VIDEOMEM + 2 * (offset + k), data[k]); 128 } 129 130 return charcount; 131 } 132 133 static int osd_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 134 { 135 unsigned x; 136 unsigned y; 137 unsigned charcount; 138 unsigned len; 139 u8 color; 140 unsigned int k; 141 u16 buf[BUFSIZE]; 142 char *text; 143 144 if (argc < 5) { 145 return cmd_usage(cmdtp); 146 } 147 148 x = simple_strtoul(argv[1], NULL, 16); 149 y = simple_strtoul(argv[2], NULL, 16); 150 color = simple_strtoul(argv[3], NULL, 16); 151 text = argv[4]; 152 charcount = strlen(text); 153 len = (charcount > BUFSIZE) ? BUFSIZE : charcount; 154 155 for (k = 0; k < len; ++k) 156 buf[k] = (text[k] << 8) | color; 157 158 return osd_write_videomem(y * BASE_WIDTH + x, buf, len); 159 } 160 161 int osd_probe(void) 162 { 163 u8 value; 164 u16 version = fpga_get_reg(REG_OSDVERSION); 165 u16 features = fpga_get_reg(REG_OSDFEATURES); 166 unsigned width; 167 unsigned height; 168 169 width = ((features & 0x3f00) >> 8) + 1; 170 height = (features & 0x001f) + 1; 171 172 printf("OSD: Digital-OSD version %01d.%02d, %d" "x%d characters\n", 173 version/100, version%100, width, height); 174 175 value = i2c_reg_read(CH7301_I2C_ADDR, CH7301_DID); 176 if (value != 0x17) { 177 printf(" Probing CH7301 failed, DID %02x\n", value); 178 return -1; 179 } 180 i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPCP, 0x08); 181 i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPD, 0x16); 182 i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPF, 0x60); 183 i2c_reg_write(CH7301_I2C_ADDR, CH7301_DC, 0x09); 184 i2c_reg_write(CH7301_I2C_ADDR, CH7301_PM, 0xc0); 185 186 mpc92469ac_set(PIXCLK_640_480_60); 187 fpga_set_reg(REG_VIDEOCONTROL, 0x0002); 188 fpga_set_reg(REG_OSDCONTROL, 0x0049); 189 190 fpga_set_reg(REG_XY_SIZE, ((32 - 1) << 8) | (16 - 1)); 191 192 return 0; 193 } 194 195 int osd_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 196 { 197 unsigned x; 198 unsigned y; 199 unsigned k; 200 u16 buffer[BASE_WIDTH]; 201 char *rp; 202 u16 *wp = buffer; 203 unsigned count = (argc > 4) ? simple_strtoul(argv[4], NULL, 16) : 1; 204 205 if ((argc < 4) || (strlen(argv[3]) % 4)) { 206 return cmd_usage(cmdtp); 207 } 208 209 x = simple_strtoul(argv[1], NULL, 16); 210 y = simple_strtoul(argv[2], NULL, 16); 211 rp = argv[3]; 212 213 214 while (*rp) { 215 char substr[5]; 216 217 memcpy(substr, rp, 4); 218 substr[4] = 0; 219 *wp = simple_strtoul(substr, NULL, 16); 220 221 rp += 4; 222 wp++; 223 if (wp - buffer > BASE_WIDTH) 224 break; 225 } 226 227 for (k = 0; k < count; ++k) { 228 unsigned offset = y * BASE_WIDTH + x + k * (wp - buffer); 229 osd_write_videomem(offset, buffer, wp - buffer); 230 } 231 232 return 0; 233 } 234 235 U_BOOT_CMD( 236 osdw, 5, 0, osd_write, 237 "write 16-bit hex encoded buffer to osd memory", 238 "pos_x pos_y buffer count\n" 239 ); 240 241 U_BOOT_CMD( 242 osdp, 5, 0, osd_print, 243 "write ASCII buffer to osd memory", 244 "pos_x pos_y color text\n" 245 ); 246