1*1802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2ca22f040SBrian Norris /* 3ca22f040SBrian Norris * Copyright © 2015 Broadcom Corporation 4ca22f040SBrian Norris */ 5ca22f040SBrian Norris 6ca22f040SBrian Norris #include <linux/device.h> 7ca22f040SBrian Norris #include <linux/io.h> 8ca22f040SBrian Norris #include <linux/ioport.h> 9ca22f040SBrian Norris #include <linux/module.h> 10ca22f040SBrian Norris #include <linux/of.h> 11ca22f040SBrian Norris #include <linux/of_address.h> 12ca22f040SBrian Norris #include <linux/platform_device.h> 13ca22f040SBrian Norris #include <linux/slab.h> 14ca22f040SBrian Norris 15ca22f040SBrian Norris #include "brcmnand.h" 16ca22f040SBrian Norris 17a86c947bSBrian Norris struct iproc_nand_soc { 18a86c947bSBrian Norris struct brcmnand_soc soc; 19a86c947bSBrian Norris 20ca22f040SBrian Norris void __iomem *idm_base; 21ca22f040SBrian Norris void __iomem *ext_base; 22ca22f040SBrian Norris spinlock_t idm_lock; 23ca22f040SBrian Norris }; 24ca22f040SBrian Norris 25ca22f040SBrian Norris #define IPROC_NAND_CTLR_READY_OFFSET 0x10 26ca22f040SBrian Norris #define IPROC_NAND_CTLR_READY BIT(0) 27ca22f040SBrian Norris 28ca22f040SBrian Norris #define IPROC_NAND_IO_CTRL_OFFSET 0x00 29ca22f040SBrian Norris #define IPROC_NAND_APB_LE_MODE BIT(24) 30ca22f040SBrian Norris #define IPROC_NAND_INT_CTRL_READ_ENABLE BIT(6) 31ca22f040SBrian Norris 32ca22f040SBrian Norris static bool iproc_nand_intc_ack(struct brcmnand_soc *soc) 33ca22f040SBrian Norris { 34a86c947bSBrian Norris struct iproc_nand_soc *priv = 35a86c947bSBrian Norris container_of(soc, struct iproc_nand_soc, soc); 36ca22f040SBrian Norris void __iomem *mmio = priv->ext_base + IPROC_NAND_CTLR_READY_OFFSET; 37ca22f040SBrian Norris u32 val = brcmnand_readl(mmio); 38ca22f040SBrian Norris 39ca22f040SBrian Norris if (val & IPROC_NAND_CTLR_READY) { 40ca22f040SBrian Norris brcmnand_writel(IPROC_NAND_CTLR_READY, mmio); 41ca22f040SBrian Norris return true; 42ca22f040SBrian Norris } 43ca22f040SBrian Norris 44ca22f040SBrian Norris return false; 45ca22f040SBrian Norris } 46ca22f040SBrian Norris 47ca22f040SBrian Norris static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en) 48ca22f040SBrian Norris { 49a86c947bSBrian Norris struct iproc_nand_soc *priv = 50a86c947bSBrian Norris container_of(soc, struct iproc_nand_soc, soc); 51ca22f040SBrian Norris void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET; 52ca22f040SBrian Norris u32 val; 53ca22f040SBrian Norris unsigned long flags; 54ca22f040SBrian Norris 55ca22f040SBrian Norris spin_lock_irqsave(&priv->idm_lock, flags); 56ca22f040SBrian Norris 57ca22f040SBrian Norris val = brcmnand_readl(mmio); 58ca22f040SBrian Norris 59ca22f040SBrian Norris if (en) 60ca22f040SBrian Norris val |= IPROC_NAND_INT_CTRL_READ_ENABLE; 61ca22f040SBrian Norris else 62ca22f040SBrian Norris val &= ~IPROC_NAND_INT_CTRL_READ_ENABLE; 63ca22f040SBrian Norris 64ca22f040SBrian Norris brcmnand_writel(val, mmio); 65ca22f040SBrian Norris 66ca22f040SBrian Norris spin_unlock_irqrestore(&priv->idm_lock, flags); 67ca22f040SBrian Norris } 68ca22f040SBrian Norris 69eab7fdc7SRay Jui static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare, 70eab7fdc7SRay Jui bool is_param) 71ca22f040SBrian Norris { 72a86c947bSBrian Norris struct iproc_nand_soc *priv = 73a86c947bSBrian Norris container_of(soc, struct iproc_nand_soc, soc); 74ca22f040SBrian Norris void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET; 75ca22f040SBrian Norris u32 val; 76ca22f040SBrian Norris unsigned long flags; 77ca22f040SBrian Norris 78ca22f040SBrian Norris spin_lock_irqsave(&priv->idm_lock, flags); 79ca22f040SBrian Norris 80ca22f040SBrian Norris val = brcmnand_readl(mmio); 81ca22f040SBrian Norris 82eab7fdc7SRay Jui /* 83eab7fdc7SRay Jui * In the case of BE or when dealing with NAND data, alway configure 84eab7fdc7SRay Jui * the APB bus to LE mode before accessing the FIFO and back to BE mode 85eab7fdc7SRay Jui * after the access is done 86eab7fdc7SRay Jui */ 87eab7fdc7SRay Jui if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) || !is_param) { 88ca22f040SBrian Norris if (prepare) 89ca22f040SBrian Norris val |= IPROC_NAND_APB_LE_MODE; 90ca22f040SBrian Norris else 91ca22f040SBrian Norris val &= ~IPROC_NAND_APB_LE_MODE; 92eab7fdc7SRay Jui } else { /* when in LE accessing the parameter page, keep APB in BE */ 93eab7fdc7SRay Jui val &= ~IPROC_NAND_APB_LE_MODE; 94eab7fdc7SRay Jui } 95ca22f040SBrian Norris 96ca22f040SBrian Norris brcmnand_writel(val, mmio); 97ca22f040SBrian Norris 98ca22f040SBrian Norris spin_unlock_irqrestore(&priv->idm_lock, flags); 99ca22f040SBrian Norris } 100ca22f040SBrian Norris 101ca22f040SBrian Norris static int iproc_nand_probe(struct platform_device *pdev) 102ca22f040SBrian Norris { 103ca22f040SBrian Norris struct device *dev = &pdev->dev; 104a86c947bSBrian Norris struct iproc_nand_soc *priv; 105ca22f040SBrian Norris struct brcmnand_soc *soc; 106ca22f040SBrian Norris struct resource *res; 107ca22f040SBrian Norris 108ca22f040SBrian Norris priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 109ca22f040SBrian Norris if (!priv) 110ca22f040SBrian Norris return -ENOMEM; 111a86c947bSBrian Norris soc = &priv->soc; 112ca22f040SBrian Norris 113ca22f040SBrian Norris spin_lock_init(&priv->idm_lock); 114ca22f040SBrian Norris 115ca22f040SBrian Norris res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-idm"); 116ca22f040SBrian Norris priv->idm_base = devm_ioremap_resource(dev, res); 117ca22f040SBrian Norris if (IS_ERR(priv->idm_base)) 118ca22f040SBrian Norris return PTR_ERR(priv->idm_base); 119ca22f040SBrian Norris 120ca22f040SBrian Norris res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-ext"); 121ca22f040SBrian Norris priv->ext_base = devm_ioremap_resource(dev, res); 122ca22f040SBrian Norris if (IS_ERR(priv->ext_base)) 123ca22f040SBrian Norris return PTR_ERR(priv->ext_base); 124ca22f040SBrian Norris 125ca22f040SBrian Norris soc->ctlrdy_ack = iproc_nand_intc_ack; 126ca22f040SBrian Norris soc->ctlrdy_set_enabled = iproc_nand_intc_set; 127ca22f040SBrian Norris soc->prepare_data_bus = iproc_nand_apb_access; 128ca22f040SBrian Norris 129ca22f040SBrian Norris return brcmnand_probe(pdev, soc); 130ca22f040SBrian Norris } 131ca22f040SBrian Norris 132ca22f040SBrian Norris static const struct of_device_id iproc_nand_of_match[] = { 133ca22f040SBrian Norris { .compatible = "brcm,nand-iproc" }, 134ca22f040SBrian Norris {}, 135ca22f040SBrian Norris }; 136ca22f040SBrian Norris MODULE_DEVICE_TABLE(of, iproc_nand_of_match); 137ca22f040SBrian Norris 138ca22f040SBrian Norris static struct platform_driver iproc_nand_driver = { 139ca22f040SBrian Norris .probe = iproc_nand_probe, 140ca22f040SBrian Norris .remove = brcmnand_remove, 141ca22f040SBrian Norris .driver = { 142ca22f040SBrian Norris .name = "iproc_nand", 143ca22f040SBrian Norris .pm = &brcmnand_pm_ops, 144ca22f040SBrian Norris .of_match_table = iproc_nand_of_match, 145ca22f040SBrian Norris } 146ca22f040SBrian Norris }; 147ca22f040SBrian Norris module_platform_driver(iproc_nand_driver); 148ca22f040SBrian Norris 149ca22f040SBrian Norris MODULE_LICENSE("GPL v2"); 150ca22f040SBrian Norris MODULE_AUTHOR("Brian Norris"); 151ca22f040SBrian Norris MODULE_AUTHOR("Ray Jui"); 152ca22f040SBrian Norris MODULE_DESCRIPTION("NAND driver for Broadcom IPROC-based SoCs"); 153