11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
293db446aSBoris Brezillon /*
393db446aSBoris Brezillon * Copyright 2015 Simon Arlott
493db446aSBoris Brezillon *
593db446aSBoris Brezillon * Derived from bcm63138_nand.c:
693db446aSBoris Brezillon * Copyright © 2015 Broadcom Corporation
793db446aSBoris Brezillon *
893db446aSBoris Brezillon * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
993db446aSBoris Brezillon * Copyright 2000-2010 Broadcom Corporation
1093db446aSBoris Brezillon *
1193db446aSBoris Brezillon * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/flash/nandflash.c:
1293db446aSBoris Brezillon * Copyright 2000-2010 Broadcom Corporation
1393db446aSBoris Brezillon */
1493db446aSBoris Brezillon
1593db446aSBoris Brezillon #include <linux/device.h>
1693db446aSBoris Brezillon #include <linux/io.h>
1793db446aSBoris Brezillon #include <linux/ioport.h>
1893db446aSBoris Brezillon #include <linux/module.h>
1993db446aSBoris Brezillon #include <linux/of.h>
2093db446aSBoris Brezillon #include <linux/of_address.h>
2193db446aSBoris Brezillon #include <linux/platform_device.h>
2293db446aSBoris Brezillon #include <linux/slab.h>
2393db446aSBoris Brezillon
2493db446aSBoris Brezillon #include "brcmnand.h"
2593db446aSBoris Brezillon
2693db446aSBoris Brezillon struct bcm6368_nand_soc {
2793db446aSBoris Brezillon struct brcmnand_soc soc;
2893db446aSBoris Brezillon void __iomem *base;
2993db446aSBoris Brezillon };
3093db446aSBoris Brezillon
3193db446aSBoris Brezillon #define BCM6368_NAND_INT 0x00
3293db446aSBoris Brezillon #define BCM6368_NAND_STATUS_SHIFT 0
3393db446aSBoris Brezillon #define BCM6368_NAND_STATUS_MASK (0xfff << BCM6368_NAND_STATUS_SHIFT)
3493db446aSBoris Brezillon #define BCM6368_NAND_ENABLE_SHIFT 16
3593db446aSBoris Brezillon #define BCM6368_NAND_ENABLE_MASK (0xffff << BCM6368_NAND_ENABLE_SHIFT)
3693db446aSBoris Brezillon #define BCM6368_NAND_BASE_ADDR0 0x04
3793db446aSBoris Brezillon #define BCM6368_NAND_BASE_ADDR1 0x0c
3893db446aSBoris Brezillon
3993db446aSBoris Brezillon enum {
4093db446aSBoris Brezillon BCM6368_NP_READ = BIT(0),
4193db446aSBoris Brezillon BCM6368_BLOCK_ERASE = BIT(1),
4293db446aSBoris Brezillon BCM6368_COPY_BACK = BIT(2),
4393db446aSBoris Brezillon BCM6368_PAGE_PGM = BIT(3),
4493db446aSBoris Brezillon BCM6368_CTRL_READY = BIT(4),
4593db446aSBoris Brezillon BCM6368_DEV_RBPIN = BIT(5),
4693db446aSBoris Brezillon BCM6368_ECC_ERR_UNC = BIT(6),
4793db446aSBoris Brezillon BCM6368_ECC_ERR_CORR = BIT(7),
4893db446aSBoris Brezillon };
4993db446aSBoris Brezillon
bcm6368_nand_intc_ack(struct brcmnand_soc * soc)5093db446aSBoris Brezillon static bool bcm6368_nand_intc_ack(struct brcmnand_soc *soc)
5193db446aSBoris Brezillon {
5293db446aSBoris Brezillon struct bcm6368_nand_soc *priv =
5393db446aSBoris Brezillon container_of(soc, struct bcm6368_nand_soc, soc);
5493db446aSBoris Brezillon void __iomem *mmio = priv->base + BCM6368_NAND_INT;
5593db446aSBoris Brezillon u32 val = brcmnand_readl(mmio);
5693db446aSBoris Brezillon
5793db446aSBoris Brezillon if (val & (BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT)) {
5893db446aSBoris Brezillon /* Ack interrupt */
5993db446aSBoris Brezillon val &= ~BCM6368_NAND_STATUS_MASK;
6093db446aSBoris Brezillon val |= BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT;
6193db446aSBoris Brezillon brcmnand_writel(val, mmio);
6293db446aSBoris Brezillon return true;
6393db446aSBoris Brezillon }
6493db446aSBoris Brezillon
6593db446aSBoris Brezillon return false;
6693db446aSBoris Brezillon }
6793db446aSBoris Brezillon
bcm6368_nand_intc_set(struct brcmnand_soc * soc,bool en)6893db446aSBoris Brezillon static void bcm6368_nand_intc_set(struct brcmnand_soc *soc, bool en)
6993db446aSBoris Brezillon {
7093db446aSBoris Brezillon struct bcm6368_nand_soc *priv =
7193db446aSBoris Brezillon container_of(soc, struct bcm6368_nand_soc, soc);
7293db446aSBoris Brezillon void __iomem *mmio = priv->base + BCM6368_NAND_INT;
7393db446aSBoris Brezillon u32 val = brcmnand_readl(mmio);
7493db446aSBoris Brezillon
7593db446aSBoris Brezillon /* Don't ack any interrupts */
7693db446aSBoris Brezillon val &= ~BCM6368_NAND_STATUS_MASK;
7793db446aSBoris Brezillon
7893db446aSBoris Brezillon if (en)
7993db446aSBoris Brezillon val |= BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT;
8093db446aSBoris Brezillon else
8193db446aSBoris Brezillon val &= ~(BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT);
8293db446aSBoris Brezillon
8393db446aSBoris Brezillon brcmnand_writel(val, mmio);
8493db446aSBoris Brezillon }
8593db446aSBoris Brezillon
bcm6368_nand_probe(struct platform_device * pdev)8693db446aSBoris Brezillon static int bcm6368_nand_probe(struct platform_device *pdev)
8793db446aSBoris Brezillon {
8893db446aSBoris Brezillon struct device *dev = &pdev->dev;
8993db446aSBoris Brezillon struct bcm6368_nand_soc *priv;
9093db446aSBoris Brezillon struct brcmnand_soc *soc;
9193db446aSBoris Brezillon
9293db446aSBoris Brezillon priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
9393db446aSBoris Brezillon if (!priv)
9493db446aSBoris Brezillon return -ENOMEM;
9593db446aSBoris Brezillon soc = &priv->soc;
9693db446aSBoris Brezillon
97*df9e5170SCai Huoqing priv->base = devm_platform_ioremap_resource_byname(pdev, "nand-int-base");
9893db446aSBoris Brezillon if (IS_ERR(priv->base))
9993db446aSBoris Brezillon return PTR_ERR(priv->base);
10093db446aSBoris Brezillon
10193db446aSBoris Brezillon soc->ctlrdy_ack = bcm6368_nand_intc_ack;
10293db446aSBoris Brezillon soc->ctlrdy_set_enabled = bcm6368_nand_intc_set;
10393db446aSBoris Brezillon
10493db446aSBoris Brezillon /* Disable and ack all interrupts */
10593db446aSBoris Brezillon brcmnand_writel(0, priv->base + BCM6368_NAND_INT);
10693db446aSBoris Brezillon brcmnand_writel(BCM6368_NAND_STATUS_MASK,
10793db446aSBoris Brezillon priv->base + BCM6368_NAND_INT);
10893db446aSBoris Brezillon
10993db446aSBoris Brezillon return brcmnand_probe(pdev, soc);
11093db446aSBoris Brezillon }
11193db446aSBoris Brezillon
11293db446aSBoris Brezillon static const struct of_device_id bcm6368_nand_of_match[] = {
11393db446aSBoris Brezillon { .compatible = "brcm,nand-bcm6368" },
11493db446aSBoris Brezillon {},
11593db446aSBoris Brezillon };
11693db446aSBoris Brezillon MODULE_DEVICE_TABLE(of, bcm6368_nand_of_match);
11793db446aSBoris Brezillon
11893db446aSBoris Brezillon static struct platform_driver bcm6368_nand_driver = {
11993db446aSBoris Brezillon .probe = bcm6368_nand_probe,
12093db446aSBoris Brezillon .remove = brcmnand_remove,
12193db446aSBoris Brezillon .driver = {
12293db446aSBoris Brezillon .name = "bcm6368_nand",
12393db446aSBoris Brezillon .pm = &brcmnand_pm_ops,
12493db446aSBoris Brezillon .of_match_table = bcm6368_nand_of_match,
12593db446aSBoris Brezillon }
12693db446aSBoris Brezillon };
12793db446aSBoris Brezillon module_platform_driver(bcm6368_nand_driver);
12893db446aSBoris Brezillon
12993db446aSBoris Brezillon MODULE_LICENSE("GPL");
13093db446aSBoris Brezillon MODULE_AUTHOR("Simon Arlott");
13193db446aSBoris Brezillon MODULE_DESCRIPTION("NAND driver for BCM6368");
132