2 * Copyright (C) 2009-2010 Samsung Electronics
6 #include <linux/mtd/mtd.h>
7 #include <linux/mtd/onenand.h>
9 #include <asm/arch/cpu.h>
10 #include <asm/arch/gpio.h>
11 #include <asm/arch/keypad.h>
12 #include <asm/arch/power.h>
17 #define PUTS(s) serial_puts(DEBUG_MARK""s)
22 #define C110_MACH_START 3100
23 #define C100_MACH_START 3000
25 /* board is MACH_AQUILA and board is like below. */
26 #define J1_B2_BOARD 0x0200
27 #define LIMO_UNIVERSAL_BOARD 0x0400
28 #define LIMO_REAL_BOARD 0x0800
29 #define MEDIA_BOARD 0x1000
30 #define BAMBOO_BOARD 0x2000
32 /* board is MACH_GONI and board is like below */
33 #define S1_BOARD 0x1000
34 #define KESSLER_BOARD 0x4000
35 #define SDK_BOARD 0x8000
37 #define BOARD_MASK 0xFF00
43 MACH_P1P2, /* Don't remove it */
52 typedef int (init_fnc_t) (void);
56 static unsigned int board_rev;
58 static void sdelay(unsigned long usec)
70 static int hwrevision(int rev)
72 return (board_rev & 0xf) == rev;
75 static int c110_machine_id(void)
77 return bd.bi_arch_number - C110_MACH_START;
80 static int mach_is_aquila(void)
82 return bd.bi_arch_number == MACH_TYPE_AQUILA;
85 static int mach_is_geminus(void)
87 return c110_machine_id() == MACH_GEMINUS;
90 static int board_is_limo_universal(void)
92 return mach_is_aquila() && (board_rev & LIMO_UNIVERSAL_BOARD);
95 static int board_is_limo_real(void)
97 return mach_is_aquila() && (board_rev & LIMO_REAL_BOARD);
101 static int mach_is_goni(void)
103 return bd.bi_arch_number == MACH_TYPE_GONI;
106 static int board_is_sdk(void)
108 return mach_is_goni() && (board_rev & SDK_BOARD);
112 static int mach_is_wmg160(void)
114 return c110_machine_id() == MACH_WMG160;
117 static void check_board_revision(int board, int rev)
119 if (board == MACH_TYPE_AQUILA) {
120 /* Limo Real or Universal */
121 if (rev & LIMO_UNIVERSAL_BOARD)
122 board_rev &= ~J1_B2_BOARD;
123 if (rev & LIMO_REAL_BOARD)
124 board_rev &= ~(J1_B2_BOARD |
125 LIMO_UNIVERSAL_BOARD);
126 if (rev & MEDIA_BOARD)
127 board_rev &= ~(J1_B2_BOARD |
128 LIMO_UNIVERSAL_BOARD);
129 if (rev & BAMBOO_BOARD)
130 board_rev &= ~(J1_B2_BOARD |
131 LIMO_UNIVERSAL_BOARD |
134 } else if (board == MACH_TYPE_GONI) {
135 if (rev & KESSLER_BOARD)
136 board_rev &= ~(J1_B2_BOARD |
137 LIMO_UNIVERSAL_BOARD);
139 board_rev &= ~(J1_B2_BOARD |
140 LIMO_UNIVERSAL_BOARD);
142 board_rev &= ~(J1_B2_BOARD | LIMO_UNIVERSAL_BOARD |
145 board_rev &= ~BOARD_MASK;
149 static unsigned int get_hw_revision(struct s5p_gpio_bank *bank, int hwrev3)
153 gpio_direction_input(bank, 2);
154 gpio_direction_input(bank, 3);
155 gpio_direction_input(bank, 4);
156 gpio_direction_input(bank, hwrev3);
158 gpio_set_pull(bank, 2, GPIO_PULL_NONE); /* HWREV_MODE0 */
159 gpio_set_pull(bank, 3, GPIO_PULL_NONE); /* HWREV_MODE1 */
160 gpio_set_pull(bank, 4, GPIO_PULL_NONE); /* HWREV_MODE2 */
161 gpio_set_pull(bank, hwrev3, GPIO_PULL_NONE); /* HWREV_MODE3 */
163 rev = gpio_get_value(bank, 2);
164 rev |= (gpio_get_value(bank, 3) << 1);
165 rev |= (gpio_get_value(bank, 4) << 2);
166 rev |= (gpio_get_value(bank, hwrev3) << 3);
171 static void check_hw_revision(void)
173 unsigned int board = MACH_UNIVERSAL; /* Default is Universal */
175 if (cpu_is_s5pc100()) {
176 struct s5pc100_gpio *gpio =
177 (struct s5pc100_gpio *)S5PC100_GPIO_BASE;
179 board_rev = get_hw_revision(&gpio->gpio_j0, 0);
181 /* C100 TickerTape */
183 board = MACH_TICKERTAPE;
185 struct s5pc110_gpio *gpio =
186 (struct s5pc110_gpio *)S5PC110_GPIO_BASE;
192 * Note Check 'Aquila' board first
196 * LRA: Limo Real Aquila
197 * LUA: Limo Universal Aquila
202 * ADDR = 0xE0200000 + OFF
204 * OFF Universal BB LRA LUA OA TT SS CYP
205 * J1: 0x0264 0x10 0x10 0x00 0x00 0x00 0x00 0x00
206 * J2: 0x0284 0x01 0x10 0x00
207 * H1: 0x0C24 W 0x28 0xA8 0x1C 0x0F
208 * H3: 0x0C64 0x03 0x07 0x0F
209 * D1: 0x00C4 0x0F 0x3F 0x3F 0x0F 0xXC 0x3F
210 * I: 0x0224 0x02 0x00 0x08
211 * MP03: 0x0324 0x9x 0xbx 0x9x
212 * MP05: 0x0364 0x80 0x88
216 if (gpio_get_value(&gpio->gpio_j1, 4) == 0) {
217 board = MACH_TYPE_AQUILA;
218 board_rev |= J1_B2_BOARD;
220 gpio_set_pull(&gpio->gpio_j2, 6, GPIO_PULL_NONE);
221 gpio_direction_input(&gpio->gpio_j2, 6);
224 if (gpio_get_value(&gpio->gpio_h1, 2) == 0)
225 board_rev |= LIMO_UNIVERSAL_BOARD;
227 if (gpio_get_value(&gpio->gpio_h3, 2) == 0)
228 board_rev |= LIMO_REAL_BOARD;
230 if (gpio_get_value(&gpio->gpio_j2, 6) == 1)
231 board_rev |= MEDIA_BOARD;
233 /* set gpio to default value. */
234 gpio_set_pull(&gpio->gpio_j2, 6, GPIO_PULL_DOWN);
235 gpio_direction_output(&gpio->gpio_j2, 6, 0);
238 /* Workaround: C110 Aquila Rev0.6 */
239 if (board_rev == 6) {
240 board = MACH_TYPE_AQUILA;
241 board_rev |= LIMO_REAL_BOARD;
244 /* C110 Aquila Bamboo */
245 if (gpio_get_value(&gpio->gpio_j2, 0) == 1) {
246 board = MACH_TYPE_AQUILA;
247 board_rev |= BAMBOO_BOARD;
250 /* C110 TickerTape */
251 if (gpio_get_value(&gpio->gpio_d1, 0) == 0 &&
252 gpio_get_value(&gpio->gpio_d1, 1) == 0)
253 board = MACH_TICKERTAPE;
255 /* WMG160 - GPH3[0:4] = 0x00 */
256 if (board == MACH_TICKERTAPE) {
259 for (i = 0; i < 4; i++) {
260 if (gpio_get_value(&gpio->gpio_h3, i) != 0) {
271 /* C110 Geminus for rev0.0 */
272 gpio_set_pull(&gpio->gpio_j1, 2, GPIO_PULL_NONE);
273 gpio_direction_input(&gpio->gpio_j1, 2);
274 if (gpio_get_value(&gpio->gpio_j1, 2) == 1) {
275 board = MACH_GEMINUS;
276 if ((board_rev & ~BOARD_MASK) == 3)
279 gpio_set_pull(&gpio->gpio_j1, 2, GPIO_PULL_DOWN);
280 gpio_direction_output(&gpio->gpio_j1, 2, 0);
282 /* C110 Geminus for rev0.1 ~ */
283 gpio_set_pull(&gpio->gpio_j0, 6, GPIO_PULL_NONE);
284 gpio_direction_input(&gpio->gpio_j0, 6);
285 if (gpio_get_value(&gpio->gpio_j0, 6) == 1) {
286 board = MACH_GEMINUS;
289 gpio_set_pull(&gpio->gpio_j0, 6, GPIO_PULL_DOWN);
291 /* Kessler MP0_5[6] == 1 */
292 gpio_direction_input(&gpio->gpio_mp0_5, 6);
293 if (gpio_get_value(&gpio->gpio_mp0_5, 6) == 1) {
294 /* Cypress: Do this for cypress */
295 gpio_set_pull(&gpio->gpio_j2, 2, GPIO_PULL_NONE);
296 gpio_direction_input(&gpio->gpio_j2, 2);
297 if (gpio_get_value(&gpio->gpio_j2, 2) == 1) {
298 board = MACH_CYPRESS;
299 gpio_direction_output(&gpio->gpio_mp0_5, 6, 0);
301 board = MACH_TYPE_GONI;
302 board_rev |= KESSLER_BOARD;
304 /* Limo SDK MP0_5[4] == 1 */
305 gpio_direction_input(&gpio->gpio_mp0_5, 4);
306 if (gpio_get_value(&gpio->gpio_mp0_5, 4) == 1) {
307 board_rev &= ~KESSLER_BOARD;
308 board_rev |= SDK_BOARD;
311 gpio_set_pull(&gpio->gpio_j2, 2, GPIO_PULL_DOWN);
314 gpio_direction_output(&gpio->gpio_mp0_5, 6, 0);
315 /* Goni S1 board detection */
316 if (board == MACH_TICKERTAPE) {
317 board = MACH_TYPE_GONI;
318 board_rev |= S1_BOARD;
323 board_rev |= get_hw_revision(&gpio->gpio_j0, hwrev3);
327 if (board < MACH_PSEUDO_END) {
328 if (cpu_is_s5pc110())
329 bd.bi_arch_number = C110_MACH_START + board;
331 bd.bi_arch_number = C100_MACH_START + board;
333 bd.bi_arch_number = board;
337 static void show_hw_revision(void)
342 * Workaround for Rev 0.3 + CP Ver ES 3.1
345 if (board_is_limo_real()) {
347 /* default is Rev 0.4 */
353 if (mach_is_goni() || mach_is_aquila())
354 board = bd.bi_arch_number;
355 else if (cpu_is_s5pc110())
356 board = bd.bi_arch_number - C110_MACH_START;
358 board = bd.bi_arch_number - C100_MACH_START;
360 check_board_revision(board, board_rev);
362 /* Set CPU Revision */
363 if (mach_is_aquila()) {
364 if (board_is_limo_real()) {
365 if ((board_rev & 0xf) < 8)
366 s5pc1xx_set_cpu_rev(0);
368 } else if (mach_is_goni()) {
369 if (board_is_sdk() &&
370 (hwrevision(2) || hwrevision(4) || hwrevision(5)))
371 s5pc1xx_set_cpu_rev(2); /* EVT1-Fused */
373 s5pc1xx_set_cpu_rev(1);
374 } else if (mach_is_geminus()) {
375 if ((board_rev & 0xf) < 1)
376 s5pc1xx_set_cpu_rev(0);
377 } else if (mach_is_wmg160()) {
379 s5pc1xx_set_cpu_rev(0);
381 s5pc1xx_set_cpu_rev(2);
383 s5pc1xx_set_cpu_rev(0);
386 if (cpu_is_s5pc110())
387 writel(0xc1100000 | (0xffff & (s5pc1xx_get_cpu_rev() ? 1 : 0)),
391 static int check_keypad(void)
395 uint col_num, row_num;
398 uint row_state[4] = {0, 0, 0, 0};
402 if (cpu_is_s5pc100()) {
403 struct s5pc100_gpio *gpio =
404 (struct s5pc100_gpio *)S5PC100_GPIO_BASE;
409 /* Set GPH2[2:0] to KP_COL[2:0] */
410 gpio_cfg_pin(&gpio->gpio_h2, 0, 0x3);
411 gpio_cfg_pin(&gpio->gpio_h2, 1, 0x3);
412 gpio_cfg_pin(&gpio->gpio_h2, 2, 0x3);
414 /* Set GPH3[2:0] to KP_ROW[2:0] */
415 gpio_cfg_pin(&gpio->gpio_h3, 0, 0x3);
416 gpio_cfg_pin(&gpio->gpio_h3, 1, 0x3);
417 gpio_cfg_pin(&gpio->gpio_h3, 2, 0x3);
419 reg = S5PC100_KEYPAD_BASE;
420 col_mask = S5PC1XX_KEYIFCOL_MASK;
423 struct s5pc110_gpio *gpio =
424 (struct s5pc110_gpio *) S5PC110_GPIO_BASE;
426 if (mach_is_wmg160())
429 if (board_is_limo_real() || board_is_limo_universal()) {
437 for (i = 0; i < row_num; i++) {
438 /* Set GPH3[3:0] to KP_ROW[3:0] */
439 gpio_cfg_pin(&gpio->gpio_h3, i, 0x3);
440 gpio_set_pull(&gpio->gpio_h3, i, GPIO_PULL_UP);
443 for (i = 0; i < col_num; i++)
444 /* Set GPH2[3:0] to KP_COL[3:0] */
445 gpio_cfg_pin(&gpio->gpio_h2, i, 0x3);
447 reg = S5PC110_KEYPAD_BASE;
448 col_mask = S5PC110_KEYIFCOLEN_MASK;
452 /* KEYIFCOL reg clear */
453 writel(0, reg + S5PC1XX_KEYIFCOL_OFFSET);
456 for (i = 0; i < col_num; i++) {
458 value &= ~(1 << i) << col_mask_shift;
460 writel(value, reg + S5PC1XX_KEYIFCOL_OFFSET);
463 value = readl(reg + S5PC1XX_KEYIFROW_OFFSET);
464 row_state[i] = ~value & ((1 << row_num) - 1);
467 /* KEYIFCOL reg clear */
468 writel(0, reg + S5PC1XX_KEYIFCOL_OFFSET);
470 cpu_rev = s5pc1xx_get_cpu_rev();
472 if ((row_state[1] & 0x6) == 0x6)
474 } else if (cpu_rev == 2) {
475 if ((row_state[2] & 0x6) == 0x6)
478 if ((row_state[1] & 0x3) == 0x3)
485 static int check_block(void)
487 struct onenand_op *onenand_ops = onenand_get_interface();
488 struct mtd_info *mtd = onenand_ops->mtd;
489 struct onenand_chip *this = mtd->priv;
492 u32 from = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
493 u32 len = 1 << this->erase_shift;
494 u32 *buf = (u32 *)CONFIG_SYS_DOWN_ADDR;
496 /* check first page of bootloader*/
497 onenand_ops->read(from, len, (ssize_t *)&retlen, (u_char *)buf, 0);
501 for (i = 0; i < (this->writesize / sizeof(this->writesize)); i++)
502 if (*(buf + i) != 0xffffffff)
508 int board_check_condition(void)
510 if (check_keypad()) {
511 PUTS("check: manual\n");
516 PUTS("check: bootloader broken\n");
523 int board_load_bootloader(unsigned char *buf)
525 struct mtd_info *mtd = &onenand_mtd;
526 struct onenand_chip *this = mtd->priv;
527 u32 ofs, len, retlen;
529 ofs = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
530 len = CONFIG_SYS_MONITOR_LEN;
532 mtd->read(mtd, ofs, len, &retlen, buf);
540 int board_lock_recoveryblock(void)
542 struct mtd_info *mtd = &onenand_mtd;
543 struct onenand_chip *this = mtd->priv;
545 u32 len = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
548 /* lock-tight the recovery block */
549 if (this->lock_tight != NULL)
550 ret = this->lock_tight(mtd, ofs, len);
555 void board_update_init(void)
557 struct mtd_info *mtd = &onenand_mtd;
558 struct onenand_chip *this = mtd->priv;
560 /* Unlock whole block */
561 this->unlock_all(mtd);
564 int board_update_image(u32 *buf, u32 len)
566 struct onenand_op *onenand_ops = onenand_get_interface();
567 struct mtd_info *mtd = &onenand_mtd;
568 struct onenand_chip *this = mtd->priv;
571 u32 ipl_edge = CONFIG_ONENAND_START_PAGE << this->page_shift;
572 u32 recovery_addr = ipl_edge;
573 u32 recovery_edge = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
574 u32 bootloader_addr = recovery_edge;
577 if (len > bootloader_addr) {
578 if (*(buf + bootloader_addr/sizeof(buf)) == 0xea000012) {
579 /* case: IPL + Recovery + bootloader */
580 PUTS("target: ipl + recovery + bootloader\n");
582 /* len = bootloader_edge; */
584 /* case: unknown format */
585 PUTS("target: unknown\n");
589 if (*(buf + recovery_addr/sizeof(buf)) == 0xea000012 &&
590 *(buf + recovery_addr/sizeof(buf) - 1) == 0x00000000) {
591 /* case: old image (IPL + bootloader) */
592 PUTS("target: ipl + bootloader (old type)\n");
594 /* len = recovery_edge; */
596 /* case: bootloader only */
597 PUTS("target: bootloader\n");
598 ofs = bootloader_addr;
599 /* len = bootloader_edge - recovery_edge; */
603 #ifdef CONFIG_S5PC1XX
604 /* Workaround: for prevent revision mismatch */
605 if (cpu_is_s5pc110() && (ofs == 0)) {
608 if (*buf == 0xea000012)
610 else if (*(buf + 0x400) == 0xea000012)
615 if (img_rev != s5pc1xx_get_cpu_rev()) {
616 PUTS("target check: CPU revision mismatch!\n");
617 PUTS("target check: system is ");
618 if (s5pc1xx_get_cpu_rev() == 1)
619 serial_puts("EVT1\n");
620 else if (s5pc1xx_get_cpu_rev() == 2)
621 serial_puts("EVT1-Fused\n");
623 serial_puts("EVT0\n");
624 PUTS("target check: download image is ");
626 serial_puts("EVT1\n");
627 else if (img_rev == 2)
628 serial_puts("EVT1-Fused\n");
630 serial_puts("EVT0\n");
638 ret = onenand_ops->erase(ofs, len, 0);
643 onenand_ops->write(ofs, len, (ssize_t *)&retlen, (u_char *)buf);
650 void board_recovery_init(void)
652 struct s5pc110_gpio *gpio_base =
653 (struct s5pc110_gpio *) S5PC110_GPIO_BASE;
655 /* basic arch cpu dependent setup */
658 /* Check H/W Revision */
663 /* set GPIO to enable UART2 */
664 gpio_cfg_pin(&gpio_base->gpio_a1, 0, 0x2);
665 gpio_cfg_pin(&gpio_base->gpio_a1, 1, 0x2);
667 /* UART_SEL MP0_5[7] at S5PC110 */
668 gpio_direction_output(&gpio_base->gpio_mp0_5, 7, 0x1);
669 gpio_set_pull(&gpio_base->gpio_mp0_5, 7, GPIO_PULL_DOWN);