1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21cbb4a1cSCyril Bur /* 31cbb4a1cSCyril Bur * OPAL PNOR flash MTD abstraction 41cbb4a1cSCyril Bur * 51cbb4a1cSCyril Bur * Copyright IBM 2015 61cbb4a1cSCyril Bur */ 71cbb4a1cSCyril Bur 81cbb4a1cSCyril Bur #include <linux/kernel.h> 91cbb4a1cSCyril Bur #include <linux/module.h> 101cbb4a1cSCyril Bur #include <linux/errno.h> 111cbb4a1cSCyril Bur #include <linux/of.h> 121cbb4a1cSCyril Bur #include <linux/of_address.h> 131cbb4a1cSCyril Bur #include <linux/platform_device.h> 141cbb4a1cSCyril Bur #include <linux/string.h> 151cbb4a1cSCyril Bur #include <linux/slab.h> 161cbb4a1cSCyril Bur #include <linux/mtd/mtd.h> 171cbb4a1cSCyril Bur #include <linux/mtd/partitions.h> 181cbb4a1cSCyril Bur 191cbb4a1cSCyril Bur #include <linux/debugfs.h> 201cbb4a1cSCyril Bur #include <linux/seq_file.h> 211cbb4a1cSCyril Bur 221cbb4a1cSCyril Bur #include <asm/opal.h> 231cbb4a1cSCyril Bur 241cbb4a1cSCyril Bur 251cbb4a1cSCyril Bur /* 261cbb4a1cSCyril Bur * This driver creates the a Linux MTD abstraction for platform PNOR flash 271cbb4a1cSCyril Bur * backed by OPAL calls 281cbb4a1cSCyril Bur */ 291cbb4a1cSCyril Bur 301cbb4a1cSCyril Bur struct powernv_flash { 311cbb4a1cSCyril Bur struct mtd_info mtd; 321cbb4a1cSCyril Bur u32 id; 331cbb4a1cSCyril Bur }; 341cbb4a1cSCyril Bur 351cbb4a1cSCyril Bur enum flash_op { 361cbb4a1cSCyril Bur FLASH_OP_READ, 371cbb4a1cSCyril Bur FLASH_OP_WRITE, 381cbb4a1cSCyril Bur FLASH_OP_ERASE, 391cbb4a1cSCyril Bur }; 401cbb4a1cSCyril Bur 41efe69414SCyril Bur /* 42efe69414SCyril Bur * Don't return -ERESTARTSYS if we can't get a token, the MTD core 43efe69414SCyril Bur * might have split up the call from userspace and called into the 44efe69414SCyril Bur * driver more than once, we'll already have done some amount of work. 45efe69414SCyril Bur */ 461cbb4a1cSCyril Bur static int powernv_flash_async_op(struct mtd_info *mtd, enum flash_op op, 471cbb4a1cSCyril Bur loff_t offset, size_t len, size_t *retlen, u_char *buf) 481cbb4a1cSCyril Bur { 491cbb4a1cSCyril Bur struct powernv_flash *info = (struct powernv_flash *)mtd->priv; 501cbb4a1cSCyril Bur struct device *dev = &mtd->dev; 511cbb4a1cSCyril Bur int token; 521cbb4a1cSCyril Bur struct opal_msg msg; 531cbb4a1cSCyril Bur int rc; 541cbb4a1cSCyril Bur 551cbb4a1cSCyril Bur dev_dbg(dev, "%s(op=%d, offset=0x%llx, len=%zu)\n", 561cbb4a1cSCyril Bur __func__, op, offset, len); 571cbb4a1cSCyril Bur 581cbb4a1cSCyril Bur token = opal_async_get_token_interruptible(); 591cbb4a1cSCyril Bur if (token < 0) { 601cbb4a1cSCyril Bur if (token != -ERESTARTSYS) 611cbb4a1cSCyril Bur dev_err(dev, "Failed to get an async token\n"); 62efe69414SCyril Bur else 63efe69414SCyril Bur token = -EINTR; 641cbb4a1cSCyril Bur return token; 651cbb4a1cSCyril Bur } 661cbb4a1cSCyril Bur 671cbb4a1cSCyril Bur switch (op) { 681cbb4a1cSCyril Bur case FLASH_OP_READ: 691cbb4a1cSCyril Bur rc = opal_flash_read(info->id, offset, __pa(buf), len, token); 701cbb4a1cSCyril Bur break; 711cbb4a1cSCyril Bur case FLASH_OP_WRITE: 721cbb4a1cSCyril Bur rc = opal_flash_write(info->id, offset, __pa(buf), len, token); 731cbb4a1cSCyril Bur break; 741cbb4a1cSCyril Bur case FLASH_OP_ERASE: 751cbb4a1cSCyril Bur rc = opal_flash_erase(info->id, offset, len, token); 761cbb4a1cSCyril Bur break; 771cbb4a1cSCyril Bur default: 7844e2aa2bSCyril Bur WARN_ON_ONCE(1); 7944e2aa2bSCyril Bur opal_async_release_token(token); 8044e2aa2bSCyril Bur return -EIO; 811cbb4a1cSCyril Bur } 821cbb4a1cSCyril Bur 836f469b67SCyril Bur if (rc == OPAL_ASYNC_COMPLETION) { 846f469b67SCyril Bur rc = opal_async_wait_response_interruptible(token, &msg); 856f469b67SCyril Bur if (rc) { 866f469b67SCyril Bur /* 876f469b67SCyril Bur * If we return the mtd core will free the 886f469b67SCyril Bur * buffer we've just passed to OPAL but OPAL 896f469b67SCyril Bur * will continue to read or write from that 906f469b67SCyril Bur * memory. 916f469b67SCyril Bur * It may be tempting to ultimately return 0 926f469b67SCyril Bur * if we're doing a read or a write since we 936f469b67SCyril Bur * are going to end up waiting until OPAL is 946f469b67SCyril Bur * done. However, because the MTD core sends 956f469b67SCyril Bur * us the userspace request in chunks, we need 966f469b67SCyril Bur * it to know we've been interrupted. 976f469b67SCyril Bur */ 986f469b67SCyril Bur rc = -EINTR; 996f469b67SCyril Bur if (opal_async_wait_response(token, &msg)) 1006f469b67SCyril Bur dev_err(dev, "opal_async_wait_response() failed\n"); 1016f469b67SCyril Bur goto out; 1026f469b67SCyril Bur } 1036f469b67SCyril Bur rc = opal_get_async_rc(msg); 1046f469b67SCyril Bur } 10525ee52e6SCyril Bur 1066f469b67SCyril Bur /* 1076f469b67SCyril Bur * OPAL does mutual exclusion on the flash, it will return 1086f469b67SCyril Bur * OPAL_BUSY. 1096f469b67SCyril Bur * During firmware updates by the service processor OPAL may 1106f469b67SCyril Bur * be (temporarily) prevented from accessing the flash, in 1116f469b67SCyril Bur * this case OPAL will also return OPAL_BUSY. 1126f469b67SCyril Bur * Both cases aren't errors exactly but the flash could have 1136f469b67SCyril Bur * changed, userspace should be informed. 1146f469b67SCyril Bur */ 1156f469b67SCyril Bur if (rc != OPAL_SUCCESS && rc != OPAL_BUSY) 1161cbb4a1cSCyril Bur dev_err(dev, "opal_flash_async_op(op=%d) failed (rc %d)\n", 1171cbb4a1cSCyril Bur op, rc); 1181cbb4a1cSCyril Bur 1196f469b67SCyril Bur if (rc == OPAL_SUCCESS && retlen) 1201cbb4a1cSCyril Bur *retlen = len; 1211cbb4a1cSCyril Bur 1226f469b67SCyril Bur rc = opal_error_code(rc); 12325ee52e6SCyril Bur out: 12425ee52e6SCyril Bur opal_async_release_token(token); 1251cbb4a1cSCyril Bur return rc; 1261cbb4a1cSCyril Bur } 1271cbb4a1cSCyril Bur 1281cbb4a1cSCyril Bur /** 1291cbb4a1cSCyril Bur * @mtd: the device 1301cbb4a1cSCyril Bur * @from: the offset to read from 1311cbb4a1cSCyril Bur * @len: the number of bytes to read 1321cbb4a1cSCyril Bur * @retlen: the number of bytes actually read 1331cbb4a1cSCyril Bur * @buf: the filled in buffer 1341cbb4a1cSCyril Bur * 1351cbb4a1cSCyril Bur * Returns 0 if read successful, or -ERRNO if an error occurred 1361cbb4a1cSCyril Bur */ 1371cbb4a1cSCyril Bur static int powernv_flash_read(struct mtd_info *mtd, loff_t from, size_t len, 1381cbb4a1cSCyril Bur size_t *retlen, u_char *buf) 1391cbb4a1cSCyril Bur { 1401cbb4a1cSCyril Bur return powernv_flash_async_op(mtd, FLASH_OP_READ, from, 1411cbb4a1cSCyril Bur len, retlen, buf); 1421cbb4a1cSCyril Bur } 1431cbb4a1cSCyril Bur 1441cbb4a1cSCyril Bur /** 1451cbb4a1cSCyril Bur * @mtd: the device 1461cbb4a1cSCyril Bur * @to: the offset to write to 1471cbb4a1cSCyril Bur * @len: the number of bytes to write 1481cbb4a1cSCyril Bur * @retlen: the number of bytes actually written 1491cbb4a1cSCyril Bur * @buf: the buffer to get bytes from 1501cbb4a1cSCyril Bur * 1511cbb4a1cSCyril Bur * Returns 0 if write successful, -ERRNO if error occurred 1521cbb4a1cSCyril Bur */ 1531cbb4a1cSCyril Bur static int powernv_flash_write(struct mtd_info *mtd, loff_t to, size_t len, 1541cbb4a1cSCyril Bur size_t *retlen, const u_char *buf) 1551cbb4a1cSCyril Bur { 1561cbb4a1cSCyril Bur return powernv_flash_async_op(mtd, FLASH_OP_WRITE, to, 1571cbb4a1cSCyril Bur len, retlen, (u_char *)buf); 1581cbb4a1cSCyril Bur } 1591cbb4a1cSCyril Bur 1601cbb4a1cSCyril Bur /** 1611cbb4a1cSCyril Bur * @mtd: the device 1621cbb4a1cSCyril Bur * @erase: the erase info 1631cbb4a1cSCyril Bur * Returns 0 if erase successful or -ERRNO if an error occurred 1641cbb4a1cSCyril Bur */ 1651cbb4a1cSCyril Bur static int powernv_flash_erase(struct mtd_info *mtd, struct erase_info *erase) 1661cbb4a1cSCyril Bur { 1671cbb4a1cSCyril Bur int rc; 1681cbb4a1cSCyril Bur 1691cbb4a1cSCyril Bur rc = powernv_flash_async_op(mtd, FLASH_OP_ERASE, erase->addr, 1701cbb4a1cSCyril Bur erase->len, NULL, NULL); 171e7bfb3fdSBoris Brezillon if (rc) 1721cbb4a1cSCyril Bur erase->fail_addr = erase->addr; 173e7bfb3fdSBoris Brezillon 1741cbb4a1cSCyril Bur return rc; 1751cbb4a1cSCyril Bur } 1761cbb4a1cSCyril Bur 1771cbb4a1cSCyril Bur /** 1781cbb4a1cSCyril Bur * powernv_flash_set_driver_info - Fill the mtd_info structure and docg3 1791cbb4a1cSCyril Bur * structure @pdev: The platform device 1801cbb4a1cSCyril Bur * @mtd: The structure to fill 1811cbb4a1cSCyril Bur */ 1821cbb4a1cSCyril Bur static int powernv_flash_set_driver_info(struct device *dev, 1831cbb4a1cSCyril Bur struct mtd_info *mtd) 1841cbb4a1cSCyril Bur { 1851cbb4a1cSCyril Bur u64 size; 1861cbb4a1cSCyril Bur u32 erase_size; 1871cbb4a1cSCyril Bur int rc; 1881cbb4a1cSCyril Bur 1891cbb4a1cSCyril Bur rc = of_property_read_u32(dev->of_node, "ibm,flash-block-size", 1901cbb4a1cSCyril Bur &erase_size); 1911cbb4a1cSCyril Bur if (rc) { 1921cbb4a1cSCyril Bur dev_err(dev, "couldn't get resource block size information\n"); 1931cbb4a1cSCyril Bur return rc; 1941cbb4a1cSCyril Bur } 1951cbb4a1cSCyril Bur 1961cbb4a1cSCyril Bur rc = of_property_read_u64(dev->of_node, "reg", &size); 1971cbb4a1cSCyril Bur if (rc) { 1981cbb4a1cSCyril Bur dev_err(dev, "couldn't get resource size information\n"); 1991cbb4a1cSCyril Bur return rc; 2001cbb4a1cSCyril Bur } 2011cbb4a1cSCyril Bur 2021cbb4a1cSCyril Bur /* 2031cbb4a1cSCyril Bur * Going to have to check what details I need to set and how to 2041cbb4a1cSCyril Bur * get them 2051cbb4a1cSCyril Bur */ 2063e35730dSAneesh Kumar K.V mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%pOFP", dev->of_node); 2071cbb4a1cSCyril Bur mtd->type = MTD_NORFLASH; 2081cbb4a1cSCyril Bur mtd->flags = MTD_WRITEABLE; 2091cbb4a1cSCyril Bur mtd->size = size; 2101cbb4a1cSCyril Bur mtd->erasesize = erase_size; 2111cbb4a1cSCyril Bur mtd->writebufsize = mtd->writesize = 1; 2121cbb4a1cSCyril Bur mtd->owner = THIS_MODULE; 2131cbb4a1cSCyril Bur mtd->_erase = powernv_flash_erase; 2141cbb4a1cSCyril Bur mtd->_read = powernv_flash_read; 2151cbb4a1cSCyril Bur mtd->_write = powernv_flash_write; 2161cbb4a1cSCyril Bur mtd->dev.parent = dev; 2179ea97a7dSRafał Miłecki mtd_set_of_node(mtd, dev->of_node); 2181cbb4a1cSCyril Bur return 0; 2191cbb4a1cSCyril Bur } 2201cbb4a1cSCyril Bur 2211cbb4a1cSCyril Bur /** 2221cbb4a1cSCyril Bur * powernv_flash_probe 2231cbb4a1cSCyril Bur * @pdev: platform device 2241cbb4a1cSCyril Bur * 2251cbb4a1cSCyril Bur * Returns 0 on success, -ENOMEM, -ENXIO on error 2261cbb4a1cSCyril Bur */ 2271cbb4a1cSCyril Bur static int powernv_flash_probe(struct platform_device *pdev) 2281cbb4a1cSCyril Bur { 2291cbb4a1cSCyril Bur struct device *dev = &pdev->dev; 2301cbb4a1cSCyril Bur struct powernv_flash *data; 2311cbb4a1cSCyril Bur int ret; 2321cbb4a1cSCyril Bur 2331cbb4a1cSCyril Bur data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 234e32ec15aSCyril Bur if (!data) 235e32ec15aSCyril Bur return -ENOMEM; 236e32ec15aSCyril Bur 2371cbb4a1cSCyril Bur data->mtd.priv = data; 2381cbb4a1cSCyril Bur 2391cbb4a1cSCyril Bur ret = of_property_read_u32(dev->of_node, "ibm,opal-id", &(data->id)); 2401cbb4a1cSCyril Bur if (ret) { 2411cbb4a1cSCyril Bur dev_err(dev, "no device property 'ibm,opal-id'\n"); 242e32ec15aSCyril Bur return ret; 2431cbb4a1cSCyril Bur } 2441cbb4a1cSCyril Bur 2451cbb4a1cSCyril Bur ret = powernv_flash_set_driver_info(dev, &data->mtd); 2461cbb4a1cSCyril Bur if (ret) 247e32ec15aSCyril Bur return ret; 2481cbb4a1cSCyril Bur 2491cbb4a1cSCyril Bur dev_set_drvdata(dev, data); 2501cbb4a1cSCyril Bur 2511cbb4a1cSCyril Bur /* 2521cbb4a1cSCyril Bur * The current flash that skiboot exposes is one contiguous flash chip 2531cbb4a1cSCyril Bur * with an ffs partition at the start, it should prove easier for users 2541cbb4a1cSCyril Bur * to deal with partitions or not as they see fit 2551cbb4a1cSCyril Bur */ 256e32ec15aSCyril Bur return mtd_device_register(&data->mtd, NULL, 0); 2571cbb4a1cSCyril Bur } 2581cbb4a1cSCyril Bur 2591cbb4a1cSCyril Bur /** 2601cbb4a1cSCyril Bur * op_release - Release the driver 2611cbb4a1cSCyril Bur * @pdev: the platform device 2621cbb4a1cSCyril Bur * 2631cbb4a1cSCyril Bur * Returns 0 2641cbb4a1cSCyril Bur */ 2651cbb4a1cSCyril Bur static int powernv_flash_release(struct platform_device *pdev) 2661cbb4a1cSCyril Bur { 2671cbb4a1cSCyril Bur struct powernv_flash *data = dev_get_drvdata(&(pdev->dev)); 2681cbb4a1cSCyril Bur 2691cbb4a1cSCyril Bur /* All resources should be freed automatically */ 2701cbb4a1cSCyril Bur return mtd_device_unregister(&(data->mtd)); 2711cbb4a1cSCyril Bur } 2721cbb4a1cSCyril Bur 2731cbb4a1cSCyril Bur static const struct of_device_id powernv_flash_match[] = { 2741cbb4a1cSCyril Bur { .compatible = "ibm,opal-flash" }, 2751cbb4a1cSCyril Bur {} 2761cbb4a1cSCyril Bur }; 2771cbb4a1cSCyril Bur 2781cbb4a1cSCyril Bur static struct platform_driver powernv_flash_driver = { 2791cbb4a1cSCyril Bur .driver = { 2801cbb4a1cSCyril Bur .name = "powernv_flash", 2811cbb4a1cSCyril Bur .of_match_table = powernv_flash_match, 2821cbb4a1cSCyril Bur }, 2831cbb4a1cSCyril Bur .remove = powernv_flash_release, 2841cbb4a1cSCyril Bur .probe = powernv_flash_probe, 2851cbb4a1cSCyril Bur }; 2861cbb4a1cSCyril Bur 2871cbb4a1cSCyril Bur module_platform_driver(powernv_flash_driver); 2881cbb4a1cSCyril Bur 2891cbb4a1cSCyril Bur MODULE_DEVICE_TABLE(of, powernv_flash_match); 2901cbb4a1cSCyril Bur MODULE_LICENSE("GPL"); 2911cbb4a1cSCyril Bur MODULE_AUTHOR("Cyril Bur <cyril.bur@au1.ibm.com>"); 2921cbb4a1cSCyril Bur MODULE_DESCRIPTION("MTD abstraction for OPAL flash"); 293