1 /* 2 * LPDDR2-NVM MTD driver. This module provides read, write, erase, lock/unlock 3 * support for LPDDR2-NVM PCM memories 4 * 5 * Copyright © 2012 Micron Technology, Inc. 6 * 7 * Vincenzo Aliberti <vincenzo.aliberti@gmail.com> 8 * Domenico Manna <domenico.manna@gmail.com> 9 * Many thanks to Andrea Vigilante for initial enabling 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation; either version 2 14 * of the License, or (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 */ 21 22 #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ 23 24 #include <linux/init.h> 25 #include <linux/io.h> 26 #include <linux/module.h> 27 #include <linux/kernel.h> 28 #include <linux/mtd/map.h> 29 #include <linux/mtd/mtd.h> 30 #include <linux/mtd/partitions.h> 31 #include <linux/slab.h> 32 #include <linux/platform_device.h> 33 #include <linux/ioport.h> 34 #include <linux/err.h> 35 36 /* Parameters */ 37 #define ERASE_BLOCKSIZE (0x00020000/2) /* in Word */ 38 #define WRITE_BUFFSIZE (0x00000400/2) /* in Word */ 39 #define OW_BASE_ADDRESS 0x00000000 /* OW offset */ 40 #define BUS_WIDTH 0x00000020 /* x32 devices */ 41 42 /* PFOW symbols address offset */ 43 #define PFOW_QUERY_STRING_P (0x0000/2) /* in Word */ 44 #define PFOW_QUERY_STRING_F (0x0002/2) /* in Word */ 45 #define PFOW_QUERY_STRING_O (0x0004/2) /* in Word */ 46 #define PFOW_QUERY_STRING_W (0x0006/2) /* in Word */ 47 48 /* OW registers address */ 49 #define CMD_CODE_OFS (0x0080/2) /* in Word */ 50 #define CMD_DATA_OFS (0x0084/2) /* in Word */ 51 #define CMD_ADD_L_OFS (0x0088/2) /* in Word */ 52 #define CMD_ADD_H_OFS (0x008A/2) /* in Word */ 53 #define MPR_L_OFS (0x0090/2) /* in Word */ 54 #define MPR_H_OFS (0x0092/2) /* in Word */ 55 #define CMD_EXEC_OFS (0x00C0/2) /* in Word */ 56 #define STATUS_REG_OFS (0x00CC/2) /* in Word */ 57 #define PRG_BUFFER_OFS (0x0010/2) /* in Word */ 58 59 /* Datamask */ 60 #define MR_CFGMASK 0x8000 61 #define SR_OK_DATAMASK 0x0080 62 63 /* LPDDR2-NVM Commands */ 64 #define LPDDR2_NVM_LOCK 0x0061 65 #define LPDDR2_NVM_UNLOCK 0x0062 66 #define LPDDR2_NVM_SW_PROGRAM 0x0041 67 #define LPDDR2_NVM_SW_OVERWRITE 0x0042 68 #define LPDDR2_NVM_BUF_PROGRAM 0x00E9 69 #define LPDDR2_NVM_BUF_OVERWRITE 0x00EA 70 #define LPDDR2_NVM_ERASE 0x0020 71 72 /* LPDDR2-NVM Registers offset */ 73 #define LPDDR2_MODE_REG_DATA 0x0040 74 #define LPDDR2_MODE_REG_CFG 0x0050 75 76 /* 77 * Internal Type Definitions 78 * pcm_int_data contains memory controller details: 79 * @reg_data : LPDDR2_MODE_REG_DATA register address after remapping 80 * @reg_cfg : LPDDR2_MODE_REG_CFG register address after remapping 81 * &bus_width: memory bus-width (eg: x16 2 Bytes, x32 4 Bytes) 82 */ 83 struct pcm_int_data { 84 void __iomem *ctl_regs; 85 int bus_width; 86 }; 87 88 static DEFINE_MUTEX(lpdd2_nvm_mutex); 89 90 /* 91 * Build a map_word starting from an u_long 92 */ 93 static inline map_word build_map_word(u_long myword) 94 { 95 map_word val = { {0} }; 96 val.x[0] = myword; 97 return val; 98 } 99 100 /* 101 * Build Mode Register Configuration DataMask based on device bus-width 102 */ 103 static inline u_int build_mr_cfgmask(u_int bus_width) 104 { 105 u_int val = MR_CFGMASK; 106 107 if (bus_width == 0x0004) /* x32 device */ 108 val = val << 16; 109 110 return val; 111 } 112 113 /* 114 * Build Status Register OK DataMask based on device bus-width 115 */ 116 static inline u_int build_sr_ok_datamask(u_int bus_width) 117 { 118 u_int val = SR_OK_DATAMASK; 119 120 if (bus_width == 0x0004) /* x32 device */ 121 val = (val << 16)+val; 122 123 return val; 124 } 125 126 /* 127 * Evaluates Overlay Window Control Registers address 128 */ 129 static inline u_long ow_reg_add(struct map_info *map, u_long offset) 130 { 131 u_long val = 0; 132 struct pcm_int_data *pcm_data = map->fldrv_priv; 133 134 val = map->pfow_base + offset*pcm_data->bus_width; 135 136 return val; 137 } 138 139 /* 140 * Enable lpddr2-nvm Overlay Window 141 * Overlay Window is a memory mapped area containing all LPDDR2-NVM registers 142 * used by device commands as well as uservisible resources like Device Status 143 * Register, Device ID, etc 144 */ 145 static inline void ow_enable(struct map_info *map) 146 { 147 struct pcm_int_data *pcm_data = map->fldrv_priv; 148 149 writel_relaxed(build_mr_cfgmask(pcm_data->bus_width) | 0x18, 150 pcm_data->ctl_regs + LPDDR2_MODE_REG_CFG); 151 writel_relaxed(0x01, pcm_data->ctl_regs + LPDDR2_MODE_REG_DATA); 152 } 153 154 /* 155 * Disable lpddr2-nvm Overlay Window 156 * Overlay Window is a memory mapped area containing all LPDDR2-NVM registers 157 * used by device commands as well as uservisible resources like Device Status 158 * Register, Device ID, etc 159 */ 160 static inline void ow_disable(struct map_info *map) 161 { 162 struct pcm_int_data *pcm_data = map->fldrv_priv; 163 164 writel_relaxed(build_mr_cfgmask(pcm_data->bus_width) | 0x18, 165 pcm_data->ctl_regs + LPDDR2_MODE_REG_CFG); 166 writel_relaxed(0x02, pcm_data->ctl_regs + LPDDR2_MODE_REG_DATA); 167 } 168 169 /* 170 * Execute lpddr2-nvm operations 171 */ 172 static int lpddr2_nvm_do_op(struct map_info *map, u_long cmd_code, 173 u_long cmd_data, u_long cmd_add, u_long cmd_mpr, u_char *buf) 174 { 175 map_word add_l = { {0} }, add_h = { {0} }, mpr_l = { {0} }, 176 mpr_h = { {0} }, data_l = { {0} }, cmd = { {0} }, 177 exec_cmd = { {0} }, sr; 178 map_word data_h = { {0} }; /* only for 2x x16 devices stacked */ 179 u_long i, status_reg, prg_buff_ofs; 180 struct pcm_int_data *pcm_data = map->fldrv_priv; 181 u_int sr_ok_datamask = build_sr_ok_datamask(pcm_data->bus_width); 182 183 /* Builds low and high words for OW Control Registers */ 184 add_l.x[0] = cmd_add & 0x0000FFFF; 185 add_h.x[0] = (cmd_add >> 16) & 0x0000FFFF; 186 mpr_l.x[0] = cmd_mpr & 0x0000FFFF; 187 mpr_h.x[0] = (cmd_mpr >> 16) & 0x0000FFFF; 188 cmd.x[0] = cmd_code & 0x0000FFFF; 189 exec_cmd.x[0] = 0x0001; 190 data_l.x[0] = cmd_data & 0x0000FFFF; 191 data_h.x[0] = (cmd_data >> 16) & 0x0000FFFF; /* only for 2x x16 */ 192 193 /* Set Overlay Window Control Registers */ 194 map_write(map, cmd, ow_reg_add(map, CMD_CODE_OFS)); 195 map_write(map, data_l, ow_reg_add(map, CMD_DATA_OFS)); 196 map_write(map, add_l, ow_reg_add(map, CMD_ADD_L_OFS)); 197 map_write(map, add_h, ow_reg_add(map, CMD_ADD_H_OFS)); 198 map_write(map, mpr_l, ow_reg_add(map, MPR_L_OFS)); 199 map_write(map, mpr_h, ow_reg_add(map, MPR_H_OFS)); 200 if (pcm_data->bus_width == 0x0004) { /* 2x16 devices stacked */ 201 map_write(map, cmd, ow_reg_add(map, CMD_CODE_OFS) + 2); 202 map_write(map, data_h, ow_reg_add(map, CMD_DATA_OFS) + 2); 203 map_write(map, add_l, ow_reg_add(map, CMD_ADD_L_OFS) + 2); 204 map_write(map, add_h, ow_reg_add(map, CMD_ADD_H_OFS) + 2); 205 map_write(map, mpr_l, ow_reg_add(map, MPR_L_OFS) + 2); 206 map_write(map, mpr_h, ow_reg_add(map, MPR_H_OFS) + 2); 207 } 208 209 /* Fill Program Buffer */ 210 if ((cmd_code == LPDDR2_NVM_BUF_PROGRAM) || 211 (cmd_code == LPDDR2_NVM_BUF_OVERWRITE)) { 212 prg_buff_ofs = (map_read(map, 213 ow_reg_add(map, PRG_BUFFER_OFS))).x[0]; 214 for (i = 0; i < cmd_mpr; i++) { 215 map_write(map, build_map_word(buf[i]), map->pfow_base + 216 prg_buff_ofs + i); 217 } 218 } 219 220 /* Command Execute */ 221 map_write(map, exec_cmd, ow_reg_add(map, CMD_EXEC_OFS)); 222 if (pcm_data->bus_width == 0x0004) /* 2x16 devices stacked */ 223 map_write(map, exec_cmd, ow_reg_add(map, CMD_EXEC_OFS) + 2); 224 225 /* Status Register Check */ 226 do { 227 sr = map_read(map, ow_reg_add(map, STATUS_REG_OFS)); 228 status_reg = sr.x[0]; 229 if (pcm_data->bus_width == 0x0004) {/* 2x16 devices stacked */ 230 sr = map_read(map, ow_reg_add(map, 231 STATUS_REG_OFS) + 2); 232 status_reg += sr.x[0] << 16; 233 } 234 } while ((status_reg & sr_ok_datamask) != sr_ok_datamask); 235 236 return (((status_reg & sr_ok_datamask) == sr_ok_datamask) ? 0 : -EIO); 237 } 238 239 /* 240 * Execute lpddr2-nvm operations @ block level 241 */ 242 static int lpddr2_nvm_do_block_op(struct mtd_info *mtd, loff_t start_add, 243 uint64_t len, u_char block_op) 244 { 245 struct map_info *map = mtd->priv; 246 u_long add, end_add; 247 int ret = 0; 248 249 mutex_lock(&lpdd2_nvm_mutex); 250 251 ow_enable(map); 252 253 add = start_add; 254 end_add = add + len; 255 256 do { 257 ret = lpddr2_nvm_do_op(map, block_op, 0x00, add, add, NULL); 258 if (ret) 259 goto out; 260 add += mtd->erasesize; 261 } while (add < end_add); 262 263 out: 264 ow_disable(map); 265 mutex_unlock(&lpdd2_nvm_mutex); 266 return ret; 267 } 268 269 /* 270 * verify presence of PFOW string 271 */ 272 static int lpddr2_nvm_pfow_present(struct map_info *map) 273 { 274 map_word pfow_val[4]; 275 unsigned int found = 1; 276 277 mutex_lock(&lpdd2_nvm_mutex); 278 279 ow_enable(map); 280 281 /* Load string from array */ 282 pfow_val[0] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_P)); 283 pfow_val[1] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_F)); 284 pfow_val[2] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_O)); 285 pfow_val[3] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_W)); 286 287 /* Verify the string loaded vs expected */ 288 if (!map_word_equal(map, build_map_word('P'), pfow_val[0])) 289 found = 0; 290 if (!map_word_equal(map, build_map_word('F'), pfow_val[1])) 291 found = 0; 292 if (!map_word_equal(map, build_map_word('O'), pfow_val[2])) 293 found = 0; 294 if (!map_word_equal(map, build_map_word('W'), pfow_val[3])) 295 found = 0; 296 297 ow_disable(map); 298 299 mutex_unlock(&lpdd2_nvm_mutex); 300 301 return found; 302 } 303 304 /* 305 * lpddr2_nvm driver read method 306 */ 307 static int lpddr2_nvm_read(struct mtd_info *mtd, loff_t start_add, 308 size_t len, size_t *retlen, u_char *buf) 309 { 310 struct map_info *map = mtd->priv; 311 312 mutex_lock(&lpdd2_nvm_mutex); 313 314 *retlen = len; 315 316 map_copy_from(map, buf, start_add, *retlen); 317 318 mutex_unlock(&lpdd2_nvm_mutex); 319 return 0; 320 } 321 322 /* 323 * lpddr2_nvm driver write method 324 */ 325 static int lpddr2_nvm_write(struct mtd_info *mtd, loff_t start_add, 326 size_t len, size_t *retlen, const u_char *buf) 327 { 328 struct map_info *map = mtd->priv; 329 struct pcm_int_data *pcm_data = map->fldrv_priv; 330 u_long add, current_len, tot_len, target_len, my_data; 331 u_char *write_buf = (u_char *)buf; 332 int ret = 0; 333 334 mutex_lock(&lpdd2_nvm_mutex); 335 336 ow_enable(map); 337 338 /* Set start value for the variables */ 339 add = start_add; 340 target_len = len; 341 tot_len = 0; 342 343 while (tot_len < target_len) { 344 if (!(IS_ALIGNED(add, mtd->writesize))) { /* do sw program */ 345 my_data = write_buf[tot_len]; 346 my_data += (write_buf[tot_len+1]) << 8; 347 if (pcm_data->bus_width == 0x0004) {/* 2x16 devices */ 348 my_data += (write_buf[tot_len+2]) << 16; 349 my_data += (write_buf[tot_len+3]) << 24; 350 } 351 ret = lpddr2_nvm_do_op(map, LPDDR2_NVM_SW_OVERWRITE, 352 my_data, add, 0x00, NULL); 353 if (ret) 354 goto out; 355 356 add += pcm_data->bus_width; 357 tot_len += pcm_data->bus_width; 358 } else { /* do buffer program */ 359 current_len = min(target_len - tot_len, 360 (u_long) mtd->writesize); 361 ret = lpddr2_nvm_do_op(map, LPDDR2_NVM_BUF_OVERWRITE, 362 0x00, add, current_len, write_buf + tot_len); 363 if (ret) 364 goto out; 365 366 add += current_len; 367 tot_len += current_len; 368 } 369 } 370 371 out: 372 *retlen = tot_len; 373 ow_disable(map); 374 mutex_unlock(&lpdd2_nvm_mutex); 375 return ret; 376 } 377 378 /* 379 * lpddr2_nvm driver erase method 380 */ 381 static int lpddr2_nvm_erase(struct mtd_info *mtd, struct erase_info *instr) 382 { 383 return lpddr2_nvm_do_block_op(mtd, instr->addr, instr->len, 384 LPDDR2_NVM_ERASE); 385 } 386 387 /* 388 * lpddr2_nvm driver unlock method 389 */ 390 static int lpddr2_nvm_unlock(struct mtd_info *mtd, loff_t start_add, 391 uint64_t len) 392 { 393 return lpddr2_nvm_do_block_op(mtd, start_add, len, LPDDR2_NVM_UNLOCK); 394 } 395 396 /* 397 * lpddr2_nvm driver lock method 398 */ 399 static int lpddr2_nvm_lock(struct mtd_info *mtd, loff_t start_add, 400 uint64_t len) 401 { 402 return lpddr2_nvm_do_block_op(mtd, start_add, len, LPDDR2_NVM_LOCK); 403 } 404 405 /* 406 * lpddr2_nvm driver probe method 407 */ 408 static int lpddr2_nvm_probe(struct platform_device *pdev) 409 { 410 struct map_info *map; 411 struct mtd_info *mtd; 412 struct resource *add_range; 413 struct resource *control_regs; 414 struct pcm_int_data *pcm_data; 415 416 /* Allocate memory control_regs data structures */ 417 pcm_data = devm_kzalloc(&pdev->dev, sizeof(*pcm_data), GFP_KERNEL); 418 if (!pcm_data) 419 return -ENOMEM; 420 421 pcm_data->bus_width = BUS_WIDTH; 422 423 /* Allocate memory for map_info & mtd_info data structures */ 424 map = devm_kzalloc(&pdev->dev, sizeof(*map), GFP_KERNEL); 425 if (!map) 426 return -ENOMEM; 427 428 mtd = devm_kzalloc(&pdev->dev, sizeof(*mtd), GFP_KERNEL); 429 if (!mtd) 430 return -ENOMEM; 431 432 /* lpddr2_nvm address range */ 433 add_range = platform_get_resource(pdev, IORESOURCE_MEM, 0); 434 435 /* Populate map_info data structure */ 436 *map = (struct map_info) { 437 .virt = devm_ioremap_resource(&pdev->dev, add_range), 438 .name = pdev->dev.init_name, 439 .phys = add_range->start, 440 .size = resource_size(add_range), 441 .bankwidth = pcm_data->bus_width / 2, 442 .pfow_base = OW_BASE_ADDRESS, 443 .fldrv_priv = pcm_data, 444 }; 445 if (IS_ERR(map->virt)) 446 return PTR_ERR(map->virt); 447 448 simple_map_init(map); /* fill with default methods */ 449 450 control_regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); 451 pcm_data->ctl_regs = devm_ioremap_resource(&pdev->dev, control_regs); 452 if (IS_ERR(pcm_data->ctl_regs)) 453 return PTR_ERR(pcm_data->ctl_regs); 454 455 /* Populate mtd_info data structure */ 456 *mtd = (struct mtd_info) { 457 .dev = { .parent = &pdev->dev }, 458 .name = pdev->dev.init_name, 459 .type = MTD_RAM, 460 .priv = map, 461 .size = resource_size(add_range), 462 .erasesize = ERASE_BLOCKSIZE * pcm_data->bus_width, 463 .writesize = 1, 464 .writebufsize = WRITE_BUFFSIZE * pcm_data->bus_width, 465 .flags = (MTD_CAP_NVRAM | MTD_POWERUP_LOCK), 466 ._read = lpddr2_nvm_read, 467 ._write = lpddr2_nvm_write, 468 ._erase = lpddr2_nvm_erase, 469 ._unlock = lpddr2_nvm_unlock, 470 ._lock = lpddr2_nvm_lock, 471 }; 472 473 /* Verify the presence of the device looking for PFOW string */ 474 if (!lpddr2_nvm_pfow_present(map)) { 475 pr_err("device not recognized\n"); 476 return -EINVAL; 477 } 478 /* Parse partitions and register the MTD device */ 479 return mtd_device_parse_register(mtd, NULL, NULL, NULL, 0); 480 } 481 482 /* 483 * lpddr2_nvm driver remove method 484 */ 485 static int lpddr2_nvm_remove(struct platform_device *pdev) 486 { 487 return mtd_device_unregister(dev_get_drvdata(&pdev->dev)); 488 } 489 490 /* Initialize platform_driver data structure for lpddr2_nvm */ 491 static struct platform_driver lpddr2_nvm_drv = { 492 .driver = { 493 .name = "lpddr2_nvm", 494 }, 495 .probe = lpddr2_nvm_probe, 496 .remove = lpddr2_nvm_remove, 497 }; 498 499 module_platform_driver(lpddr2_nvm_drv); 500 MODULE_LICENSE("GPL"); 501 MODULE_AUTHOR("Vincenzo Aliberti <vincenzo.aliberti@gmail.com>"); 502 MODULE_DESCRIPTION("MTD driver for LPDDR2-NVM PCM memories"); 503