drivers: rkflash: Support spinand non aligned read

Change-Id: I185838a57024af141fdd24f076186e3e068df3b1
Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
This commit is contained in:
Jon Lin
2020-09-17 16:13:51 +08:00
committed by Tao Huang
parent 5e0cb7287b
commit 69f3c341d9
3 changed files with 31 additions and 48 deletions

View File

@@ -649,13 +649,12 @@ u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
return ret; return ret;
} }
u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf) u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len)
{ {
int ret; int ret;
u32 plane; u32 plane;
struct rk_sfc_op op; struct rk_sfc_op op;
u32 ecc_result; u32 ecc_result;
u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
u8 status; u8 status;
op.sfcmd.d32 = 0; op.sfcmd.d32 = 0;
@@ -665,7 +664,7 @@ u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
op.sfctrl.d32 = 0; op.sfctrl.d32 = 0;
sfc_request(&op, addr, p_page_buf, 0); sfc_request(&op, row, p_page_buf, 0);
if (sfc_nand_dev.read_lines == DATA_LINES_X4 && if (sfc_nand_dev.read_lines == DATA_LINES_X4 &&
p_nand_info->feature & FEA_SOFT_QOP_BIT && p_nand_info->feature & FEA_SOFT_QOP_BIT &&
@@ -677,14 +676,16 @@ u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
op.sfcmd.d32 = 0; op.sfcmd.d32 = 0;
op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd; op.sfcmd.b.cmd = sfc_nand_dev.page_read_cmd;
op.sfcmd.b.addrbits = SFC_ADDR_24BITS; op.sfcmd.b.addrbits = SFC_ADDR_XBITS;
op.sfcmd.b.dummybits = 8;
op.sfctrl.d32 = 0; op.sfctrl.d32 = 0;
op.sfctrl.b.datalines = sfc_nand_dev.read_lines; op.sfctrl.b.datalines = sfc_nand_dev.read_lines;
op.sfctrl.b.addrbits = 16;
plane = p_nand_info->plane_per_die == 2 ? ((addr >> 6) & 0x1) << 12 : 0; plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
ret = sfc_request(&op, plane << 8, p_page_buf, page_size); ret = sfc_request(&op, plane | column, p_page_buf, len);
rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]); rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]);
if (ret != SFC_OK) if (ret != SFC_OK)
return SFC_NAND_HW_ERROR; return SFC_NAND_HW_ERROR;
@@ -692,6 +693,13 @@ u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
return ecc_result; return ecc_result;
} }
u32 sfc_nand_read_page_raw(u8 cs, u32 addr, u32 *p_page_buf)
{
u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
return sfc_nand_read(addr, gp_page_buf, 0, page_size);
}
u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare) u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
{ {
u32 ret; u32 ret;
@@ -729,17 +737,17 @@ u32 sfc_nand_check_bad_block(u8 cs, u32 addr)
{ {
u32 ret; u32 ret;
u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE; u32 data_size = p_nand_info->sec_per_page * SFC_NAND_SECTOR_SIZE;
u32 marker = 0;
ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf); ret = sfc_nand_read(addr, &marker, data_size, 2);
/* unify with mtd framework */ /* unify with mtd framework */
if (ret == SFC_NAND_ECC_ERROR) if (ret == SFC_NAND_ECC_ERROR)
rkflash_print_error("%s page= %x ret= %x data0= %x, spare0= %x\n", rkflash_print_error("%s page= %x ret= %x spare= %x\n",
__func__, addr, ret, gp_page_buf[0], __func__, addr, ret, marker);
(gp_page_buf[data_size / 4] & 0xFF));
/* Original bad block */ /* Original bad block */
if ((gp_page_buf[data_size / 4] & 0xFFFF) != 0xFFFF) if ((u16)marker != 0xffff)
return true; return true;
return false; return false;

View File

@@ -125,5 +125,6 @@ u32 sfc_nand_mark_bad_block(u8 cs, u32 addr);
void sfc_nand_ftl_ops_init(void); void sfc_nand_ftl_ops_init(void);
struct SFNAND_DEV *sfc_nand_get_private_dev(void); struct SFNAND_DEV *sfc_nand_get_private_dev(void);
struct nand_info *sfc_nand_get_nand_info(void); struct nand_info *sfc_nand_get_nand_info(void);
u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len);
#endif #endif

View File

@@ -39,27 +39,21 @@ static int sfc_nand_write_mtd(struct mtd_info *mtd, loff_t to,
{ {
struct snand_mtd_dev *p_dev = mtd_to_priv(mtd); struct snand_mtd_dev *p_dev = mtd_to_priv(mtd);
u8 *data = (u8 *)ops->datbuf; u8 *data = (u8 *)ops->datbuf;
u8 *oob_buf = (u8 *)ops->oobbuf;
size_t remaining = ops->len; size_t remaining = ops->len;
size_t oob_left = ops->ooblen, oob_real;
u32 ret = 0; u32 ret = 0;
rkflash_print_dio("%s addr= %llx len= %x\n", __func__, to, (u32)remaining); rkflash_print_dio("%s addr= %llx len= %x\n", __func__, to, (u32)remaining);
if ((to + remaining) > mtd->size || to & mtd->writesize_mask || if ((to + remaining) > mtd->size || to & mtd->writesize_mask ||
remaining & mtd->writesize_mask) { remaining & mtd->writesize_mask || ops->ooblen) {
rkflash_print_error("%s input error, %llx %x\n", __func__, to, (u32)remaining); rkflash_print_error("%s input error, %llx %x\n", __func__, to, (u32)remaining);
return -EINVAL; return -EINVAL;
} }
ops->retlen = 0; ops->retlen = 0;
ops->oobretlen = 0;
while (remaining) { while (remaining) {
memcpy(p_dev->dma_buf, data, mtd->writesize); memcpy(p_dev->dma_buf, data, mtd->writesize);
memset(p_dev->dma_buf + mtd->writesize, 0xff, mtd->oobsize); memset(p_dev->dma_buf + mtd->writesize, 0xff, mtd->oobsize);
oob_real = min((u32)oob_left, mtd->oobsize - ops->ooboffs);
if (oob_real)
memcpy(p_dev->dma_buf + mtd->writesize + ops->ooboffs, oob_buf, oob_real);
ret = sfc_nand_prog_page_raw(0, to >> mtd->writesize_shift, ret = sfc_nand_prog_page_raw(0, to >> mtd->writesize_shift,
(u32 *)p_dev->dma_buf); (u32 *)p_dev->dma_buf);
if (ret != SFC_OK) { if (ret != SFC_OK) {
@@ -73,10 +67,6 @@ static int sfc_nand_write_mtd(struct mtd_info *mtd, loff_t to,
ops->retlen += mtd->writesize; ops->retlen += mtd->writesize;
remaining -= mtd->writesize; remaining -= mtd->writesize;
to += mtd->writesize; to += mtd->writesize;
if (oob_real) {
ops->oobretlen += oob_real;
oob_buf += oob_real;
}
} }
return ret; return ret;
@@ -85,28 +75,28 @@ static int sfc_nand_write_mtd(struct mtd_info *mtd, loff_t to,
static int sfc_nand_read_mtd(struct mtd_info *mtd, loff_t from, static int sfc_nand_read_mtd(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops) struct mtd_oob_ops *ops)
{ {
struct snand_mtd_dev *p_dev = mtd_to_priv(mtd);
u8 *data = (u8 *)ops->datbuf; u8 *data = (u8 *)ops->datbuf;
u8 *oob_buf = (u8 *)ops->oobbuf;
size_t remaining = ops->len; size_t remaining = ops->len;
size_t oob_left = ops->ooblen, oob_real;
u32 ret = 0; u32 ret = 0;
bool ecc_failed = false; bool ecc_failed = false;
size_t off, real_size; size_t page, off, real_size;
int max_bitflips = 0; int max_bitflips = 0;
rkflash_print_dio("%s addr= %llx len= %x\n", __func__, from, (u32)remaining); rkflash_print_dio("%s addr= %llx len= %x\n", __func__, from, (u32)remaining);
if ((from + remaining) > mtd->size) { if ((from + remaining) > mtd->size || ops->ooblen) {
rkflash_print_error("%s input error, %llx %x\n", __func__, from, (u32)remaining); rkflash_print_error("%s input error, from= %llx len= %x oob= %x\n",
__func__, from, (u32)remaining, (u32)ops->ooblen);
return -EINVAL; return -EINVAL;
} }
ops->retlen = 0; ops->retlen = 0;
ops->oobretlen = 0;
while (remaining) { while (remaining) {
ret = sfc_nand_read_page_raw(0, from >> mtd->writesize_shift, page = from >> mtd->writesize_shift;
(u32 *)p_dev->dma_buf); off = from & mtd->writesize_mask;
real_size = min_t(u32, remaining, mtd->writesize - off);
ret = sfc_nand_read(page, (u32 *)data, off, real_size);
if (ret == SFC_NAND_HW_ERROR) { if (ret == SFC_NAND_HW_ERROR) {
rkflash_print_error("%s addr %llx ret= %d\n", rkflash_print_error("%s addr %llx ret= %d\n",
__func__, from, ret); __func__, from, ret);
@@ -124,27 +114,11 @@ static int sfc_nand_read_mtd(struct mtd_info *mtd, loff_t from,
max_bitflips = 1; max_bitflips = 1;
} }
off = from & mtd->writesize_mask;
real_size = min_t(u32, remaining, mtd->writesize);
if ((from >> mtd->writesize_shift) !=
(loff_t)((from + real_size - 1) >> mtd->writesize_shift))
real_size = mtd->writesize - off;
memcpy(data, p_dev->dma_buf + off, real_size);
oob_real = min((u32)oob_left, mtd->oobsize - ops->ooboffs);
if (oob_real)
memcpy(oob_buf, p_dev->dma_buf + mtd->writesize + ops->ooboffs,
oob_real);
ret = 0; ret = 0;
data += real_size; data += real_size;
ops->retlen += real_size; ops->retlen += real_size;
remaining -= real_size; remaining -= real_size;
from += real_size; from += real_size;
if (oob_real) {
ops->oobretlen += oob_real;
oob_buf += oob_real;
}
} }
if (ecc_failed && !ret) if (ecc_failed && !ret)