15fe42d5bSRafał Miłecki #include <linux/kernel.h> 25fe42d5bSRafał Miłecki #include <linux/module.h> 35fe42d5bSRafał Miłecki #include <linux/slab.h> 4bddcb5e7SRafał Miłecki #include <linux/delay.h> 55fe42d5bSRafał Miłecki #include <linux/mtd/mtd.h> 65fe42d5bSRafał Miłecki #include <linux/platform_device.h> 75fe42d5bSRafał Miłecki #include <linux/bcma/bcma.h> 85fe42d5bSRafał Miłecki 9a2f74a7dSRafał Miłecki #include "bcm47xxsflash.h" 10a2f74a7dSRafał Miłecki 115fe42d5bSRafał Miłecki MODULE_LICENSE("GPL"); 125fe42d5bSRafał Miłecki MODULE_DESCRIPTION("Serial flash driver for BCMA bus"); 135fe42d5bSRafał Miłecki 14afffeec9SArtem Bityutskiy static const char * const probes[] = { "bcm47xxpart", NULL }; 155fe42d5bSRafał Miłecki 16bddcb5e7SRafał Miłecki /************************************************** 17bddcb5e7SRafał Miłecki * Various helpers 18bddcb5e7SRafał Miłecki **************************************************/ 19bddcb5e7SRafał Miłecki 20bddcb5e7SRafał Miłecki static void bcm47xxsflash_cmd(struct bcm47xxsflash *b47s, u32 opcode) 21bddcb5e7SRafał Miłecki { 22bddcb5e7SRafał Miłecki int i; 23bddcb5e7SRafał Miłecki 24bddcb5e7SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHCTL, BCMA_CC_FLASHCTL_START | opcode); 25bddcb5e7SRafał Miłecki for (i = 0; i < 1000; i++) { 26bddcb5e7SRafał Miłecki if (!(b47s->cc_read(b47s, BCMA_CC_FLASHCTL) & 27bddcb5e7SRafał Miłecki BCMA_CC_FLASHCTL_BUSY)) 28bddcb5e7SRafał Miłecki return; 29bddcb5e7SRafał Miłecki cpu_relax(); 30bddcb5e7SRafał Miłecki } 31bddcb5e7SRafał Miłecki pr_err("Control command failed (timeout)!\n"); 32bddcb5e7SRafał Miłecki } 33bddcb5e7SRafał Miłecki 34bddcb5e7SRafał Miłecki static int bcm47xxsflash_poll(struct bcm47xxsflash *b47s, int timeout) 35bddcb5e7SRafał Miłecki { 36bddcb5e7SRafał Miłecki unsigned long deadline = jiffies + timeout; 37bddcb5e7SRafał Miłecki 38bddcb5e7SRafał Miłecki do { 39bddcb5e7SRafał Miłecki switch (b47s->type) { 40bddcb5e7SRafał Miłecki case BCM47XXSFLASH_TYPE_ST: 41bddcb5e7SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_RDSR); 42bddcb5e7SRafał Miłecki if (!(b47s->cc_read(b47s, BCMA_CC_FLASHDATA) & 43bddcb5e7SRafał Miłecki SR_ST_WIP)) 44bddcb5e7SRafał Miłecki return 0; 45bddcb5e7SRafał Miłecki break; 46bddcb5e7SRafał Miłecki case BCM47XXSFLASH_TYPE_ATMEL: 47bddcb5e7SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_AT_STATUS); 48bddcb5e7SRafał Miłecki if (b47s->cc_read(b47s, BCMA_CC_FLASHDATA) & 49bddcb5e7SRafał Miłecki SR_AT_READY) 50bddcb5e7SRafał Miłecki return 0; 51bddcb5e7SRafał Miłecki break; 52bddcb5e7SRafał Miłecki } 53bddcb5e7SRafał Miłecki 54bddcb5e7SRafał Miłecki cpu_relax(); 55bddcb5e7SRafał Miłecki udelay(1); 56bddcb5e7SRafał Miłecki } while (!time_after_eq(jiffies, deadline)); 57bddcb5e7SRafał Miłecki 58bddcb5e7SRafał Miłecki pr_err("Timeout waiting for flash to be ready!\n"); 59bddcb5e7SRafał Miłecki 60bddcb5e7SRafał Miłecki return -EBUSY; 61bddcb5e7SRafał Miłecki } 62bddcb5e7SRafał Miłecki 63bddcb5e7SRafał Miłecki /************************************************** 64bddcb5e7SRafał Miłecki * MTD ops 65bddcb5e7SRafał Miłecki **************************************************/ 66bddcb5e7SRafał Miłecki 675fe42d5bSRafał Miłecki static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, 685fe42d5bSRafał Miłecki size_t *retlen, u_char *buf) 695fe42d5bSRafał Miłecki { 70a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s = mtd->priv; 715fe42d5bSRafał Miłecki 725fe42d5bSRafał Miłecki /* Check address range */ 735fe42d5bSRafał Miłecki if ((from + len) > mtd->size) 745fe42d5bSRafał Miłecki return -EINVAL; 755fe42d5bSRafał Miłecki 76a2f74a7dSRafał Miłecki memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from), 775fe42d5bSRafał Miłecki len); 7860aca067SHauke Mehrtens *retlen = len; 795fe42d5bSRafał Miłecki 805fe42d5bSRafał Miłecki return len; 815fe42d5bSRafał Miłecki } 825fe42d5bSRafał Miłecki 83a2f74a7dSRafał Miłecki static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) 845fe42d5bSRafał Miłecki { 85a2f74a7dSRafał Miłecki struct mtd_info *mtd = &b47s->mtd; 86a2f74a7dSRafał Miłecki 87a2f74a7dSRafał Miłecki mtd->priv = b47s; 885fe42d5bSRafał Miłecki mtd->name = "bcm47xxsflash"; 895fe42d5bSRafał Miłecki mtd->owner = THIS_MODULE; 905fe42d5bSRafał Miłecki mtd->type = MTD_ROM; 91a2f74a7dSRafał Miłecki mtd->size = b47s->size; 925fe42d5bSRafał Miłecki mtd->_read = bcm47xxsflash_read; 935fe42d5bSRafał Miłecki 945fe42d5bSRafał Miłecki /* TODO: implement writing support and verify/change following code */ 955fe42d5bSRafał Miłecki mtd->flags = MTD_CAP_ROM; 965fe42d5bSRafał Miłecki mtd->writebufsize = mtd->writesize = 1; 975fe42d5bSRafał Miłecki } 985fe42d5bSRafał Miłecki 99f1a7c9d3SRafał Miłecki /************************************************** 100f1a7c9d3SRafał Miłecki * BCMA 101f1a7c9d3SRafał Miłecki **************************************************/ 102f1a7c9d3SRafał Miłecki 103265dfbd9SRafał Miłecki static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset) 104265dfbd9SRafał Miłecki { 105265dfbd9SRafał Miłecki return bcma_cc_read32(b47s->bcma_cc, offset); 106265dfbd9SRafał Miłecki } 107265dfbd9SRafał Miłecki 108265dfbd9SRafał Miłecki static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset, 109265dfbd9SRafał Miłecki u32 value) 110265dfbd9SRafał Miłecki { 111265dfbd9SRafał Miłecki bcma_cc_write32(b47s->bcma_cc, offset, value); 112265dfbd9SRafał Miłecki } 113265dfbd9SRafał Miłecki 114f1a7c9d3SRafał Miłecki static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) 1155fe42d5bSRafał Miłecki { 1165fe42d5bSRafał Miłecki struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); 117a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s; 1185fe42d5bSRafał Miłecki int err; 1195fe42d5bSRafał Miłecki 120*d2b1bd14SLibo Chen b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL); 121*d2b1bd14SLibo Chen if (!b47s) 122*d2b1bd14SLibo Chen return -ENOMEM; 123a2f74a7dSRafał Miłecki sflash->priv = b47s; 1245fe42d5bSRafał Miłecki 12541c81536SRafał Miłecki b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash); 126265dfbd9SRafał Miłecki b47s->cc_read = bcm47xxsflash_bcma_cc_read; 127265dfbd9SRafał Miłecki b47s->cc_write = bcm47xxsflash_bcma_cc_write; 12841c81536SRafał Miłecki 1291f816bc7SRafał Miłecki switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) { 1301f816bc7SRafał Miłecki case BCMA_CC_FLASHT_STSER: 1311f816bc7SRafał Miłecki b47s->type = BCM47XXSFLASH_TYPE_ST; 1321f816bc7SRafał Miłecki break; 1331f816bc7SRafał Miłecki case BCMA_CC_FLASHT_ATSER: 1341f816bc7SRafał Miłecki b47s->type = BCM47XXSFLASH_TYPE_ATMEL; 1351f816bc7SRafał Miłecki break; 1361f816bc7SRafał Miłecki } 1371f816bc7SRafał Miłecki 138a2f74a7dSRafał Miłecki b47s->window = sflash->window; 139a2f74a7dSRafał Miłecki b47s->blocksize = sflash->blocksize; 140a2f74a7dSRafał Miłecki b47s->numblocks = sflash->numblocks; 141a2f74a7dSRafał Miłecki b47s->size = sflash->size; 142a2f74a7dSRafał Miłecki bcm47xxsflash_fill_mtd(b47s); 143a2f74a7dSRafał Miłecki 144a2f74a7dSRafał Miłecki err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0); 1455fe42d5bSRafał Miłecki if (err) { 1465fe42d5bSRafał Miłecki pr_err("Failed to register MTD device: %d\n", err); 147*d2b1bd14SLibo Chen return err; 1485fe42d5bSRafał Miłecki } 1495fe42d5bSRafał Miłecki 150bddcb5e7SRafał Miłecki if (bcm47xxsflash_poll(b47s, HZ / 10)) 151bddcb5e7SRafał Miłecki pr_warn("Serial flash busy\n"); 152bddcb5e7SRafał Miłecki 1535fe42d5bSRafał Miłecki return 0; 1545fe42d5bSRafał Miłecki } 1555fe42d5bSRafał Miłecki 156f1a7c9d3SRafał Miłecki static int bcm47xxsflash_bcma_remove(struct platform_device *pdev) 1575fe42d5bSRafał Miłecki { 1585fe42d5bSRafał Miłecki struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); 159a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s = sflash->priv; 1605fe42d5bSRafał Miłecki 161a2f74a7dSRafał Miłecki mtd_device_unregister(&b47s->mtd); 1625fe42d5bSRafał Miłecki 1635fe42d5bSRafał Miłecki return 0; 1645fe42d5bSRafał Miłecki } 1655fe42d5bSRafał Miłecki 1665fe42d5bSRafał Miłecki static struct platform_driver bcma_sflash_driver = { 167f1a7c9d3SRafał Miłecki .probe = bcm47xxsflash_bcma_probe, 168f1a7c9d3SRafał Miłecki .remove = bcm47xxsflash_bcma_remove, 1695fe42d5bSRafał Miłecki .driver = { 1705fe42d5bSRafał Miłecki .name = "bcma_sflash", 1715fe42d5bSRafał Miłecki .owner = THIS_MODULE, 1725fe42d5bSRafał Miłecki }, 1735fe42d5bSRafał Miłecki }; 1745fe42d5bSRafał Miłecki 175f1a7c9d3SRafał Miłecki /************************************************** 176f1a7c9d3SRafał Miłecki * Init 177f1a7c9d3SRafał Miłecki **************************************************/ 178f1a7c9d3SRafał Miłecki 1795fe42d5bSRafał Miłecki static int __init bcm47xxsflash_init(void) 1805fe42d5bSRafał Miłecki { 1815fe42d5bSRafał Miłecki int err; 1825fe42d5bSRafał Miłecki 1832d13dc3bSHauke Mehrtens err = platform_driver_register(&bcma_sflash_driver); 1845fe42d5bSRafał Miłecki if (err) 1855fe42d5bSRafał Miłecki pr_err("Failed to register BCMA serial flash driver: %d\n", 1865fe42d5bSRafał Miłecki err); 1875fe42d5bSRafał Miłecki 1885fe42d5bSRafał Miłecki return err; 1895fe42d5bSRafał Miłecki } 1905fe42d5bSRafał Miłecki 1915fe42d5bSRafał Miłecki static void __exit bcm47xxsflash_exit(void) 1925fe42d5bSRafał Miłecki { 1935fe42d5bSRafał Miłecki platform_driver_unregister(&bcma_sflash_driver); 1945fe42d5bSRafał Miłecki } 1955fe42d5bSRafał Miłecki 1965fe42d5bSRafał Miłecki module_init(bcm47xxsflash_init); 1975fe42d5bSRafał Miłecki module_exit(bcm47xxsflash_exit); 198