1 | /* |
2 | * USB_BOOT Handle routines |
3 | * |
4 | * Copyright (C) 2009 Qi Hardware Inc., |
5 | * Author: Xiangfu Liu <xiangfu@sharism.cc> |
6 | * |
7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License |
9 | * version 3 as published by the Free Software Foundation. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | * Boston, MA 02110-1301, USA |
20 | */ |
21 | |
22 | #include "target/jz4740.h" |
23 | #include "target/error.h" |
24 | #include "target/usb_boot.h" |
25 | #include "usb_boot_defines.h" |
26 | #include "target/nandflash.h" |
27 | #include "usb/udc.h" |
28 | #include "usb/usb.h" |
29 | |
30 | #define dprintf(x) serial_puts(x) |
31 | |
32 | unsigned int (*nand_query)(u8 *); |
33 | int (*nand_init)(int bus_width, int row_cycle, int page_size, int page_per_block, |
34 | int,int,int,int); |
35 | int (*nand_fini)(void); |
36 | u32 (*nand_program)(void *context, int spage, int pages,int option); |
37 | u32 (*nand_erase)(int blk_num, int sblk, int force); |
38 | u32 (*nand_read)(void *buf, u32 startpage, u32 pagenum,int option); |
39 | u32 (*nand_read_oob)(void *buf, u32 startpage, u32 pagenum); |
40 | u32 (*nand_read_raw)(void *buf, u32 startpage, u32 pagenum,int); |
41 | u32 (*nand_mark_bad) (int bad); |
42 | void (*nand_enable) (unsigned int csn); |
43 | void (*nand_disable) (unsigned int csn); |
44 | |
45 | struct hand Hand; |
46 | extern u32 Bulk_out_buf[BULK_OUT_BUF_SIZE]; |
47 | extern u32 Bulk_in_buf[BULK_IN_BUF_SIZE]; |
48 | extern u16 handshake_PKT[4]; |
49 | extern udc_state; |
50 | extern void *memset(void *s, int c, size_t count); |
51 | extern void *memcpy(void *dest, const void *src, size_t count); |
52 | |
53 | u32 ret_dat; |
54 | u32 start_addr; /* program operation start address or sector */ |
55 | u32 ops_length; /* number of operation unit ,in byte or sector */ |
56 | u32 ram_addr; |
57 | |
58 | void dump_data(unsigned int *p, int size) |
59 | { |
60 | int i; |
61 | for(i = 0; i < size; i ++) |
62 | serial_put_hex(*p++); |
63 | } |
64 | |
65 | void config_flash_info() |
66 | { |
67 | } |
68 | |
69 | void config_hand() |
70 | { |
71 | memcpy(&Hand, (unsigned char *)Bulk_out_buf, sizeof(struct hand)); |
72 | } |
73 | |
74 | int GET_CPU_INFO_Handle() |
75 | { |
76 | dprintf("\n GET_CPU_INFO:\t"); |
77 | serial_put_hex(Hand.fw_args.cpu_id); |
78 | switch (Hand.fw_args.cpu_id) { |
79 | case 0x4760: |
80 | HW_SendPKT(0, "Boot4760", 8); |
81 | break; |
82 | case 0x4740: |
83 | HW_SendPKT(0, "Boot4740", 8); |
84 | break; |
85 | default: |
86 | HW_SendPKT(0, " UNKNOW ", 8); |
87 | break; |
88 | } |
89 | udc_state = IDLE; |
90 | return ERR_OK; |
91 | } |
92 | |
93 | int SET_DATA_ADDERSS_Handle(u8 *buf) |
94 | { |
95 | USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; |
96 | start_addr=(((u32)dreq->wValue)<<16)+(u32)dreq->wIndex; |
97 | dprintf("\n SET ADDRESS:\t"); |
98 | serial_put_hex(start_addr); |
99 | return ERR_OK; |
100 | } |
101 | |
102 | int SET_DATA_LENGTH_Handle(u8 *buf) |
103 | { |
104 | USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; |
105 | ops_length=(((u32)dreq->wValue)<<16)+(u32)dreq->wIndex; |
106 | dprintf("\n DATA_LENGTH:\t"); |
107 | serial_put_hex(ops_length); |
108 | return ERR_OK; |
109 | } |
110 | |
111 | int FLUSH_CACHES_Handle() |
112 | { |
113 | return ERR_OK; |
114 | } |
115 | |
116 | int PROGRAM_START1_Handle(u8 *buf) |
117 | { |
118 | USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; |
119 | ram_addr=(((u32)dreq->wValue)<<16)+(u32)dreq->wIndex; |
120 | return ERR_OK; |
121 | } |
122 | |
123 | int PROGRAM_START2_Handle(u8 *buf) |
124 | { |
125 | void (*f)(void); |
126 | USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; |
127 | f=(void *) ((((u32)dreq->wValue)<<16)+(u32)dreq->wIndex); |
128 | __dcache_writeback_all(); |
129 | /* stop udc connet before execute program! */ |
130 | jz_writeb(USB_REG_POWER,0x0); /* High speed */ |
131 | |
132 | f(); |
133 | return ERR_OK; |
134 | } |
135 | |
136 | int NOR_OPS_Handle(u8 *buf) |
137 | { |
138 | USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; |
139 | return ERR_OK; |
140 | } |
141 | |
142 | int NAND_OPS_Handle(u8 *buf) |
143 | { |
144 | USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; |
145 | u32 temp; |
146 | int option; |
147 | u8 CSn; |
148 | |
149 | CSn = (dreq->wValue>>4) & 0xff; |
150 | option = (dreq->wValue>>12) & 0xff; |
151 | nand_enable(CSn); |
152 | switch ((dreq->wValue)&0xf) |
153 | { |
154 | case NAND_QUERY: |
155 | dprintf("\n Request : NAND_QUERY!"); |
156 | nand_query((u8 *)Bulk_in_buf); |
157 | HW_SendPKT(1, Bulk_in_buf, 8); |
158 | handshake_PKT[3]=(u16)ERR_OK; |
159 | udc_state = BULK_IN; |
160 | break; |
161 | case NAND_INIT: |
162 | dprintf("\n Request : NAND_INIT!"); |
163 | |
164 | break; |
165 | case NAND_MARK_BAD: |
166 | dprintf("\n Request : NAND_MARK_BAD!"); |
167 | ret_dat = nand_mark_bad(start_addr); |
168 | handshake_PKT[0] = (u16) ret_dat; |
169 | handshake_PKT[1] = (u16) (ret_dat>>16); |
170 | HW_SendPKT(1,handshake_PKT,sizeof(handshake_PKT)); |
171 | udc_state = IDLE; |
172 | |
173 | break; |
174 | case NAND_READ_OOB: |
175 | dprintf("\n Request : NAND_READ_OOB!"); |
176 | memset(Bulk_in_buf,0,ops_length*Hand.nand_ps); |
177 | ret_dat = nand_read_oob(Bulk_in_buf,start_addr,ops_length); |
178 | handshake_PKT[0] = (u16) ret_dat; |
179 | handshake_PKT[1] = (u16) (ret_dat>>16); |
180 | HW_SendPKT(1,(u8 *)Bulk_in_buf,ops_length*Hand.nand_ps); |
181 | udc_state = BULK_IN; |
182 | break; |
183 | case NAND_READ_RAW: |
184 | dprintf("\n Request : NAND_READ_RAW!"); |
185 | switch (option) |
186 | { |
187 | case OOB_ECC: |
188 | nand_read_raw(Bulk_in_buf,start_addr,ops_length,option); |
189 | HW_SendPKT(1,(u8 *)Bulk_in_buf,ops_length*(Hand.nand_ps + Hand.nand_os)); |
190 | handshake_PKT[0] = (u16) ret_dat; |
191 | handshake_PKT[1] = (u16) (ret_dat>>16); |
192 | udc_state = BULK_IN; |
193 | break; |
194 | default: |
195 | nand_read_raw(Bulk_in_buf,start_addr,ops_length,option); |
196 | HW_SendPKT(1,(u8 *)Bulk_in_buf,ops_length*Hand.nand_ps); |
197 | handshake_PKT[0] = (u16) ret_dat; |
198 | handshake_PKT[1] = (u16) (ret_dat>>16); |
199 | udc_state = BULK_IN; |
200 | break; |
201 | } |
202 | break; |
203 | case NAND_ERASE: |
204 | dprintf("\n Request : NAND_ERASE"); |
205 | ret_dat = nand_erase(ops_length,start_addr, |
206 | Hand.nand_force_erase); |
207 | handshake_PKT[0] = (u16) ret_dat; |
208 | handshake_PKT[1] = (u16) (ret_dat>>16); |
209 | HW_SendPKT(1,handshake_PKT,sizeof(handshake_PKT)); |
210 | udc_state = IDLE; |
211 | dprintf(" ... finished."); |
212 | break; |
213 | case NAND_READ: |
214 | dprintf("\n Request : NAND_READ!"); |
215 | switch (option) { |
216 | case OOB_ECC: |
217 | ret_dat = nand_read(Bulk_in_buf,start_addr,ops_length,OOB_ECC); |
218 | handshake_PKT[0] = (u16) ret_dat; |
219 | handshake_PKT[1] = (u16) (ret_dat>>16); |
220 | HW_SendPKT(1,(u8 *)Bulk_in_buf,ops_length*(Hand.nand_ps + Hand.nand_os )); |
221 | udc_state = BULK_IN; |
222 | break; |
223 | case OOB_NO_ECC: |
224 | ret_dat = nand_read(Bulk_in_buf,start_addr,ops_length,OOB_NO_ECC); |
225 | handshake_PKT[0] = (u16) ret_dat; |
226 | handshake_PKT[1] = (u16) (ret_dat>>16); |
227 | HW_SendPKT(1,(u8 *)Bulk_in_buf,ops_length*(Hand.nand_ps + Hand.nand_os)); |
228 | udc_state = BULK_IN; |
229 | break; |
230 | case NO_OOB: |
231 | ret_dat = nand_read(Bulk_in_buf,start_addr,ops_length,NO_OOB); |
232 | handshake_PKT[0] = (u16) ret_dat; |
233 | handshake_PKT[1] = (u16) (ret_dat>>16); |
234 | HW_SendPKT(1,(u8 *)Bulk_in_buf,ops_length*Hand.nand_ps); |
235 | udc_state = BULK_IN; |
236 | break; |
237 | } |
238 | dprintf(" ... finished."); |
239 | break; |
240 | case NAND_PROGRAM: |
241 | dprintf("\n Request : NAND_PROGRAM!"); |
242 | ret_dat = nand_program((void *)Bulk_out_buf, |
243 | start_addr,ops_length,option); |
244 | handshake_PKT[0] = (u16) ret_dat; |
245 | handshake_PKT[1] = (u16) (ret_dat>>16); |
246 | HW_SendPKT(1,handshake_PKT,sizeof(handshake_PKT)); |
247 | udc_state = IDLE; |
248 | dprintf(" ... finished."); |
249 | break; |
250 | case NAND_READ_TO_RAM: |
251 | dprintf("\n Request : NAND_READ_TO_RAM!"); |
252 | nand_read((u8 *)ram_addr,start_addr,ops_length,NO_OOB); |
253 | __dcache_writeback_all(); |
254 | handshake_PKT[3]=(u16)ERR_OK; |
255 | HW_SendPKT(1,handshake_PKT,sizeof(handshake_PKT)); |
256 | udc_state = IDLE; |
257 | break; |
258 | default: |
259 | nand_disable(CSn); |
260 | return ERR_OPS_NOTSUPPORT; |
261 | } |
262 | |
263 | return ERR_OK; |
264 | } |
265 | |
266 | int SDRAM_OPS_Handle(u8 *buf) |
267 | { |
268 | USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; |
269 | u32 temp,i; |
270 | u8 *obj; |
271 | |
272 | switch ((dreq->wValue)&0xf) |
273 | { |
274 | case SDRAM_LOAD: |
275 | ret_dat = (u32)memcpy((u8 *)start_addr,Bulk_out_buf,ops_length); |
276 | handshake_PKT[0] = (u16) ret_dat; |
277 | handshake_PKT[1] = (u16) (ret_dat>>16); |
278 | HW_SendPKT(1,handshake_PKT,sizeof(handshake_PKT)); |
279 | udc_state = IDLE; |
280 | break; |
281 | } |
282 | return ERR_OK; |
283 | } |
284 | |
285 | void Board_Init() |
286 | { |
287 | dprintf("\n Board_init! "); |
288 | serial_put_hex(Hand.fw_args.cpu_id); |
289 | switch (Hand.fw_args.cpu_id) |
290 | { |
291 | case 0x4740: |
292 | nand_init_4740(Hand.nand_bw, Hand.nand_rc, Hand.nand_ps, |
293 | Hand.nand_ppb, Hand.nand_bbpage, Hand.nand_bbpos, |
294 | Hand.nand_force_erase, Hand.nand_eccpos); |
295 | |
296 | nand_program = nand_program_4740; |
297 | nand_erase = nand_erase_4740; |
298 | nand_read = nand_read_4740; |
299 | nand_read_oob = nand_read_oob_4740; |
300 | nand_read_raw = nand_read_raw_4740; |
301 | nand_query = nand_query_4740; |
302 | nand_enable = nand_enable_4740; |
303 | nand_disable = nand_disable_4740; |
304 | nand_mark_bad = nand_mark_bad_4740; |
305 | break; |
306 | case 0x4760: |
307 | nand_init_4760(Hand.nand_bw, Hand.nand_rc, Hand.nand_ps, |
308 | Hand.nand_ppb, Hand.nand_bchbit, Hand.nand_eccpos, |
309 | Hand.nand_bbpos, Hand.nand_bbpage, Hand.nand_force_erase); |
310 | |
311 | nand_program=nand_program_4760; |
312 | nand_erase =nand_erase_4760; |
313 | nand_read =nand_read_4760; |
314 | nand_read_oob=nand_read_oob_4760; |
315 | nand_read_raw=nand_read_raw_4760; |
316 | nand_query = nand_query_4760; |
317 | nand_enable = nand_enable_4760; |
318 | nand_disable= nand_disable_4760; |
319 | nand_mark_bad = nand_mark_bad_4760; |
320 | break; |
321 | default: |
322 | serial_puts("\n Not support CPU ID!"); |
323 | } |
324 | } |
325 | |
326 | int CONFIGRATION_Handle(u8 *buf) |
327 | { |
328 | dprintf("\n Configuration:\t"); |
329 | |
330 | USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; |
331 | switch ((dreq->wValue)&0xf) { |
332 | case DS_flash_info: |
333 | dprintf("DS_flash_info_t!"); |
334 | config_flash_info(); |
335 | break; |
336 | |
337 | case DS_hand: |
338 | dprintf("DS_hand_t!"); |
339 | config_hand(); |
340 | break; |
341 | default: |
342 | ; |
343 | } |
344 | |
345 | Board_Init(); |
346 | return ERR_OK; |
347 | } |
348 | |
349 | |
350 | int RESET_Handle(u8 *buf) |
351 | { |
352 | dprintf("\n RESET Device"); |
353 | __wdt_select_extalclk(); |
354 | __wdt_select_clk_div64(); |
355 | __wdt_set_data(100); |
356 | __wdt_set_count(0); |
357 | __tcu_start_wdt_clock(); |
358 | __wdt_start(); |
359 | while(1); |
360 | } |
361 | |