| 1 | /* |
| 2 | * (C) Copyright 2007 OpenMoko, Inc. |
| 3 | * Author: Andy Green <andy@openmoko.com> |
| 4 | * |
| 5 | * (port_init_gta02 came out of Openmoko U-Boot) |
| 6 | * |
| 7 | * Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone |
| 8 | * |
| 9 | * This program is free software; you can redistribute it and/or |
| 10 | * modify it under the terms of the GNU General Public License as |
| 11 | * published by the Free Software Foundation; either version 2 of |
| 12 | * the License, or (at your option) any later version. |
| 13 | * |
| 14 | * This program is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | * GNU General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU General Public License |
| 20 | * along with this program; if not, write to the Free Software |
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| 22 | * MA 02111-1307 USA |
| 23 | * |
| 24 | */ |
| 25 | |
| 26 | #include <qi.h> |
| 27 | #include <neo_gta02.h> |
| 28 | #include <serial-s3c24xx.h> |
| 29 | #include <ports-s3c24xx.h> |
| 30 | #include <i2c-bitbang-s3c24xx.h> |
| 31 | #include <pcf50633.h> |
| 32 | #include <glamo-init.h> |
| 33 | #include <string.h> |
| 34 | #include <ext2.h> |
| 35 | |
| 36 | #define GTA02_DEBUG_UART 2 |
| 37 | #define PCF50633_I2C_ADS 0x73 |
| 38 | #define BOOST_TO_400MHZ 1 |
| 39 | |
| 40 | static int battery_condition_reasonable = 0; |
| 41 | |
| 42 | extern unsigned long partition_offset_blocks; |
| 43 | extern unsigned long partition_length_blocks; |
| 44 | |
| 45 | const struct board_api board_api_gta02; |
| 46 | |
| 47 | struct nand_dynparts { |
| 48 | const char *name; /* name of this partition for Linux */ |
| 49 | u32 good_length; /* bytes needed from good sectors in this partition */ |
| 50 | u32 true_offset; |
| 51 | }; |
| 52 | |
| 53 | /* |
| 54 | * These are the NAND partitions U-Boot leaves in GTA02 NAND. |
| 55 | * The "dynparts" business means that in the case of bad blocks, all the |
| 56 | * following partitions move up accordingly to have the right amount of |
| 57 | * good blocks. To allow for this, the length of the last, largest |
| 58 | * partition is computed according to the bad blocks that went before. |
| 59 | */ |
| 60 | |
| 61 | static struct nand_dynparts nand_dynparts[] = { |
| 62 | { "qi", 0x40000 }, |
| 63 | { "depr-ub-env", 0x40000 }, |
| 64 | { "kernel", 0x800000 }, |
| 65 | { "depr", 0xa0000 }, |
| 66 | { "identity-ext2", 0x40000 }, |
| 67 | { "rootfs", 0 }, |
| 68 | }; |
| 69 | |
| 70 | static u32 nand_extent_block512 = 256 * 1024 * 1024 / 512; |
| 71 | |
| 72 | const struct pcf50633_init pcf50633_init[] = { |
| 73 | |
| 74 | { PCF50633_REG_OOCWAKE, 0xd3 }, /* wake from ONKEY,EXTON!,RTC,USB,ADP */ |
| 75 | { PCF50633_REG_OOCTIM1, 0xaa }, /* debounce 14ms everything */ |
| 76 | { PCF50633_REG_OOCTIM2, 0x4a }, |
| 77 | { PCF50633_REG_OOCMODE, 0x55 }, |
| 78 | { PCF50633_REG_OOCCTL, 0x47 }, |
| 79 | |
| 80 | { PCF50633_REG_GPIO2CFG, 0x00 }, /* GSM_ON = 0 */ |
| 81 | { PCF50633_REG_GPIOCTL, 0x01 }, /* only GPIO1 is input */ |
| 82 | |
| 83 | { PCF50633_REG_SVMCTL, 0x08 }, /* 3.10V SYS vth, 62ms filter */ |
| 84 | { PCF50633_REG_BVMCTL, 0x02 }, /* 2.80V BAT vth, 62ms filter */ |
| 85 | |
| 86 | { PCF50633_REG_AUTOENA, 0x01 }, /* always on */ |
| 87 | |
| 88 | { PCF50633_REG_DOWN1OUT, 0x1b }, /* 1.3V (0x1b * .025V + 0.625V) */ |
| 89 | { PCF50633_REG_DOWN1ENA, 0x02 }, /* enabled if GPIO1 = HIGH */ |
| 90 | { PCF50633_REG_HCLDOOUT, 21 }, /* 3.0V (21 * 0.1V + 0.9V) */ |
| 91 | { PCF50633_REG_HCLDOENA, 0x01 }, /* ON by default*/ |
| 92 | |
| 93 | { PCF50633_REG_DOWN1OUT, 0x1b }, /* 1.3V (0x1b * .025V + 0.625V) */ |
| 94 | { PCF50633_REG_DOWN1ENA, 0x02 }, /* enabled if GPIO1 = HIGH */ |
| 95 | |
| 96 | { PCF50633_REG_INT1M, 0x00 }, |
| 97 | { PCF50633_REG_INT2M, 0x00 }, |
| 98 | { PCF50633_REG_INT3M, 0x00 }, |
| 99 | { PCF50633_REG_INT4M, 0x00 }, |
| 100 | { PCF50633_REG_INT5M, 0x00 }, |
| 101 | |
| 102 | { PCF50633_REG_MBCC2, 0x28 }, /* Vbatconid=2.7V, Vmax=4.20V */ |
| 103 | { PCF50633_REG_MBCC3, 0x19 }, /* 25/255 == 98mA pre-charge */ |
| 104 | { PCF50633_REG_MBCC4, 0xff }, /* 255/255 == 1A adapter fast */ |
| 105 | { PCF50633_REG_MBCC5, 0xff }, /* 255/255 == 1A usb fast */ |
| 106 | { PCF50633_REG_MBCC6, 0x01 }, /* cutoff current 2/32 * Ichg */ |
| 107 | { PCF50633_REG_MBCC7, 0x00 }, /* 1.6A max bat curr, USB 100mA */ |
| 108 | { PCF50633_REG_MBCC8, 0x00 }, |
| 109 | { PCF50633_REG_MBCC1, 0xff }, /* chgena */ |
| 110 | |
| 111 | { PCF50633_REG_LDO1ENA, 2 }, /* accel enabled if GPIO1 = H */ |
| 112 | { PCF50633_REG_LDO2ENA, 2 }, /* codec enabled if GPIO1 = H */ |
| 113 | { PCF50633_REG_LDO4ENA, 0 }, /* bt off */ |
| 114 | { PCF50633_REG_LDO5ENA, 0 }, /* gps off */ |
| 115 | { PCF50633_REG_LDO6ENA, 2 }, /* lcm enabled if GPIO1 = H */ |
| 116 | |
| 117 | { PCF50633_REG_BBCCTL, 0x19 }, /* 3V, 200uA, on */ |
| 118 | { PCF50633_REG_OOCSHDWN, 0x04 }, /* defeat 8s death from lowsys on A5 */ |
| 119 | |
| 120 | }; |
| 121 | |
| 122 | static const struct board_variant board_variants[] = { |
| 123 | [0] = { |
| 124 | .name = "A5 PCB", |
| 125 | .machine_revision = 0x350, |
| 126 | }, |
| 127 | [1] = { |
| 128 | .name = "A6 PCB", |
| 129 | .machine_revision = 0x360, |
| 130 | }, |
| 131 | [9] = { /* 01001 */ |
| 132 | .name = "A7 PCB", |
| 133 | .machine_revision = 0x360, /* report as A6 */ |
| 134 | }, |
| 135 | }; |
| 136 | |
| 137 | |
| 138 | void port_init_gta02(void) |
| 139 | { |
| 140 | unsigned int * MPLLCON = (unsigned int *)0x4c000004; |
| 141 | unsigned int * UPLLCON = (unsigned int *)0x4c000008; |
| 142 | unsigned int * CLKDIVN = (unsigned int *)0x4c000014; |
| 143 | int n; |
| 144 | u32 block512 = 0; |
| 145 | u32 start_block512 = 0; |
| 146 | const u32 GTA02_NAND_READBLOCK_SIZE = 2048; |
| 147 | extern int s3c2442_nand_is_bad_block(unsigned long block_index_512); |
| 148 | |
| 149 | //CAUTION:Follow the configuration order for setting the ports. |
| 150 | // 1) setting value(GPnDAT) |
| 151 | // 2) setting control register (GPnCON) |
| 152 | // 3) configure pull-down resistor(GPnUP) |
| 153 | |
| 154 | /* 32bit data bus configuration */ |
| 155 | /* |
| 156 | * === PORT A GROUP |
| 157 | * Ports : GPA22 GPA21 GPA20 GPA19 GPA18 GPA17 GPA16 GPA15 GPA14 GPA13 GPA12 |
| 158 | * Signal : nFCE nRSTOUT nFRE nFWE ALE CLE nGCS5 nGCS4 nGCS3 nGCS2 nGCS1 |
| 159 | * Binary : 1 1 1 , 1 1 1 1 , 1 1 1 1 |
| 160 | * Ports : GPA11 GPA10 GPA9 GPA8 GPA7 GPA6 GPA5 GPA4 GPA3 GPA2 GPA1 GPA0 |
| 161 | * Signal : ADDR26 ADDR25 ADDR24 ADDR23 ADDR22 ADDR21 ADDR20 ADDR19 ADDR18 ADDR17 ADDR16 ADDR0 |
| 162 | * Binary : 1 1 1 1 , 1 1 1 1 , 1 1 1 1 |
| 163 | */ |
| 164 | rGPACON = 0x007E5FFF; |
| 165 | rGPADAT = 0x00000000; |
| 166 | /* |
| 167 | * ===* PORT B GROUP |
| 168 | * Ports : GPB10 GPB9 GPB8 GPB7 GPB6 GPB5 GPB4 GPB3 GPB2 GPB1 GPB0 |
| 169 | * Signal : nXDREQ0 nXDACK0 nXDREQ1 nXDACK1 nSS_KBD nDIS_OFF L3CLOCK L3DATA L3MODE nIrDATXDEN Keyboard |
| 170 | * Setting: INPUT OUTPUT INPUT OUTPUT INPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT |
| 171 | * Binary : 00 , 01 00 , 01 00 , 01 01 , 01 01 , 01 01 |
| 172 | */ |
| 173 | rGPBCON = 0x00155555; |
| 174 | rGPBUP = 0x000007FF; |
| 175 | rGPBDAT = 0x00000000; |
| 176 | /* |
| 177 | * === PORT C GROUP |
| 178 | * Ports : GPC15 GPC14 GPC13 GPC12 GPC11 GPC10 GPC9 GPC8 GPC7 GPC6 GPC5 GPC4 GPC3 GPC2 GPC1 GPC0 |
| 179 | * Signal : VD7 VD6 VD5 VD4 VD3 VD2 VD1 VD0 LCDVF2 LCDVF1 LCDVF0 VM VFRAME VLINE VCLK LEND |
| 180 | * Binary : 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 |
| 181 | */ |
| 182 | rGPCCON = 0x55555155; |
| 183 | rGPCUP = 0x0000FFFF & ~(1 << 5); |
| 184 | rGPCDAT = (1 << 13) | (1 << 15); /* index detect -> hi */ |
| 185 | /* |
| 186 | * === PORT D GROUP |
| 187 | * Ports : GPD15 GPD14 GPD13 GPD12 GPD11 GPD10 GPD9 GPD8 GPD7 GPD6 GPD5 GPD4 GPD3 GPD2 GPD1 GPD0 |
| 188 | * Signal : VD23 VD22 VD21 VD20 VD19 VD18 VD17 VD16 VD15 VD14 VD13 VD12 VD11 VD10 VD9 VD8 |
| 189 | * Binary : 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 ,10 10 |
| 190 | */ |
| 191 | rGPDCON = 0x55555555; |
| 192 | rGPDUP = 0x0000FFFF; |
| 193 | rGPDDAT = (1 << 0) | (1 << 3) | (1 << 4); /* index detect -> hi */ |
| 194 | /* |
| 195 | * === PORT E GROUP |
| 196 | * Ports : GPE15 GPE14 GPE13 GPE12 GPE11 GPE10 GPE9 GPE8 GPE7 GPE6 GPE5 GPE4 |
| 197 | * Signal : IICSDA IICSCL SPICLK SPIMOSI SPIMISO SDDATA3 SDDATA2 SDDATA1 SDDATA0 SDCMD SDCLK I2SSDO |
| 198 | * Binary : 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , |
| 199 | * ------------------------------------------------------------------------------------------------------- |
| 200 | * Ports : GPE3 GPE2 GPE1 GPE0 |
| 201 | * Signal : I2SSDI CDCLK I2SSCLK I2SLRCK |
| 202 | * Binary : 10 10 , 10 10 |
| 203 | */ |
| 204 | rGPECON = 0xAAAAAAAA; |
| 205 | rGPEUP = 0x0000FFFF & ~(1 << 11); |
| 206 | rGPEDAT = 0x00000000; |
| 207 | /* |
| 208 | * === PORT F GROUP |
| 209 | * Ports : GPF7 GPF6 GPF5 GPF4 GPF3 GPF2 GPF1 GPF0 |
| 210 | * Signal : nLED_8 nLED_4 nLED_2 nLED_1 nIRQ_PCMCIA EINT2 KBDINT EINT0 |
| 211 | * Setting: Output Output Output Output EINT3 EINT2 EINT1 EINT0 |
| 212 | * Binary : 01 01 , 01 01 , 10 10 , 10 10 |
| 213 | */ |
| 214 | /* pulldown on GPF03: TP-4705+debug - debug conn will float */ |
| 215 | rGPFCON = 0x00008AAA; |
| 216 | rGPFUP = 0x000000FF & ~(1 << 3); |
| 217 | rGPFDAT = 0x00000000; |
| 218 | |
| 219 | |
| 220 | /* |
| 221 | * === PORT G GROUP |
| 222 | * Ports : GPG15 GPG14 GPG13 GPG12 GPG11 GPG10 GPG9 GPG8 GPG7 GPG6 |
| 223 | * Signal : nYPON YMON nXPON XMON EINT19 DMAMODE1 DMAMODE0 DMASTART KBDSPICLK KBDSPIMOSI |
| 224 | * Setting: nYPON YMON nXPON XMON EINT19 Output Output Output SPICLK1 SPIMOSI1 |
| 225 | * Binary : 11 11 , 11 11 , 10 01 , 01 01 , 11 11 |
| 226 | * ----------------------------------------------------------------------------------------- |
| 227 | * Ports : GPG5 GPG4 GPG3 GPG2 GPG1 GPG0 |
| 228 | * Signal : KBDSPIMISO LCD_PWREN EINT11 nSS_SPI IRQ_LAN IRQ_PCMCIA |
| 229 | * Setting: SPIMISO1 LCD_PWRDN EINT11 nSS0 EINT9 EINT8 |
| 230 | * Binary : 11 11 , 10 11 , 10 10 |
| 231 | */ |
| 232 | rGPGCON = 0x01AAFE79; |
| 233 | rGPGUP = 0x0000FFFF; |
| 234 | rGPGDAT = 0x00000000; |
| 235 | |
| 236 | /* |
| 237 | * === PORT H GROUP |
| 238 | * Ports : GPH10 GPH9 GPH8 GPH7 GPH6 GPH5 GPH4 GPH3 GPH2 GPH1 GPH0 |
| 239 | * Signal : CLKOUT1 CLKOUT0 UCLK RXD2 TXD2 RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0 |
| 240 | * Binary : 10 , 10 10 , 11 11 , 10 10 , 10 10 , 10 10 |
| 241 | */ |
| 242 | |
| 243 | /* |
| 244 | * FIXME the following should be removed eventually and only the first stanza |
| 245 | * kept unconditionally. As it stands it allows TX and RTS to drive high into |
| 246 | * a powered-down GSM unit, which draws considerable fault current. |
| 247 | * |
| 248 | * However kernels earlier than andy-tracking from end Feb 2009 do not enforce |
| 249 | * the mode of these GPIOs, so Qi doing the correct thing here "breaks GSM" |
| 250 | * apparently for those users. |
| 251 | * |
| 252 | * Upgrading to current kernel will solve this, so after most distros are on |
| 253 | * 2.6.29-rc3 and later, we should return here and again disable driving out |
| 254 | * into unpowered GSM. |
| 255 | */ |
| 256 | |
| 257 | #if 0 |
| 258 | rGPHCON = 0x001AAA82; /* H1 and H2 are INPUTs to start with, not UART */ |
| 259 | #else |
| 260 | rGPHCON = 0x001AAAAA; /* Wrong but compatible: H1 and H2 = UART */ |
| 261 | #endif |
| 262 | |
| 263 | /* pulldown on GPH08: UEXTCLK, just floats! |
| 264 | * pulldown GPH1 -- nCTS0 / RTS_MODEM -- floats when GSM off |
| 265 | * pulldown GPH3 -- RXD[0] / RX_MODEM -- floats when GSM off |
| 266 | */ |
| 267 | rGPHUP = 0x000007FF & ~(1 << 8) & ~(1 << 1) & ~(1 << 3); |
| 268 | rGPHDAT = 0x00000000; |
| 269 | |
| 270 | /* pulldown on GPJ00: input, just floats! */ |
| 271 | /* pulldown on GPJ07: WLAN module WLAN_GPIO0, no ext pull */ |
| 272 | rGPJCON = 0x1551544; |
| 273 | rGPJUP = 0x1ffff & ~(1 << 0) & ~(1 << 7); |
| 274 | rGPJDAT = 0x00000100; |
| 275 | |
| 276 | rGPJDAT |= (1 << 4) | (1 << 6); |
| 277 | /* Set GPJ4 to high (nGSM_EN) */ |
| 278 | /* Set GPJ6 to high (nDL_GSM) */ |
| 279 | rGPJDAT &= ~(1 << 5); /* Set GPJ5 to low 3D RST */ |
| 280 | |
| 281 | /* leaving Glamo forced to Reset# active here killed |
| 282 | * U-Boot when you touched the memory region |
| 283 | */ |
| 284 | |
| 285 | rGPJDAT |= (1 << 5); /* Set GPJ5 to high 3D RST */ |
| 286 | |
| 287 | |
| 288 | /* |
| 289 | * We have to talk to the PMU a little bit |
| 290 | */ |
| 291 | |
| 292 | for (n = 0; n < ARRAY_SIZE(pcf50633_init); n++) |
| 293 | i2c_write_sync(&bb_s3c24xx, PCF50633_I2C_ADS, |
| 294 | pcf50633_init[n].index, pcf50633_init[n].value); |
| 295 | |
| 296 | /* what does the battery monitoring unit say about the battery? */ |
| 297 | |
| 298 | battery_condition_reasonable = !(i2c_read_sync(&bb_s3c24xx, |
| 299 | PCF50633_I2C_ADS, PCF50633_REG_BVMCTL) & 1); |
| 300 | |
| 301 | if (battery_condition_reasonable) { |
| 302 | /* change CPU clocking to 400MHz 1:4:8 */ |
| 303 | |
| 304 | /* clock divide 1:4:8 - do it first */ |
| 305 | *CLKDIVN = 5; |
| 306 | /* configure UPLL */ |
| 307 | *UPLLCON = ((88 << 12) + (4 << 4) + 2); |
| 308 | /* Magic delay: Page 7-19, seven nops between UPLL and MPLL */ |
| 309 | asm __volatile__ ( |
| 310 | "nop\n" |
| 311 | "nop\n" |
| 312 | "nop\n" |
| 313 | "nop\n" |
| 314 | "nop\n" |
| 315 | "nop\n" |
| 316 | "nop\n" |
| 317 | ); |
| 318 | /* configure MPLL */ |
| 319 | *MPLLCON = ((42 << 12) + (1 << 4) + 0); |
| 320 | |
| 321 | /* get debug UART working at 115kbps */ |
| 322 | serial_init_115200_s3c24xx(GTA02_DEBUG_UART, 50 /* 50MHz */); |
| 323 | } else { |
| 324 | serial_init_115200_s3c24xx(GTA02_DEBUG_UART, 33 /* 33MHz */); |
| 325 | } |
| 326 | |
| 327 | /* we're going to use Glamo for SD Card access, so we need to init the |
| 328 | * evil beast |
| 329 | */ |
| 330 | glamo_core_init(); |
| 331 | |
| 332 | /* |
| 333 | * dynparts computation |
| 334 | */ |
| 335 | |
| 336 | n = 0; |
| 337 | while (n < ARRAY_SIZE(nand_dynparts)) { |
| 338 | |
| 339 | if (nand_dynparts[n].good_length) |
| 340 | while (nand_dynparts[n].good_length) { |
| 341 | if (!s3c2442_nand_is_bad_block(block512)) |
| 342 | nand_dynparts[n].good_length -= |
| 343 | GTA02_NAND_READBLOCK_SIZE; |
| 344 | block512 += GTA02_NAND_READBLOCK_SIZE / 512; |
| 345 | } |
| 346 | else |
| 347 | /* |
| 348 | * cannot afford to compute real size of last block |
| 349 | * set it to extent - end of last block |
| 350 | */ |
| 351 | block512 = nand_extent_block512; |
| 352 | |
| 353 | /* stash a copy of real offset for each partition */ |
| 354 | nand_dynparts[n].true_offset = start_block512; |
| 355 | |
| 356 | /* and the accurate length */ |
| 357 | nand_dynparts[n].good_length = block512 - start_block512; |
| 358 | |
| 359 | start_block512 = block512; |
| 360 | |
| 361 | n++; |
| 362 | } |
| 363 | |
| 364 | /* fix up the true start of kernel partition */ |
| 365 | |
| 366 | ((struct board_api *)&board_api_gta02)->kernel_source[3]. |
| 367 | offset_blocks512_if_no_partition = nand_dynparts[2].true_offset; |
| 368 | |
| 369 | } |
| 370 | |
| 371 | /** |
| 372 | * returns PCB revision information in b9,b8 and b2,b1,b0 |
| 373 | * Pre-GTA02 A6 returns 0x000 |
| 374 | * GTA02 A6 returns 0x001 |
| 375 | */ |
| 376 | |
| 377 | int gta02_get_pcb_revision(void) |
| 378 | { |
| 379 | int n; |
| 380 | u32 u; |
| 381 | |
| 382 | /* make C13 and C15 pulled-down inputs */ |
| 383 | rGPCCON &= ~0xcc000000; |
| 384 | rGPCUP &= ~((1 << 13) | (1 << 15)); |
| 385 | /* D0, D3 and D4 pulled-down inputs */ |
| 386 | rGPDCON &= ~0x000003c3; |
| 387 | rGPDUP &= ~((1 << 0) | (1 << 3) | (1 << 4)); |
| 388 | |
| 389 | /* delay after changing pulldowns */ |
| 390 | u = rGPCDAT; |
| 391 | u = rGPDDAT; |
| 392 | |
| 393 | /* read the version info */ |
| 394 | u = rGPCDAT; |
| 395 | n = (u >> (13 - 0)) & 0x001; |
| 396 | n |= (u >> (15 - 1)) & 0x002; |
| 397 | u = rGPDDAT; |
| 398 | n |= (u << (0 + 2)) & 0x004; |
| 399 | |
| 400 | n |= (u << (3 - 3)) & 0x008; |
| 401 | n |= (u << (4 - 4)) & 0x010; |
| 402 | |
| 403 | /* |
| 404 | * when not being interrogated, all of the revision GPIO |
| 405 | * are set to output HIGH without pulldown so no current flows |
| 406 | * if they are NC or pulled up. |
| 407 | */ |
| 408 | /* make C13 and C15 high ouputs with no pulldowns */ |
| 409 | rGPCCON |= 0x44000000; |
| 410 | rGPCUP |= (1 << 13) | (1 << 15); |
| 411 | rGPCDAT |= (1 << 13) | (1 << 15); |
| 412 | /* D0, D3 and D4 high ouputs with no pulldowns */ |
| 413 | rGPDCON |= 0x00000141; |
| 414 | rGPDUP |= (1 << 0) | (1 << 3) | (1 << 4); |
| 415 | rGPDDAT |= (1 << 0) | (1 << 3) | (1 << 4); |
| 416 | |
| 417 | n &= 1; |
| 418 | |
| 419 | return n; |
| 420 | } |
| 421 | |
| 422 | int sd_card_init_gta02(void) |
| 423 | { |
| 424 | extern int mmc_init(int verbose); |
| 425 | |
| 426 | return mmc_init(1); |
| 427 | } |
| 428 | |
| 429 | int sd_card_block_read_gta02(unsigned char * buf, unsigned long start512, |
| 430 | int blocks512) |
| 431 | { |
| 432 | unsigned long mmc_bread(int dev_num, unsigned long blknr, unsigned long blkcnt, |
| 433 | void *dst); |
| 434 | |
| 435 | return mmc_bread(0, start512, blocks512, buf); |
| 436 | } |
| 437 | |
| 438 | /* return nonzero if we believe we run on GTA02 */ |
| 439 | |
| 440 | int is_this_board_gta02(void) |
| 441 | { |
| 442 | /* look for GTA02 NOR */ |
| 443 | |
| 444 | *(volatile unsigned short *)(0x18000000) = 0x98; |
| 445 | |
| 446 | return !!(*(volatile unsigned short *)(0x18000000) == 0x0020); |
| 447 | } |
| 448 | |
| 449 | const struct board_variant const * get_board_variant_gta02(void) |
| 450 | { |
| 451 | int rev = gta02_get_pcb_revision() & 0x1f; |
| 452 | |
| 453 | if (!board_variants[rev].name) |
| 454 | return &board_variants[1]; /* A6 */ |
| 455 | |
| 456 | return &board_variants[rev]; |
| 457 | } |
| 458 | |
| 459 | static __attribute__ (( section (".steppingstone") )) void putc_gta02(char c) |
| 460 | { |
| 461 | serial_putc_s3c24xx(GTA02_DEBUG_UART, c); |
| 462 | } |
| 463 | |
| 464 | static void close_gta02(void) |
| 465 | { |
| 466 | /* explicitly clear any pending 8s timeout */ |
| 467 | |
| 468 | i2c_write_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_OOCSHDWN, 0x04); |
| 469 | |
| 470 | /* clear any pending timeouts by reading interrupts */ |
| 471 | |
| 472 | i2c_read_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_INT1); |
| 473 | i2c_read_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_INT2); |
| 474 | i2c_read_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_INT3); |
| 475 | i2c_read_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_INT4); |
| 476 | i2c_read_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_INT5); |
| 477 | |
| 478 | /* set I2C GPIO back to peripheral unit */ |
| 479 | |
| 480 | (bb_s3c24xx.close)(); |
| 481 | |
| 482 | /* aux back to being EINT */ |
| 483 | rGPFCON = 0x0000AAAA; |
| 484 | |
| 485 | } |
| 486 | |
| 487 | /* Here we will care only about AUX button as polling for PWR button |
| 488 | * through i2c slows down the boot */ |
| 489 | |
| 490 | static u8 get_ui_keys_gta02(void) |
| 491 | { |
| 492 | u8 keys; |
| 493 | u8 ret = 0; |
| 494 | static u8 old_keys = 0; /* previous state for debounce */ |
| 495 | static u8 older_keys = 0; /* previous debounced output for edge detect */ |
| 496 | |
| 497 | /* GPF6 is AUX on GTA02, map to UI_ACTION_SKIPKERNEL, down = 1 */ |
| 498 | keys = !!(rGPFDAT & (1 << 6)); |
| 499 | |
| 500 | /* edge action */ |
| 501 | if ((old_keys & 1) && !(older_keys & 1)) |
| 502 | ret |= UI_ACTION_SKIPKERNEL; |
| 503 | |
| 504 | older_keys = old_keys; |
| 505 | old_keys = keys; |
| 506 | |
| 507 | return ret; |
| 508 | } |
| 509 | |
| 510 | static u8 get_ui_debug_gta02(void) |
| 511 | { |
| 512 | /* PWR button state can be seen in OOCSTAT b0, down = 0, map to UI_ACTION_ADD_DEBUG */ |
| 513 | return !(i2c_read_sync(&bb_s3c24xx, PCF50633_I2C_ADS, PCF50633_REG_OOCSTAT) & 1); |
| 514 | } |
| 515 | |
| 516 | static void set_ui_indication_gta02(enum ui_indication ui_indication) |
| 517 | { |
| 518 | |
| 519 | switch (ui_indication) { |
| 520 | case UI_IND_UPDATE_ONLY: |
| 521 | break; |
| 522 | |
| 523 | case UI_IND_MOUNT_PART: |
| 524 | case UI_IND_KERNEL_PULL_OK: |
| 525 | case UI_IND_INITRAMFS_PULL_OK: |
| 526 | if (battery_condition_reasonable) |
| 527 | rGPBDAT |= 4; |
| 528 | break; |
| 529 | |
| 530 | case UI_IND_KERNEL_PULL_FAIL: |
| 531 | case UI_IND_SKIPPING: |
| 532 | case UI_IND_INITRAMFS_PULL_FAIL: |
| 533 | case UI_IND_MOUNT_FAIL: |
| 534 | rGPBDAT &= ~4; |
| 535 | if (battery_condition_reasonable) { |
| 536 | rGPBDAT |= 8; |
| 537 | udelay(2000000); |
| 538 | rGPBDAT &= ~8; |
| 539 | udelay(200000); |
| 540 | } |
| 541 | break; |
| 542 | |
| 543 | case UI_IND_KERNEL_START: |
| 544 | case UI_IND_MEM_TEST: |
| 545 | case UI_IND_KERNEL_PULL: |
| 546 | case UI_IND_INITRAMFS_PULL: |
| 547 | rGPBDAT &= ~4; |
| 548 | break; |
| 549 | } |
| 550 | } |
| 551 | |
| 552 | |
| 553 | void post_serial_init_gta02(void) |
| 554 | { |
| 555 | if (battery_condition_reasonable) |
| 556 | puts("Battery condition reasonable\n"); |
| 557 | else |
| 558 | puts("BATTERY CONDITION LOW\n"); |
| 559 | } |
| 560 | |
| 561 | /* |
| 562 | * Increment a hexadecimal digit represented by a char and |
| 563 | * return 1 if an overflow occured. |
| 564 | */ |
| 565 | static char inc_hexchar(char * p) |
| 566 | { |
| 567 | if (*p == '9') |
| 568 | *p = 'A'; |
| 569 | else if (*p != 'F') |
| 570 | (*p)++; |
| 571 | else { |
| 572 | *p = '0'; |
| 573 | return 1; |
| 574 | } |
| 575 | return 0; |
| 576 | } |
| 577 | |
| 578 | /* |
| 579 | * create and append device-specific Linux kernel commandline |
| 580 | * |
| 581 | * This takes care of legacy dyanmic partition sizing and USB Ethernet |
| 582 | * MAC address identity information. |
| 583 | */ |
| 584 | |
| 585 | char * append_device_specific_cmdline_gta02(char * cmdline) |
| 586 | { |
| 587 | int n = 0; |
| 588 | int i; |
| 589 | int len; |
| 590 | static char mac[64]; |
| 591 | struct kernel_source const * real_kernel = this_kernel; |
| 592 | |
| 593 | /* |
| 594 | * dynparts computation |
| 595 | */ |
| 596 | |
| 597 | cmdline += strlen(strcpy(cmdline, |
| 598 | " mtdparts=physmap-flash:-(nor);neo1973-nand:")); |
| 599 | |
| 600 | while (n < ARRAY_SIZE(nand_dynparts)) { |
| 601 | |
| 602 | *cmdline++ = '0'; |
| 603 | *cmdline++ = 'x'; |
| 604 | set32(cmdline, nand_dynparts[n].good_length * 512); |
| 605 | cmdline += 8; |
| 606 | *cmdline++ = '('; |
| 607 | cmdline += strlen(strcpy(cmdline, nand_dynparts[n].name)); |
| 608 | *cmdline++ = ')'; |
| 609 | |
| 610 | if (++n == ARRAY_SIZE(nand_dynparts)) |
| 611 | *cmdline++ = ' '; |
| 612 | else |
| 613 | *cmdline++ = ','; |
| 614 | |
| 615 | } |
| 616 | |
| 617 | *cmdline = '\0'; |
| 618 | |
| 619 | /* |
| 620 | * Identity |
| 621 | */ |
| 622 | |
| 623 | /* position ourselves at true start of GTA02 identity partition */ |
| 624 | partition_offset_blocks = nand_dynparts[4].true_offset; |
| 625 | partition_length_blocks = 0x40000 / 512; |
| 626 | |
| 627 | /* |
| 628 | * lie that we are in NAND context... GTA02 specific |
| 629 | * all filesystem access is completed before we are called |
| 630 | */ |
| 631 | this_kernel = &board_api_gta02.kernel_source[3]; |
| 632 | |
| 633 | if (!ext2fs_mount()) { |
| 634 | puts("Unable to mount ext2 filesystem\n"); |
| 635 | goto bail; |
| 636 | } |
| 637 | |
| 638 | len = ext2fs_open("usb"); |
| 639 | if (len < 0) { |
| 640 | puts(" Open failed\n"); |
| 641 | goto bail; |
| 642 | } |
| 643 | |
| 644 | n = ext2fs_read(mac, sizeof(mac)); |
| 645 | if (n < 0) { |
| 646 | puts(" Read failed\n"); |
| 647 | goto bail; |
| 648 | } |
| 649 | |
| 650 | mac[len] = '\0'; |
| 651 | |
| 652 | cmdline += strlen(strcpy(cmdline, " g_ether.dev_addr=")); |
| 653 | cmdline += strlen(strcpy(cmdline, &mac[2])); |
| 654 | |
| 655 | for (i = 0; i != 10; i++) { |
| 656 | if ((i % 3) == 2) |
| 657 | continue; |
| 658 | if (!inc_hexchar(mac + 18 - i)) |
| 659 | break; /* Carry not needed. */ |
| 660 | } |
| 661 | |
| 662 | cmdline += strlen(strcpy(cmdline, " g_ether.host_addr=")); |
| 663 | cmdline += strlen(strcpy(cmdline, &mac[2])); |
| 664 | *cmdline++ = ' ' ; |
| 665 | bail: |
| 666 | this_kernel = real_kernel; |
| 667 | |
| 668 | *cmdline = '\0'; |
| 669 | |
| 670 | return cmdline; |
| 671 | } |
| 672 | |
| 673 | /* |
| 674 | * our API for bootloader on this machine |
| 675 | */ |
| 676 | |
| 677 | const struct board_api board_api_gta02 = { |
| 678 | .name = "Freerunner / GTA02", |
| 679 | .linux_machine_id = 1304, |
| 680 | .linux_mem_start = 0x30000000, |
| 681 | .linux_mem_size = (128 * 1024 * 1024), |
| 682 | .linux_tag_placement = 0x30000000 + 0x100, |
| 683 | .get_board_variant = get_board_variant_gta02, |
| 684 | .is_this_board = is_this_board_gta02, |
| 685 | .port_init = port_init_gta02, |
| 686 | .post_serial_init = post_serial_init_gta02, |
| 687 | .append_device_specific_cmdline = append_device_specific_cmdline_gta02, |
| 688 | .putc = putc_gta02, |
| 689 | .close = close_gta02, |
| 690 | .get_ui_keys = get_ui_keys_gta02, |
| 691 | .get_ui_debug = get_ui_debug_gta02, |
| 692 | .set_ui_indication = set_ui_indication_gta02, |
| 693 | .commandline_board = "loglevel=4 " |
| 694 | "console=tty0 " |
| 695 | "console=ttySAC2,115200 " |
| 696 | "init=/sbin/init " |
| 697 | "ro ", |
| 698 | .commandline_board_debug = " loglevel=8", |
| 699 | .noboot = "boot/noboot-GTA02", |
| 700 | .append = "boot/append-GTA02", |
| 701 | /* these are the ways we could boot GTA02 in the order to try */ |
| 702 | .kernel_source = { |
| 703 | [0] = { |
| 704 | .name = "SD Card EXT2 P1 Kernel", |
| 705 | .block_init = sd_card_init_gta02, |
| 706 | .block_read = sd_card_block_read_gta02, |
| 707 | .partition_index = 1, |
| 708 | .filesystem = FS_EXT2, |
| 709 | .filepath = "boot/uImage-GTA02.bin", |
| 710 | .commandline_append = " root=/dev/mmcblk0p1 rootdelay=1 ", |
| 711 | }, |
| 712 | [1] = { |
| 713 | .name = "SD Card EXT2 P2 Kernel", |
| 714 | .block_init = sd_card_init_gta02, |
| 715 | .block_read = sd_card_block_read_gta02, |
| 716 | .partition_index = 2, |
| 717 | .filesystem = FS_EXT2, |
| 718 | .filepath = "boot/uImage-GTA02.bin", |
| 719 | .commandline_append = " root=/dev/mmcblk0p2 rootdelay=1 ", |
| 720 | }, |
| 721 | [2] = { |
| 722 | .name = "SD Card EXT2 P3 Kernel", |
| 723 | .block_init = sd_card_init_gta02, |
| 724 | .block_read = sd_card_block_read_gta02, |
| 725 | .partition_index = 3, |
| 726 | .filesystem = FS_EXT2, |
| 727 | .filepath = "boot/uImage-GTA02.bin", |
| 728 | .commandline_append = " root=/dev/mmcblk0p3 rootdelay=1 ", |
| 729 | }, |
| 730 | [3] = { |
| 731 | .name = "NAND Kernel", |
| 732 | .block_read = nand_read_ll, |
| 733 | /* NOTE offset below is replaced at runtime */ |
| 734 | .offset_blocks512_if_no_partition = 0x80000 / 512, |
| 735 | .filesystem = FS_RAW, |
| 736 | .commandline_append = " rootfstype=jffs2 " |
| 737 | "root=/dev/mtdblock6 ", |
| 738 | }, |
| 739 | }, |
| 740 | }; |
| 741 | |