Root/usbboot/src/nand.c

1#include <stdlib.h>
2#include <stdio.h>
3#include <fcntl.h>
4#include <unistd.h>
5#include <errno.h>
6#include <sys/stat.h>
7#include <string.h>
8
9#include "nand.h"
10#include "ingenic_usb.h"
11#include "usb_boot_defines.h"
12
13#define NAND_OP(idx, op, mode) (((mode << 12) & 0xf000) | ((idx << 4) & 0xff0) | op)
14
15#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
16
17static const char IMAGE_TYPE[][30] = {
18    "with oob and ecc",
19    "with oob and without ecc",
20    "without oob",
21};
22
23static int error_check(const char *a, const char *b, unsigned int size)
24{
25    unsigned int i;
26    const unsigned char *org = (const unsigned char *)a;
27    const unsigned char *obj= (const unsigned char *)b;
28
29
30    printf("Comparing %d bytes - ", size);
31    for (i = 0; i < size; i++) {
32        if (org[i] != obj[i]) {
33            unsigned int s = (i < 8) ? i : i - 8; // start_dump
34            printf("FAIL at off %d, wrote 0x%x, read 0x%x\n", i, org[i], obj[i]);
35            printf(" off %d write: %02x %02x %02x %02x %02x %02x %02x %02x"
36                   " %02x %02x %02x %02x %02x %02x %02x %02x\n", s,
37                org[s], org[s+1], org[s+2], org[s+3], org[s+4], org[s+5], org[s+6], org[s+7],
38                org[s+8], org[s+9], org[s+10], org[s+11], org[s+12], org[s+13], org[s+14], org[s+15]);
39            printf(" off %d read: %02x %02x %02x %02x %02x %02x %02x %02x"
40                   " %02x %02x %02x %02x %02x %02x %02x %02x\n", s,
41                obj[s], obj[s+1], obj[s+2], obj[s+3], obj[s+4], obj[s+5], obj[s+6], obj[s+7],
42                obj[s+8], obj[s+9], obj[s+10], obj[s+11], obj[s+12], obj[s+13], obj[s+14], obj[s+15]);
43            return 0;
44        }
45    }
46    printf("SUCCESS\n");
47    return 1;
48}
49
50static int nand_read_pages(struct ingenic_dev *dev, unsigned int start_page, int num_pages, char *buf,
51                          int length, uint16_t op, char *ret)
52{
53        usb_send_data_address_to_ingenic(dev, start_page);
54        usb_send_data_length_to_ingenic(dev, num_pages);
55
56        usb_ingenic_nand_ops(dev, op);
57
58        usb_read_data_from_ingenic(dev, buf, length);
59
60        usb_read_data_from_ingenic(dev, ret, 8);
61
62        return 0;
63}
64int nand_markbad(struct ingenic_dev *dev, uint8_t nand_idx, uint32_t block)
65{
66    char ret[8];
67    (void)nand_idx;
68
69    if (usb_get_ingenic_cpu(dev) < 3) {
70        fprintf(stderr, "Device unboot! Boot it first!\n");
71        return -ENODEV;
72    }
73    printf("Mark bad block : %d\n", block);
74    usb_send_data_address_to_ingenic(dev, block);
75    usb_ingenic_nand_ops(dev, NAND_MARK_BAD);
76    usb_read_data_from_ingenic(dev, ret, ARRAY_SIZE(ret));
77    printf("Mark bad block at %d\n",((ret[3] << 24) |
78                       (ret[2] << 16) |
79                       (ret[1] << 8) |
80                       (ret[0] << 0)) / dev->config.nand_ppb);
81
82    return 0;
83}
84
85int nand_program_check(struct ingenic_dev *dev, uint8_t nand_idx,
86                        unsigned int start_page, const char *data,
87                        uint32_t length, unsigned int mode)
88{
89    unsigned int page_num, cur_page = -1;
90    unsigned short op;
91    static char read_back_buf[MAX_TRANSFER_SIZE];
92    char ret[8];
93
94    printf("Writing NAND page %u len %u...\n", start_page, length);
95    if (length > (unsigned int)MAX_TRANSFER_SIZE) {
96        fprintf(stderr, "Buffer size too long!\n");
97        return -EINVAL;
98    }
99
100    if (usb_get_ingenic_cpu(dev) < 3) {
101        fprintf(stderr, "Device unboot! Boot it first!\n");
102        return -ENODEV;
103    }
104    usb_send_data_to_ingenic(dev, data, length);
105
106    if (mode == NO_OOB)
107        page_num = DIV_ROUND_UP(length, dev->config.nand_ps);
108    else
109        page_num = DIV_ROUND_UP(length, dev->config.nand_ps + dev->config.nand_os);
110
111    op = NAND_OP(nand_idx, NAND_PROGRAM, mode);
112
113    usb_send_data_address_to_ingenic(dev, start_page);
114    usb_send_data_length_to_ingenic(dev, page_num);
115    usb_ingenic_nand_ops(dev, op);
116
117    usb_read_data_from_ingenic(dev, ret, 8);
118    printf("Finish! (len %d start_page %d page_num %d)\n",
119               length, start_page, page_num);
120
121    switch(mode) {
122    case NO_OOB:
123        op = NAND_OP(nand_idx, NAND_READ, NO_OOB);
124        break;
125    default:
126        op = NAND_OP(nand_idx, NAND_READ_RAW, OOB_ECC);
127        break;
128    }
129
130    nand_read_pages(dev, start_page, page_num, read_back_buf, length, op, ret);
131    printf("Checking %d bytes...", length);
132
133    cur_page = (ret[3] << 24) | (ret[2] << 16) | (ret[1] << 8) |
134        (ret[0] << 0);
135
136    if (start_page < 1 &&
137        dev->config.nand_ps == 4096 &&
138        dev->config.fw_args.cpu_id == 0x4740) {
139        printf("no check! End at Page: %d\n", cur_page);
140    }
141
142    if (!error_check(data, read_back_buf, length)) {
143        // tbd: doesn't the other side skip bad blocks too? Can we just deduct 1 from cur_page?
144        // tbd: why do we only mark a block as bad if the last page in the block was written?
145        if (cur_page % dev->config.nand_ppb == 0)
146            nand_markbad(dev, nand_idx, (cur_page - 1) / dev->config.nand_ppb);
147    }
148
149    printf("End at Page: %d\n", cur_page);
150
151/* *start_page = cur_page;*/
152    return 0;
153}
154
155int nand_erase(struct ingenic_dev *dev, uint8_t nand_idx, uint32_t start_block,
156                uint32_t num_blocks)
157{
158    uint32_t end_block;
159    uint16_t op;
160    static char ret[8];
161
162    if (start_block > (unsigned int)NAND_MAX_BLK_NUM) {
163        fprintf(stderr, "Start block number overflow!\n");
164        return -EINVAL;
165    }
166    if (num_blocks > (unsigned int)NAND_MAX_BLK_NUM) {
167        fprintf(stderr, "Length block number overflow!\n");
168        return -EINVAL;
169    }
170
171    if (usb_get_ingenic_cpu(dev) < 3) {
172        fprintf(stderr, "Device unboot! Boot it first!\n");
173        return -ENODEV;
174    }
175
176    printf("Erasing No.%d device No.%d flash (start_blk %u blk_num %u)......\n",
177           0, nand_idx, start_block, num_blocks);
178
179    usb_send_data_address_to_ingenic(dev, start_block);
180    usb_send_data_length_to_ingenic(dev, num_blocks);
181
182    op = NAND_OP(nand_idx, NAND_ERASE, 0);
183    usb_ingenic_nand_ops(dev, op);
184
185    usb_read_data_from_ingenic(dev, ret, 8);
186    printf("Finish!");
187
188    end_block = ((ret[3] << 24) | (ret[2] << 16) |
189             (ret[1] << 8) | (ret[0] << 0)) / dev->config.nand_ppb;
190    printf("Return: %02x %02x %02x %02x %02x %02x %02x %02x (position %d)\n",
191           ret[0], ret[1], ret[2], ret[3], ret[4], ret[5], ret[6], ret[7], end_block);
192    if (!dev->config.nand_force_erase) {
193    /* not force erase, show bad block infomation */
194        printf("There are marked bad blocks: %d\n",
195               end_block - start_block - num_blocks );
196    } else {
197    /* force erase, no bad block infomation can show */
198        printf("Force erase, no bad block infomation!\n" );
199    }
200
201    return 0;
202}
203
204int nand_program_file(struct ingenic_dev *dev, uint8_t nand_idx,
205                    uint32_t start_page, const char *filename, int mode)
206{
207    uint32_t start_block, num_blocks;
208    int flen, m, j, k;
209    unsigned int page_num, code_len, offset, transfer_size;
210    int fd, status;
211    struct stat fstat;
212    static char code_buf[MAX_TRANSFER_SIZE];
213
214    status = stat(filename, &fstat);
215
216    if (status < 0) {
217        fprintf(stderr, "Error - can't get file size from '%s': %s\n",
218            filename, strerror(errno));
219        return -EEXIST;
220    }
221    flen = fstat.st_size;
222
223    fd = open(filename, O_RDONLY);
224    if (fd < 0) {
225        fprintf(stderr, "Error - can't open file '%s': %s\n",
226            filename, strerror(errno));
227        return errno;
228    }
229
230    printf("Programing No.%d device, flen %d, start page %d...\n", 0,
231            flen, start_page);
232
233    /* printf("length %d flen %d\n", n_in.length, flen); */
234    if (mode == NO_OOB)
235        transfer_size = (dev->config.nand_ppb * dev->config.nand_ps);
236    else
237        transfer_size = (dev->config.nand_ppb * (dev->config.nand_ps +
238        dev->config.nand_os));
239
240    start_block = start_page / dev->config.nand_ppb;
241    num_blocks = flen / (transfer_size - 1) + 1;
242
243    if (nand_erase(dev, nand_idx, start_block, num_blocks))
244        return -1;
245
246    m = flen / transfer_size;
247    j = flen % transfer_size;
248
249    printf("Size to send %d, transfer_size %d\n", flen, transfer_size);
250/* printf("Image type : %s\n", IMAGE_TYPE[mode]);*/
251    printf("It will cause %d times buffer transfer.\n", j == 0 ? m : m + 1);
252
253    if (mode == NO_OOB)
254        page_num = transfer_size / dev->config.nand_ps;
255    else
256        page_num = transfer_size / (dev->config.nand_ps + dev->config.nand_os);
257
258
259    offset = 0;
260    for (k = 0; k < m; k++) {
261        code_len = transfer_size;
262        status = read(fd, code_buf, code_len);
263        if (status < (int)code_len) {
264            fprintf(stderr, "Error - can't read file '%s': %s\n",
265                filename, strerror(errno));
266            goto close;
267        }
268
269        if (nand_program_check(dev, nand_idx, start_page, code_buf, code_len, mode) == -1)
270            goto close;
271
272/* if (start_page - nand_in->start > dev->config.nand_ppb)
273            printf("Skip a old bad block !\n");*/
274
275        offset += code_len ;
276    }
277
278    if (j) {
279        code_len = j;
280        if (j % dev->config.nand_ps)
281            j += dev->config.nand_ps - (j % dev->config.nand_ps);
282        memset(code_buf, 0, j); /* set all to null */
283
284        status = read(fd, code_buf, code_len);
285
286        if (status < (int)code_len) {
287            fprintf(stderr, "Error - can't read file '%s': %s\n",
288                filename, strerror(errno));
289            goto close;
290        }
291
292        if (nand_program_check(dev, nand_idx, start_page, code_buf, j, mode) == -1)
293            goto close;
294
295/*
296        if (start_page - nand_in->start > dev->config.nand_ppb)
297            printf("Skip a old bad block !");
298*/
299    }
300close:
301    close(fd);
302    return 0;
303}
304
305int nand_prog(struct ingenic_dev *dev, uint8_t nand_idx, uint32_t start_page,
306            const char *filename, int mode)
307{
308    if (dev->config.nand_plane > 1)
309        printf("ERROR");
310    else
311        nand_program_file(dev, nand_idx, start_page, filename, mode);
312
313    return 0;
314}
315
316int nand_query(struct ingenic_dev *dev, uint8_t nand_idx)
317{
318    uint16_t op;
319    char ret[8] = {0,0,0,0,0,0,0,0};
320    int ret2;
321
322    if (usb_get_ingenic_cpu(dev) < 3) {
323        fprintf(stderr, "Device unboot! Boot it first!\n");
324        return -ENODEV;
325    }
326
327    printf("ID of No.%u device No.%u flash: \n", 0, nand_idx);
328
329    op = NAND_OP(nand_idx, NAND_QUERY, 0);
330
331    usb_ingenic_nand_ops(dev, op);
332    ret2 = usb_read_data_from_ingenic(dev, ret, ARRAY_SIZE(ret));
333
334    if (ret2 < 0)
335        return ret2;
336
337    printf("Vendor ID :0x%x \n", (unsigned char)ret[0]);
338    printf("Product ID :0x%x \n", (unsigned char)ret[1]);
339    printf("Chip ID :0x%x \n", (unsigned char)ret[2]);
340    printf("Page ID :0x%x \n", (unsigned char)ret[3]);
341    printf("Plane ID :0x%x \n", (unsigned char)ret[4]);
342
343    usb_read_data_from_ingenic(dev, ret, ARRAY_SIZE(ret));
344    printf("Operation status: Success!\n");
345
346    return 0;
347}
348
349int nand_read(struct ingenic_dev *dev, uint8_t nand_idx, int mode,
350                uint32_t start_page, uint32_t length, uint32_t ram_addr,
351                nand_read_cb_t callback, void *userdata)
352{
353    uint16_t op;
354    uint32_t page;
355    uint32_t request_length;
356    uint32_t pages_per_request;
357    char ret[8];
358    char *buf;
359    int ret2;
360
361    if (start_page > NAND_MAX_PAGE_NUM) {
362        fprintf(stderr, "Page number overflow!\n");
363        return -EINVAL;
364    }
365    if (usb_get_ingenic_cpu(dev) < 3) {
366        fprintf(stderr, "Device unboot! Boot it first!\n");
367        return -EINVAL;
368    }
369    if (nand_idx >= 16)
370        return -EINVAL;
371
372    printf("Reading from No.%u device No.%u flash....\n", 0, nand_idx);
373
374
375    switch(mode) {
376    case NAND_READ:
377        op = NAND_OP(nand_idx, NAND_READ, NO_OOB);
378        break;
379    case NAND_READ_OOB:
380        op = NAND_OP(nand_idx, NAND_READ_OOB, 0);
381        break;
382    case NAND_READ_RAW:
383        op = NAND_OP(nand_idx, NAND_READ_RAW, OOB_ECC);
384        break;
385    case NAND_READ_TO_RAM:
386        op = NAND_OP(nand_idx, NAND_READ_TO_RAM, NO_OOB);
387        usb_ingenic_start(dev, VR_PROGRAM_START1, ram_addr);
388        break;
389    default:
390        return -EINVAL;
391    }
392
393    pages_per_request = 1;
394    if (mode == NAND_READ_OOB || mode == NAND_READ_RAW)
395        request_length = (dev->config.nand_ps + dev->config.nand_os) * pages_per_request;
396    else
397        request_length = dev->config.nand_ps * pages_per_request;
398
399    page = start_page;
400
401    buf = malloc(request_length);
402
403    while (length > 0) {
404        if (request_length > length)
405            request_length = length;
406
407        nand_read_pages(dev, page, pages_per_request, buf, request_length, op, ret);
408
409        ret2 = callback(userdata, buf, request_length);
410        if (ret2)
411            return ret2;
412
413        length -= request_length;
414        page += pages_per_request;
415    }
416
417    printf("Operation end position : %u \n",
418           (ret[3]<<24)|(ret[2]<<16)|(ret[1]<<8)|(ret[0]<<0));
419    free(buf);
420
421    return 0;
422}
423

Archive Download this file



interactive