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

Commit fc256f57 authored by Miquel Raynal's avatar Miquel Raynal Committed by Boris Brezillon
Browse files

mtd: nand: pxa3xx: enable NAND controller if the SoC needs it



Marvell recent SoCs like A7k/A8k do not boot with NAND flash
controller activated by default. Enabling the controller is a matter of
writing in a system controller register that may also be used for other
NAND related choices.

This change is needed to stay bootloader independent.

Signed-off-by: default avatarMiquel Raynal <miquel.raynal@free-electrons.com>
Signed-off-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
parent b330213d
Loading
Loading
Loading
Loading
+37 −4
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_data/mtd-nand-pxa3xx.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>

#define	CHIP_DELAY_TIMEOUT	msecs_to_jiffies(200)
#define NAND_STOP_DELAY		msecs_to_jiffies(40)
@@ -45,6 +47,10 @@
 */
#define INIT_BUFFER_SIZE	2048

/* System control register and bit to enable NAND on some SoCs */
#define GENCONF_SOC_DEVICE_MUX	0x208
#define GENCONF_SOC_DEVICE_MUX_NFC_EN BIT(0)

/* registers and bit definitions */
#define NDCR		(0x00) /* Control register */
#define NDTR0CS0	(0x04) /* Timing Parameter 0 for CS0 */
@@ -174,6 +180,7 @@ enum {
enum pxa3xx_nand_variant {
	PXA3XX_NAND_VARIANT_PXA,
	PXA3XX_NAND_VARIANT_ARMADA370,
	PXA3XX_NAND_VARIANT_ARMADA_8K,
};

struct pxa3xx_nand_host {
@@ -425,6 +432,10 @@ static const struct of_device_id pxa3xx_nand_dt_ids[] = {
		.compatible = "marvell,armada370-nand",
		.data       = (void *)PXA3XX_NAND_VARIANT_ARMADA370,
	},
	{
		.compatible = "marvell,armada-8k-nand",
		.data       = (void *)PXA3XX_NAND_VARIANT_ARMADA_8K,
	},
	{}
};
MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
@@ -825,7 +836,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
		info->retcode = ERR_UNCORERR;
	if (status & NDSR_CORERR) {
		info->retcode = ERR_CORERR;
		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 &&
		if ((info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
		     info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) &&
		    info->ecc_bch)
			info->ecc_err_cnt = NDSR_ERR_CNT(status);
		else
@@ -888,7 +900,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
		nand_writel(info, NDCB0, info->ndcb2);

		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
		    info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K)
			nand_writel(info, NDCB0, info->ndcb3);
	}

@@ -1671,7 +1684,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
		chip->options |= NAND_BUSWIDTH_16;

	/* Device detection must be done with ECC disabled */
	if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
	if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
	    info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K)
		nand_writel(info, NDECCCTRL, 0x0);

	if (pdata->flash_bbt)
@@ -1709,7 +1723,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
	 * (aka splitted) command handling,
	 */
	if (mtd->writesize > PAGE_CHUNK_SIZE) {
		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
		    info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) {
			chip->cmdfunc = nand_cmdfunc_extended;
		} else {
			dev_err(&info->pdev->dev,
@@ -1928,6 +1943,24 @@ static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
	if (!of_id)
		return 0;

	/*
	 * Some SoCs like A7k/A8k need to enable manually the NAND
	 * controller to avoid being bootloader dependent. This is done
	 * through the use of a single bit in the System Functions registers.
	 */
	if (pxa3xx_nand_get_variant(pdev) == PXA3XX_NAND_VARIANT_ARMADA_8K) {
		struct regmap *sysctrl_base = syscon_regmap_lookup_by_phandle(
			pdev->dev.of_node, "marvell,system-controller");
		u32 reg;

		if (IS_ERR(sysctrl_base))
			return PTR_ERR(sysctrl_base);

		regmap_read(sysctrl_base, GENCONF_SOC_DEVICE_MUX, &reg);
		reg |= GENCONF_SOC_DEVICE_MUX_NFC_EN;
		regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
	}

	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
	if (!pdata)
		return -ENOMEM;