1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * LPDDR2-NVM MTD driver. This module provides read, write, erase, lock/unlock
4 * support for LPDDR2-NVM PCM memories
6 * Copyright © 2012 Micron Technology, Inc.
8 * Vincenzo Aliberti <vincenzo.aliberti@gmail.com>
9 * Domenico Manna <domenico.manna@gmail.com>
10 * Many thanks to Andrea Vigilante for initial enabling
13 #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
15 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/mtd/map.h>
20 #include <linux/mtd/mtd.h>
21 #include <linux/mtd/partitions.h>
22 #include <linux/slab.h>
23 #include <linux/platform_device.h>
24 #include <linux/ioport.h>
25 #include <linux/err.h>
28 #define ERASE_BLOCKSIZE (0x00020000/2) /* in Word */
29 #define WRITE_BUFFSIZE (0x00000400/2) /* in Word */
30 #define OW_BASE_ADDRESS 0x00000000 /* OW offset */
31 #define BUS_WIDTH 0x00000020 /* x32 devices */
33 /* PFOW symbols address offset */
34 #define PFOW_QUERY_STRING_P (0x0000/2) /* in Word */
35 #define PFOW_QUERY_STRING_F (0x0002/2) /* in Word */
36 #define PFOW_QUERY_STRING_O (0x0004/2) /* in Word */
37 #define PFOW_QUERY_STRING_W (0x0006/2) /* in Word */
39 /* OW registers address */
40 #define CMD_CODE_OFS (0x0080/2) /* in Word */
41 #define CMD_DATA_OFS (0x0084/2) /* in Word */
42 #define CMD_ADD_L_OFS (0x0088/2) /* in Word */
43 #define CMD_ADD_H_OFS (0x008A/2) /* in Word */
44 #define MPR_L_OFS (0x0090/2) /* in Word */
45 #define MPR_H_OFS (0x0092/2) /* in Word */
46 #define CMD_EXEC_OFS (0x00C0/2) /* in Word */
47 #define STATUS_REG_OFS (0x00CC/2) /* in Word */
48 #define PRG_BUFFER_OFS (0x0010/2) /* in Word */
51 #define MR_CFGMASK 0x8000
52 #define SR_OK_DATAMASK 0x0080
54 /* LPDDR2-NVM Commands */
55 #define LPDDR2_NVM_LOCK 0x0061
56 #define LPDDR2_NVM_UNLOCK 0x0062
57 #define LPDDR2_NVM_SW_PROGRAM 0x0041
58 #define LPDDR2_NVM_SW_OVERWRITE 0x0042
59 #define LPDDR2_NVM_BUF_PROGRAM 0x00E9
60 #define LPDDR2_NVM_BUF_OVERWRITE 0x00EA
61 #define LPDDR2_NVM_ERASE 0x0020
63 /* LPDDR2-NVM Registers offset */
64 #define LPDDR2_MODE_REG_DATA 0x0040
65 #define LPDDR2_MODE_REG_CFG 0x0050
68 * Internal Type Definitions
69 * pcm_int_data contains memory controller details:
70 * @reg_data : LPDDR2_MODE_REG_DATA register address after remapping
71 * @reg_cfg : LPDDR2_MODE_REG_CFG register address after remapping
72 * &bus_width: memory bus-width (eg: x16 2 Bytes, x32 4 Bytes)
75 void __iomem
*ctl_regs
;
79 static DEFINE_MUTEX(lpdd2_nvm_mutex
);
82 * Build a map_word starting from an u_long
84 static inline map_word
build_map_word(u_long myword
)
86 map_word val
= { {0} };
92 * Build Mode Register Configuration DataMask based on device bus-width
94 static inline u_int
build_mr_cfgmask(u_int bus_width
)
96 u_int val
= MR_CFGMASK
;
98 if (bus_width
== 0x0004) /* x32 device */
105 * Build Status Register OK DataMask based on device bus-width
107 static inline u_int
build_sr_ok_datamask(u_int bus_width
)
109 u_int val
= SR_OK_DATAMASK
;
111 if (bus_width
== 0x0004) /* x32 device */
112 val
= (val
<< 16)+val
;
118 * Evaluates Overlay Window Control Registers address
120 static inline u_long
ow_reg_add(struct map_info
*map
, u_long offset
)
123 struct pcm_int_data
*pcm_data
= map
->fldrv_priv
;
125 val
= map
->pfow_base
+ offset
*pcm_data
->bus_width
;
131 * Enable lpddr2-nvm Overlay Window
132 * Overlay Window is a memory mapped area containing all LPDDR2-NVM registers
133 * used by device commands as well as uservisible resources like Device Status
134 * Register, Device ID, etc
136 static inline void ow_enable(struct map_info
*map
)
138 struct pcm_int_data
*pcm_data
= map
->fldrv_priv
;
140 writel_relaxed(build_mr_cfgmask(pcm_data
->bus_width
) | 0x18,
141 pcm_data
->ctl_regs
+ LPDDR2_MODE_REG_CFG
);
142 writel_relaxed(0x01, pcm_data
->ctl_regs
+ LPDDR2_MODE_REG_DATA
);
146 * Disable lpddr2-nvm Overlay Window
147 * Overlay Window is a memory mapped area containing all LPDDR2-NVM registers
148 * used by device commands as well as uservisible resources like Device Status
149 * Register, Device ID, etc
151 static inline void ow_disable(struct map_info
*map
)
153 struct pcm_int_data
*pcm_data
= map
->fldrv_priv
;
155 writel_relaxed(build_mr_cfgmask(pcm_data
->bus_width
) | 0x18,
156 pcm_data
->ctl_regs
+ LPDDR2_MODE_REG_CFG
);
157 writel_relaxed(0x02, pcm_data
->ctl_regs
+ LPDDR2_MODE_REG_DATA
);
161 * Execute lpddr2-nvm operations
163 static int lpddr2_nvm_do_op(struct map_info
*map
, u_long cmd_code
,
164 u_long cmd_data
, u_long cmd_add
, u_long cmd_mpr
, u_char
*buf
)
166 map_word add_l
= { {0} }, add_h
= { {0} }, mpr_l
= { {0} },
167 mpr_h
= { {0} }, data_l
= { {0} }, cmd
= { {0} },
168 exec_cmd
= { {0} }, sr
;
169 map_word data_h
= { {0} }; /* only for 2x x16 devices stacked */
170 u_long i
, status_reg
, prg_buff_ofs
;
171 struct pcm_int_data
*pcm_data
= map
->fldrv_priv
;
172 u_int sr_ok_datamask
= build_sr_ok_datamask(pcm_data
->bus_width
);
174 /* Builds low and high words for OW Control Registers */
175 add_l
.x
[0] = cmd_add
& 0x0000FFFF;
176 add_h
.x
[0] = (cmd_add
>> 16) & 0x0000FFFF;
177 mpr_l
.x
[0] = cmd_mpr
& 0x0000FFFF;
178 mpr_h
.x
[0] = (cmd_mpr
>> 16) & 0x0000FFFF;
179 cmd
.x
[0] = cmd_code
& 0x0000FFFF;
180 exec_cmd
.x
[0] = 0x0001;
181 data_l
.x
[0] = cmd_data
& 0x0000FFFF;
182 data_h
.x
[0] = (cmd_data
>> 16) & 0x0000FFFF; /* only for 2x x16 */
184 /* Set Overlay Window Control Registers */
185 map_write(map
, cmd
, ow_reg_add(map
, CMD_CODE_OFS
));
186 map_write(map
, data_l
, ow_reg_add(map
, CMD_DATA_OFS
));
187 map_write(map
, add_l
, ow_reg_add(map
, CMD_ADD_L_OFS
));
188 map_write(map
, add_h
, ow_reg_add(map
, CMD_ADD_H_OFS
));
189 map_write(map
, mpr_l
, ow_reg_add(map
, MPR_L_OFS
));
190 map_write(map
, mpr_h
, ow_reg_add(map
, MPR_H_OFS
));
191 if (pcm_data
->bus_width
== 0x0004) { /* 2x16 devices stacked */
192 map_write(map
, cmd
, ow_reg_add(map
, CMD_CODE_OFS
) + 2);
193 map_write(map
, data_h
, ow_reg_add(map
, CMD_DATA_OFS
) + 2);
194 map_write(map
, add_l
, ow_reg_add(map
, CMD_ADD_L_OFS
) + 2);
195 map_write(map
, add_h
, ow_reg_add(map
, CMD_ADD_H_OFS
) + 2);
196 map_write(map
, mpr_l
, ow_reg_add(map
, MPR_L_OFS
) + 2);
197 map_write(map
, mpr_h
, ow_reg_add(map
, MPR_H_OFS
) + 2);
200 /* Fill Program Buffer */
201 if ((cmd_code
== LPDDR2_NVM_BUF_PROGRAM
) ||
202 (cmd_code
== LPDDR2_NVM_BUF_OVERWRITE
)) {
203 prg_buff_ofs
= (map_read(map
,
204 ow_reg_add(map
, PRG_BUFFER_OFS
))).x
[0];
205 for (i
= 0; i
< cmd_mpr
; i
++) {
206 map_write(map
, build_map_word(buf
[i
]), map
->pfow_base
+
211 /* Command Execute */
212 map_write(map
, exec_cmd
, ow_reg_add(map
, CMD_EXEC_OFS
));
213 if (pcm_data
->bus_width
== 0x0004) /* 2x16 devices stacked */
214 map_write(map
, exec_cmd
, ow_reg_add(map
, CMD_EXEC_OFS
) + 2);
216 /* Status Register Check */
218 sr
= map_read(map
, ow_reg_add(map
, STATUS_REG_OFS
));
219 status_reg
= sr
.x
[0];
220 if (pcm_data
->bus_width
== 0x0004) {/* 2x16 devices stacked */
221 sr
= map_read(map
, ow_reg_add(map
,
222 STATUS_REG_OFS
) + 2);
223 status_reg
+= sr
.x
[0] << 16;
225 } while ((status_reg
& sr_ok_datamask
) != sr_ok_datamask
);
227 return (((status_reg
& sr_ok_datamask
) == sr_ok_datamask
) ? 0 : -EIO
);
231 * Execute lpddr2-nvm operations @ block level
233 static int lpddr2_nvm_do_block_op(struct mtd_info
*mtd
, loff_t start_add
,
234 uint64_t len
, u_char block_op
)
236 struct map_info
*map
= mtd
->priv
;
240 mutex_lock(&lpdd2_nvm_mutex
);
248 ret
= lpddr2_nvm_do_op(map
, block_op
, 0x00, add
, add
, NULL
);
251 add
+= mtd
->erasesize
;
252 } while (add
< end_add
);
256 mutex_unlock(&lpdd2_nvm_mutex
);
261 * verify presence of PFOW string
263 static int lpddr2_nvm_pfow_present(struct map_info
*map
)
265 map_word pfow_val
[4];
266 unsigned int found
= 1;
268 mutex_lock(&lpdd2_nvm_mutex
);
272 /* Load string from array */
273 pfow_val
[0] = map_read(map
, ow_reg_add(map
, PFOW_QUERY_STRING_P
));
274 pfow_val
[1] = map_read(map
, ow_reg_add(map
, PFOW_QUERY_STRING_F
));
275 pfow_val
[2] = map_read(map
, ow_reg_add(map
, PFOW_QUERY_STRING_O
));
276 pfow_val
[3] = map_read(map
, ow_reg_add(map
, PFOW_QUERY_STRING_W
));
278 /* Verify the string loaded vs expected */
279 if (!map_word_equal(map
, build_map_word('P'), pfow_val
[0]))
281 if (!map_word_equal(map
, build_map_word('F'), pfow_val
[1]))
283 if (!map_word_equal(map
, build_map_word('O'), pfow_val
[2]))
285 if (!map_word_equal(map
, build_map_word('W'), pfow_val
[3]))
290 mutex_unlock(&lpdd2_nvm_mutex
);
296 * lpddr2_nvm driver read method
298 static int lpddr2_nvm_read(struct mtd_info
*mtd
, loff_t start_add
,
299 size_t len
, size_t *retlen
, u_char
*buf
)
301 struct map_info
*map
= mtd
->priv
;
303 mutex_lock(&lpdd2_nvm_mutex
);
307 map_copy_from(map
, buf
, start_add
, *retlen
);
309 mutex_unlock(&lpdd2_nvm_mutex
);
314 * lpddr2_nvm driver write method
316 static int lpddr2_nvm_write(struct mtd_info
*mtd
, loff_t start_add
,
317 size_t len
, size_t *retlen
, const u_char
*buf
)
319 struct map_info
*map
= mtd
->priv
;
320 struct pcm_int_data
*pcm_data
= map
->fldrv_priv
;
321 u_long add
, current_len
, tot_len
, target_len
, my_data
;
322 u_char
*write_buf
= (u_char
*)buf
;
325 mutex_lock(&lpdd2_nvm_mutex
);
329 /* Set start value for the variables */
334 while (tot_len
< target_len
) {
335 if (!(IS_ALIGNED(add
, mtd
->writesize
))) { /* do sw program */
336 my_data
= write_buf
[tot_len
];
337 my_data
+= (write_buf
[tot_len
+1]) << 8;
338 if (pcm_data
->bus_width
== 0x0004) {/* 2x16 devices */
339 my_data
+= (write_buf
[tot_len
+2]) << 16;
340 my_data
+= (write_buf
[tot_len
+3]) << 24;
342 ret
= lpddr2_nvm_do_op(map
, LPDDR2_NVM_SW_OVERWRITE
,
343 my_data
, add
, 0x00, NULL
);
347 add
+= pcm_data
->bus_width
;
348 tot_len
+= pcm_data
->bus_width
;
349 } else { /* do buffer program */
350 current_len
= min(target_len
- tot_len
,
351 (u_long
) mtd
->writesize
);
352 ret
= lpddr2_nvm_do_op(map
, LPDDR2_NVM_BUF_OVERWRITE
,
353 0x00, add
, current_len
, write_buf
+ tot_len
);
358 tot_len
+= current_len
;
365 mutex_unlock(&lpdd2_nvm_mutex
);
370 * lpddr2_nvm driver erase method
372 static int lpddr2_nvm_erase(struct mtd_info
*mtd
, struct erase_info
*instr
)
374 return lpddr2_nvm_do_block_op(mtd
, instr
->addr
, instr
->len
,
379 * lpddr2_nvm driver unlock method
381 static int lpddr2_nvm_unlock(struct mtd_info
*mtd
, loff_t start_add
,
384 return lpddr2_nvm_do_block_op(mtd
, start_add
, len
, LPDDR2_NVM_UNLOCK
);
388 * lpddr2_nvm driver lock method
390 static int lpddr2_nvm_lock(struct mtd_info
*mtd
, loff_t start_add
,
393 return lpddr2_nvm_do_block_op(mtd
, start_add
, len
, LPDDR2_NVM_LOCK
);
396 static const struct mtd_info lpddr2_nvm_mtd_info
= {
399 .flags
= (MTD_CAP_NVRAM
| MTD_POWERUP_LOCK
),
400 ._read
= lpddr2_nvm_read
,
401 ._write
= lpddr2_nvm_write
,
402 ._erase
= lpddr2_nvm_erase
,
403 ._unlock
= lpddr2_nvm_unlock
,
404 ._lock
= lpddr2_nvm_lock
,
408 * lpddr2_nvm driver probe method
410 static int lpddr2_nvm_probe(struct platform_device
*pdev
)
412 struct map_info
*map
;
413 struct mtd_info
*mtd
;
414 struct resource
*add_range
;
415 struct resource
*control_regs
;
416 struct pcm_int_data
*pcm_data
;
418 /* Allocate memory control_regs data structures */
419 pcm_data
= devm_kzalloc(&pdev
->dev
, sizeof(*pcm_data
), GFP_KERNEL
);
423 pcm_data
->bus_width
= BUS_WIDTH
;
425 /* Allocate memory for map_info & mtd_info data structures */
426 map
= devm_kzalloc(&pdev
->dev
, sizeof(*map
), GFP_KERNEL
);
430 mtd
= devm_kzalloc(&pdev
->dev
, sizeof(*mtd
), GFP_KERNEL
);
434 /* lpddr2_nvm address range */
435 add_range
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
437 /* Populate map_info data structure */
438 *map
= (struct map_info
) {
439 .virt
= devm_ioremap_resource(&pdev
->dev
, add_range
),
440 .name
= pdev
->dev
.init_name
,
441 .phys
= add_range
->start
,
442 .size
= resource_size(add_range
),
443 .bankwidth
= pcm_data
->bus_width
/ 2,
444 .pfow_base
= OW_BASE_ADDRESS
,
445 .fldrv_priv
= pcm_data
,
448 if (IS_ERR(map
->virt
))
449 return PTR_ERR(map
->virt
);
451 simple_map_init(map
); /* fill with default methods */
453 control_regs
= platform_get_resource(pdev
, IORESOURCE_MEM
, 1);
454 pcm_data
->ctl_regs
= devm_ioremap_resource(&pdev
->dev
, control_regs
);
455 if (IS_ERR(pcm_data
->ctl_regs
))
456 return PTR_ERR(pcm_data
->ctl_regs
);
458 /* Populate mtd_info data structure */
459 *mtd
= lpddr2_nvm_mtd_info
;
460 mtd
->dev
.parent
= &pdev
->dev
;
461 mtd
->name
= pdev
->dev
.init_name
;
463 mtd
->size
= resource_size(add_range
);
464 mtd
->erasesize
= ERASE_BLOCKSIZE
* pcm_data
->bus_width
;
465 mtd
->writebufsize
= WRITE_BUFFSIZE
* pcm_data
->bus_width
;
467 /* Verify the presence of the device looking for PFOW string */
468 if (!lpddr2_nvm_pfow_present(map
)) {
469 pr_err("device not recognized\n");
472 /* Parse partitions and register the MTD device */
473 return mtd_device_register(mtd
, NULL
, 0);
477 * lpddr2_nvm driver remove method
479 static int lpddr2_nvm_remove(struct platform_device
*pdev
)
481 return mtd_device_unregister(dev_get_drvdata(&pdev
->dev
));
484 /* Initialize platform_driver data structure for lpddr2_nvm */
485 static struct platform_driver lpddr2_nvm_drv
= {
487 .name
= "lpddr2_nvm",
489 .probe
= lpddr2_nvm_probe
,
490 .remove
= lpddr2_nvm_remove
,
493 module_platform_driver(lpddr2_nvm_drv
);
494 MODULE_LICENSE("GPL");
495 MODULE_AUTHOR("Vincenzo Aliberti <vincenzo.aliberti@gmail.com>");
496 MODULE_DESCRIPTION("MTD driver for LPDDR2-NVM PCM memories");