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 67c0fcbc56SRafał Miłecki static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase) 68c0fcbc56SRafał Miłecki { 69c0fcbc56SRafał Miłecki struct bcm47xxsflash *b47s = mtd->priv; 70c0fcbc56SRafał Miłecki int err; 71c0fcbc56SRafał Miłecki 72c0fcbc56SRafał Miłecki switch (b47s->type) { 73c0fcbc56SRafał Miłecki case BCM47XXSFLASH_TYPE_ST: 74c0fcbc56SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN); 75c0fcbc56SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr); 76c0fcbc56SRafał Miłecki /* Newer flashes have "sub-sectors" which can be erased 77c0fcbc56SRafał Miłecki * independently with a new command: ST_SSE. The ST_SE command 78c0fcbc56SRafał Miłecki * erases 64KB just as before. 79c0fcbc56SRafał Miłecki */ 80c0fcbc56SRafał Miłecki if (b47s->blocksize < (64 * 1024)) 81c0fcbc56SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_SSE); 82c0fcbc56SRafał Miłecki else 83c0fcbc56SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_SE); 84c0fcbc56SRafał Miłecki break; 85c0fcbc56SRafał Miłecki case BCM47XXSFLASH_TYPE_ATMEL: 86c0fcbc56SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr << 1); 87c0fcbc56SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_AT_PAGE_ERASE); 88c0fcbc56SRafał Miłecki break; 89c0fcbc56SRafał Miłecki } 90c0fcbc56SRafał Miłecki 91c0fcbc56SRafał Miłecki err = bcm47xxsflash_poll(b47s, HZ); 92c0fcbc56SRafał Miłecki if (err) 93c0fcbc56SRafał Miłecki erase->state = MTD_ERASE_FAILED; 94c0fcbc56SRafał Miłecki else 95c0fcbc56SRafał Miłecki erase->state = MTD_ERASE_DONE; 96c0fcbc56SRafał Miłecki 97c0fcbc56SRafał Miłecki if (erase->callback) 98c0fcbc56SRafał Miłecki erase->callback(erase); 99c0fcbc56SRafał Miłecki 100c0fcbc56SRafał Miłecki return err; 101c0fcbc56SRafał Miłecki } 102c0fcbc56SRafał Miłecki 1035fe42d5bSRafał Miłecki static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, 1045fe42d5bSRafał Miłecki size_t *retlen, u_char *buf) 1055fe42d5bSRafał Miłecki { 106a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s = mtd->priv; 1075fe42d5bSRafał Miłecki 1085fe42d5bSRafał Miłecki /* Check address range */ 1095fe42d5bSRafał Miłecki if ((from + len) > mtd->size) 1105fe42d5bSRafał Miłecki return -EINVAL; 1115fe42d5bSRafał Miłecki 112a2f74a7dSRafał Miłecki memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from), 1135fe42d5bSRafał Miłecki len); 11460aca067SHauke Mehrtens *retlen = len; 1155fe42d5bSRafał Miłecki 1165fe42d5bSRafał Miłecki return len; 1175fe42d5bSRafał Miłecki } 1185fe42d5bSRafał Miłecki 119*13134f48SRafał Miłecki static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len, 120*13134f48SRafał Miłecki const u_char *buf) 121*13134f48SRafał Miłecki { 122*13134f48SRafał Miłecki struct bcm47xxsflash *b47s = mtd->priv; 123*13134f48SRafał Miłecki int written = 0; 124*13134f48SRafał Miłecki 125*13134f48SRafał Miłecki /* Enable writes */ 126*13134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN); 127*13134f48SRafał Miłecki 128*13134f48SRafał Miłecki /* Write first byte */ 129*13134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset); 130*13134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++); 131*13134f48SRafał Miłecki 132*13134f48SRafał Miłecki /* Program page */ 133*13134f48SRafał Miłecki if (b47s->bcma_cc->core->id.rev < 20) { 134*13134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_PP); 135*13134f48SRafał Miłecki return 1; /* 1B written */ 136*13134f48SRafał Miłecki } 137*13134f48SRafał Miłecki 138*13134f48SRafał Miłecki /* Program page and set CSA (on newer chips we can continue writing) */ 139*13134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP); 140*13134f48SRafał Miłecki offset++; 141*13134f48SRafał Miłecki len--; 142*13134f48SRafał Miłecki written++; 143*13134f48SRafał Miłecki 144*13134f48SRafał Miłecki while (len > 0) { 145*13134f48SRafał Miłecki /* Page boundary, another function call is needed */ 146*13134f48SRafał Miłecki if ((offset & 0xFF) == 0) 147*13134f48SRafał Miłecki break; 148*13134f48SRafał Miłecki 149*13134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++); 150*13134f48SRafał Miłecki offset++; 151*13134f48SRafał Miłecki len--; 152*13134f48SRafał Miłecki written++; 153*13134f48SRafał Miłecki } 154*13134f48SRafał Miłecki 155*13134f48SRafał Miłecki /* All done, drop CSA & poll */ 156*13134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0); 157*13134f48SRafał Miłecki udelay(1); 158*13134f48SRafał Miłecki if (bcm47xxsflash_poll(b47s, HZ / 10)) 159*13134f48SRafał Miłecki pr_err("Flash rejected dropping CSA\n"); 160*13134f48SRafał Miłecki 161*13134f48SRafał Miłecki return written; 162*13134f48SRafał Miłecki } 163*13134f48SRafał Miłecki 164*13134f48SRafał Miłecki static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len, 165*13134f48SRafał Miłecki const u_char *buf) 166*13134f48SRafał Miłecki { 167*13134f48SRafał Miłecki struct bcm47xxsflash *b47s = mtd->priv; 168*13134f48SRafał Miłecki u32 mask = b47s->blocksize - 1; 169*13134f48SRafał Miłecki u32 page = (offset & ~mask) << 1; 170*13134f48SRafał Miłecki u32 byte = offset & mask; 171*13134f48SRafał Miłecki int written = 0; 172*13134f48SRafał Miłecki 173*13134f48SRafał Miłecki /* If we don't overwrite whole page, read it to the buffer first */ 174*13134f48SRafał Miłecki if (byte || (len < b47s->blocksize)) { 175*13134f48SRafał Miłecki int err; 176*13134f48SRafał Miłecki 177*13134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page); 178*13134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD); 179*13134f48SRafał Miłecki /* 250 us for AT45DB321B */ 180*13134f48SRafał Miłecki err = bcm47xxsflash_poll(b47s, HZ / 1000); 181*13134f48SRafał Miłecki if (err) { 182*13134f48SRafał Miłecki pr_err("Timeout reading page 0x%X info buffer\n", page); 183*13134f48SRafał Miłecki return err; 184*13134f48SRafał Miłecki } 185*13134f48SRafał Miłecki } 186*13134f48SRafał Miłecki 187*13134f48SRafał Miłecki /* Change buffer content with our data */ 188*13134f48SRafał Miłecki while (len > 0) { 189*13134f48SRafał Miłecki /* Page boundary, another function call is needed */ 190*13134f48SRafał Miłecki if (byte == b47s->blocksize) 191*13134f48SRafał Miłecki break; 192*13134f48SRafał Miłecki 193*13134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++); 194*13134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++); 195*13134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE); 196*13134f48SRafał Miłecki len--; 197*13134f48SRafał Miłecki written++; 198*13134f48SRafał Miłecki } 199*13134f48SRafał Miłecki 200*13134f48SRafał Miłecki /* Program page with the buffer content */ 201*13134f48SRafał Miłecki b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page); 202*13134f48SRafał Miłecki bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM); 203*13134f48SRafał Miłecki 204*13134f48SRafał Miłecki return written; 205*13134f48SRafał Miłecki } 206*13134f48SRafał Miłecki 207*13134f48SRafał Miłecki static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len, 208*13134f48SRafał Miłecki size_t *retlen, const u_char *buf) 209*13134f48SRafał Miłecki { 210*13134f48SRafał Miłecki struct bcm47xxsflash *b47s = mtd->priv; 211*13134f48SRafał Miłecki int written; 212*13134f48SRafał Miłecki 213*13134f48SRafał Miłecki /* Writing functions can return without writing all passed data, for 214*13134f48SRafał Miłecki * example when the hardware is too old or when we git page boundary. 215*13134f48SRafał Miłecki */ 216*13134f48SRafał Miłecki while (len > 0) { 217*13134f48SRafał Miłecki switch (b47s->type) { 218*13134f48SRafał Miłecki case BCM47XXSFLASH_TYPE_ST: 219*13134f48SRafał Miłecki written = bcm47xxsflash_write_st(mtd, to, len, buf); 220*13134f48SRafał Miłecki break; 221*13134f48SRafał Miłecki case BCM47XXSFLASH_TYPE_ATMEL: 222*13134f48SRafał Miłecki written = bcm47xxsflash_write_at(mtd, to, len, buf); 223*13134f48SRafał Miłecki break; 224*13134f48SRafał Miłecki default: 225*13134f48SRafał Miłecki BUG_ON(1); 226*13134f48SRafał Miłecki } 227*13134f48SRafał Miłecki if (written < 0) { 228*13134f48SRafał Miłecki pr_err("Error writing at offset 0x%llX\n", to); 229*13134f48SRafał Miłecki return written; 230*13134f48SRafał Miłecki } 231*13134f48SRafał Miłecki to += (loff_t)written; 232*13134f48SRafał Miłecki len -= written; 233*13134f48SRafał Miłecki *retlen += written; 234*13134f48SRafał Miłecki buf += written; 235*13134f48SRafał Miłecki } 236*13134f48SRafał Miłecki 237*13134f48SRafał Miłecki return 0; 238*13134f48SRafał Miłecki } 239*13134f48SRafał Miłecki 240a2f74a7dSRafał Miłecki static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) 2415fe42d5bSRafał Miłecki { 242a2f74a7dSRafał Miłecki struct mtd_info *mtd = &b47s->mtd; 243a2f74a7dSRafał Miłecki 244a2f74a7dSRafał Miłecki mtd->priv = b47s; 2455fe42d5bSRafał Miłecki mtd->name = "bcm47xxsflash"; 2465fe42d5bSRafał Miłecki mtd->owner = THIS_MODULE; 2475fe42d5bSRafał Miłecki 248*13134f48SRafał Miłecki mtd->type = MTD_NORFLASH; 249*13134f48SRafał Miłecki mtd->flags = MTD_CAP_NORFLASH; 250c0fcbc56SRafał Miłecki mtd->size = b47s->size; 251c0fcbc56SRafał Miłecki mtd->erasesize = b47s->blocksize; 252*13134f48SRafał Miłecki mtd->writesize = 1; 253*13134f48SRafał Miłecki mtd->writebufsize = 1; 254c0fcbc56SRafał Miłecki 255c0fcbc56SRafał Miłecki mtd->_erase = bcm47xxsflash_erase; 256c0fcbc56SRafał Miłecki mtd->_read = bcm47xxsflash_read; 257*13134f48SRafał Miłecki mtd->_write = bcm47xxsflash_write; 2585fe42d5bSRafał Miłecki } 2595fe42d5bSRafał Miłecki 260f1a7c9d3SRafał Miłecki /************************************************** 261f1a7c9d3SRafał Miłecki * BCMA 262f1a7c9d3SRafał Miłecki **************************************************/ 263f1a7c9d3SRafał Miłecki 264265dfbd9SRafał Miłecki static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset) 265265dfbd9SRafał Miłecki { 266265dfbd9SRafał Miłecki return bcma_cc_read32(b47s->bcma_cc, offset); 267265dfbd9SRafał Miłecki } 268265dfbd9SRafał Miłecki 269265dfbd9SRafał Miłecki static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset, 270265dfbd9SRafał Miłecki u32 value) 271265dfbd9SRafał Miłecki { 272265dfbd9SRafał Miłecki bcma_cc_write32(b47s->bcma_cc, offset, value); 273265dfbd9SRafał Miłecki } 274265dfbd9SRafał Miłecki 275f1a7c9d3SRafał Miłecki static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) 2765fe42d5bSRafał Miłecki { 2775fe42d5bSRafał Miłecki struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); 278a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s; 2795fe42d5bSRafał Miłecki int err; 2805fe42d5bSRafał Miłecki 281d2b1bd14SLibo Chen b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL); 282d2b1bd14SLibo Chen if (!b47s) 283d2b1bd14SLibo Chen return -ENOMEM; 284a2f74a7dSRafał Miłecki sflash->priv = b47s; 2855fe42d5bSRafał Miłecki 28641c81536SRafał Miłecki b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash); 287265dfbd9SRafał Miłecki b47s->cc_read = bcm47xxsflash_bcma_cc_read; 288265dfbd9SRafał Miłecki b47s->cc_write = bcm47xxsflash_bcma_cc_write; 28941c81536SRafał Miłecki 2901f816bc7SRafał Miłecki switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) { 2911f816bc7SRafał Miłecki case BCMA_CC_FLASHT_STSER: 2921f816bc7SRafał Miłecki b47s->type = BCM47XXSFLASH_TYPE_ST; 2931f816bc7SRafał Miłecki break; 2941f816bc7SRafał Miłecki case BCMA_CC_FLASHT_ATSER: 2951f816bc7SRafał Miłecki b47s->type = BCM47XXSFLASH_TYPE_ATMEL; 2961f816bc7SRafał Miłecki break; 2971f816bc7SRafał Miłecki } 2981f816bc7SRafał Miłecki 299a2f74a7dSRafał Miłecki b47s->window = sflash->window; 300a2f74a7dSRafał Miłecki b47s->blocksize = sflash->blocksize; 301a2f74a7dSRafał Miłecki b47s->numblocks = sflash->numblocks; 302a2f74a7dSRafał Miłecki b47s->size = sflash->size; 303a2f74a7dSRafał Miłecki bcm47xxsflash_fill_mtd(b47s); 304a2f74a7dSRafał Miłecki 305a2f74a7dSRafał Miłecki err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0); 3065fe42d5bSRafał Miłecki if (err) { 3075fe42d5bSRafał Miłecki pr_err("Failed to register MTD device: %d\n", err); 308d2b1bd14SLibo Chen return err; 3095fe42d5bSRafał Miłecki } 3105fe42d5bSRafał Miłecki 311bddcb5e7SRafał Miłecki if (bcm47xxsflash_poll(b47s, HZ / 10)) 312bddcb5e7SRafał Miłecki pr_warn("Serial flash busy\n"); 313bddcb5e7SRafał Miłecki 3145fe42d5bSRafał Miłecki return 0; 3155fe42d5bSRafał Miłecki } 3165fe42d5bSRafał Miłecki 317f1a7c9d3SRafał Miłecki static int bcm47xxsflash_bcma_remove(struct platform_device *pdev) 3185fe42d5bSRafał Miłecki { 3195fe42d5bSRafał Miłecki struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); 320a2f74a7dSRafał Miłecki struct bcm47xxsflash *b47s = sflash->priv; 3215fe42d5bSRafał Miłecki 322a2f74a7dSRafał Miłecki mtd_device_unregister(&b47s->mtd); 3235fe42d5bSRafał Miłecki 3245fe42d5bSRafał Miłecki return 0; 3255fe42d5bSRafał Miłecki } 3265fe42d5bSRafał Miłecki 3275fe42d5bSRafał Miłecki static struct platform_driver bcma_sflash_driver = { 328f1a7c9d3SRafał Miłecki .probe = bcm47xxsflash_bcma_probe, 329f1a7c9d3SRafał Miłecki .remove = bcm47xxsflash_bcma_remove, 3305fe42d5bSRafał Miłecki .driver = { 3315fe42d5bSRafał Miłecki .name = "bcma_sflash", 3325fe42d5bSRafał Miłecki .owner = THIS_MODULE, 3335fe42d5bSRafał Miłecki }, 3345fe42d5bSRafał Miłecki }; 3355fe42d5bSRafał Miłecki 336f1a7c9d3SRafał Miłecki /************************************************** 337f1a7c9d3SRafał Miłecki * Init 338f1a7c9d3SRafał Miłecki **************************************************/ 339f1a7c9d3SRafał Miłecki 3408268df26SLibo Chen module_platform_driver(bcma_sflash_driver); 341