xref: /linux/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
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 
97df9e5170SCai 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,
120*215283a1SUwe Kleine-König 	.remove_new		= 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