Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * LPDDR2-NVM MTD driver. This module provides read, write, erase, lock/unlock
0004  * support for LPDDR2-NVM PCM memories
0005  *
0006  * Copyright © 2012 Micron Technology, Inc.
0007  *
0008  * Vincenzo Aliberti <vincenzo.aliberti@gmail.com>
0009  * Domenico Manna <domenico.manna@gmail.com>
0010  * Many thanks to Andrea Vigilante for initial enabling
0011  */
0012 
0013 #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
0014 
0015 #include <linux/init.h>
0016 #include <linux/io.h>
0017 #include <linux/module.h>
0018 #include <linux/kernel.h>
0019 #include <linux/mtd/map.h>
0020 #include <linux/mtd/mtd.h>
0021 #include <linux/mtd/partitions.h>
0022 #include <linux/slab.h>
0023 #include <linux/platform_device.h>
0024 #include <linux/ioport.h>
0025 #include <linux/err.h>
0026 
0027 /* Parameters */
0028 #define ERASE_BLOCKSIZE         (0x00020000/2)  /* in Word */
0029 #define WRITE_BUFFSIZE          (0x00000400/2)  /* in Word */
0030 #define OW_BASE_ADDRESS         0x00000000  /* OW offset */
0031 #define BUS_WIDTH           0x00000020  /* x32 devices */
0032 
0033 /* PFOW symbols address offset */
0034 #define PFOW_QUERY_STRING_P     (0x0000/2)  /* in Word */
0035 #define PFOW_QUERY_STRING_F     (0x0002/2)  /* in Word */
0036 #define PFOW_QUERY_STRING_O     (0x0004/2)  /* in Word */
0037 #define PFOW_QUERY_STRING_W     (0x0006/2)  /* in Word */
0038 
0039 /* OW registers address */
0040 #define CMD_CODE_OFS            (0x0080/2)  /* in Word */
0041 #define CMD_DATA_OFS            (0x0084/2)  /* in Word */
0042 #define CMD_ADD_L_OFS           (0x0088/2)  /* in Word */
0043 #define CMD_ADD_H_OFS           (0x008A/2)  /* in Word */
0044 #define MPR_L_OFS           (0x0090/2)  /* in Word */
0045 #define MPR_H_OFS           (0x0092/2)  /* in Word */
0046 #define CMD_EXEC_OFS            (0x00C0/2)  /* in Word */
0047 #define STATUS_REG_OFS          (0x00CC/2)  /* in Word */
0048 #define PRG_BUFFER_OFS          (0x0010/2)  /* in Word */
0049 
0050 /* Datamask */
0051 #define MR_CFGMASK          0x8000
0052 #define SR_OK_DATAMASK          0x0080
0053 
0054 /* LPDDR2-NVM Commands */
0055 #define LPDDR2_NVM_LOCK         0x0061
0056 #define LPDDR2_NVM_UNLOCK       0x0062
0057 #define LPDDR2_NVM_SW_PROGRAM       0x0041
0058 #define LPDDR2_NVM_SW_OVERWRITE     0x0042
0059 #define LPDDR2_NVM_BUF_PROGRAM      0x00E9
0060 #define LPDDR2_NVM_BUF_OVERWRITE    0x00EA
0061 #define LPDDR2_NVM_ERASE        0x0020
0062 
0063 /* LPDDR2-NVM Registers offset */
0064 #define LPDDR2_MODE_REG_DATA        0x0040
0065 #define LPDDR2_MODE_REG_CFG     0x0050
0066 
0067 /*
0068  * Internal Type Definitions
0069  * pcm_int_data contains memory controller details:
0070  * @reg_data : LPDDR2_MODE_REG_DATA register address after remapping
0071  * @reg_cfg  : LPDDR2_MODE_REG_CFG register address after remapping
0072  * &bus_width: memory bus-width (eg: x16 2 Bytes, x32 4 Bytes)
0073  */
0074 struct pcm_int_data {
0075     void __iomem *ctl_regs;
0076     int bus_width;
0077 };
0078 
0079 static DEFINE_MUTEX(lpdd2_nvm_mutex);
0080 
0081 /*
0082  * Build a map_word starting from an u_long
0083  */
0084 static inline map_word build_map_word(u_long myword)
0085 {
0086     map_word val = { {0} };
0087     val.x[0] = myword;
0088     return val;
0089 }
0090 
0091 /*
0092  * Build Mode Register Configuration DataMask based on device bus-width
0093  */
0094 static inline u_int build_mr_cfgmask(u_int bus_width)
0095 {
0096     u_int val = MR_CFGMASK;
0097 
0098     if (bus_width == 0x0004)        /* x32 device */
0099         val = val << 16;
0100 
0101     return val;
0102 }
0103 
0104 /*
0105  * Build Status Register OK DataMask based on device bus-width
0106  */
0107 static inline u_int build_sr_ok_datamask(u_int bus_width)
0108 {
0109     u_int val = SR_OK_DATAMASK;
0110 
0111     if (bus_width == 0x0004)        /* x32 device */
0112         val = (val << 16)+val;
0113 
0114     return val;
0115 }
0116 
0117 /*
0118  * Evaluates Overlay Window Control Registers address
0119  */
0120 static inline u_long ow_reg_add(struct map_info *map, u_long offset)
0121 {
0122     u_long val = 0;
0123     struct pcm_int_data *pcm_data = map->fldrv_priv;
0124 
0125     val = map->pfow_base + offset*pcm_data->bus_width;
0126 
0127     return val;
0128 }
0129 
0130 /*
0131  * Enable lpddr2-nvm Overlay Window
0132  * Overlay Window is a memory mapped area containing all LPDDR2-NVM registers
0133  * used by device commands as well as uservisible resources like Device Status
0134  * Register, Device ID, etc
0135  */
0136 static inline void ow_enable(struct map_info *map)
0137 {
0138     struct pcm_int_data *pcm_data = map->fldrv_priv;
0139 
0140     writel_relaxed(build_mr_cfgmask(pcm_data->bus_width) | 0x18,
0141         pcm_data->ctl_regs + LPDDR2_MODE_REG_CFG);
0142     writel_relaxed(0x01, pcm_data->ctl_regs + LPDDR2_MODE_REG_DATA);
0143 }
0144 
0145 /*
0146  * Disable lpddr2-nvm Overlay Window
0147  * Overlay Window is a memory mapped area containing all LPDDR2-NVM registers
0148  * used by device commands as well as uservisible resources like Device Status
0149  * Register, Device ID, etc
0150  */
0151 static inline void ow_disable(struct map_info *map)
0152 {
0153     struct pcm_int_data *pcm_data = map->fldrv_priv;
0154 
0155     writel_relaxed(build_mr_cfgmask(pcm_data->bus_width) | 0x18,
0156         pcm_data->ctl_regs + LPDDR2_MODE_REG_CFG);
0157     writel_relaxed(0x02, pcm_data->ctl_regs + LPDDR2_MODE_REG_DATA);
0158 }
0159 
0160 /*
0161  * Execute lpddr2-nvm operations
0162  */
0163 static int lpddr2_nvm_do_op(struct map_info *map, u_long cmd_code,
0164     u_long cmd_data, u_long cmd_add, u_long cmd_mpr, u_char *buf)
0165 {
0166     map_word add_l = { {0} }, add_h = { {0} }, mpr_l = { {0} },
0167         mpr_h = { {0} }, data_l = { {0} }, cmd = { {0} },
0168         exec_cmd = { {0} }, sr;
0169     map_word data_h = { {0} };  /* only for 2x x16 devices stacked */
0170     u_long i, status_reg, prg_buff_ofs;
0171     struct pcm_int_data *pcm_data = map->fldrv_priv;
0172     u_int sr_ok_datamask = build_sr_ok_datamask(pcm_data->bus_width);
0173 
0174     /* Builds low and high words for OW Control Registers */
0175     add_l.x[0]  = cmd_add & 0x0000FFFF;
0176     add_h.x[0]  = (cmd_add >> 16) & 0x0000FFFF;
0177     mpr_l.x[0]  = cmd_mpr & 0x0000FFFF;
0178     mpr_h.x[0]  = (cmd_mpr >> 16) & 0x0000FFFF;
0179     cmd.x[0]    = cmd_code & 0x0000FFFF;
0180     exec_cmd.x[0]   = 0x0001;
0181     data_l.x[0] = cmd_data & 0x0000FFFF;
0182     data_h.x[0] = (cmd_data >> 16) & 0x0000FFFF; /* only for 2x x16 */
0183 
0184     /* Set Overlay Window Control Registers */
0185     map_write(map, cmd, ow_reg_add(map, CMD_CODE_OFS));
0186     map_write(map, data_l, ow_reg_add(map, CMD_DATA_OFS));
0187     map_write(map, add_l, ow_reg_add(map, CMD_ADD_L_OFS));
0188     map_write(map, add_h, ow_reg_add(map, CMD_ADD_H_OFS));
0189     map_write(map, mpr_l, ow_reg_add(map, MPR_L_OFS));
0190     map_write(map, mpr_h, ow_reg_add(map, MPR_H_OFS));
0191     if (pcm_data->bus_width == 0x0004) {    /* 2x16 devices stacked */
0192         map_write(map, cmd, ow_reg_add(map, CMD_CODE_OFS) + 2);
0193         map_write(map, data_h, ow_reg_add(map, CMD_DATA_OFS) + 2);
0194         map_write(map, add_l, ow_reg_add(map, CMD_ADD_L_OFS) + 2);
0195         map_write(map, add_h, ow_reg_add(map, CMD_ADD_H_OFS) + 2);
0196         map_write(map, mpr_l, ow_reg_add(map, MPR_L_OFS) + 2);
0197         map_write(map, mpr_h, ow_reg_add(map, MPR_H_OFS) + 2);
0198     }
0199 
0200     /* Fill Program Buffer */
0201     if ((cmd_code == LPDDR2_NVM_BUF_PROGRAM) ||
0202         (cmd_code == LPDDR2_NVM_BUF_OVERWRITE)) {
0203         prg_buff_ofs = (map_read(map,
0204             ow_reg_add(map, PRG_BUFFER_OFS))).x[0];
0205         for (i = 0; i < cmd_mpr; i++) {
0206             map_write(map, build_map_word(buf[i]), map->pfow_base +
0207             prg_buff_ofs + i);
0208         }
0209     }
0210 
0211     /* Command Execute */
0212     map_write(map, exec_cmd, ow_reg_add(map, CMD_EXEC_OFS));
0213     if (pcm_data->bus_width == 0x0004)  /* 2x16 devices stacked */
0214         map_write(map, exec_cmd, ow_reg_add(map, CMD_EXEC_OFS) + 2);
0215 
0216     /* Status Register Check */
0217     do {
0218         sr = map_read(map, ow_reg_add(map, STATUS_REG_OFS));
0219         status_reg = sr.x[0];
0220         if (pcm_data->bus_width == 0x0004) {/* 2x16 devices stacked */
0221             sr = map_read(map, ow_reg_add(map,
0222                 STATUS_REG_OFS) + 2);
0223             status_reg += sr.x[0] << 16;
0224         }
0225     } while ((status_reg & sr_ok_datamask) != sr_ok_datamask);
0226 
0227     return (((status_reg & sr_ok_datamask) == sr_ok_datamask) ? 0 : -EIO);
0228 }
0229 
0230 /*
0231  * Execute lpddr2-nvm operations @ block level
0232  */
0233 static int lpddr2_nvm_do_block_op(struct mtd_info *mtd, loff_t start_add,
0234     uint64_t len, u_char block_op)
0235 {
0236     struct map_info *map = mtd->priv;
0237     u_long add, end_add;
0238     int ret = 0;
0239 
0240     mutex_lock(&lpdd2_nvm_mutex);
0241 
0242     ow_enable(map);
0243 
0244     add = start_add;
0245     end_add = add + len;
0246 
0247     do {
0248         ret = lpddr2_nvm_do_op(map, block_op, 0x00, add, add, NULL);
0249         if (ret)
0250             goto out;
0251         add += mtd->erasesize;
0252     } while (add < end_add);
0253 
0254 out:
0255     ow_disable(map);
0256     mutex_unlock(&lpdd2_nvm_mutex);
0257     return ret;
0258 }
0259 
0260 /*
0261  * verify presence of PFOW string
0262  */
0263 static int lpddr2_nvm_pfow_present(struct map_info *map)
0264 {
0265     map_word pfow_val[4];
0266     unsigned int found = 1;
0267 
0268     mutex_lock(&lpdd2_nvm_mutex);
0269 
0270     ow_enable(map);
0271 
0272     /* Load string from array */
0273     pfow_val[0] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_P));
0274     pfow_val[1] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_F));
0275     pfow_val[2] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_O));
0276     pfow_val[3] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_W));
0277 
0278     /* Verify the string loaded vs expected */
0279     if (!map_word_equal(map, build_map_word('P'), pfow_val[0]))
0280         found = 0;
0281     if (!map_word_equal(map, build_map_word('F'), pfow_val[1]))
0282         found = 0;
0283     if (!map_word_equal(map, build_map_word('O'), pfow_val[2]))
0284         found = 0;
0285     if (!map_word_equal(map, build_map_word('W'), pfow_val[3]))
0286         found = 0;
0287 
0288     ow_disable(map);
0289 
0290     mutex_unlock(&lpdd2_nvm_mutex);
0291 
0292     return found;
0293 }
0294 
0295 /*
0296  * lpddr2_nvm driver read method
0297  */
0298 static int lpddr2_nvm_read(struct mtd_info *mtd, loff_t start_add,
0299                 size_t len, size_t *retlen, u_char *buf)
0300 {
0301     struct map_info *map = mtd->priv;
0302 
0303     mutex_lock(&lpdd2_nvm_mutex);
0304 
0305     *retlen = len;
0306 
0307     map_copy_from(map, buf, start_add, *retlen);
0308 
0309     mutex_unlock(&lpdd2_nvm_mutex);
0310     return 0;
0311 }
0312 
0313 /*
0314  * lpddr2_nvm driver write method
0315  */
0316 static int lpddr2_nvm_write(struct mtd_info *mtd, loff_t start_add,
0317                 size_t len, size_t *retlen, const u_char *buf)
0318 {
0319     struct map_info *map = mtd->priv;
0320     struct pcm_int_data *pcm_data = map->fldrv_priv;
0321     u_long add, current_len, tot_len, target_len, my_data;
0322     u_char *write_buf = (u_char *)buf;
0323     int ret = 0;
0324 
0325     mutex_lock(&lpdd2_nvm_mutex);
0326 
0327     ow_enable(map);
0328 
0329     /* Set start value for the variables */
0330     add = start_add;
0331     target_len = len;
0332     tot_len = 0;
0333 
0334     while (tot_len < target_len) {
0335         if (!(IS_ALIGNED(add, mtd->writesize))) { /* do sw program */
0336             my_data = write_buf[tot_len];
0337             my_data += (write_buf[tot_len+1]) << 8;
0338             if (pcm_data->bus_width == 0x0004) {/* 2x16 devices */
0339                 my_data += (write_buf[tot_len+2]) << 16;
0340                 my_data += (write_buf[tot_len+3]) << 24;
0341             }
0342             ret = lpddr2_nvm_do_op(map, LPDDR2_NVM_SW_OVERWRITE,
0343                 my_data, add, 0x00, NULL);
0344             if (ret)
0345                 goto out;
0346 
0347             add += pcm_data->bus_width;
0348             tot_len += pcm_data->bus_width;
0349         } else {        /* do buffer program */
0350             current_len = min(target_len - tot_len,
0351                 (u_long) mtd->writesize);
0352             ret = lpddr2_nvm_do_op(map, LPDDR2_NVM_BUF_OVERWRITE,
0353                 0x00, add, current_len, write_buf + tot_len);
0354             if (ret)
0355                 goto out;
0356 
0357             add += current_len;
0358             tot_len += current_len;
0359         }
0360     }
0361 
0362 out:
0363     *retlen = tot_len;
0364     ow_disable(map);
0365     mutex_unlock(&lpdd2_nvm_mutex);
0366     return ret;
0367 }
0368 
0369 /*
0370  * lpddr2_nvm driver erase method
0371  */
0372 static int lpddr2_nvm_erase(struct mtd_info *mtd, struct erase_info *instr)
0373 {
0374     return lpddr2_nvm_do_block_op(mtd, instr->addr, instr->len,
0375                       LPDDR2_NVM_ERASE);
0376 }
0377 
0378 /*
0379  * lpddr2_nvm driver unlock method
0380  */
0381 static int lpddr2_nvm_unlock(struct mtd_info *mtd, loff_t start_add,
0382     uint64_t len)
0383 {
0384     return lpddr2_nvm_do_block_op(mtd, start_add, len, LPDDR2_NVM_UNLOCK);
0385 }
0386 
0387 /*
0388  * lpddr2_nvm driver lock method
0389  */
0390 static int lpddr2_nvm_lock(struct mtd_info *mtd, loff_t start_add,
0391     uint64_t len)
0392 {
0393     return lpddr2_nvm_do_block_op(mtd, start_add, len, LPDDR2_NVM_LOCK);
0394 }
0395 
0396 static const struct mtd_info lpddr2_nvm_mtd_info = {
0397     .type       = MTD_RAM,
0398     .writesize  = 1,
0399     .flags      = (MTD_CAP_NVRAM | MTD_POWERUP_LOCK),
0400     ._read      = lpddr2_nvm_read,
0401     ._write     = lpddr2_nvm_write,
0402     ._erase     = lpddr2_nvm_erase,
0403     ._unlock    = lpddr2_nvm_unlock,
0404     ._lock      = lpddr2_nvm_lock,
0405 };
0406 
0407 /*
0408  * lpddr2_nvm driver probe method
0409  */
0410 static int lpddr2_nvm_probe(struct platform_device *pdev)
0411 {
0412     struct map_info *map;
0413     struct mtd_info *mtd;
0414     struct resource *add_range;
0415     struct resource *control_regs;
0416     struct pcm_int_data *pcm_data;
0417 
0418     /* Allocate memory control_regs data structures */
0419     pcm_data = devm_kzalloc(&pdev->dev, sizeof(*pcm_data), GFP_KERNEL);
0420     if (!pcm_data)
0421         return -ENOMEM;
0422 
0423     pcm_data->bus_width = BUS_WIDTH;
0424 
0425     /* Allocate memory for map_info & mtd_info data structures */
0426     map = devm_kzalloc(&pdev->dev, sizeof(*map), GFP_KERNEL);
0427     if (!map)
0428         return -ENOMEM;
0429 
0430     mtd = devm_kzalloc(&pdev->dev, sizeof(*mtd), GFP_KERNEL);
0431     if (!mtd)
0432         return -ENOMEM;
0433 
0434     /* lpddr2_nvm address range */
0435     add_range = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0436 
0437     /* Populate map_info data structure */
0438     *map = (struct map_info) {
0439         .virt       = devm_ioremap_resource(&pdev->dev, add_range),
0440         .name       = pdev->dev.init_name,
0441         .phys       = add_range->start,
0442         .size       = resource_size(add_range),
0443         .bankwidth  = pcm_data->bus_width / 2,
0444         .pfow_base  = OW_BASE_ADDRESS,
0445         .fldrv_priv = pcm_data,
0446     };
0447 
0448     if (IS_ERR(map->virt))
0449         return PTR_ERR(map->virt);
0450 
0451     simple_map_init(map);   /* fill with default methods */
0452 
0453     control_regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
0454     pcm_data->ctl_regs = devm_ioremap_resource(&pdev->dev, control_regs);
0455     if (IS_ERR(pcm_data->ctl_regs))
0456         return PTR_ERR(pcm_data->ctl_regs);
0457 
0458     /* Populate mtd_info data structure */
0459     *mtd = lpddr2_nvm_mtd_info;
0460     mtd->dev.parent     = &pdev->dev;
0461     mtd->name       = pdev->dev.init_name;
0462     mtd->priv       = map;
0463     mtd->size       = resource_size(add_range);
0464     mtd->erasesize      = ERASE_BLOCKSIZE * pcm_data->bus_width;
0465     mtd->writebufsize   = WRITE_BUFFSIZE * pcm_data->bus_width;
0466 
0467     /* Verify the presence of the device looking for PFOW string */
0468     if (!lpddr2_nvm_pfow_present(map)) {
0469         pr_err("device not recognized\n");
0470         return -EINVAL;
0471     }
0472     /* Parse partitions and register the MTD device */
0473     return mtd_device_register(mtd, NULL, 0);
0474 }
0475 
0476 /*
0477  * lpddr2_nvm driver remove method
0478  */
0479 static int lpddr2_nvm_remove(struct platform_device *pdev)
0480 {
0481     WARN_ON(mtd_device_unregister(dev_get_drvdata(&pdev->dev)));
0482 
0483     return 0;
0484 }
0485 
0486 /* Initialize platform_driver data structure for lpddr2_nvm */
0487 static struct platform_driver lpddr2_nvm_drv = {
0488     .driver     = {
0489         .name   = "lpddr2_nvm",
0490     },
0491     .probe      = lpddr2_nvm_probe,
0492     .remove     = lpddr2_nvm_remove,
0493 };
0494 
0495 module_platform_driver(lpddr2_nvm_drv);
0496 MODULE_LICENSE("GPL");
0497 MODULE_AUTHOR("Vincenzo Aliberti <vincenzo.aliberti@gmail.com>");
0498 MODULE_DESCRIPTION("MTD driver for LPDDR2-NVM PCM memories");