xref: /linux/drivers/mtd/lpddr/lpddr2_nvm.c (revision 954ea91fb68b771dba6d87cfa61b68e09cc2497f)
1  // SPDX-License-Identifier: GPL-2.0-or-later
2  /*
3   * LPDDR2-NVM MTD driver. This module provides read, write, erase, lock/unlock
4   * support for LPDDR2-NVM PCM memories
5   *
6   * Copyright © 2012 Micron Technology, Inc.
7   *
8   * Vincenzo Aliberti <vincenzo.aliberti@gmail.com>
9   * Domenico Manna <domenico.manna@gmail.com>
10   * Many thanks to Andrea Vigilante for initial enabling
11   */
12  
13  #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
14  
15  #include <linux/init.h>
16  #include <linux/io.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>
26  
27  /* Parameters */
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 */
32  
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 */
38  
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 */
49  
50  /* Datamask */
51  #define MR_CFGMASK			0x8000
52  #define SR_OK_DATAMASK			0x0080
53  
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
62  
63  /* LPDDR2-NVM Registers offset */
64  #define LPDDR2_MODE_REG_DATA		0x0040
65  #define LPDDR2_MODE_REG_CFG		0x0050
66  
67  /*
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)
73   */
74  struct pcm_int_data {
75  	void __iomem *ctl_regs;
76  	int bus_width;
77  };
78  
79  static DEFINE_MUTEX(lpdd2_nvm_mutex);
80  
81  /*
82   * Build a map_word starting from an u_long
83   */
84  static inline map_word build_map_word(u_long myword)
85  {
86  	map_word val = { {0} };
87  	val.x[0] = myword;
88  	return val;
89  }
90  
91  /*
92   * Build Mode Register Configuration DataMask based on device bus-width
93   */
94  static inline u_int build_mr_cfgmask(u_int bus_width)
95  {
96  	u_int val = MR_CFGMASK;
97  
98  	if (bus_width == 0x0004)		/* x32 device */
99  		val = val << 16;
100  
101  	return val;
102  }
103  
104  /*
105   * Build Status Register OK DataMask based on device bus-width
106   */
107  static inline u_int build_sr_ok_datamask(u_int bus_width)
108  {
109  	u_int val = SR_OK_DATAMASK;
110  
111  	if (bus_width == 0x0004)		/* x32 device */
112  		val = (val << 16)+val;
113  
114  	return val;
115  }
116  
117  /*
118   * Evaluates Overlay Window Control Registers address
119   */
120  static inline u_long ow_reg_add(struct map_info *map, u_long offset)
121  {
122  	u_long val = 0;
123  	struct pcm_int_data *pcm_data = map->fldrv_priv;
124  
125  	val = map->pfow_base + offset*pcm_data->bus_width;
126  
127  	return val;
128  }
129  
130  /*
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
135   */
136  static inline void ow_enable(struct map_info *map)
137  {
138  	struct pcm_int_data *pcm_data = map->fldrv_priv;
139  
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);
143  }
144  
145  /*
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
150   */
151  static inline void ow_disable(struct map_info *map)
152  {
153  	struct pcm_int_data *pcm_data = map->fldrv_priv;
154  
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);
158  }
159  
160  /*
161   * Execute lpddr2-nvm operations
162   */
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)
165  {
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);
173  
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 */
183  
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);
198  	}
199  
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 +
207  			prg_buff_ofs + i);
208  		}
209  	}
210  
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);
215  
216  	/* Status Register Check */
217  	do {
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;
224  		}
225  	} while ((status_reg & sr_ok_datamask) != sr_ok_datamask);
226  
227  	return (((status_reg & sr_ok_datamask) == sr_ok_datamask) ? 0 : -EIO);
228  }
229  
230  /*
231   * Execute lpddr2-nvm operations @ block level
232   */
233  static int lpddr2_nvm_do_block_op(struct mtd_info *mtd, loff_t start_add,
234  	uint64_t len, u_char block_op)
235  {
236  	struct map_info *map = mtd->priv;
237  	u_long add, end_add;
238  	int ret = 0;
239  
240  	mutex_lock(&lpdd2_nvm_mutex);
241  
242  	ow_enable(map);
243  
244  	add = start_add;
245  	end_add = add + len;
246  
247  	do {
248  		ret = lpddr2_nvm_do_op(map, block_op, 0x00, add, add, NULL);
249  		if (ret)
250  			goto out;
251  		add += mtd->erasesize;
252  	} while (add < end_add);
253  
254  out:
255  	ow_disable(map);
256  	mutex_unlock(&lpdd2_nvm_mutex);
257  	return ret;
258  }
259  
260  /*
261   * verify presence of PFOW string
262   */
263  static int lpddr2_nvm_pfow_present(struct map_info *map)
264  {
265  	map_word pfow_val[4];
266  	unsigned int found = 1;
267  
268  	mutex_lock(&lpdd2_nvm_mutex);
269  
270  	ow_enable(map);
271  
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));
277  
278  	/* Verify the string loaded vs expected */
279  	if (!map_word_equal(map, build_map_word('P'), pfow_val[0]))
280  		found = 0;
281  	if (!map_word_equal(map, build_map_word('F'), pfow_val[1]))
282  		found = 0;
283  	if (!map_word_equal(map, build_map_word('O'), pfow_val[2]))
284  		found = 0;
285  	if (!map_word_equal(map, build_map_word('W'), pfow_val[3]))
286  		found = 0;
287  
288  	ow_disable(map);
289  
290  	mutex_unlock(&lpdd2_nvm_mutex);
291  
292  	return found;
293  }
294  
295  /*
296   * lpddr2_nvm driver read method
297   */
298  static int lpddr2_nvm_read(struct mtd_info *mtd, loff_t start_add,
299  				size_t len, size_t *retlen, u_char *buf)
300  {
301  	struct map_info *map = mtd->priv;
302  
303  	mutex_lock(&lpdd2_nvm_mutex);
304  
305  	*retlen = len;
306  
307  	map_copy_from(map, buf, start_add, *retlen);
308  
309  	mutex_unlock(&lpdd2_nvm_mutex);
310  	return 0;
311  }
312  
313  /*
314   * lpddr2_nvm driver write method
315   */
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)
318  {
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;
323  	int ret = 0;
324  
325  	mutex_lock(&lpdd2_nvm_mutex);
326  
327  	ow_enable(map);
328  
329  	/* Set start value for the variables */
330  	add = start_add;
331  	target_len = len;
332  	tot_len = 0;
333  
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;
341  			}
342  			ret = lpddr2_nvm_do_op(map, LPDDR2_NVM_SW_OVERWRITE,
343  				my_data, add, 0x00, NULL);
344  			if (ret)
345  				goto out;
346  
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);
354  			if (ret)
355  				goto out;
356  
357  			add += current_len;
358  			tot_len += current_len;
359  		}
360  	}
361  
362  out:
363  	*retlen = tot_len;
364  	ow_disable(map);
365  	mutex_unlock(&lpdd2_nvm_mutex);
366  	return ret;
367  }
368  
369  /*
370   * lpddr2_nvm driver erase method
371   */
372  static int lpddr2_nvm_erase(struct mtd_info *mtd, struct erase_info *instr)
373  {
374  	return lpddr2_nvm_do_block_op(mtd, instr->addr, instr->len,
375  				      LPDDR2_NVM_ERASE);
376  }
377  
378  /*
379   * lpddr2_nvm driver unlock method
380   */
381  static int lpddr2_nvm_unlock(struct mtd_info *mtd, loff_t start_add,
382  	uint64_t len)
383  {
384  	return lpddr2_nvm_do_block_op(mtd, start_add, len, LPDDR2_NVM_UNLOCK);
385  }
386  
387  /*
388   * lpddr2_nvm driver lock method
389   */
390  static int lpddr2_nvm_lock(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_LOCK);
394  }
395  
396  static const struct mtd_info lpddr2_nvm_mtd_info = {
397  	.type		= MTD_RAM,
398  	.writesize	= 1,
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,
405  };
406  
407  /*
408   * lpddr2_nvm driver probe method
409   */
410  static int lpddr2_nvm_probe(struct platform_device *pdev)
411  {
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;
417  
418  	/* Allocate memory control_regs data structures */
419  	pcm_data = devm_kzalloc(&pdev->dev, sizeof(*pcm_data), GFP_KERNEL);
420  	if (!pcm_data)
421  		return -ENOMEM;
422  
423  	pcm_data->bus_width = BUS_WIDTH;
424  
425  	/* Allocate memory for map_info & mtd_info data structures */
426  	map = devm_kzalloc(&pdev->dev, sizeof(*map), GFP_KERNEL);
427  	if (!map)
428  		return -ENOMEM;
429  
430  	mtd = devm_kzalloc(&pdev->dev, sizeof(*mtd), GFP_KERNEL);
431  	if (!mtd)
432  		return -ENOMEM;
433  
434  	/* lpddr2_nvm address range */
435  	add_range = platform_get_resource(pdev, IORESOURCE_MEM, 0);
436  	if (!add_range)
437  		return -ENODEV;
438  
439  	/* Populate map_info data structure */
440  	*map = (struct map_info) {
441  		.virt		= devm_ioremap_resource(&pdev->dev, add_range),
442  		.name		= pdev->dev.init_name,
443  		.phys		= add_range->start,
444  		.size		= resource_size(add_range),
445  		.bankwidth	= pcm_data->bus_width / 2,
446  		.pfow_base	= OW_BASE_ADDRESS,
447  		.fldrv_priv	= pcm_data,
448  	};
449  
450  	if (IS_ERR(map->virt))
451  		return PTR_ERR(map->virt);
452  
453  	simple_map_init(map);	/* fill with default methods */
454  
455  	control_regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
456  	pcm_data->ctl_regs = devm_ioremap_resource(&pdev->dev, control_regs);
457  	if (IS_ERR(pcm_data->ctl_regs))
458  		return PTR_ERR(pcm_data->ctl_regs);
459  
460  	/* Populate mtd_info data structure */
461  	*mtd = lpddr2_nvm_mtd_info;
462  	mtd->dev.parent		= &pdev->dev;
463  	mtd->name		= pdev->dev.init_name;
464  	mtd->priv		= map;
465  	mtd->size		= resource_size(add_range);
466  	mtd->erasesize		= ERASE_BLOCKSIZE * pcm_data->bus_width;
467  	mtd->writebufsize	= WRITE_BUFFSIZE * pcm_data->bus_width;
468  
469  	/* Verify the presence of the device looking for PFOW string */
470  	if (!lpddr2_nvm_pfow_present(map)) {
471  		pr_err("device not recognized\n");
472  		return -EINVAL;
473  	}
474  	/* Parse partitions and register the MTD device */
475  	return mtd_device_register(mtd, NULL, 0);
476  }
477  
478  /*
479   * lpddr2_nvm driver remove method
480   */
481  static int lpddr2_nvm_remove(struct platform_device *pdev)
482  {
483  	WARN_ON(mtd_device_unregister(dev_get_drvdata(&pdev->dev)));
484  
485  	return 0;
486  }
487  
488  /* Initialize platform_driver data structure for lpddr2_nvm */
489  static struct platform_driver lpddr2_nvm_drv = {
490  	.driver		= {
491  		.name	= "lpddr2_nvm",
492  	},
493  	.probe		= lpddr2_nvm_probe,
494  	.remove		= lpddr2_nvm_remove,
495  };
496  
497  module_platform_driver(lpddr2_nvm_drv);
498  MODULE_LICENSE("GPL");
499  MODULE_AUTHOR("Vincenzo Aliberti <vincenzo.aliberti@gmail.com>");
500  MODULE_DESCRIPTION("MTD driver for LPDDR2-NVM PCM memories");
501