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 cmd_usage(cmdtp); 146 return 1; 147 } 148 149 x = simple_strtoul(argv[1], NULL, 16); 150 y = simple_strtoul(argv[2], NULL, 16); 151 color = simple_strtoul(argv[3], NULL, 16); 152 text = argv[4]; 153 charcount = strlen(text); 154 len = (charcount > BUFSIZE) ? BUFSIZE : charcount; 155 156 for (k = 0; k < len; ++k) 157 buf[k] = (text[k] << 8) | color; 158 159 return osd_write_videomem(y * BASE_WIDTH + x, buf, len); 160 } 161 162 int osd_probe(void) 163 { 164 u8 value; 165 u16 version = fpga_get_reg(REG_OSDVERSION); 166 u16 features = fpga_get_reg(REG_OSDFEATURES); 167 unsigned width; 168 unsigned height; 169 170 width = ((features & 0x3f00) >> 8) + 1; 171 height = (features & 0x001f) + 1; 172 173 printf("OSD: Digital-OSD version %01d.%02d, %d" "x%d characters\n", 174 version/100, version%100, width, height); 175 176 value = i2c_reg_read(CH7301_I2C_ADDR, CH7301_DID); 177 if (value != 0x17) { 178 printf(" Probing CH7301 failed, DID %02x\n", value); 179 return -1; 180 } 181 i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPCP, 0x08); 182 i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPD, 0x16); 183 i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPF, 0x60); 184 i2c_reg_write(CH7301_I2C_ADDR, CH7301_DC, 0x09); 185 i2c_reg_write(CH7301_I2C_ADDR, CH7301_PM, 0xc0); 186 187 mpc92469ac_set(PIXCLK_640_480_60); 188 fpga_set_reg(REG_VIDEOCONTROL, 0x0002); 189 fpga_set_reg(REG_OSDCONTROL, 0x0049); 190 191 fpga_set_reg(REG_XY_SIZE, ((32 - 1) << 8) | (16 - 1)); 192 193 return 0; 194 } 195 196 int osd_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 197 { 198 unsigned x; 199 unsigned y; 200 unsigned k; 201 u16 buffer[BASE_WIDTH]; 202 char *rp; 203 u16 *wp = buffer; 204 unsigned count = (argc > 4) ? simple_strtoul(argv[4], NULL, 16) : 1; 205 206 if ((argc < 4) || (strlen(argv[3]) % 4)) { 207 cmd_usage(cmdtp); 208 return 1; 209 } 210 211 x = simple_strtoul(argv[1], NULL, 16); 212 y = simple_strtoul(argv[2], NULL, 16); 213 rp = argv[3]; 214 215 216 while (*rp) { 217 char substr[5]; 218 219 memcpy(substr, rp, 4); 220 substr[4] = 0; 221 *wp = simple_strtoul(substr, NULL, 16); 222 223 rp += 4; 224 wp++; 225 if (wp - buffer > BASE_WIDTH) 226 break; 227 } 228 229 for (k = 0; k < count; ++k) { 230 unsigned offset = y * BASE_WIDTH + x + k * (wp - buffer); 231 osd_write_videomem(offset, buffer, wp - buffer); 232 } 233 234 return 0; 235 } 236 237 U_BOOT_CMD( 238 osdw, 5, 0, osd_write, 239 "write 16-bit hex encoded buffer to osd memory", 240 "pos_x pos_y buffer count\n" 241 ); 242 243 U_BOOT_CMD( 244 osdp, 5, 0, osd_print, 245 "write ASCII buffer to osd memory", 246 "pos_x pos_y color text\n" 247 ); 248