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 = (struct s5pc110_gpio *) S5PC110_GPIO_BASE;
26 static void sdelay(unsigned long usec)
38 static int check_keypad(void)
40 unsigned int condition = 0;
41 unsigned int reg, value;
42 unsigned int col_num, row_num;
43 unsigned int col_mask;
44 unsigned int col_mask_shift;
45 unsigned int row_state[4] = {0, 0, 0, 0};
48 /* board is limo universal */
53 for (i = 0; i < sizeof(row_state)/sizeof(int); i++)
56 for (i = 0; i < row_num; i++) {
57 /* Set GPH3[3:0] to KP_ROW[3:0] */
58 gpio_cfg_pin(&gpio_base->gpio_h3, i, 0x3);
59 gpio_set_pull(&gpio_base->gpio_h3, i, GPIO_PULL_UP);
62 for (i = 0; i < col_num; i++)
63 /* Set GPH2[3:0] to KP_COL[3:0] */
64 gpio_cfg_pin(&gpio_base->gpio_h2, i, 0x3);
66 reg = S5PC110_KEYPAD_BASE;
67 col_mask = S5PC110_KEYIFCOLEN_MASK;
70 /* KEYIFCOL reg clear */
71 writel(0, reg + S5PC1XX_KEYIFCOL_OFFSET);
74 for (i = 0; i < col_num; i++) {
76 value &= ~(1 << i) << col_mask_shift;
78 writel(value, reg + S5PC1XX_KEYIFCOL_OFFSET);
81 value = readl(reg + S5PC1XX_KEYIFROW_OFFSET);
82 row_state[i] = ~value & ((1 << row_num) - 1);
85 /* KEYIFCOL reg clear */
86 writel(0, reg + S5PC1XX_KEYIFCOL_OFFSET);
88 /* check volume up/down */
89 if ((row_state[1] & 0x3) == 0x3)
95 static int check_block(void)
97 struct onenand_op *onenand_ops = onenand_get_interface();
98 struct mtd_info *mtd = onenand_ops->mtd;
99 struct onenand_chip *this = mtd->priv;
101 int page_to_check = 4;
103 ulong blocksize = 1 << this->erase_shift;
104 ulong pagesize = 1 << this->page_shift;
105 u_char *down_ram_addr;
107 u_char verify_buf[0x10];
109 down_ram_addr = (unsigned char *)CONFIG_SYS_DOWN_ADDR;
110 uboot_addr = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
112 onenand_ops->read(uboot_addr, blocksize, &retlen, down_ram_addr, 0);
113 if (retlen != blocksize)
116 memset(verify_buf, 0xFF, sizeof(verify_buf));
118 for (i = 0; i < page_to_check; i++) {
119 ret = memcmp(down_ram_addr + pagesize*i, verify_buf,
125 if (i == page_to_check)
131 int board_check_condition(void)
133 if (check_keypad()) {
134 PUTS("manual mode\n");
139 PUTS("bootloader image broken\n");
146 int board_load_uboot(unsigned char *buf)
148 struct mtd_info *mtd = &onenand_mtd;
149 struct onenand_chip *this = mtd->priv;
154 offset = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
155 size = CONFIG_SYS_MONITOR_LEN;
157 mtd->read(mtd, offset, size, &ret, buf);
165 void board_recovery_init(void)
167 /* set GPIO to enable UART2 */
168 gpio_cfg_pin(&gpio_base->gpio_a1, 0, 0x2);
169 gpio_cfg_pin(&gpio_base->gpio_a1, 1, 0x2);
171 /* UART_SEL MP0_5[7] at S5PC110 */
172 gpio_direction_output(&gpio_base->gpio_mp0_5, 7, 0x1);
173 gpio_set_pull(&gpio_base->gpio_mp0_5, 7, GPIO_PULL_DOWN);