Commit a894cf6c authored by Boris Brezillon's avatar Boris Brezillon

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: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
parent d50b5239
...@@ -149,7 +149,7 @@ struct mxc_nand_devtype_data { ...@@ -149,7 +149,7 @@ struct mxc_nand_devtype_data {
int (*check_int)(struct mxc_nand_host *); int (*check_int)(struct mxc_nand_host *);
void (*irq_control)(struct mxc_nand_host *, int); void (*irq_control)(struct mxc_nand_host *, int);
u32 (*get_ecc_status)(struct mxc_nand_host *); 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); void (*select_chip)(struct mtd_info *mtd, int chip);
int (*correct_data)(struct mtd_info *mtd, u_char *dat, int (*correct_data)(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc); u_char *read_ecc, u_char *calc_ecc);
...@@ -200,73 +200,6 @@ struct mxc_nand_host { ...@@ -200,73 +200,6 @@ struct mxc_nand_host {
struct mxc_nand_platform_data pdata; 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[] = { static const char * const part_probes[] = {
"cmdlinepart", "RedBoot", "ofpart", NULL }; "cmdlinepart", "RedBoot", "ofpart", NULL };
...@@ -942,6 +875,99 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) ...@@ -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 * 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 * 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) ...@@ -959,23 +985,6 @@ static int get_eccsize(struct mtd_info *mtd)
return 8; 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) static void preset_v1(struct mtd_info *mtd)
{ {
struct nand_chip *nand_chip = mtd_to_nand(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 = { ...@@ -1269,9 +1278,7 @@ static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
.check_int = check_int_v1_v2, .check_int = check_int_v1_v2,
.irq_control = irq_control_v1_v2, .irq_control = irq_control_v1_v2,
.get_ecc_status = get_ecc_status_v1, .get_ecc_status = get_ecc_status_v1,
.ecclayout_512 = &nandv1_hw_eccoob_smallpage, .ooblayout = &mxc_v1_ooblayout_ops,
.ecclayout_2k = &nandv1_hw_eccoob_largepage,
.ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */
.select_chip = mxc_nand_select_chip_v1_v3, .select_chip = mxc_nand_select_chip_v1_v3,
.correct_data = mxc_nand_correct_data_v1, .correct_data = mxc_nand_correct_data_v1,
.irqpending_quirk = 1, .irqpending_quirk = 1,
...@@ -1294,9 +1301,7 @@ static const struct mxc_nand_devtype_data imx27_nand_devtype_data = { ...@@ -1294,9 +1301,7 @@ static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
.check_int = check_int_v1_v2, .check_int = check_int_v1_v2,
.irq_control = irq_control_v1_v2, .irq_control = irq_control_v1_v2,
.get_ecc_status = get_ecc_status_v1, .get_ecc_status = get_ecc_status_v1,
.ecclayout_512 = &nandv1_hw_eccoob_smallpage, .ooblayout = &mxc_v1_ooblayout_ops,
.ecclayout_2k = &nandv1_hw_eccoob_largepage,
.ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */
.select_chip = mxc_nand_select_chip_v1_v3, .select_chip = mxc_nand_select_chip_v1_v3,
.correct_data = mxc_nand_correct_data_v1, .correct_data = mxc_nand_correct_data_v1,
.irqpending_quirk = 0, .irqpending_quirk = 0,
...@@ -1320,9 +1325,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { ...@@ -1320,9 +1325,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
.check_int = check_int_v1_v2, .check_int = check_int_v1_v2,
.irq_control = irq_control_v1_v2, .irq_control = irq_control_v1_v2,
.get_ecc_status = get_ecc_status_v2, .get_ecc_status = get_ecc_status_v2,
.ecclayout_512 = &nandv2_hw_eccoob_smallpage, .ooblayout = &mxc_v2_ooblayout_ops,
.ecclayout_2k = &nandv2_hw_eccoob_largepage,
.ecclayout_4k = &nandv2_hw_eccoob_4k,
.select_chip = mxc_nand_select_chip_v2, .select_chip = mxc_nand_select_chip_v2,
.correct_data = mxc_nand_correct_data_v2_v3, .correct_data = mxc_nand_correct_data_v2_v3,
.irqpending_quirk = 0, .irqpending_quirk = 0,
...@@ -1346,9 +1349,7 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { ...@@ -1346,9 +1349,7 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
.check_int = check_int_v3, .check_int = check_int_v3,
.irq_control = irq_control_v3, .irq_control = irq_control_v3,
.get_ecc_status = get_ecc_status_v3, .get_ecc_status = get_ecc_status_v3,
.ecclayout_512 = &nandv2_hw_eccoob_smallpage, .ooblayout = &mxc_v2_ooblayout_ops,
.ecclayout_2k = &nandv2_hw_eccoob_largepage,
.ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
.select_chip = mxc_nand_select_chip_v1_v3, .select_chip = mxc_nand_select_chip_v1_v3,
.correct_data = mxc_nand_correct_data_v2_v3, .correct_data = mxc_nand_correct_data_v2_v3,
.irqpending_quirk = 0, .irqpending_quirk = 0,
...@@ -1373,9 +1374,7 @@ static const struct mxc_nand_devtype_data imx53_nand_devtype_data = { ...@@ -1373,9 +1374,7 @@ static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
.check_int = check_int_v3, .check_int = check_int_v3,
.irq_control = irq_control_v3, .irq_control = irq_control_v3,
.get_ecc_status = get_ecc_status_v3, .get_ecc_status = get_ecc_status_v3,
.ecclayout_512 = &nandv2_hw_eccoob_smallpage, .ooblayout = &mxc_v2_ooblayout_ops,
.ecclayout_2k = &nandv2_hw_eccoob_largepage,
.ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
.select_chip = mxc_nand_select_chip_v1_v3, .select_chip = mxc_nand_select_chip_v1_v3,
.correct_data = mxc_nand_correct_data_v2_v3, .correct_data = mxc_nand_correct_data_v2_v3,
.irqpending_quirk = 0, .irqpending_quirk = 0,
...@@ -1576,7 +1575,7 @@ static int mxcnd_probe(struct platform_device *pdev) ...@@ -1576,7 +1575,7 @@ static int mxcnd_probe(struct platform_device *pdev)
this->select_chip = host->devtype_data->select_chip; this->select_chip = host->devtype_data->select_chip;
this->ecc.size = 512; 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) { if (host->pdata.hw_ecc) {
this->ecc.calculate = mxc_nand_calculate_ecc; this->ecc.calculate = mxc_nand_calculate_ecc;
...@@ -1650,12 +1649,11 @@ static int mxcnd_probe(struct platform_device *pdev) ...@@ -1650,12 +1649,11 @@ static int mxcnd_probe(struct platform_device *pdev)
/* Call preset again, with correct writesize this time */ /* Call preset again, with correct writesize this time */
host->devtype_data->preset(mtd); host->devtype_data->preset(mtd);
if (mtd->writesize == 2048) if (!this->ecc.bytes) {
this->ecc.layout = host->devtype_data->ecclayout_2k; if (host->eccsize == 8)
else if (mtd->writesize == 4096) { this->ecc.bytes = 18;
this->ecc.layout = host->devtype_data->ecclayout_4k; else if (host->eccsize == 4)
if (get_eccsize(mtd) == 8) this->ecc.bytes = 9;
ecc_8bit_layout_4k(this->ecc.layout);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment