recovery: modify the license
[kernel/u-boot.git] / recovery / board / samsung / universal / universal.c
1 /*
2  * Copyright (C) 2009-2010 Samsung Electronics
3  */
4
5 #include <common.h>
6 #include <linux/mtd/mtd.h>
7 #include <linux/mtd/onenand.h>
8 #include <asm/io.h>
9 #include <asm/arch/gpio.h>
10 #include <asm/arch/keypad.h>
11 #include "recovery.h"
12 #include "onenand.h"
13
14 #ifdef RECOVERY_DEBUG
15 #define PUTS(s) serial_puts (DEBUG_MARK""s)
16 #else
17 #define PUTS(s)
18 #endif
19
20 typedef int (init_fnc_t) (void);
21
22 DECLARE_GLOBAL_DATA_PTR;
23
24 static struct s5pc110_gpio *gpio_base = (struct s5pc110_gpio *) S5PC110_GPIO_BASE;
25
26 static void sdelay(unsigned long usec)
27 {
28         ulong kv;
29
30         do {
31                 kv = 0x100000;
32                 while (kv)
33                         kv--;
34                 usec--;
35         } while (usec);
36 }
37
38 static int check_keypad(void)
39 {
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};
46         unsigned int i;
47
48         /* board is limo universal */
49
50         row_num = 2;
51         col_num = 3;
52
53         for (i = 0; i < sizeof(row_state)/sizeof(int); i++)
54                 row_state[i] = 0;
55
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);
60         }
61
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);
65
66         reg = S5PC110_KEYPAD_BASE;
67         col_mask = S5PC110_KEYIFCOLEN_MASK;
68         col_mask_shift = 8;
69
70         /* KEYIFCOL reg clear */
71         writel(0, reg + S5PC1XX_KEYIFCOL_OFFSET);
72
73         /* key_scan */
74         for (i = 0; i < col_num; i++) {
75                 value = col_mask;
76                 value &= ~(1 << i) << col_mask_shift;
77
78                 writel(value, reg + S5PC1XX_KEYIFCOL_OFFSET);
79                 sdelay(1000);
80
81                 value = readl(reg + S5PC1XX_KEYIFROW_OFFSET);
82                 row_state[i] = ~value & ((1 << row_num) - 1);
83         }
84
85         /* KEYIFCOL reg clear */
86         writel(0, reg + S5PC1XX_KEYIFCOL_OFFSET);
87
88         /* check volume up/down */
89         if ((row_state[1] & 0x3) == 0x3)
90                 condition = 1;
91
92         return condition;
93 }
94
95 static int check_block(void)
96 {
97         struct onenand_op *onenand_ops = onenand_get_interface();
98         struct mtd_info *mtd = onenand_ops->mtd;
99         struct onenand_chip *this = mtd->priv;
100         int i;
101         int page_to_check = 4;
102         int ret, retlen = 0;
103         ulong blocksize = 1 << this->erase_shift;
104         ulong pagesize = 1 << this->page_shift;
105         u_char *down_ram_addr;
106         ulong uboot_addr;
107         u_char verify_buf[0x10];
108
109         down_ram_addr = (unsigned char *)CONFIG_SYS_DOWN_ADDR;
110         uboot_addr = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
111
112         onenand_ops->read(uboot_addr, blocksize, &retlen, down_ram_addr, 0);
113         if (retlen != blocksize)
114                 return 1;
115
116         memset(verify_buf, 0xFF, sizeof(verify_buf));
117
118         for (i = 0; i < page_to_check; i++) {
119                 ret = memcmp(down_ram_addr + pagesize*i, verify_buf,
120                                 sizeof(verify_buf));
121                 if (ret)
122                         break;
123         }
124
125         if (i == page_to_check)
126                 return 1;
127
128         return 0;
129 }
130
131 int board_check_condition(void)
132 {
133         if (check_keypad()) {
134                 PUTS("manual mode\n");
135                 return 1;
136         }
137
138         if (check_block()) {
139                 PUTS("bootloader image broken\n");
140                 return 1;
141         }
142
143         return 0;
144 }
145
146 int board_load_uboot(unsigned char *buf)
147 {
148         struct mtd_info *mtd = &onenand_mtd;
149         struct onenand_chip *this = mtd->priv;
150         int offset;
151         size_t size;
152         size_t ret;
153
154         offset = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
155         size = CONFIG_SYS_MONITOR_LEN;
156
157         mtd->read(mtd, offset, size, &ret, buf);
158
159         if (size != ret)
160                 return -1;
161
162         return 0;
163 }
164
165 void board_recovery_init(void)
166 {
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);
170
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);
174 }