1 /* 2 * Copyright 2015 Simon Arlott 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * Derived from bcm63138_nand.c: 14 * Copyright © 2015 Broadcom Corporation 15 * 16 * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h: 17 * Copyright 2000-2010 Broadcom Corporation 18 * 19 * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/flash/nandflash.c: 20 * Copyright 2000-2010 Broadcom Corporation 21 */ 22 23 #include <linux/device.h> 24 #include <linux/io.h> 25 #include <linux/ioport.h> 26 #include <linux/module.h> 27 #include <linux/of.h> 28 #include <linux/of_address.h> 29 #include <linux/platform_device.h> 30 #include <linux/slab.h> 31 32 #include "brcmnand.h" 33 34 struct bcm6368_nand_soc { 35 struct brcmnand_soc soc; 36 void __iomem *base; 37 }; 38 39 #define BCM6368_NAND_INT 0x00 40 #define BCM6368_NAND_STATUS_SHIFT 0 41 #define BCM6368_NAND_STATUS_MASK (0xfff << BCM6368_NAND_STATUS_SHIFT) 42 #define BCM6368_NAND_ENABLE_SHIFT 16 43 #define BCM6368_NAND_ENABLE_MASK (0xffff << BCM6368_NAND_ENABLE_SHIFT) 44 #define BCM6368_NAND_BASE_ADDR0 0x04 45 #define BCM6368_NAND_BASE_ADDR1 0x0c 46 47 enum { 48 BCM6368_NP_READ = BIT(0), 49 BCM6368_BLOCK_ERASE = BIT(1), 50 BCM6368_COPY_BACK = BIT(2), 51 BCM6368_PAGE_PGM = BIT(3), 52 BCM6368_CTRL_READY = BIT(4), 53 BCM6368_DEV_RBPIN = BIT(5), 54 BCM6368_ECC_ERR_UNC = BIT(6), 55 BCM6368_ECC_ERR_CORR = BIT(7), 56 }; 57 58 static bool bcm6368_nand_intc_ack(struct brcmnand_soc *soc) 59 { 60 struct bcm6368_nand_soc *priv = 61 container_of(soc, struct bcm6368_nand_soc, soc); 62 void __iomem *mmio = priv->base + BCM6368_NAND_INT; 63 u32 val = brcmnand_readl(mmio); 64 65 if (val & (BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT)) { 66 /* Ack interrupt */ 67 val &= ~BCM6368_NAND_STATUS_MASK; 68 val |= BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT; 69 brcmnand_writel(val, mmio); 70 return true; 71 } 72 73 return false; 74 } 75 76 static void bcm6368_nand_intc_set(struct brcmnand_soc *soc, bool en) 77 { 78 struct bcm6368_nand_soc *priv = 79 container_of(soc, struct bcm6368_nand_soc, soc); 80 void __iomem *mmio = priv->base + BCM6368_NAND_INT; 81 u32 val = brcmnand_readl(mmio); 82 83 /* Don't ack any interrupts */ 84 val &= ~BCM6368_NAND_STATUS_MASK; 85 86 if (en) 87 val |= BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT; 88 else 89 val &= ~(BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT); 90 91 brcmnand_writel(val, mmio); 92 } 93 94 static int bcm6368_nand_probe(struct platform_device *pdev) 95 { 96 struct device *dev = &pdev->dev; 97 struct bcm6368_nand_soc *priv; 98 struct brcmnand_soc *soc; 99 struct resource *res; 100 101 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 102 if (!priv) 103 return -ENOMEM; 104 soc = &priv->soc; 105 106 res = platform_get_resource_byname(pdev, 107 IORESOURCE_MEM, "nand-int-base"); 108 priv->base = devm_ioremap_resource(dev, res); 109 if (IS_ERR(priv->base)) 110 return PTR_ERR(priv->base); 111 112 soc->ctlrdy_ack = bcm6368_nand_intc_ack; 113 soc->ctlrdy_set_enabled = bcm6368_nand_intc_set; 114 115 /* Disable and ack all interrupts */ 116 brcmnand_writel(0, priv->base + BCM6368_NAND_INT); 117 brcmnand_writel(BCM6368_NAND_STATUS_MASK, 118 priv->base + BCM6368_NAND_INT); 119 120 return brcmnand_probe(pdev, soc); 121 } 122 123 static const struct of_device_id bcm6368_nand_of_match[] = { 124 { .compatible = "brcm,nand-bcm6368" }, 125 {}, 126 }; 127 MODULE_DEVICE_TABLE(of, bcm6368_nand_of_match); 128 129 static struct platform_driver bcm6368_nand_driver = { 130 .probe = bcm6368_nand_probe, 131 .remove = brcmnand_remove, 132 .driver = { 133 .name = "bcm6368_nand", 134 .pm = &brcmnand_pm_ops, 135 .of_match_table = bcm6368_nand_of_match, 136 } 137 }; 138 module_platform_driver(bcm6368_nand_driver); 139 140 MODULE_LICENSE("GPL"); 141 MODULE_AUTHOR("Simon Arlott"); 142 MODULE_DESCRIPTION("NAND driver for BCM6368"); 143