0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/errno.h>
0011 #include <linux/of.h>
0012 #include <linux/of_address.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/string.h>
0015 #include <linux/slab.h>
0016 #include <linux/mtd/mtd.h>
0017 #include <linux/mtd/partitions.h>
0018
0019 #include <linux/debugfs.h>
0020 #include <linux/seq_file.h>
0021
0022 #include <asm/opal.h>
0023
0024
0025
0026
0027
0028
0029
0030 struct powernv_flash {
0031 struct mtd_info mtd;
0032 u32 id;
0033 };
0034
0035 enum flash_op {
0036 FLASH_OP_READ,
0037 FLASH_OP_WRITE,
0038 FLASH_OP_ERASE,
0039 };
0040
0041
0042
0043
0044
0045
0046 static int powernv_flash_async_op(struct mtd_info *mtd, enum flash_op op,
0047 loff_t offset, size_t len, size_t *retlen, u_char *buf)
0048 {
0049 struct powernv_flash *info = (struct powernv_flash *)mtd->priv;
0050 struct device *dev = &mtd->dev;
0051 int token;
0052 struct opal_msg msg;
0053 int rc;
0054
0055 dev_dbg(dev, "%s(op=%d, offset=0x%llx, len=%zu)\n",
0056 __func__, op, offset, len);
0057
0058 token = opal_async_get_token_interruptible();
0059 if (token < 0) {
0060 if (token != -ERESTARTSYS)
0061 dev_err(dev, "Failed to get an async token\n");
0062 else
0063 token = -EINTR;
0064 return token;
0065 }
0066
0067 switch (op) {
0068 case FLASH_OP_READ:
0069 rc = opal_flash_read(info->id, offset, __pa(buf), len, token);
0070 break;
0071 case FLASH_OP_WRITE:
0072 rc = opal_flash_write(info->id, offset, __pa(buf), len, token);
0073 break;
0074 case FLASH_OP_ERASE:
0075 rc = opal_flash_erase(info->id, offset, len, token);
0076 break;
0077 default:
0078 WARN_ON_ONCE(1);
0079 opal_async_release_token(token);
0080 return -EIO;
0081 }
0082
0083 if (rc == OPAL_ASYNC_COMPLETION) {
0084 rc = opal_async_wait_response_interruptible(token, &msg);
0085 if (rc) {
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098 rc = -EINTR;
0099 if (opal_async_wait_response(token, &msg))
0100 dev_err(dev, "opal_async_wait_response() failed\n");
0101 goto out;
0102 }
0103 rc = opal_get_async_rc(msg);
0104 }
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115 if (rc != OPAL_SUCCESS && rc != OPAL_BUSY)
0116 dev_err(dev, "opal_flash_async_op(op=%d) failed (rc %d)\n",
0117 op, rc);
0118
0119 if (rc == OPAL_SUCCESS && retlen)
0120 *retlen = len;
0121
0122 rc = opal_error_code(rc);
0123 out:
0124 opal_async_release_token(token);
0125 return rc;
0126 }
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138 static int powernv_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
0139 size_t *retlen, u_char *buf)
0140 {
0141 return powernv_flash_async_op(mtd, FLASH_OP_READ, from,
0142 len, retlen, buf);
0143 }
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155 static int powernv_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
0156 size_t *retlen, const u_char *buf)
0157 {
0158 return powernv_flash_async_op(mtd, FLASH_OP_WRITE, to,
0159 len, retlen, (u_char *)buf);
0160 }
0161
0162
0163
0164
0165
0166
0167
0168 static int powernv_flash_erase(struct mtd_info *mtd, struct erase_info *erase)
0169 {
0170 int rc;
0171
0172 rc = powernv_flash_async_op(mtd, FLASH_OP_ERASE, erase->addr,
0173 erase->len, NULL, NULL);
0174 if (rc)
0175 erase->fail_addr = erase->addr;
0176
0177 return rc;
0178 }
0179
0180
0181
0182
0183
0184
0185 static int powernv_flash_set_driver_info(struct device *dev,
0186 struct mtd_info *mtd)
0187 {
0188 u64 size;
0189 u32 erase_size;
0190 int rc;
0191
0192 rc = of_property_read_u32(dev->of_node, "ibm,flash-block-size",
0193 &erase_size);
0194 if (rc) {
0195 dev_err(dev, "couldn't get resource block size information\n");
0196 return rc;
0197 }
0198
0199 rc = of_property_read_u64(dev->of_node, "reg", &size);
0200 if (rc) {
0201 dev_err(dev, "couldn't get resource size information\n");
0202 return rc;
0203 }
0204
0205
0206
0207
0208
0209 mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%pOFP", dev->of_node);
0210 mtd->type = MTD_NORFLASH;
0211 mtd->flags = MTD_WRITEABLE;
0212 mtd->size = size;
0213 mtd->erasesize = erase_size;
0214 mtd->writebufsize = mtd->writesize = 1;
0215 mtd->owner = THIS_MODULE;
0216 mtd->_erase = powernv_flash_erase;
0217 mtd->_read = powernv_flash_read;
0218 mtd->_write = powernv_flash_write;
0219 mtd->dev.parent = dev;
0220 mtd_set_of_node(mtd, dev->of_node);
0221 return 0;
0222 }
0223
0224
0225
0226
0227
0228
0229
0230 static int powernv_flash_probe(struct platform_device *pdev)
0231 {
0232 struct device *dev = &pdev->dev;
0233 struct powernv_flash *data;
0234 int ret;
0235
0236 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0237 if (!data)
0238 return -ENOMEM;
0239
0240 data->mtd.priv = data;
0241
0242 ret = of_property_read_u32(dev->of_node, "ibm,opal-id", &(data->id));
0243 if (ret) {
0244 dev_err(dev, "no device property 'ibm,opal-id'\n");
0245 return ret;
0246 }
0247
0248 ret = powernv_flash_set_driver_info(dev, &data->mtd);
0249 if (ret)
0250 return ret;
0251
0252 dev_set_drvdata(dev, data);
0253
0254
0255
0256
0257
0258
0259 return mtd_device_register(&data->mtd, NULL, 0);
0260 }
0261
0262
0263
0264
0265
0266
0267
0268 static int powernv_flash_release(struct platform_device *pdev)
0269 {
0270 struct powernv_flash *data = dev_get_drvdata(&(pdev->dev));
0271
0272
0273 WARN_ON(mtd_device_unregister(&data->mtd));
0274
0275 return 0;
0276 }
0277
0278 static const struct of_device_id powernv_flash_match[] = {
0279 { .compatible = "ibm,opal-flash" },
0280 {}
0281 };
0282
0283 static struct platform_driver powernv_flash_driver = {
0284 .driver = {
0285 .name = "powernv_flash",
0286 .of_match_table = powernv_flash_match,
0287 },
0288 .remove = powernv_flash_release,
0289 .probe = powernv_flash_probe,
0290 };
0291
0292 module_platform_driver(powernv_flash_driver);
0293
0294 MODULE_DEVICE_TABLE(of, powernv_flash_match);
0295 MODULE_LICENSE("GPL");
0296 MODULE_AUTHOR("Cyril Bur <cyril.bur@au1.ibm.com>");
0297 MODULE_DESCRIPTION("MTD abstraction for OPAL flash");