mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 11:19:37 +00:00
mtd: nand: mxc: switch to mtd_ooblayout_ops
Implementing the mtd_ooblayout_ops interface is the new way of exposing ECC/OOB layout to MTD users. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
This commit is contained in:
parent
d50b523986
commit
a894cf6c5a
1 changed files with 105 additions and 107 deletions
|
@ -149,7 +149,7 @@ struct mxc_nand_devtype_data {
|
|||
int (*check_int)(struct mxc_nand_host *);
|
||||
void (*irq_control)(struct mxc_nand_host *, int);
|
||||
u32 (*get_ecc_status)(struct mxc_nand_host *);
|
||||
struct nand_ecclayout *ecclayout_512, *ecclayout_2k, *ecclayout_4k;
|
||||
const struct mtd_ooblayout_ops *ooblayout;
|
||||
void (*select_chip)(struct mtd_info *mtd, int chip);
|
||||
int (*correct_data)(struct mtd_info *mtd, u_char *dat,
|
||||
u_char *read_ecc, u_char *calc_ecc);
|
||||
|
@ -200,73 +200,6 @@ struct mxc_nand_host {
|
|||
struct mxc_nand_platform_data pdata;
|
||||
};
|
||||
|
||||
/* OOB placement block for use with hardware ecc generation */
|
||||
static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
|
||||
.eccbytes = 5,
|
||||
.eccpos = {6, 7, 8, 9, 10},
|
||||
.oobfree = {{0, 5}, {12, 4}, }
|
||||
};
|
||||
|
||||
static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
|
||||
.eccbytes = 20,
|
||||
.eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
|
||||
38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
|
||||
.oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, }
|
||||
};
|
||||
|
||||
/* OOB description for 512 byte pages with 16 byte OOB */
|
||||
static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
|
||||
.eccbytes = 1 * 9,
|
||||
.eccpos = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||
},
|
||||
.oobfree = {
|
||||
{.offset = 0, .length = 5}
|
||||
}
|
||||
};
|
||||
|
||||
/* OOB description for 2048 byte pages with 64 byte OOB */
|
||||
static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
|
||||
.eccbytes = 4 * 9,
|
||||
.eccpos = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
55, 56, 57, 58, 59, 60, 61, 62, 63
|
||||
},
|
||||
.oobfree = {
|
||||
{.offset = 2, .length = 4},
|
||||
{.offset = 16, .length = 7},
|
||||
{.offset = 32, .length = 7},
|
||||
{.offset = 48, .length = 7}
|
||||
}
|
||||
};
|
||||
|
||||
/* OOB description for 4096 byte pages with 128 byte OOB */
|
||||
static struct nand_ecclayout nandv2_hw_eccoob_4k = {
|
||||
.eccbytes = 8 * 9,
|
||||
.eccpos = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
87, 88, 89, 90, 91, 92, 93, 94, 95,
|
||||
103, 104, 105, 106, 107, 108, 109, 110, 111,
|
||||
119, 120, 121, 122, 123, 124, 125, 126, 127,
|
||||
},
|
||||
.oobfree = {
|
||||
{.offset = 2, .length = 4},
|
||||
{.offset = 16, .length = 7},
|
||||
{.offset = 32, .length = 7},
|
||||
{.offset = 48, .length = 7},
|
||||
{.offset = 64, .length = 7},
|
||||
{.offset = 80, .length = 7},
|
||||
{.offset = 96, .length = 7},
|
||||
{.offset = 112, .length = 7},
|
||||
}
|
||||
};
|
||||
|
||||
static const char * const part_probes[] = {
|
||||
"cmdlinepart", "RedBoot", "ofpart", NULL };
|
||||
|
||||
|
@ -942,6 +875,99 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
|
|||
}
|
||||
}
|
||||
|
||||
static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *oobregion)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
|
||||
if (section >= nand_chip->ecc.steps)
|
||||
return -ERANGE;
|
||||
|
||||
oobregion->offset = (section * 16) + 6;
|
||||
oobregion->length = nand_chip->ecc.bytes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxc_v1_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *oobregion)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
|
||||
if (section > nand_chip->ecc.steps)
|
||||
return -ERANGE;
|
||||
|
||||
if (!section) {
|
||||
if (mtd->writesize <= 512) {
|
||||
oobregion->offset = 0;
|
||||
oobregion->length = 5;
|
||||
} else {
|
||||
oobregion->offset = 2;
|
||||
oobregion->length = 4;
|
||||
}
|
||||
} else {
|
||||
oobregion->offset = ((section - 1) * 16) +
|
||||
nand_chip->ecc.bytes + 6;
|
||||
if (section < nand_chip->ecc.steps)
|
||||
oobregion->length = (section * 16) + 6 -
|
||||
oobregion->offset;
|
||||
else
|
||||
oobregion->length = mtd->oobsize - oobregion->offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mtd_ooblayout_ops mxc_v1_ooblayout_ops = {
|
||||
.ecc = mxc_v1_ooblayout_ecc,
|
||||
.free = mxc_v1_ooblayout_free,
|
||||
};
|
||||
|
||||
static int mxc_v2_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *oobregion)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
|
||||
|
||||
if (section >= nand_chip->ecc.steps)
|
||||
return -ERANGE;
|
||||
|
||||
oobregion->offset = (section * stepsize) + 7;
|
||||
oobregion->length = nand_chip->ecc.bytes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxc_v2_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *oobregion)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
|
||||
|
||||
if (section > nand_chip->ecc.steps)
|
||||
return -ERANGE;
|
||||
|
||||
if (!section) {
|
||||
if (mtd->writesize <= 512) {
|
||||
oobregion->offset = 0;
|
||||
oobregion->length = 5;
|
||||
} else {
|
||||
oobregion->offset = 2;
|
||||
oobregion->length = 4;
|
||||
}
|
||||
} else {
|
||||
oobregion->offset = section * stepsize;
|
||||
oobregion->length = 7;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mtd_ooblayout_ops mxc_v2_ooblayout_ops = {
|
||||
.ecc = mxc_v2_ooblayout_ecc,
|
||||
.free = mxc_v2_ooblayout_free,
|
||||
};
|
||||
|
||||
/*
|
||||
* v2 and v3 type controllers can do 4bit or 8bit ecc depending
|
||||
* on how much oob the nand chip has. For 8bit ecc we need at least
|
||||
|
@ -959,23 +985,6 @@ static int get_eccsize(struct mtd_info *mtd)
|
|||
return 8;
|
||||
}
|
||||
|
||||
static void ecc_8bit_layout_4k(struct nand_ecclayout *layout)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
layout->eccbytes = 8*18;
|
||||
for (i = 0; i < 8; i++)
|
||||
for (j = 0; j < 18; j++)
|
||||
layout->eccpos[i*18 + j] = i*26 + j + 7;
|
||||
|
||||
layout->oobfree[0].offset = 2;
|
||||
layout->oobfree[0].length = 4;
|
||||
for (i = 1; i < 8; i++) {
|
||||
layout->oobfree[i].offset = i*26;
|
||||
layout->oobfree[i].length = 7;
|
||||
}
|
||||
}
|
||||
|
||||
static void preset_v1(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
|
@ -1269,9 +1278,7 @@ static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
|
|||
.check_int = check_int_v1_v2,
|
||||
.irq_control = irq_control_v1_v2,
|
||||
.get_ecc_status = get_ecc_status_v1,
|
||||
.ecclayout_512 = &nandv1_hw_eccoob_smallpage,
|
||||
.ecclayout_2k = &nandv1_hw_eccoob_largepage,
|
||||
.ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */
|
||||
.ooblayout = &mxc_v1_ooblayout_ops,
|
||||
.select_chip = mxc_nand_select_chip_v1_v3,
|
||||
.correct_data = mxc_nand_correct_data_v1,
|
||||
.irqpending_quirk = 1,
|
||||
|
@ -1294,9 +1301,7 @@ static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
|
|||
.check_int = check_int_v1_v2,
|
||||
.irq_control = irq_control_v1_v2,
|
||||
.get_ecc_status = get_ecc_status_v1,
|
||||
.ecclayout_512 = &nandv1_hw_eccoob_smallpage,
|
||||
.ecclayout_2k = &nandv1_hw_eccoob_largepage,
|
||||
.ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */
|
||||
.ooblayout = &mxc_v1_ooblayout_ops,
|
||||
.select_chip = mxc_nand_select_chip_v1_v3,
|
||||
.correct_data = mxc_nand_correct_data_v1,
|
||||
.irqpending_quirk = 0,
|
||||
|
@ -1320,9 +1325,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
|
|||
.check_int = check_int_v1_v2,
|
||||
.irq_control = irq_control_v1_v2,
|
||||
.get_ecc_status = get_ecc_status_v2,
|
||||
.ecclayout_512 = &nandv2_hw_eccoob_smallpage,
|
||||
.ecclayout_2k = &nandv2_hw_eccoob_largepage,
|
||||
.ecclayout_4k = &nandv2_hw_eccoob_4k,
|
||||
.ooblayout = &mxc_v2_ooblayout_ops,
|
||||
.select_chip = mxc_nand_select_chip_v2,
|
||||
.correct_data = mxc_nand_correct_data_v2_v3,
|
||||
.irqpending_quirk = 0,
|
||||
|
@ -1346,9 +1349,7 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
|
|||
.check_int = check_int_v3,
|
||||
.irq_control = irq_control_v3,
|
||||
.get_ecc_status = get_ecc_status_v3,
|
||||
.ecclayout_512 = &nandv2_hw_eccoob_smallpage,
|
||||
.ecclayout_2k = &nandv2_hw_eccoob_largepage,
|
||||
.ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
|
||||
.ooblayout = &mxc_v2_ooblayout_ops,
|
||||
.select_chip = mxc_nand_select_chip_v1_v3,
|
||||
.correct_data = mxc_nand_correct_data_v2_v3,
|
||||
.irqpending_quirk = 0,
|
||||
|
@ -1373,9 +1374,7 @@ static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
|
|||
.check_int = check_int_v3,
|
||||
.irq_control = irq_control_v3,
|
||||
.get_ecc_status = get_ecc_status_v3,
|
||||
.ecclayout_512 = &nandv2_hw_eccoob_smallpage,
|
||||
.ecclayout_2k = &nandv2_hw_eccoob_largepage,
|
||||
.ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
|
||||
.ooblayout = &mxc_v2_ooblayout_ops,
|
||||
.select_chip = mxc_nand_select_chip_v1_v3,
|
||||
.correct_data = mxc_nand_correct_data_v2_v3,
|
||||
.irqpending_quirk = 0,
|
||||
|
@ -1576,7 +1575,7 @@ static int mxcnd_probe(struct platform_device *pdev)
|
|||
|
||||
this->select_chip = host->devtype_data->select_chip;
|
||||
this->ecc.size = 512;
|
||||
this->ecc.layout = host->devtype_data->ecclayout_512;
|
||||
mtd_set_ooblayout(mtd, host->devtype_data->ooblayout);
|
||||
|
||||
if (host->pdata.hw_ecc) {
|
||||
this->ecc.calculate = mxc_nand_calculate_ecc;
|
||||
|
@ -1650,12 +1649,11 @@ static int mxcnd_probe(struct platform_device *pdev)
|
|||
/* Call preset again, with correct writesize this time */
|
||||
host->devtype_data->preset(mtd);
|
||||
|
||||
if (mtd->writesize == 2048)
|
||||
this->ecc.layout = host->devtype_data->ecclayout_2k;
|
||||
else if (mtd->writesize == 4096) {
|
||||
this->ecc.layout = host->devtype_data->ecclayout_4k;
|
||||
if (get_eccsize(mtd) == 8)
|
||||
ecc_8bit_layout_4k(this->ecc.layout);
|
||||
if (!this->ecc.bytes) {
|
||||
if (host->eccsize == 8)
|
||||
this->ecc.bytes = 18;
|
||||
else if (host->eccsize == 4)
|
||||
this->ecc.bytes = 9;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue