]> git.sur5r.net Git - openocd/blob - src/flash/mflash.c
unsik Kim <donari75@gmail.com> - mflash support
[openocd] / src / flash / mflash.c
1 /***************************************************************************\r
2  *   Copyright (C) 2007-2008 by unsik Kim <donari75@gmail.com>             *\r
3  *                                                                         *\r
4  *   This program is free software; you can redistribute it and/or modify  *\r
5  *   it under the terms of the GNU General Public License as published by  *\r
6  *   the Free Software Foundation; either version 2 of the License, or     *\r
7  *   (at your option) any later version.                                   *\r
8  *                                                                         *\r
9  *   This program is distributed in the hope that it will be useful,       *\r
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
12  *   GNU General Public License for more details.                          *\r
13  *                                                                         *\r
14  *   You should have received a copy of the GNU General Public License     *\r
15  *   along with this program; if not, write to the                         *\r
16  *   Free Software Foundation, Inc.,                                       *\r
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
18  ***************************************************************************/\r
19 \r
20 #ifdef HAVE_CONFIG_H\r
21 #include "config.h"\r
22 #endif\r
23 \r
24 #include <ctype.h>\r
25 #include <string.h>\r
26 #include <unistd.h>\r
27 #include <stdlib.h>\r
28 #include <sys/types.h>\r
29 #include <sys/stat.h>\r
30 #include <errno.h>\r
31 #include <inttypes.h>\r
32 \r
33 #include "command.h"\r
34 #include "log.h"\r
35 #include "target.h"\r
36 #include "time_support.h"\r
37 #include "fileio.h"\r
38 #include "mflash.h"\r
39 \r
40 static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio);\r
41 static int s3c2440_set_gpio_output_val (mflash_gpio_num_t gpio, u8 val);\r
42 static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio);\r
43 static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, u8 val);\r
44 \r
45 static command_t *mflash_cmd;\r
46 \r
47 static mflash_bank_t *mflash_bank;\r
48 \r
49 static mflash_gpio_drv_t pxa270_gpio = {\r
50         .name = "pxa270",\r
51         .set_gpio_to_output = pxa270_set_gpio_to_output,\r
52         .set_gpio_output_val = pxa270_set_gpio_output_val\r
53 };\r
54 \r
55 static mflash_gpio_drv_t s3c2440_gpio = {\r
56         .name = "s3c2440",\r
57         .set_gpio_to_output = s3c2440_set_gpio_to_output,\r
58         .set_gpio_output_val = s3c2440_set_gpio_output_val\r
59 };\r
60 \r
61 static mflash_gpio_drv_t *mflash_gpio[] =\r
62 {\r
63                 &pxa270_gpio,\r
64                 &s3c2440_gpio,\r
65                 NULL\r
66 };\r
67 \r
68 #define PXA270_GAFR0_L 0x40E00054\r
69 #define PXA270_GAFR3_U 0x40E00070\r
70 #define PXA270_GAFR3_U_RESERVED_BITS  0xfffc0000u\r
71 #define PXA270_GPDR0 0x40E0000C\r
72 #define PXA270_GPDR3 0x40E0010C\r
73 #define PXA270_GPDR3_RESERVED_BITS  0xfe000000u\r
74 #define PXA270_GPSR0 0x40E00018\r
75 #define PXA270_GPCR0 0x40E00024\r
76 \r
77 static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio)\r
78 {\r
79         u32 addr, value, mask;\r
80         target_t *target = mflash_bank->target;\r
81         int ret;\r
82 \r
83         // remove alternate function.\r
84         mask = 0x3u << (gpio.num & 0xF)*2;\r
85 \r
86         addr = PXA270_GAFR0_L + (gpio.num >> 4) * 4;\r
87 \r
88         if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK)\r
89                 return ret;\r
90 \r
91         value &= ~mask;\r
92         if (addr == PXA270_GAFR3_U)\r
93                 value &= ~PXA270_GAFR3_U_RESERVED_BITS;\r
94 \r
95         if ((ret = target_write_u32(target, addr, value)) != ERROR_OK)\r
96                 return ret;\r
97 \r
98         // set direction to output\r
99         mask = 0x1u << (gpio.num & 0x1F);\r
100 \r
101         addr = PXA270_GPDR0 + (gpio.num >> 5) * 4;\r
102 \r
103         if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK)\r
104                 return ret;\r
105 \r
106         value |= mask;\r
107         if (addr == PXA270_GPDR3)\r
108                 value &= ~PXA270_GPDR3_RESERVED_BITS;\r
109 \r
110         ret = target_write_u32(target, addr, value);\r
111         return ret;\r
112 }\r
113 \r
114 static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, u8 val)\r
115 {\r
116         u32 addr, value, mask;\r
117         target_t *target = mflash_bank->target;\r
118         int ret;\r
119 \r
120         mask = 0x1u << (gpio.num & 0x1F);\r
121 \r
122         if (val) {\r
123                 addr = PXA270_GPSR0 + (gpio.num >> 5) * 4;\r
124         } else {\r
125                 addr = PXA270_GPCR0 + (gpio.num >> 5) * 4;\r
126         }\r
127 \r
128         if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK)\r
129                 return ret;\r
130 \r
131         value |= mask;\r
132 \r
133         ret = target_write_u32(target, addr, value);\r
134 \r
135         return ret;\r
136 }\r
137 \r
138 #define S3C2440_GPACON 0x56000000\r
139 #define S3C2440_GPADAT 0x56000004\r
140 #define S3C2440_GPJCON 0x560000d0\r
141 #define S3C2440_GPJDAT 0x560000d4\r
142 \r
143 static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio)\r
144 {\r
145         u32 data, mask, gpio_con;\r
146         target_t *target = mflash_bank->target;\r
147         int ret;\r
148 \r
149         if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') {\r
150                 gpio_con = S3C2440_GPACON + (gpio.port[0] - 'a') * 0x10;\r
151         } else if (gpio.port[0] == 'j') {\r
152                 gpio_con = S3C2440_GPJCON;\r
153         } else {\r
154                 LOG_ERROR("invalid port %d%s", gpio.num, gpio.port);\r
155                 return ERROR_INVALID_ARGUMENTS;\r
156         }\r
157 \r
158         ret = target_read_u32(target, gpio_con, &data);\r
159 \r
160         if (ret == ERROR_OK) {\r
161                 if (gpio.port[0] == 'a') {\r
162                         mask = 1 << gpio.num;\r
163                         data &= ~mask;\r
164                 } else {\r
165                         mask = 3 << gpio.num * 2;\r
166                         data &= ~mask;\r
167                         data |= (1 << gpio.num * 2);\r
168                 }\r
169 \r
170                 ret = target_write_u32(target, gpio_con, data);\r
171         }\r
172         return ret;\r
173 }\r
174 \r
175 static int s3c2440_set_gpio_output_val (mflash_gpio_num_t gpio, u8 val)\r
176 {\r
177         u32 data, mask, gpio_dat;\r
178         target_t *target = mflash_bank->target;\r
179         int ret;\r
180 \r
181         if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') {\r
182                 gpio_dat = S3C2440_GPADAT + (gpio.port[0] - 'a') * 0x10;\r
183         } else if (gpio.port[0] == 'j') {\r
184                 gpio_dat = S3C2440_GPJDAT;\r
185         } else {\r
186                 LOG_ERROR("invalid port %d%s", gpio.num, gpio.port);\r
187                 return ERROR_INVALID_ARGUMENTS;\r
188         }\r
189 \r
190         ret = target_read_u32(target, gpio_dat, &data);\r
191 \r
192         if (ret == ERROR_OK) {\r
193                 mask = 1 << gpio.num;\r
194                 if (val)\r
195                         data |= mask;\r
196                 else\r
197                         data &= ~mask;\r
198 \r
199                 ret = target_write_u32(target, gpio_dat, data);\r
200         }\r
201         return ret;\r
202 }\r
203 \r
204 static int mflash_rst(u8 level)\r
205 {\r
206         return mflash_bank->gpio_drv->set_gpio_output_val(mflash_bank->rst_pin, level);\r
207 }\r
208 \r
209 static int mg_dump_task_reg (void)\r
210 {\r
211         target_t *target = mflash_bank->target;\r
212         u32 address = mflash_bank->base + MG_REG_OFFSET + MG_REG_ERROR;\r
213         u8 value, i;\r
214         char *reg_name[9] = {\r
215                 "error                  ",\r
216                 "sector count           ",\r
217                 "sector num (LBA  7- 0) ",\r
218                 "cyl. low   (LBA 15- 8) ",\r
219                 "cyl. high  (LBA 23-16) ",\r
220                 "drv/head               ",\r
221                 "status                 ",\r
222                 "dev control            ",\r
223                 "burst control          "\r
224         };\r
225 \r
226         for (i = 0; i < 9; i++) {\r
227                 target_read_u8(target, address + i * 2, &value);\r
228                 LOG_INFO("%s : 0x%2.2x", reg_name[i], value);\r
229         }\r
230 \r
231         return ERROR_OK;\r
232 \r
233 }\r
234 static int mflash_init_gpio (void)\r
235 {\r
236         mflash_gpio_drv_t *gpio_drv = mflash_bank->gpio_drv;\r
237 \r
238         gpio_drv->set_gpio_to_output(mflash_bank->rst_pin);\r
239         gpio_drv->set_gpio_output_val(mflash_bank->rst_pin, 1);\r
240 \r
241         if (mflash_bank->wp_pin.num != -1) {\r
242                 gpio_drv->set_gpio_to_output(mflash_bank->wp_pin);\r
243                 gpio_drv->set_gpio_output_val(mflash_bank->wp_pin, 1);\r
244         }\r
245 \r
246         if (mflash_bank->dpd_pin.num != -1) {\r
247                 gpio_drv->set_gpio_to_output(mflash_bank->dpd_pin);\r
248                 gpio_drv->set_gpio_output_val(mflash_bank->dpd_pin, 1);\r
249         }\r
250 \r
251         return ERROR_OK;\r
252 }\r
253 \r
254 static int mg_dsk_wait(mg_io_type_wait wait, u32 time)\r
255 {\r
256         u8 status, error;\r
257         target_t *target = mflash_bank->target;\r
258         u32 mg_task_reg = mflash_bank->base + MG_REG_OFFSET;\r
259         duration_t duration;\r
260         long long t=0;\r
261 \r
262         duration_start_measure(&duration);\r
263 \r
264     while (time) {\r
265 \r
266         target_read_u8(target, mg_task_reg + MG_REG_STATUS, &status);\r
267 \r
268         if (status & mg_io_rbit_status_busy)\r
269             {\r
270                 if (wait == mg_io_wait_bsy)\r
271                        return ERROR_OK;\r
272             } else {\r
273                 switch(wait)\r
274                 {\r
275                     case mg_io_wait_not_bsy:\r
276                         return ERROR_OK;\r
277                     case mg_io_wait_rdy_noerr:\r
278                         if (status & mg_io_rbit_status_ready)\r
279                             return ERROR_OK;\r
280                         break;\r
281                     case mg_io_wait_drq_noerr:\r
282                         if (status & mg_io_rbit_status_data_req)\r
283                             return ERROR_OK;\r
284                         break;\r
285                     default:\r
286                         break;\r
287                 }\r
288 \r
289                 // Now we check the error condition!\r
290                 if (status & mg_io_rbit_status_error)\r
291                 {\r
292                     target_read_u8(target, mg_task_reg + MG_REG_ERROR, &error);\r
293 \r
294                 if (error & mg_io_rbit_err_bad_sect_num) {\r
295                         LOG_ERROR("sector not found");\r
296                     return ERROR_FAIL;\r
297                 }\r
298                 else if (error & (mg_io_rbit_err_bad_block | mg_io_rbit_err_uncorrectable)) {\r
299                         LOG_ERROR("bad block");\r
300                     return ERROR_FAIL;\r
301                 } else {\r
302                         LOG_ERROR("disk operation fail");\r
303                         return ERROR_FAIL;\r
304                     }\r
305                 }\r
306 \r
307                 switch (wait)\r
308                 {\r
309                     case mg_io_wait_rdy:\r
310                         if (status & mg_io_rbit_status_ready)\r
311                             return ERROR_OK;\r
312 \r
313                     case mg_io_wait_drq:\r
314                         if (status & mg_io_rbit_status_data_req)\r
315                             return ERROR_OK;\r
316 \r
317                     default:\r
318                         break;\r
319                 }\r
320             }\r
321 \r
322         duration_stop_measure(&duration, NULL);\r
323 \r
324                 t=duration.duration.tv_usec/1000;\r
325                 t+=duration.duration.tv_sec*1000;\r
326 \r
327                 if (t > time)\r
328             break;\r
329     }\r
330 \r
331     LOG_ERROR("timeout occured");\r
332     return ERROR_FAIL;\r
333 }\r
334 \r
335 static int mg_dsk_srst(u8 on)\r
336 {\r
337         target_t *target = mflash_bank->target;\r
338         u32 mg_task_reg = mflash_bank->base + MG_REG_OFFSET;\r
339         u8 value;\r
340         int ret;\r
341 \r
342         if ((ret = target_read_u8(target, mg_task_reg + MG_REG_DRV_CTRL, &value)) != ERROR_OK)\r
343                 return ret;\r
344 \r
345         if(on) {\r
346                 value |= (mg_io_rbit_devc_srst);\r
347         } else {\r
348                 value &= ~mg_io_rbit_devc_srst;\r
349         }\r
350 \r
351         ret = target_write_u8(target, mg_task_reg + MG_REG_DRV_CTRL, value);\r
352         return ret;\r
353 }\r
354 \r
355 static int mg_dsk_io_cmd(u32 sect_num, u32 cnt, u8 cmd)\r
356 {\r
357         target_t *target = mflash_bank->target;\r
358         u32 mg_task_reg = mflash_bank->base + MG_REG_OFFSET;\r
359         u8 value;\r
360 \r
361         if (mg_dsk_wait(mg_io_wait_rdy_noerr, MG_OEM_DISK_WAIT_TIME_NORMAL) != ERROR_OK)\r
362                 return ERROR_FAIL;\r
363 \r
364         value = mg_io_rval_dev_drv_master | mg_io_rval_dev_lba_mode |((sect_num >> 24) & 0xf);\r
365 \r
366         target_write_u8(target, mg_task_reg + MG_REG_DRV_HEAD, value);\r
367         target_write_u8(target, mg_task_reg + MG_REG_SECT_CNT, (u8)cnt);\r
368         target_write_u8(target, mg_task_reg + MG_REG_SECT_NUM, (u8)sect_num);\r
369         target_write_u8(target, mg_task_reg + MG_REG_CYL_LOW, (u8)(sect_num >> 8));\r
370         target_write_u8(target, mg_task_reg + MG_REG_CYL_HIGH, (u8)(sect_num >> 16));\r
371 \r
372         target_write_u8(target, mg_task_reg + MG_REG_COMMAND, cmd);\r
373 \r
374         return ERROR_OK;\r
375 }\r
376 \r
377 static int mg_dsk_drv_info(void)\r
378 {\r
379         target_t *target = mflash_bank->target;\r
380         u32 mg_buff = mflash_bank->base + MG_BUFFER_OFFSET;\r
381 \r
382         if ( mg_dsk_io_cmd(0, 1, mg_io_cmd_identify) != ERROR_OK)\r
383                 return ERROR_FAIL;\r
384 \r
385         if ( mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL) != ERROR_OK)\r
386                 return ERROR_FAIL;\r
387 \r
388         LOG_INFO("read drive info.");\r
389 \r
390         if (! mflash_bank->drv_info)\r
391                 mflash_bank->drv_info = malloc(sizeof(mg_drv_info_t));\r
392 \r
393         target->type->read_memory(target, mg_buff, 2, sizeof(mg_io_type_drv_info) >> 1,\r
394                         (u8 *)&mflash_bank->drv_info->drv_id);\r
395 \r
396         mflash_bank->drv_info->tot_sects = (u32)(mflash_bank->drv_info->drv_id.total_user_addressable_sectors_hi << 16)\r
397                                                                         + mflash_bank->drv_info->drv_id.total_user_addressable_sectors_lo;\r
398 \r
399         target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_read);\r
400 \r
401         return ERROR_OK;\r
402 }\r
403 \r
404 static int mg_mflash_probe(void)\r
405 {\r
406         mflash_bank->proved = 0;\r
407 \r
408         mflash_init_gpio();\r
409 \r
410         LOG_INFO("reset mflash");\r
411 \r
412         mflash_rst(0);\r
413 \r
414         if (mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG) != ERROR_OK)\r
415                 return ERROR_FAIL;\r
416 \r
417         mflash_rst(1);\r
418 \r
419         if (mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG) != ERROR_OK)\r
420                 return ERROR_FAIL;\r
421 \r
422         mg_dsk_srst(1);\r
423 \r
424         if (mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG) != ERROR_OK)\r
425                 return ERROR_FAIL;\r
426 \r
427         mg_dsk_srst(0);\r
428 \r
429         if (mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG) != ERROR_OK)\r
430                 return ERROR_FAIL;\r
431 \r
432         if (mg_dsk_drv_info() != ERROR_OK)\r
433                 return ERROR_FAIL;\r
434 \r
435         mflash_bank->proved = 1;\r
436 \r
437         return ERROR_OK;\r
438 }\r
439 \r
440 static int mflash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
441 {\r
442         int ret;\r
443 \r
444         ret = mg_mflash_probe();\r
445 \r
446         if (ret == ERROR_OK) {\r
447                 command_print(cmd_ctx, "mflash (total %u sectors) found at 0x%8.8x",\r
448                                 mflash_bank->drv_info->tot_sects, mflash_bank->base );\r
449         }\r
450 \r
451         return ret;\r
452 }\r
453 \r
454 static int mg_mflash_do_read_sects(void *buff, u32 sect_num, u32 sect_cnt)\r
455 {\r
456         u32 i, address;\r
457         int ret;\r
458         target_t *target = mflash_bank->target;\r
459         u8 *buff_ptr = buff;\r
460         duration_t duration;\r
461 \r
462         if ( mg_dsk_io_cmd(sect_num, sect_cnt, mg_io_cmd_read) != ERROR_OK )\r
463                 return ERROR_FAIL;\r
464 \r
465         address = mflash_bank->base + MG_BUFFER_OFFSET;\r
466 \r
467         duration_start_measure(&duration);\r
468 \r
469         for (i = 0; i < sect_cnt; i++) {\r
470                 mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL);\r
471 \r
472                 target->type->read_memory(target, address, 2, MG_MFLASH_SECTOR_SIZE / 2, buff_ptr);\r
473                 buff_ptr += MG_MFLASH_SECTOR_SIZE;\r
474 \r
475                 target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_read);\r
476 \r
477                 LOG_DEBUG("%u (0x%8.8x) sector read", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE);\r
478 \r
479                 duration_stop_measure(&duration, NULL);\r
480 \r
481                 if ((duration.duration.tv_sec * 1000 + duration.duration.tv_usec / 1000) > 3000) {\r
482                         LOG_INFO("read %u'th sectors", sect_num + i);\r
483                         duration_start_measure(&duration);\r
484                 }\r
485         }\r
486 \r
487         ret = mg_dsk_wait(mg_io_wait_rdy, MG_OEM_DISK_WAIT_TIME_NORMAL);\r
488 \r
489         return ret;\r
490 }\r
491 \r
492 static int mg_mflash_read_sects(void *buff, u32 sect_num, u32 sect_cnt)\r
493 {\r
494         u32 quotient, residue, i;\r
495         u8 *buff_ptr = buff;\r
496 \r
497         quotient = sect_cnt >> 8;\r
498         residue = sect_cnt % 256;\r
499 \r
500         for (i = 0; i < quotient; i++) {\r
501                 LOG_DEBUG("sect num : %u buff : 0x%8.8x", sect_num, (u32)buff_ptr);\r
502                 mg_mflash_do_read_sects(buff_ptr, sect_num, 256);\r
503                 sect_num += 256;\r
504                 buff_ptr += 256 * MG_MFLASH_SECTOR_SIZE;\r
505         }\r
506 \r
507         if (residue) {\r
508                 LOG_DEBUG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);\r
509                 mg_mflash_do_read_sects(buff_ptr, sect_num, residue);\r
510         }\r
511 \r
512         return ERROR_OK;\r
513 }\r
514 \r
515 static int mg_mflash_do_write_sects(void *buff, u32 sect_num, u32 sect_cnt)\r
516 {\r
517         u32 i, address;\r
518         int ret;\r
519         target_t *target = mflash_bank->target;\r
520         u8 *buff_ptr = buff;\r
521         duration_t duration;\r
522 \r
523         if ( mg_dsk_io_cmd(sect_num, sect_cnt, mg_io_cmd_write) != ERROR_OK ) {\r
524                 LOG_ERROR("mg_io_cmd_write fail");\r
525                 return ERROR_FAIL;\r
526         }\r
527 \r
528         address = mflash_bank->base + MG_BUFFER_OFFSET;\r
529 \r
530         duration_start_measure(&duration);\r
531 \r
532         for (i = 0; i < sect_cnt; i++) {\r
533                 ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL);\r
534                 if (ret != ERROR_OK)\r
535                         LOG_ERROR("mg_io_wait_drq time out");\r
536 \r
537                 ret = target->type->write_memory(target, address, 2, MG_MFLASH_SECTOR_SIZE / 2, buff_ptr);\r
538                 if (ret != ERROR_OK)\r
539                         LOG_ERROR("mem write error");\r
540                 buff_ptr += MG_MFLASH_SECTOR_SIZE;\r
541 \r
542                 ret = target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_write);\r
543                 if (ret != ERROR_OK)\r
544                         LOG_ERROR("mg_io_cmd_confirm_write error");\r
545 \r
546                 LOG_DEBUG("%u (0x%8.8x) sector write", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE);\r
547 \r
548                 duration_stop_measure(&duration, NULL);\r
549 \r
550                 if ((duration.duration.tv_sec * 1000 + duration.duration.tv_usec / 1000) > 3000) {\r
551                         LOG_INFO("wrote %u'th sectors", sect_num + i);\r
552                         duration_start_measure(&duration);\r
553                 }\r
554         }\r
555 \r
556         ret = mg_dsk_wait(mg_io_wait_rdy, MG_OEM_DISK_WAIT_TIME_NORMAL);\r
557 \r
558         return ret;\r
559 }\r
560 \r
561 static int mg_mflash_write_sects(void *buff, u32 sect_num, u32 sect_cnt)\r
562 {\r
563         u32 quotient, residue, i;\r
564         u8 *buff_ptr = buff;\r
565 \r
566         quotient = sect_cnt >> 8;\r
567         residue = sect_cnt % 256;\r
568 \r
569         for (i = 0; i < quotient; i++) {\r
570                 LOG_DEBUG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);\r
571                 mg_mflash_do_write_sects(buff_ptr, sect_num, 256);\r
572                 sect_num += 256;\r
573                 buff_ptr += 256 * MG_MFLASH_SECTOR_SIZE;\r
574         }\r
575 \r
576         if (residue) {\r
577                 LOG_DEBUG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);\r
578                 mg_mflash_do_write_sects(buff_ptr, sect_num, residue);\r
579         }\r
580 \r
581         return ERROR_OK;\r
582 }\r
583 \r
584 static int mg_mflash_read (u32 addr, u8 *buff, u32 len)\r
585 {\r
586         u8 *sect_buff, *buff_ptr = buff;\r
587         u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num;\r
588 \r
589         cnt = 0;\r
590         cur_addr = addr;\r
591         end_addr = addr + len;\r
592 \r
593         sect_buff = malloc(MG_MFLASH_SECTOR_SIZE);\r
594 \r
595         if (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK) {\r
596 \r
597                 next_sec_addr = (cur_addr + MG_MFLASH_SECTOR_SIZE) & ~MG_MFLASH_SECTOR_SIZE_MASK;\r
598                 sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT;\r
599                 mg_mflash_read_sects(sect_buff, sect_num, 1);\r
600 \r
601                 if (end_addr < next_sec_addr) {\r
602                         memcpy(buff_ptr, sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), end_addr - cur_addr);\r
603                         LOG_DEBUG("copies %u byte from sector offset 0x%8.8x", end_addr - cur_addr, cur_addr);\r
604                         cur_addr = end_addr;\r
605                 } else {\r
606                         memcpy(buff_ptr, sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), next_sec_addr - cur_addr);\r
607                         LOG_DEBUG("copies %u byte from sector offset 0x%8.8x", next_sec_addr - cur_addr, cur_addr);\r
608                         buff_ptr += (next_sec_addr - cur_addr);\r
609                         cur_addr = next_sec_addr;\r
610                 }\r
611         }\r
612 \r
613         if (cur_addr < end_addr) {\r
614 \r
615                 sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT;\r
616                 next_sec_addr = cur_addr + MG_MFLASH_SECTOR_SIZE;\r
617 \r
618                 while (next_sec_addr <= end_addr) {\r
619                         cnt++;\r
620                         next_sec_addr += MG_MFLASH_SECTOR_SIZE;\r
621                 }\r
622 \r
623                 if (cnt)\r
624                         mg_mflash_read_sects(buff_ptr, sect_num, cnt);\r
625 \r
626                 buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE;\r
627                 cur_addr += cnt * MG_MFLASH_SECTOR_SIZE;\r
628 \r
629                 if (cur_addr < end_addr) {\r
630 \r
631                         sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT;\r
632                         mg_mflash_read_sects(sect_buff, sect_num, 1);\r
633                         memcpy(buff_ptr, sect_buff, end_addr - cur_addr);\r
634                         LOG_DEBUG("copies %u byte", end_addr - cur_addr);\r
635 \r
636                 }\r
637 \r
638         }\r
639 \r
640         free(sect_buff);\r
641 \r
642         return ERROR_OK;\r
643 }\r
644 \r
645 static int mg_mflash_write(u32 addr, u8 *buff, u32 len)\r
646 {\r
647         u8 *sect_buff, *buff_ptr = buff;\r
648         u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num;\r
649 \r
650         cnt = 0;\r
651         cur_addr = addr;\r
652         end_addr = addr + len;\r
653 \r
654         sect_buff = malloc(MG_MFLASH_SECTOR_SIZE);\r
655 \r
656         if (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK) {\r
657 \r
658                 next_sec_addr = (cur_addr + MG_MFLASH_SECTOR_SIZE) & ~MG_MFLASH_SECTOR_SIZE_MASK;\r
659                 sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT;\r
660                 mg_mflash_read_sects(sect_buff, sect_num, 1);\r
661 \r
662                 if (end_addr < next_sec_addr) {\r
663                         memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), buff_ptr, end_addr - cur_addr);\r
664                         LOG_DEBUG("copies %u byte to sector offset 0x%8.8x", end_addr - cur_addr, cur_addr);\r
665                         cur_addr = end_addr;\r
666                 } else {\r
667                         memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), buff_ptr, next_sec_addr - cur_addr);\r
668                         LOG_DEBUG("copies %u byte to sector offset 0x%8.8x", next_sec_addr - cur_addr, cur_addr);\r
669                         buff_ptr += (next_sec_addr - cur_addr);\r
670                         cur_addr = next_sec_addr;\r
671                 }\r
672 \r
673                 mg_mflash_write_sects(sect_buff, sect_num, 1);\r
674 \r
675         }\r
676 \r
677         if (cur_addr < end_addr) {\r
678 \r
679                 sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT;\r
680                 next_sec_addr = cur_addr + MG_MFLASH_SECTOR_SIZE;\r
681 \r
682                 while (next_sec_addr <= end_addr) {\r
683                         cnt++;\r
684                         next_sec_addr += MG_MFLASH_SECTOR_SIZE;\r
685                 }\r
686 \r
687                 if (cnt)\r
688                         mg_mflash_write_sects(buff_ptr, sect_num, cnt);\r
689 \r
690                 buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE;\r
691                 cur_addr += cnt * MG_MFLASH_SECTOR_SIZE;\r
692 \r
693                 if (cur_addr < end_addr) {\r
694 \r
695                         sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT;\r
696                         mg_mflash_read_sects(sect_buff, sect_num, 1);\r
697                         memcpy(sect_buff, buff_ptr, end_addr - cur_addr);\r
698                         LOG_DEBUG("copies %u byte", end_addr - cur_addr);\r
699                         mg_mflash_write_sects(sect_buff, sect_num, 1);\r
700 \r
701                 }\r
702 \r
703         }\r
704 \r
705         free(sect_buff);\r
706 \r
707         return ERROR_OK;\r
708 }\r
709 \r
710 static int mflash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
711 {\r
712         u32 address, buf_cnt;\r
713         u8 *buffer;\r
714         // TODO : multi-bank support, large file support\r
715         fileio_t fileio;\r
716         duration_t duration;\r
717         char *duration_text;\r
718         int ret;\r
719 \r
720         if (argc != 3) {\r
721                 return ERROR_COMMAND_SYNTAX_ERROR;\r
722         }\r
723 \r
724         address = strtoul(args[2], NULL, 0);\r
725 \r
726         if (! mflash_bank->proved ) {\r
727                 mg_mflash_probe();\r
728         }\r
729 \r
730 \r
731         if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) {\r
732                 return ERROR_FAIL;\r
733         }\r
734 \r
735         buffer = malloc(fileio.size);\r
736 \r
737         if (fileio_read(&fileio, fileio.size, buffer, &buf_cnt) != ERROR_OK)\r
738         {\r
739                 free(buffer);\r
740                 fileio_close(&fileio);\r
741                 return ERROR_FAIL;\r
742         }\r
743 \r
744         duration_start_measure(&duration);\r
745 \r
746         ret = mg_mflash_write(address, buffer, (u32)fileio.size);\r
747 \r
748         duration_stop_measure(&duration, &duration_text);\r
749 \r
750         command_print(cmd_ctx, "wrote %lli byte from file %s in %s (%f kB/s)",\r
751                 fileio.size, args[1], duration_text,\r
752                 (float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));\r
753 \r
754         free(duration_text);\r
755 \r
756         fileio_close(&fileio);\r
757 \r
758         free(buffer);\r
759 \r
760         return ERROR_OK;\r
761 }\r
762 \r
763 static int mflash_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
764 {\r
765         u32 address, size_written, size;\r
766         u8 *buffer;\r
767         // TODO : multi-bank support\r
768         fileio_t fileio;\r
769         duration_t duration;\r
770         char *duration_text;\r
771 \r
772         if (argc != 4) {\r
773                 return ERROR_COMMAND_SYNTAX_ERROR;\r
774         }\r
775 \r
776         address = strtoul(args[2], NULL, 0);\r
777         size = strtoul(args[3], NULL, 0);\r
778 \r
779         if (! mflash_bank->proved ) {\r
780                         mg_mflash_probe();\r
781         }\r
782 \r
783         if (fileio_open(&fileio, args[1], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) {\r
784                 return ERROR_FAIL;\r
785         }\r
786 \r
787         buffer = malloc(size);\r
788 \r
789         duration_start_measure(&duration);\r
790 \r
791         mg_mflash_read(address, buffer, size);\r
792 \r
793         duration_stop_measure(&duration, &duration_text);\r
794 \r
795         fileio_write(&fileio, size, buffer, &size_written);\r
796 \r
797         command_print(cmd_ctx, "dump image (address 0x%8.8x size %u) to file %s in %s (%f kB/s)",\r
798                                 address, size, args[1], duration_text,\r
799                                 (float)size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));\r
800 \r
801         free(duration_text);\r
802 \r
803         fileio_close(&fileio);\r
804 \r
805         free(buffer);\r
806 \r
807         return ERROR_OK;\r
808 }\r
809 \r
810 int mflash_init_drivers(struct command_context_s *cmd_ctx)\r
811 {\r
812         if (mflash_bank) {\r
813                 register_command(cmd_ctx, mflash_cmd, "probe", mflash_probe_command, COMMAND_EXEC, NULL);\r
814                 register_command(cmd_ctx, mflash_cmd, "write", mflash_write_command, COMMAND_EXEC,\r
815                                 "mflash write <num> <file> <address>");\r
816                 register_command(cmd_ctx, mflash_cmd, "dump", mflash_dump_command, COMMAND_EXEC,\r
817                                                 "mflash dump <num> <file> <address> <size>");\r
818         }\r
819 \r
820         return ERROR_OK;\r
821 }\r
822 \r
823 static int mflash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
824 {\r
825         target_t *target;\r
826         char *str;\r
827         int i;\r
828 \r
829         if (argc < 8)\r
830         {\r
831                 return ERROR_COMMAND_SYNTAX_ERROR;\r
832         }\r
833 \r
834         if ((target = get_target_by_num(strtoul(args[7], NULL, 0))) == NULL)\r
835         {\r
836                 LOG_ERROR("target %lu not defined", strtoul(args[7], NULL, 0));\r
837                 return ERROR_FAIL;\r
838         }\r
839 \r
840         mflash_bank = calloc(sizeof(mflash_bank_t), 1);\r
841         mflash_bank->base = strtoul(args[1], NULL, 0);\r
842         mflash_bank->chip_width = strtoul(args[2], NULL, 0);\r
843         mflash_bank->bus_width = strtoul(args[3], NULL, 0);\r
844         mflash_bank->rst_pin.num = strtoul(args[4], &str, 0);\r
845         if (*str)\r
846                 mflash_bank->rst_pin.port[0] = (u16)tolower(str[0]);\r
847         mflash_bank->wp_pin.num = strtol(args[5], &str, 0);\r
848         if (*str)\r
849                 mflash_bank->wp_pin.port[0] = (u16)tolower(str[0]);\r
850         mflash_bank->dpd_pin.num = strtol(args[6], &str, 0);\r
851         if (*str)\r
852                 mflash_bank->dpd_pin.port[0] = (u16)tolower(str[0]);\r
853 \r
854         mflash_bank->target = target;\r
855 \r
856         for (i = 0; mflash_gpio[i] ; i++) {\r
857                 if (! strcmp(mflash_gpio[i]->name, args[0])) {\r
858                         mflash_bank->gpio_drv = mflash_gpio[i];\r
859                 }\r
860         }\r
861 \r
862         if (! mflash_bank->gpio_drv) {\r
863                 LOG_ERROR("%s is unsupported soc", args[0]);\r
864                 return ERROR_INVALID_ARGUMENTS;\r
865         }\r
866 \r
867         return ERROR_OK;\r
868 }\r
869 \r
870 int mflash_register_commands(struct command_context_s *cmd_ctx)\r
871 {\r
872         mflash_cmd = register_command(cmd_ctx, NULL, "mflash", NULL, COMMAND_ANY, NULL);\r
873         register_command(cmd_ctx, mflash_cmd, "bank", mflash_bank_command, COMMAND_CONFIG,\r
874                         "mflash bank <soc> <base> <chip_width> <bus_width> <RST pin> <WP pin> <DPD pin> <target #>");\r
875         return ERROR_OK;\r
876 }\r