Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a894cf6c authored by Boris Brezillon's avatar Boris Brezillon
Browse files

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
Loading
Loading
Loading
Loading
+105 −107
Original line number Diff line number Diff line
@@ -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;
	}

	/*