Skip to content

Commit 57cf5cf

Browse files
committed
update BCH code and lic
1 parent 31af402 commit 57cf5cf

File tree

5 files changed

+318
-1392
lines changed

5 files changed

+318
-1392
lines changed

storage/blockdevice/COMPONENT_SPINAND/include/SPINAND/SPINANDBlockDevice.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "drivers/QSPI.h"
2121
#include "blockdevice/BlockDevice.h"
2222
#include "platform/Callback.h"
23+
#include "bch.h"
2324

2425
#ifndef MBED_CONF_SPINAND_QSPI_IO0
2526
#define MBED_CONF_SPINAND_QSPI_IO0 NC
@@ -356,9 +357,9 @@ class SPINANDBlockDevice : public mbed::BlockDevice {
356357
uint8_t _continuous_read;
357358

358359
struct nand_bch_control {
359-
struct bch_control *bch;
360-
unsigned int *errloc;
361-
unsigned char *eccmask;
360+
struct bch_code *bch;
361+
unsigned int *errloc;
362+
unsigned char *eccmask;
362363
};
363364
struct nand_bch_control _nbc;
364365
};
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,43 @@
11
/*
2-
* Generic binary BCH encoding/decoding library
3-
*
4-
* This program is free software; you can redistribute it and/or modify it
5-
* under the terms of the GNU General Public License version 2 as published by
6-
* the Free Software Foundation.
7-
*
8-
* This program is distributed in the hope that it will be useful, but WITHOUT
9-
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10-
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11-
* more details.
12-
*
13-
* You should have received a copy of the GNU General Public License along with
14-
* this program; if not, write to the Free Software Foundation, Inc., 51
15-
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
16-
*
17-
* Copyright © 2011 Parrot S.A.
18-
*
19-
* Author: Ivan Djelic <[email protected]>
20-
*
21-
* Description:
22-
*
23-
* This library provides runtime configurable encoding/decoding of binary
24-
* Bose-Chaudhuri-Hocquenghem (BCH) codes.
25-
*/
26-
/* mbed Microcontroller Library
27-
* Copyright (c) 2022 ARM Limited
2+
* Copyright (c) 2022 Macronix International Co., Ltd.
283
* SPDX-License-Identifier: Apache-2.0
29-
*
30-
* Licensed under the Apache License, Version 2.0 (the "License");
31-
* you may not use this file except in compliance with the License.
32-
* You may obtain a copy of the License at
33-
*
34-
* http://www.apache.org/licenses/LICENSE-2.0
35-
*
36-
* Unless required by applicable law or agreed to in writing, software
37-
* distributed under the License is distributed on an "AS IS" BASIS,
38-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
39-
* See the License for the specific language governing permissions and
40-
* limitations under the License.
414
*/
5+
426
#ifndef _BCH_H
437
#define _BCH_H
448
#ifdef __cplusplus
459
extern "C" {
4610
#endif
4711
#include <stdint.h>
48-
//typedef unsigned char uint8_t;
49-
//typedef unsigned short uint16_t;
50-
//typedef unsigned int uint32_t;
5112

5213
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
53-
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
54-
/**
55-
* struct bch_control - BCH control structure
56-
* @m: Galois field order
57-
* @n: maximum codeword size in bits (= 2^m-1)
58-
* @t: error correction capability in bits
59-
* @ecc_bits: ecc exact size in bits, i.e. generator polynomial degree (<=m*t)
60-
* @ecc_bytes: ecc max size (m*t bits) in bytes
61-
* @a_pow_tab: Galois field GF(2^m) exponentiation lookup table
62-
* @a_log_tab: Galois field GF(2^m) log lookup table
63-
* @mod8_tab: remainder generator polynomial lookup tables
64-
* @ecc_buf: ecc parity words buffer
65-
* @ecc_buf2: ecc parity words buffer
66-
* @xi_tab: GF(2^m) base for solving degree 2 polynomial roots
67-
* @syn: syndrome buffer
68-
* @cache: log-based polynomial representation buffer
69-
* @elp: error locator polynomial
70-
* @poly_2t: temporary polynomials of degree 2t
71-
*/
72-
struct bch_control {
14+
15+
struct bch_code {
7316
unsigned int m;
7417
unsigned int n;
7518
unsigned int t;
7619
unsigned int ecc_bits;
77-
unsigned int ecc_bytes;
78-
/* private: */
79-
uint16_t *a_pow_tab;
80-
uint16_t *a_log_tab;
81-
uint32_t *mod8_tab;
82-
uint32_t *ecc_buf;
83-
uint32_t *ecc_buf2;
84-
unsigned int *xi_tab;
20+
unsigned int ecc_words;
21+
unsigned int len;
22+
unsigned int *a_pow;
23+
unsigned int *a_log;
24+
unsigned int *mod_tab;
25+
unsigned int *ecc;
8526
unsigned int *syn;
86-
int *cache;
87-
struct gf_poly *elp;
88-
struct gf_poly *poly_2t[4];
27+
unsigned int *elp;
28+
unsigned int *buf;
29+
unsigned int *buf2;
30+
unsigned char *input_data;
31+
unsigned int endian;
8932
};
9033

91-
struct bch_control *init_bch(int m, int t, unsigned int prim_poly);
92-
93-
void free_bch(struct bch_control *bch);
94-
95-
void encode_bch(struct bch_control *bch, const uint8_t *data,
96-
unsigned int len, uint8_t *ecc);
97-
98-
int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len,
99-
const uint8_t *recv_ecc, const uint8_t *calc_ecc,
100-
const unsigned int *syn, unsigned int *errloc);
34+
struct bch_code *bch_init(unsigned int m, unsigned int t);
35+
void bch_free(struct bch_code *bch);
36+
void bch_encode(struct bch_code *bch, unsigned char *data, unsigned int *ecc);
37+
int bch_decode(struct bch_code *bch, unsigned char *data, unsigned int *ecc);
10138
int fls(int x);
102-
#ifdef _X86_
103-
#define cpu_to_be32(x) ((((x)&0xff)<<24) | (((x)&0xff00)<<8) | (((x)>>8)&0xff00) | (((x)>>24)&0xff))
104-
#else
105-
#define cpu_to_be32(x) x
106-
#endif
39+
10740
#ifdef __cplusplus
10841
}
10942
#endif
110-
#endif /* _BCH_H */
43+
#endif

storage/blockdevice/COMPONENT_SPINAND/source/SPINANDBlockDevice.cpp

+30-58
Original file line numberDiff line numberDiff line change
@@ -343,23 +343,22 @@ int SPINANDBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
343343
goto exit_point;
344344
}
345345

346-
// calculate the software ECC
347-
for (uint8_t i = 0; ecc_steps; ecc_steps--, i += _ecc_bytes, p += _ecc_size) {
348-
_bch_calculate_ecc(p, _ecc_calc + i);
349-
}
350-
351346
memcpy(_ecc_code, _page_buf + _page_size + _ecc_layout_pos, _ecc_bytes * _ecc_steps);
352347

353348
p = (uint8_t *)_page_buf;
354349
ecc_steps = _ecc_steps;
355350
for (uint8_t i = 0 ; ecc_steps; ecc_steps--, i += _ecc_bytes, p += _ecc_size) {
356-
int res = _bch_correct_data(p, _ecc_code + i, _ecc_calc + i);
351+
memset(_nbc.bch->input_data, 0x0, (1 << _nbc.bch->m) / 8);
352+
memcpy(_nbc.bch->input_data + _ecc_bytes, p, _ecc_size);
353+
354+
int res = bch_decode(_nbc.bch, _nbc.bch->input_data, (unsigned int *)(_ecc_code + i));
357355
if (res < 0) {
358356
tr_error("Reading data failed");
359357
status = SPINAND_BD_ERROR_DEVICE_ERROR;
360358
read_failed = true;
361359
goto exit_point;
362360
}
361+
memcpy(p, _nbc.bch->input_data + _ecc_bytes, _ecc_size);
363362
}
364363
memcpy(buffer, _page_buf + offset, read_bytes);
365364
}
@@ -431,7 +430,9 @@ int SPINANDBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t si
431430

432431
// calculate the software ECC
433432
for (uint8_t i = 0; ecc_steps; ecc_steps--, i += _ecc_bytes, p += _ecc_size) {
434-
_bch_calculate_ecc(p, _ecc_calc + i);
433+
memset(_nbc.bch->input_data, 0x0, (1 << _nbc.bch->m) / 8);
434+
memcpy(_nbc.bch->input_data + _ecc_bytes, p, _ecc_size);
435+
_bch_calculate_ecc(_nbc.bch->input_data, _ecc_calc + i);
435436
}
436437

437438
// prepare ECC code
@@ -532,7 +533,7 @@ bool SPINANDBlockDevice::is_bad_block(uint16_t blk_idx)
532533
{
533534
mbed::bd_addr_t addr;
534535
uint8_t mark[2];
535-
536+
536537
addr = (blk_idx << _block_shift) + _page_size;
537538
if (QSPI_STATUS_OK != _read_oob(mark, addr, sizeof(mark))) {
538539
tr_error("Read Command failed");
@@ -547,8 +548,8 @@ int SPINANDBlockDevice::mark_bad_block(uint16_t blk_idx)
547548
mbed::bd_addr_t addr;
548549
uint8_t mark[2];
549550

550-
mark[0] = 0x00;
551-
mark[1] = 0x00;
551+
mark[0] = 0x00;
552+
mark[1] = 0x00;
552553
addr = (blk_idx << _block_shift) + _page_size;
553554
if (QSPI_STATUS_OK != _program_oob(mark, addr, sizeof(mark))) {
554555
tr_error("Program Command failed");
@@ -707,6 +708,12 @@ bool SPINANDBlockDevice::_read_otp_onfi()
707708
_ecc_bits = onfi_table[112];
708709
if (_ecc_bits > 0) {
709710
_bch_init(_ecc_bits);
711+
secur_reg &= ~SPINAND_SECURE_BIT_ECC_EN;
712+
713+
if (QSPI_STATUS_OK != _qspi_send_general_command(SPINAND_INST_SET_FEATURE, FEATURES_ADDR_SECURE_OTP,
714+
(char *) &secur_reg, 1, NULL, 0)) {
715+
tr_error("Writing Register failed");
716+
}
710717
} else {
711718
secur_reg |= SPINAND_SECURE_BIT_ECC_EN;
712719

@@ -768,7 +775,7 @@ int SPINANDBlockDevice::_program_oob(const void *buffer, bd_addr_t addr, bd_size
768775
int status = SPINAND_BD_ERROR_OK;
769776

770777
_mutex.lock();
771-
778+
772779
//Send WREN
773780
if (_set_write_enable() != 0) {
774781
tr_error("Write Enable failed");
@@ -892,7 +899,7 @@ int SPINANDBlockDevice::_set_write_enable()
892899

893900
int SPINANDBlockDevice::_set_conti_read_enable()
894901
{
895-
uint8_t secur_reg = 0;uint8_t secur_reg1 = 0;
902+
uint8_t secur_reg = 0;
896903

897904
if (false == _is_mem_ready()) {
898905
tr_error("Device not ready, set quad enable failed");
@@ -918,10 +925,6 @@ int SPINANDBlockDevice::_set_conti_read_enable()
918925
tr_error("Device not ready, set quad enable failed");
919926
return -1;
920927
}
921-
if (QSPI_STATUS_OK != _qspi_send_general_command(SPINAND_INST_GET_FEATURE, FEATURES_ADDR_SECURE_OTP,
922-
NULL, 0, (char *) &secur_reg1, 1)) {
923-
tr_error("Reading Security Register failed");
924-
}
925928

926929
return 0;
927930
}
@@ -1249,26 +1252,26 @@ void SPINANDBlockDevice::_bch_init(uint8_t ecc_bits)
12491252
{
12501253
unsigned int m, t, i;
12511254
unsigned char *erased_page;
1252-
unsigned int eccsize = 512;
1255+
unsigned int eccsize = 410;
12531256
unsigned int eccbytes = 0;
12541257

1255-
_ecc_bytes = eccbytes = DIV_ROUND_UP(ecc_bits * fls(8 * eccsize), 8);
1258+
m = fls(1 + 8 * eccsize);
1259+
t = ecc_bits;
1260+
1261+
_ecc_bytes = eccbytes = ((m * t + 31) / 32) * 4;
12561262
_ecc_size = eccsize;
12571263
_ecc_steps = _page_size / eccsize;
12581264
_ecc_layout_pos = 2; // skip the bad block mark for Macronix spi nand
12591265

1260-
m = fls(1 + 8 * eccsize);
1261-
t = (eccbytes * 8) / m;
1262-
1263-
_nbc.bch = init_bch(m, t, 0);
1266+
_nbc.bch = bch_init(m, t);
12641267
if (!_nbc.bch) {
12651268
return;
12661269
}
12671270

12681271
/* verify that eccbytes has the expected value */
1269-
if (_nbc.bch->ecc_bytes != eccbytes) {
1272+
if (_nbc.bch->ecc_words * 4 != eccbytes) {
12701273
tr_error("invalid eccbytes %u, should be %u\n",
1271-
eccbytes, _nbc.bch->ecc_bytes);
1274+
eccbytes, _nbc.bch->ecc_words);
12721275
return;
12731276
}
12741277

@@ -1290,7 +1293,7 @@ void SPINANDBlockDevice::_bch_init(uint8_t ecc_bits)
12901293
memset(_page_buf, 0xff, _page_size + _oob_size);
12911294
memset(erased_page, 0xff, eccsize);
12921295
memset(_nbc.eccmask, 0, eccbytes);
1293-
encode_bch(_nbc.bch, erased_page, eccsize, _nbc.eccmask);
1296+
bch_encode(_nbc.bch, erased_page, (unsigned int *)_nbc.eccmask);
12941297
free(erased_page);
12951298

12961299
for (i = 0; i < eccbytes; i++) {
@@ -1300,7 +1303,7 @@ void SPINANDBlockDevice::_bch_init(uint8_t ecc_bits)
13001303

13011304
void SPINANDBlockDevice::_bch_free()
13021305
{
1303-
free_bch(_nbc.bch);
1306+
bch_free(_nbc.bch);
13041307
free(_nbc.errloc);
13051308
free(_nbc.eccmask);
13061309
free(_page_buf);
@@ -1310,42 +1313,11 @@ void SPINANDBlockDevice::_bch_free()
13101313

13111314
int SPINANDBlockDevice::_bch_calculate_ecc(unsigned char *buf, unsigned char *code)
13121315
{
1313-
unsigned int i;
13141316

13151317
memset(code, 0, _ecc_bytes);
13161318

1317-
encode_bch(_nbc.bch, buf, _ecc_size, code);
1318-
1319-
/* apply mask so that an erased page is a valid codeword */
1320-
for (i = 0; i < _ecc_bytes; i++) {
1321-
code[i] ^= _nbc.eccmask[i];
1322-
}
1319+
bch_encode(_nbc.bch, buf, (unsigned int *)code);
13231320

13241321
return 0;
13251322
}
13261323

1327-
int SPINANDBlockDevice::_bch_correct_data(unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc)
1328-
{
1329-
unsigned int *errloc = _nbc.errloc;
1330-
int i, count;
1331-
1332-
count = decode_bch(_nbc.bch, NULL, _ecc_size, read_ecc, calc_ecc,
1333-
NULL, errloc);
1334-
if (count > 0) {
1335-
for (i = 0; i < count; i++) {
1336-
if (errloc[i] < (_ecc_size * 8)) {
1337-
/* error is located in data, correct it */
1338-
buf[(errloc[i] >> 3) ^ 3] ^= (1 << (errloc[i] & 7));
1339-
}
1340-
1341-
/* else error in ecc, no action needed */
1342-
tr_error("corrected bitflip %04x:%d\n", (errloc[i] >> 3) ^ 3, errloc[i] & 7);
1343-
}
1344-
} else if (count < 0) {
1345-
tr_error("ecc unrecoverable error\n");
1346-
count = -EBADMSG;
1347-
}
1348-
return count;
1349-
}
1350-
1351-

0 commit comments

Comments
 (0)