mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +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;
|
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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user