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