summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/brcmnand
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/brcmnand')
-rw-r--r--drivers/mtd/nand/brcmnand/bcm63138_nand.c18
-rw-r--r--drivers/mtd/nand/brcmnand/brcmnand.c61
-rw-r--r--drivers/mtd/nand/brcmnand/brcmnand.h2
-rw-r--r--drivers/mtd/nand/brcmnand/iproc_nand.c22
4 files changed, 67 insertions, 36 deletions
diff --git a/drivers/mtd/nand/brcmnand/bcm63138_nand.c b/drivers/mtd/nand/brcmnand/bcm63138_nand.c
index 3f4c44c24..59444b3a6 100644
--- a/drivers/mtd/nand/brcmnand/bcm63138_nand.c
+++ b/drivers/mtd/nand/brcmnand/bcm63138_nand.c
@@ -22,7 +22,8 @@
#include "brcmnand.h"
-struct bcm63138_nand_soc_priv {
+struct bcm63138_nand_soc {
+ struct brcmnand_soc soc;
void __iomem *base;
};
@@ -35,7 +36,8 @@ enum {
static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc)
{
- struct bcm63138_nand_soc_priv *priv = soc->priv;
+ struct bcm63138_nand_soc *priv =
+ container_of(soc, struct bcm63138_nand_soc, soc);
void __iomem *mmio = priv->base + BCM63138_NAND_INT_STATUS;
u32 val = brcmnand_readl(mmio);
@@ -49,7 +51,8 @@ static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc)
static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en)
{
- struct bcm63138_nand_soc_priv *priv = soc->priv;
+ struct bcm63138_nand_soc *priv =
+ container_of(soc, struct bcm63138_nand_soc, soc);
void __iomem *mmio = priv->base + BCM63138_NAND_INT_EN;
u32 val = brcmnand_readl(mmio);
@@ -64,25 +67,20 @@ static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en)
static int bcm63138_nand_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct bcm63138_nand_soc_priv *priv;
+ struct bcm63138_nand_soc *priv;
struct brcmnand_soc *soc;
struct resource *res;
- soc = devm_kzalloc(dev, sizeof(*soc), GFP_KERNEL);
- if (!soc)
- return -ENOMEM;
-
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ soc = &priv->soc;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-int-base");
priv->base = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- soc->pdev = pdev;
- soc->priv = priv;
soc->ctlrdy_ack = bcm63138_nand_intc_ack;
soc->ctlrdy_set_enabled = bcm63138_nand_intc_set;
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index fddb795ee..12c6190c6 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -344,6 +344,28 @@ static const u8 brcmnand_cs_offsets_cs0[] = {
[BRCMNAND_CS_TIMING2] = 0x14,
};
+/*
+ * Bitfields for the CFG and CFG_EXT registers. Pre-v7.1 controllers only had
+ * one config register, but once the bitfields overflowed, newer controllers
+ * (v7.1 and newer) added a CFG_EXT register and shuffled a few fields around.
+ */
+enum {
+ CFG_BLK_ADR_BYTES_SHIFT = 8,
+ CFG_COL_ADR_BYTES_SHIFT = 12,
+ CFG_FUL_ADR_BYTES_SHIFT = 16,
+ CFG_BUS_WIDTH_SHIFT = 23,
+ CFG_BUS_WIDTH = BIT(CFG_BUS_WIDTH_SHIFT),
+ CFG_DEVICE_SIZE_SHIFT = 24,
+
+ /* Only for pre-v7.1 (with no CFG_EXT register) */
+ CFG_PAGE_SIZE_SHIFT = 20,
+ CFG_BLK_SIZE_SHIFT = 28,
+
+ /* Only for v7.1+ (with CFG_EXT register) */
+ CFG_EXT_PAGE_SIZE_SHIFT = 0,
+ CFG_EXT_BLK_SIZE_SHIFT = 4,
+};
+
/* BRCMNAND_INTFC_STATUS */
enum {
INTFC_FLASH_STATUS = GENMASK(7, 0),
@@ -1544,9 +1566,9 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
dev_dbg(ctrl->dev, "write %llx <- %p\n", (unsigned long long)addr, buf);
- if (unlikely((u32)buf & 0x03)) {
+ if (unlikely((unsigned long)buf & 0x03)) {
dev_warn(ctrl->dev, "unaligned buffer: %p\n", buf);
- buf = (u32 *)((u32)buf & ~0x03);
+ buf = (u32 *)((unsigned long)buf & ~0x03);
}
brcmnand_wp(mtd, 0);
@@ -1606,7 +1628,7 @@ out:
}
static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required)
+ const uint8_t *buf, int oob_required, int page)
{
struct brcmnand_host *host = chip->priv;
void *oob = oob_required ? chip->oob_poi : NULL;
@@ -1617,7 +1639,7 @@ static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
static int brcmnand_write_page_raw(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf,
- int oob_required)
+ int oob_required, int page)
{
struct brcmnand_host *host = chip->priv;
void *oob = oob_required ? chip->oob_poi : NULL;
@@ -1720,17 +1742,19 @@ static int brcmnand_set_cfg(struct brcmnand_host *host,
}
device_size = fls64(cfg->device_size) - fls64(BRCMNAND_MIN_DEVSIZE);
- tmp = (cfg->blk_adr_bytes << 8) |
- (cfg->col_adr_bytes << 12) |
- (cfg->ful_adr_bytes << 16) |
- (!!(cfg->device_width == 16) << 23) |
- (device_size << 24);
+ tmp = (cfg->blk_adr_bytes << CFG_BLK_ADR_BYTES_SHIFT) |
+ (cfg->col_adr_bytes << CFG_COL_ADR_BYTES_SHIFT) |
+ (cfg->ful_adr_bytes << CFG_FUL_ADR_BYTES_SHIFT) |
+ (!!(cfg->device_width == 16) << CFG_BUS_WIDTH_SHIFT) |
+ (device_size << CFG_DEVICE_SIZE_SHIFT);
if (cfg_offs == cfg_ext_offs) {
- tmp |= (page_size << 20) | (block_size << 28);
+ tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) |
+ (block_size << CFG_BLK_SIZE_SHIFT);
nand_writereg(ctrl, cfg_offs, tmp);
} else {
nand_writereg(ctrl, cfg_offs, tmp);
- tmp = page_size | (block_size << 4);
+ tmp = (page_size << CFG_EXT_PAGE_SIZE_SHIFT) |
+ (block_size << CFG_EXT_BLK_SIZE_SHIFT);
nand_writereg(ctrl, cfg_ext_offs, tmp);
}
@@ -1792,7 +1816,8 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
memset(cfg, 0, sizeof(*cfg));
- ret = of_property_read_u32(chip->dn, "brcm,nand-oob-sector-size",
+ ret = of_property_read_u32(chip->flash_node,
+ "brcm,nand-oob-sector-size",
&oob_sector);
if (ret) {
/* Use detected size */
@@ -1888,6 +1913,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host)
struct mtd_info *mtd;
struct nand_chip *chip;
int ret;
+ u16 cfg_offs;
struct mtd_part_parser_data ppdata = { .of_node = dn };
ret = of_property_read_u32(dn, "reg", &host->cs);
@@ -1899,7 +1925,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host)
mtd = &host->mtd;
chip = &host->chip;
- chip->dn = dn;
+ chip->flash_node = dn;
chip->priv = host;
mtd->priv = chip;
mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d",
@@ -1930,6 +1956,15 @@ static int brcmnand_init_cs(struct brcmnand_host *host)
chip->controller = &ctrl->controller;
+ /*
+ * The bootloader might have configured 16bit mode but
+ * NAND READID command only works in 8bit mode. We force
+ * 8bit mode here to ensure that NAND READID commands works.
+ */
+ cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
+ nand_writereg(ctrl, cfg_offs,
+ nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
+
if (nand_scan_ident(mtd, 1, NULL))
return -ENXIO;
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.h b/drivers/mtd/nand/brcmnand/brcmnand.h
index 169f99e38..ef5eabba8 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.h
+++ b/drivers/mtd/nand/brcmnand/brcmnand.h
@@ -21,8 +21,6 @@ struct platform_device;
struct dev_pm_ops;
struct brcmnand_soc {
- struct platform_device *pdev;
- void *priv;
bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare);
diff --git a/drivers/mtd/nand/brcmnand/iproc_nand.c b/drivers/mtd/nand/brcmnand/iproc_nand.c
index 683495c74..585596c54 100644
--- a/drivers/mtd/nand/brcmnand/iproc_nand.c
+++ b/drivers/mtd/nand/brcmnand/iproc_nand.c
@@ -22,7 +22,9 @@
#include "brcmnand.h"
-struct iproc_nand_soc_priv {
+struct iproc_nand_soc {
+ struct brcmnand_soc soc;
+
void __iomem *idm_base;
void __iomem *ext_base;
spinlock_t idm_lock;
@@ -37,7 +39,8 @@ struct iproc_nand_soc_priv {
static bool iproc_nand_intc_ack(struct brcmnand_soc *soc)
{
- struct iproc_nand_soc_priv *priv = soc->priv;
+ struct iproc_nand_soc *priv =
+ container_of(soc, struct iproc_nand_soc, soc);
void __iomem *mmio = priv->ext_base + IPROC_NAND_CTLR_READY_OFFSET;
u32 val = brcmnand_readl(mmio);
@@ -51,7 +54,8 @@ static bool iproc_nand_intc_ack(struct brcmnand_soc *soc)
static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
{
- struct iproc_nand_soc_priv *priv = soc->priv;
+ struct iproc_nand_soc *priv =
+ container_of(soc, struct iproc_nand_soc, soc);
void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
u32 val;
unsigned long flags;
@@ -72,7 +76,8 @@ static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
{
- struct iproc_nand_soc_priv *priv = soc->priv;
+ struct iproc_nand_soc *priv =
+ container_of(soc, struct iproc_nand_soc, soc);
void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
u32 val;
unsigned long flags;
@@ -94,17 +99,14 @@ static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
static int iproc_nand_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct iproc_nand_soc_priv *priv;
+ struct iproc_nand_soc *priv;
struct brcmnand_soc *soc;
struct resource *res;
- soc = devm_kzalloc(dev, sizeof(*soc), GFP_KERNEL);
- if (!soc)
- return -ENOMEM;
-
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ soc = &priv->soc;
spin_lock_init(&priv->idm_lock);
@@ -118,8 +120,6 @@ static int iproc_nand_probe(struct platform_device *pdev)
if (IS_ERR(priv->ext_base))
return PTR_ERR(priv->ext_base);
- soc->pdev = pdev;
- soc->priv = priv;
soc->ctlrdy_ack = iproc_nand_intc_ack;
soc->ctlrdy_set_enabled = iproc_nand_intc_set;
soc->prepare_data_bus = iproc_nand_apb_access;