2 * Copyright (C) 2009-2010 Samsung Electronics
6 #include <linux/mtd/mtd.h>
7 #include <linux/mtd/onenand.h>
9 #include <asm/arch/gpio.h>
10 #include <asm/arch/keypad.h>
15 #define PUTS(s) serial_puts(DEBUG_MARK""s)
20 typedef int (init_fnc_t) (void);
22 DECLARE_GLOBAL_DATA_PTR;
24 static struct s5pc110_gpio *gpio_base =
25 (struct s5pc110_gpio *) S5PC110_GPIO_BASE;
27 static void sdelay(unsigned long usec)
39 static int check_keypad(void)
41 unsigned int condition = 0;
42 unsigned int reg, value;
43 unsigned int col_num, row_num;
44 unsigned int col_mask;
45 unsigned int col_mask_shift;
46 unsigned int row_state[4] = {0, 0, 0, 0};
49 /* board is limo universal */
54 for (i = 0; i < sizeof(row_state)/sizeof(int); i++)
57 for (i = 0; i < row_num; i++) {
58 /* Set GPH3[3:0] to KP_ROW[3:0] */
59 gpio_cfg_pin(&gpio_base->gpio_h3, i, 0x3);
60 gpio_set_pull(&gpio_base->gpio_h3, i, GPIO_PULL_UP);
63 for (i = 0; i < col_num; i++)
64 /* Set GPH2[3:0] to KP_COL[3:0] */
65 gpio_cfg_pin(&gpio_base->gpio_h2, i, 0x3);
67 reg = S5PC110_KEYPAD_BASE;
68 col_mask = S5PC110_KEYIFCOLEN_MASK;
71 /* KEYIFCOL reg clear */
72 writel(0, reg + S5PC1XX_KEYIFCOL_OFFSET);
75 for (i = 0; i < col_num; i++) {
77 value &= ~(1 << i) << col_mask_shift;
79 writel(value, reg + S5PC1XX_KEYIFCOL_OFFSET);
82 value = readl(reg + S5PC1XX_KEYIFROW_OFFSET);
83 row_state[i] = ~value & ((1 << row_num) - 1);
86 /* KEYIFCOL reg clear */
87 writel(0, reg + S5PC1XX_KEYIFCOL_OFFSET);
89 /* check volume up/down */
90 if ((row_state[1] & 0x3) == 0x3)
96 static int check_block(void)
98 struct onenand_op *onenand_ops = onenand_get_interface();
99 struct mtd_info *mtd = onenand_ops->mtd;
100 struct onenand_chip *this = mtd->priv;
102 int page_to_check = 4;
104 ulong blocksize = 1 << this->erase_shift;
105 ulong pagesize = 1 << this->page_shift;
106 u_char *down_ram_addr;
108 u_char verify_buf[0x10];
110 down_ram_addr = (unsigned char *)CONFIG_SYS_DOWN_ADDR;
111 uboot_addr = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
113 onenand_ops->read(uboot_addr, blocksize, &retlen, down_ram_addr, 0);
114 if (retlen != blocksize)
117 memset(verify_buf, 0xFF, sizeof(verify_buf));
119 for (i = 0; i < page_to_check; i++) {
120 ret = memcmp(down_ram_addr + pagesize*i, verify_buf,
126 if (i == page_to_check)
132 int board_check_condition(void)
134 if (check_keypad()) {
135 PUTS("manual mode\n");
140 PUTS("bootloader image broken\n");
147 int board_load_uboot(unsigned char *buf)
149 struct mtd_info *mtd = &onenand_mtd;
150 struct onenand_chip *this = mtd->priv;
155 offset = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
156 size = CONFIG_SYS_MONITOR_LEN;
158 mtd->read(mtd, offset, size, &ret, buf);
166 void board_recovery_init(void)
168 /* set GPIO to enable UART2 */
169 gpio_cfg_pin(&gpio_base->gpio_a1, 0, 0x2);
170 gpio_cfg_pin(&gpio_base->gpio_a1, 1, 0x2);
172 /* UART_SEL MP0_5[7] at S5PC110 */
173 gpio_direction_output(&gpio_base->gpio_mp0_5, 7, 0x1);
174 gpio_set_pull(&gpio_base->gpio_mp0_5, 7, GPIO_PULL_DOWN);