Skip to content

Commit 833912b

Browse files
committed
Read bad blocks automatically if skip flag is set
1 parent 41ccee2 commit 833912b

File tree

3 files changed

+124
-59
lines changed

3 files changed

+124
-59
lines changed

firmware/nand_bad_block.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,30 @@ bool nand_bad_block_table_lookup(uint32_t addr)
3838

3939
return false;
4040
}
41+
42+
void *nand_bad_block_table_iter_alloc(uint32_t *addr)
43+
{
44+
if (!nand_bad_block_table_count)
45+
return NULL;
46+
47+
*addr = nand_bad_block_table[0];
48+
49+
return &nand_bad_block_table[0];
50+
}
51+
52+
void *nand_bad_block_table_iter_next(void *iter, uint32_t *addr)
53+
{
54+
uint32_t *bbt_iter = iter;
55+
56+
if (!bbt_iter)
57+
return NULL;
58+
59+
bbt_iter++;
60+
61+
if (bbt_iter - &nand_bad_block_table[0] >= nand_bad_block_table_count)
62+
return NULL;
63+
64+
*addr = *bbt_iter;
65+
66+
return bbt_iter;
67+
}

firmware/nand_bad_block.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@
1212
void nand_bad_block_table_init();
1313
int nand_bad_block_table_add(uint32_t addr);
1414
bool nand_bad_block_table_lookup(uint32_t addr);
15+
void *nand_bad_block_table_iter_alloc(uint32_t *addr);
16+
void *nand_bad_block_table_iter_next(void *iter, uint32_t *addr);
1517

1618
#endif

firmware/nand_programmer.c

Lines changed: 95 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ enum
5151
NP_ERR_LEN_NOT_ALIGN = -111,
5252
NP_ERR_LEN_EXCEEDED = -112,
5353
NP_ERR_LEN_INVALID = -113,
54+
NP_ERR_BBT_OVERFLOW = -114,
5455
};
5556

5657
typedef struct __attribute__((__packed__))
@@ -170,6 +171,7 @@ typedef struct
170171
uint32_t addr;
171172
uint32_t len;
172173
int addr_is_set;
174+
int bb_is_read;
173175
np_page_t page;
174176
uint32_t bytes_written;
175177
uint32_t bytes_ack;
@@ -251,6 +253,73 @@ static int np_cmd_nand_read_id(np_prog_t *prog)
251253
return ret;
252254
}
253255

256+
static int np_read_bad_block_info_from_page(np_prog_t *prog, uint32_t block,
257+
uint32_t page, chip_info_t *chip_info, bool *is_bad)
258+
{
259+
uint8_t bad_block_data;
260+
uint32_t status, addr = block * chip_info->block_size;
261+
262+
status = nand_read_data(&bad_block_data, page, chip_info->page_size,
263+
sizeof(bad_block_data));
264+
switch (status)
265+
{
266+
case NAND_READY:
267+
break;
268+
case NAND_ERROR:
269+
ERROR_PRINT("NAND read bad block info error at 0x%lx\r\n", addr);
270+
return NP_ERR_NAND_RD;
271+
case NAND_TIMEOUT_ERROR:
272+
ERROR_PRINT("NAND read timeout at 0x%lx\r\n", addr);
273+
return NP_ERR_NAND_RD;
274+
default:
275+
ERROR_PRINT("Unknown NAND status\r\n");
276+
return NP_ERR_NAND_RD;
277+
}
278+
279+
*is_bad = bad_block_data != NP_NAND_GOOD_BLOCK_MARK;
280+
281+
return 0;
282+
}
283+
284+
static int _np_cmd_read_bad_blocks(np_prog_t *prog)
285+
{
286+
int ret;
287+
bool is_bad;
288+
uint32_t block, block_num, page_num, page;
289+
290+
block_num = prog->chip_info->size / prog->chip_info->block_size;
291+
page_num = prog->chip_info->block_size / prog->chip_info->page_size;
292+
293+
/* Bad block - not 0xFF value in the first or second page in the block at
294+
* zero offset in the page spare area
295+
*/
296+
for (block = 0; block < block_num; block++)
297+
{
298+
page = block * page_num;
299+
if ((ret = np_read_bad_block_info_from_page(prog, block, page,
300+
prog->chip_info, &is_bad)))
301+
{
302+
return ret;
303+
}
304+
305+
if (!is_bad && (ret = np_read_bad_block_info_from_page(prog, block,
306+
page + 1, prog->chip_info, &is_bad)))
307+
{
308+
return ret;
309+
}
310+
311+
if (is_bad && nand_bad_block_table_add(block *
312+
prog->chip_info->block_size))
313+
{
314+
return NP_ERR_BBT_OVERFLOW;
315+
}
316+
}
317+
318+
prog->bb_is_read = 1;
319+
320+
return 0;
321+
}
322+
254323
static int np_nand_erase(np_prog_t *prog, uint32_t page)
255324
{
256325
uint32_t status;
@@ -280,6 +349,7 @@ static int np_nand_erase(np_prog_t *prog, uint32_t page)
280349

281350
static int _np_cmd_nand_erase(np_prog_t *prog)
282351
{
352+
int ret;
283353
uint32_t addr, page, pages_in_block, len;
284354
np_erase_cmd_t *erase_cmd = (np_erase_cmd_t *)prog->rx_buf;
285355
bool is_bad = false, skip_bb = erase_cmd->flags.skip_bb;
@@ -289,6 +359,9 @@ static int _np_cmd_nand_erase(np_prog_t *prog)
289359

290360
DEBUG_PRINT("Erase at 0x%lx %lx bytes command\r\n", addr, len);
291361

362+
if (skip_bb && !prog->bb_is_read && (ret = _np_cmd_read_bad_blocks(prog)))
363+
return ret;
364+
292365
if (addr & (prog->chip_info->block_size - 1))
293366
{
294367
ERROR_PRINT("Address 0x%lx is not aligned to block size 0x%lx\r\n",
@@ -372,6 +445,7 @@ static int np_send_write_ack(uint32_t bytes_ack)
372445

373446
static int np_cmd_nand_write_start(np_prog_t *prog)
374447
{
448+
int ret;
375449
uint32_t addr, len;
376450

377451
np_write_start_cmd_t *write_start_cmd =
@@ -408,6 +482,13 @@ static int np_cmd_nand_write_start(np_prog_t *prog)
408482
return NP_ERR_ADDR_NOT_ALIGN;
409483
}
410484

485+
prog->skip_bb = write_start_cmd->flags.skip_bb;
486+
if (prog->skip_bb && !prog->bb_is_read &&
487+
(ret = _np_cmd_read_bad_blocks(prog)))
488+
{
489+
return ret;
490+
}
491+
411492
prog->addr = addr;
412493
prog->len = len;
413494
prog->addr_is_set = 1;
@@ -417,7 +498,6 @@ static int np_cmd_nand_write_start(np_prog_t *prog)
417498

418499
prog->bytes_written = 0;
419500
prog->bytes_ack = 0;
420-
prog->skip_bb = write_start_cmd->flags.skip_bb;
421501

422502
return np_send_ok_status();
423503
}
@@ -627,6 +707,7 @@ static int np_nand_read(uint32_t addr, np_page_t *page,
627707

628708
static int _np_cmd_nand_read(np_prog_t *prog)
629709
{
710+
int ret;
630711
uint32_t addr, len, send_len;
631712
static np_page_t page;
632713
uint32_t resp_header_size = offsetof(np_resp_t, data);
@@ -666,6 +747,9 @@ static int _np_cmd_nand_read(np_prog_t *prog)
666747
return NP_ERR_LEN_NOT_ALIGN;
667748
}
668749

750+
if (skip_bb && !prog->bb_is_read && (ret = _np_cmd_read_bad_blocks(prog)))
751+
return ret;
752+
669753
page.page = addr / prog->chip_info->page_size;
670754
page.offset = 0;
671755

@@ -752,6 +836,7 @@ static int np_cmd_nand_select(np_prog_t *prog)
752836
{
753837
nand_init();
754838
nand_bad_block_table_init();
839+
prog->bb_is_read = 0;
755840
prog->chip_info = chip_info_selected_get();
756841
}
757842
else
@@ -765,73 +850,21 @@ static int np_cmd_nand_select(np_prog_t *prog)
765850
return np_send_ok_status();
766851
}
767852

768-
static int np_read_bad_block_info_from_page(np_prog_t *prog, uint32_t block,
769-
uint32_t page, chip_info_t *chip_info, bool *is_bad)
853+
static int np_send_bad_blocks(np_prog_t *prog)
770854
{
771-
uint8_t bad_block_data;
772-
uint32_t status, addr = block * chip_info->block_size;
773-
774-
status = nand_read_data(&bad_block_data, page, chip_info->page_size,
775-
sizeof(bad_block_data));
776-
switch (status)
777-
{
778-
case NAND_READY:
779-
break;
780-
case NAND_ERROR:
781-
ERROR_PRINT("NAND read bad block info error at 0x%lx\r\n", addr);
782-
return NP_ERR_NAND_RD;
783-
case NAND_TIMEOUT_ERROR:
784-
ERROR_PRINT("NAND read timeout at 0x%lx\r\n", addr);
785-
return NP_ERR_NAND_RD;
786-
default:
787-
ERROR_PRINT("Unknown NAND status\r\n");
788-
return NP_ERR_NAND_RD;
789-
}
855+
uint32_t addr;
856+
void *bb_iter;
790857

791-
if (bad_block_data != NP_NAND_GOOD_BLOCK_MARK)
858+
for (bb_iter = nand_bad_block_table_iter_alloc(&addr); bb_iter;
859+
bb_iter = nand_bad_block_table_iter_next(bb_iter, &addr))
792860
{
793-
*is_bad = true;
794861
if (np_send_bad_block_info(addr, prog->chip_info->block_size))
795862
return -1;
796-
if (nand_bad_block_table_add(addr))
797-
return -1;
798863
}
799-
else
800-
*is_bad = false;
801864

802865
return 0;
803866
}
804867

805-
static int _np_cmd_read_bad_blocks(np_prog_t *prog)
806-
{
807-
bool is_bad;
808-
uint32_t block, block_num, page_num, page;
809-
810-
block_num = prog->chip_info->size / prog->chip_info->block_size;
811-
page_num = prog->chip_info->block_size / prog->chip_info->page_size;
812-
813-
/* Bad block - not 0xFF value in the first or second page in the block at
814-
* zero offset in the page spare area
815-
*/
816-
for (block = 0; block < block_num; block++)
817-
{
818-
page = block * page_num;
819-
if (np_read_bad_block_info_from_page(prog, block, page, prog->chip_info,
820-
&is_bad))
821-
{
822-
return -1;
823-
}
824-
825-
if (!is_bad && np_read_bad_block_info_from_page(prog, block, page + 1,
826-
prog->chip_info, &is_bad))
827-
{
828-
return -1;
829-
}
830-
}
831-
832-
return np_send_ok_status();
833-
}
834-
835868
int np_cmd_read_bad_blocks(np_prog_t *prog)
836869
{
837870
int ret;
@@ -840,7 +873,10 @@ int np_cmd_read_bad_blocks(np_prog_t *prog)
840873
ret = _np_cmd_read_bad_blocks(prog);
841874
led_rd_set(false);
842875

843-
return ret;
876+
if (ret || (ret = np_send_bad_blocks(prog)))
877+
return ret;
878+
879+
return np_send_ok_status();
844880
}
845881

846882
static np_cmd_handler_t cmd_handler[] =

0 commit comments

Comments
 (0)