1// SPDX-License-Identifier: GPL-2.0+ 2 3#include <common.h> 4#include <asm/io.h> 5#include <memalign.h> 6#include <nand.h> 7#include <linux/bitops.h> 8#include <linux/errno.h> 9#include <linux/io.h> 10#include <linux/ioport.h> 11#include <dm.h> 12#include <linux/printk.h> 13 14#include "brcmnand.h" 15 16struct bcm68360_nand_soc { 17 struct brcmnand_soc soc; 18 void __iomem *base; 19}; 20 21#define BCM68360_NAND_INT 0x00 22#define BCM68360_NAND_STATUS_SHIFT 0 23#define BCM68360_NAND_STATUS_MASK (0xfff << BCM68360_NAND_STATUS_SHIFT) 24 25#define BCM68360_NAND_INT_EN 0x04 26#define BCM68360_NAND_ENABLE_SHIFT 0 27#define BCM68360_NAND_ENABLE_MASK (0xffff << BCM68360_NAND_ENABLE_SHIFT) 28 29enum { 30 BCM68360_NP_READ = BIT(0), 31 BCM68360_BLOCK_ERASE = BIT(1), 32 BCM68360_COPY_BACK = BIT(2), 33 BCM68360_PAGE_PGM = BIT(3), 34 BCM68360_CTRL_READY = BIT(4), 35 BCM68360_DEV_RBPIN = BIT(5), 36 BCM68360_ECC_ERR_UNC = BIT(6), 37 BCM68360_ECC_ERR_CORR = BIT(7), 38}; 39 40static bool bcm68360_nand_intc_ack(struct brcmnand_soc *soc) 41{ 42 struct bcm68360_nand_soc *priv = 43 container_of(soc, struct bcm68360_nand_soc, soc); 44 void __iomem *mmio = priv->base + BCM68360_NAND_INT; 45 u32 val = brcmnand_readl(mmio); 46 47 if (val & (BCM68360_CTRL_READY << BCM68360_NAND_STATUS_SHIFT)) { 48 /* Ack interrupt */ 49 val &= ~BCM68360_NAND_STATUS_MASK; 50 val |= BCM68360_CTRL_READY << BCM68360_NAND_STATUS_SHIFT; 51 brcmnand_writel(val, mmio); 52 return true; 53 } 54 55 return false; 56} 57 58static void bcm68360_nand_intc_set(struct brcmnand_soc *soc, bool en) 59{ 60 struct bcm68360_nand_soc *priv = 61 container_of(soc, struct bcm68360_nand_soc, soc); 62 void __iomem *mmio = priv->base + BCM68360_NAND_INT_EN; 63 u32 val = brcmnand_readl(mmio); 64 65 /* Don't ack any interrupts */ 66 val &= ~BCM68360_NAND_STATUS_MASK; 67 68 if (en) 69 val |= BCM68360_CTRL_READY << BCM68360_NAND_ENABLE_SHIFT; 70 else 71 val &= ~(BCM68360_CTRL_READY << BCM68360_NAND_ENABLE_SHIFT); 72 73 brcmnand_writel(val, mmio); 74} 75 76static int bcm68360_nand_probe(struct udevice *dev) 77{ 78 struct udevice *pdev = dev; 79 struct bcm68360_nand_soc *priv = dev_get_priv(dev); 80 struct brcmnand_soc *soc; 81 struct resource res; 82 83 soc = &priv->soc; 84 85 dev_read_resource_byname(pdev, "nand-int-base", &res); 86 priv->base = devm_ioremap(dev, res.start, resource_size(&res)); 87 if (IS_ERR(priv->base)) 88 return PTR_ERR(priv->base); 89 90 soc->ctlrdy_ack = bcm68360_nand_intc_ack; 91 soc->ctlrdy_set_enabled = bcm68360_nand_intc_set; 92 93 /* Disable and ack all interrupts */ 94 brcmnand_writel(0, priv->base + BCM68360_NAND_INT_EN); 95 brcmnand_writel(0, priv->base + BCM68360_NAND_INT); 96 97 return brcmnand_probe(pdev, soc); 98} 99 100static const struct udevice_id bcm68360_nand_dt_ids[] = { 101 { 102 .compatible = "brcm,nand-bcm68360", 103 }, 104 { /* sentinel */ } 105}; 106 107U_BOOT_DRIVER(bcm68360_nand) = { 108 .name = "bcm68360-nand", 109 .id = UCLASS_MTD, 110 .of_match = bcm68360_nand_dt_ids, 111 .probe = bcm68360_nand_probe, 112 .priv_auto = sizeof(struct bcm68360_nand_soc), 113}; 114 115void board_nand_init(void) 116{ 117 struct udevice *dev; 118 int ret; 119 120 ret = uclass_get_device_by_driver(UCLASS_MTD, 121 DM_DRIVER_GET(bcm68360_nand), &dev); 122 if (ret && ret != -ENODEV) 123 pr_err("Failed to initialize %s. (error %d)\n", dev->name, 124 ret); 125} 126