mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
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:
@@ -649,13 +649,12 @@ u32 sfc_nand_prog_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
|
||||
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;
|
||||
u32 plane;
|
||||
struct rk_sfc_op op;
|
||||
u32 ecc_result;
|
||||
u32 page_size = SFC_NAND_SECTOR_FULL_SIZE * p_nand_info->sec_per_page;
|
||||
u8 status;
|
||||
|
||||
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;
|
||||
|
||||
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 &&
|
||||
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.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.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;
|
||||
ret = sfc_request(&op, plane << 8, p_page_buf, page_size);
|
||||
rkflash_print_dio("%s %x %x\n", __func__, addr, p_page_buf[0]);
|
||||
plane = p_nand_info->plane_per_die == 2 ? ((row >> 6) & 0x1) << 12 : 0;
|
||||
ret = sfc_request(&op, plane | column, p_page_buf, len);
|
||||
rkflash_print_dio("%s %x %x\n", __func__, row, p_page_buf[0]);
|
||||
|
||||
if (ret != SFC_OK)
|
||||
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;
|
||||
}
|
||||
|
||||
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 ret;
|
||||
@@ -729,17 +737,17 @@ u32 sfc_nand_check_bad_block(u8 cs, u32 addr)
|
||||
{
|
||||
u32 ret;
|
||||
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 */
|
||||
if (ret == SFC_NAND_ECC_ERROR)
|
||||
rkflash_print_error("%s page= %x ret= %x data0= %x, spare0= %x\n",
|
||||
__func__, addr, ret, gp_page_buf[0],
|
||||
(gp_page_buf[data_size / 4] & 0xFF));
|
||||
rkflash_print_error("%s page= %x ret= %x spare= %x\n",
|
||||
__func__, addr, ret, marker);
|
||||
|
||||
/* Original bad block */
|
||||
if ((gp_page_buf[data_size / 4] & 0xFFFF) != 0xFFFF)
|
||||
if ((u16)marker != 0xffff)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -125,5 +125,6 @@ u32 sfc_nand_mark_bad_block(u8 cs, u32 addr);
|
||||
void sfc_nand_ftl_ops_init(void);
|
||||
struct SFNAND_DEV *sfc_nand_get_private_dev(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
|
||||
|
||||
@@ -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);
|
||||
u8 *data = (u8 *)ops->datbuf;
|
||||
u8 *oob_buf = (u8 *)ops->oobbuf;
|
||||
size_t remaining = ops->len;
|
||||
size_t oob_left = ops->ooblen, oob_real;
|
||||
u32 ret = 0;
|
||||
|
||||
rkflash_print_dio("%s addr= %llx len= %x\n", __func__, to, (u32)remaining);
|
||||
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);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ops->retlen = 0;
|
||||
ops->oobretlen = 0;
|
||||
while (remaining) {
|
||||
memcpy(p_dev->dma_buf, data, mtd->writesize);
|
||||
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,
|
||||
(u32 *)p_dev->dma_buf);
|
||||
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;
|
||||
remaining -= mtd->writesize;
|
||||
to += mtd->writesize;
|
||||
if (oob_real) {
|
||||
ops->oobretlen += oob_real;
|
||||
oob_buf += oob_real;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
struct snand_mtd_dev *p_dev = mtd_to_priv(mtd);
|
||||
u8 *data = (u8 *)ops->datbuf;
|
||||
u8 *oob_buf = (u8 *)ops->oobbuf;
|
||||
size_t remaining = ops->len;
|
||||
size_t oob_left = ops->ooblen, oob_real;
|
||||
u32 ret = 0;
|
||||
bool ecc_failed = false;
|
||||
size_t off, real_size;
|
||||
size_t page, off, real_size;
|
||||
int max_bitflips = 0;
|
||||
|
||||
rkflash_print_dio("%s addr= %llx len= %x\n", __func__, from, (u32)remaining);
|
||||
if ((from + remaining) > mtd->size) {
|
||||
rkflash_print_error("%s input error, %llx %x\n", __func__, from, (u32)remaining);
|
||||
if ((from + remaining) > mtd->size || ops->ooblen) {
|
||||
rkflash_print_error("%s input error, from= %llx len= %x oob= %x\n",
|
||||
__func__, from, (u32)remaining, (u32)ops->ooblen);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ops->retlen = 0;
|
||||
ops->oobretlen = 0;
|
||||
while (remaining) {
|
||||
ret = sfc_nand_read_page_raw(0, from >> mtd->writesize_shift,
|
||||
(u32 *)p_dev->dma_buf);
|
||||
page = from >> mtd->writesize_shift;
|
||||
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) {
|
||||
rkflash_print_error("%s addr %llx ret= %d\n",
|
||||
__func__, from, ret);
|
||||
@@ -124,27 +114,11 @@ static int sfc_nand_read_mtd(struct mtd_info *mtd, loff_t from,
|
||||
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;
|
||||
data += real_size;
|
||||
ops->retlen += real_size;
|
||||
remaining -= real_size;
|
||||
from += real_size;
|
||||
if (oob_real) {
|
||||
ops->oobretlen += oob_real;
|
||||
oob_buf += oob_real;
|
||||
}
|
||||
}
|
||||
|
||||
if (ecc_failed && !ret)
|
||||
|
||||
Reference in New Issue
Block a user