Blame view

drivers/memory/mvebu-devbus.c 9.24 KB
2b72c9e36   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
3edad321b   Ezequiel Garcia   drivers: memory: ...
2
3
4
5
  /*
   * Marvell EBU SoC Device Bus Controller
   * (memory controller for NOR/NAND/SRAM/FPGA devices)
   *
c4ec7430c   Thomas Petazzoni   memory: mvebu-dev...
6
   * Copyright (C) 2013-2014 Marvell
3edad321b   Ezequiel Garcia   drivers: memory: ...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/err.h>
  #include <linux/io.h>
  #include <linux/clk.h>
  #include <linux/mbus.h>
  #include <linux/of_platform.h>
  #include <linux/of_address.h>
  #include <linux/platform_device.h>
  
  /* Register definitions */
8a33692ee   Thomas Petazzoni   memory: mvebu-dev...
21
22
23
24
25
26
  #define ARMADA_DEV_WIDTH_SHIFT		30
  #define ARMADA_BADR_SKEW_SHIFT		28
  #define ARMADA_RD_HOLD_SHIFT		23
  #define ARMADA_ACC_NEXT_SHIFT		17
  #define ARMADA_RD_SETUP_SHIFT		12
  #define ARMADA_ACC_FIRST_SHIFT		6
3edad321b   Ezequiel Garcia   drivers: memory: ...
27

8a33692ee   Thomas Petazzoni   memory: mvebu-dev...
28
29
30
  #define ARMADA_SYNC_ENABLE_SHIFT	24
  #define ARMADA_WR_HIGH_SHIFT		16
  #define ARMADA_WR_LOW_SHIFT		8
3edad321b   Ezequiel Garcia   drivers: memory: ...
31

71e2e5d39   Thomas Petazzoni   memory: mvebu-dev...
32
33
  #define ARMADA_READ_PARAM_OFFSET	0x0
  #define ARMADA_WRITE_PARAM_OFFSET	0x4
3edad321b   Ezequiel Garcia   drivers: memory: ...
34

c4ec7430c   Thomas Petazzoni   memory: mvebu-dev...
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  #define ORION_RESERVED			(0x2 << 30)
  #define ORION_BADR_SKEW_SHIFT		28
  #define ORION_WR_HIGH_EXT_BIT		BIT(27)
  #define ORION_WR_HIGH_EXT_MASK		0x8
  #define ORION_WR_LOW_EXT_BIT		BIT(26)
  #define ORION_WR_LOW_EXT_MASK		0x8
  #define ORION_ALE_WR_EXT_BIT		BIT(25)
  #define ORION_ALE_WR_EXT_MASK		0x8
  #define ORION_ACC_NEXT_EXT_BIT		BIT(24)
  #define ORION_ACC_NEXT_EXT_MASK		0x10
  #define ORION_ACC_FIRST_EXT_BIT		BIT(23)
  #define ORION_ACC_FIRST_EXT_MASK	0x10
  #define ORION_TURN_OFF_EXT_BIT		BIT(22)
  #define ORION_TURN_OFF_EXT_MASK		0x8
  #define ORION_DEV_WIDTH_SHIFT		20
  #define ORION_WR_HIGH_SHIFT		17
  #define ORION_WR_HIGH_MASK		0x7
  #define ORION_WR_LOW_SHIFT		14
  #define ORION_WR_LOW_MASK		0x7
  #define ORION_ALE_WR_SHIFT		11
  #define ORION_ALE_WR_MASK		0x7
  #define ORION_ACC_NEXT_SHIFT		7
  #define ORION_ACC_NEXT_MASK		0xF
  #define ORION_ACC_FIRST_SHIFT		3
  #define ORION_ACC_FIRST_MASK		0xF
  #define ORION_TURN_OFF_SHIFT		0
  #define ORION_TURN_OFF_MASK		0x7
3edad321b   Ezequiel Garcia   drivers: memory: ...
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  struct devbus_read_params {
  	u32 bus_width;
  	u32 badr_skew;
  	u32 turn_off;
  	u32 acc_first;
  	u32 acc_next;
  	u32 rd_setup;
  	u32 rd_hold;
  };
  
  struct devbus_write_params {
  	u32 sync_enable;
  	u32 wr_high;
  	u32 wr_low;
  	u32 ale_wr;
  };
  
  struct devbus {
  	struct device *dev;
  	void __iomem *base;
  	unsigned long tick_ps;
  };
  
  static int get_timing_param_ps(struct devbus *devbus,
  			       struct device_node *node,
  			       const char *name,
  			       u32 *ticks)
  {
  	u32 time_ps;
  	int err;
  
  	err = of_property_read_u32(node, name, &time_ps);
  	if (err < 0) {
db749d17c   Rob Herring   memory: Convert t...
95
96
97
  		dev_err(devbus->dev, "%pOF has no '%s' property
  ",
  			node, name);
3edad321b   Ezequiel Garcia   drivers: memory: ...
98
99
100
101
102
103
104
105
106
107
  		return err;
  	}
  
  	*ticks = (time_ps + devbus->tick_ps - 1) / devbus->tick_ps;
  
  	dev_dbg(devbus->dev, "%s: %u ps -> 0x%x
  ",
  		name, time_ps, *ticks);
  	return 0;
  }
30bd30b60   Thomas Petazzoni   memory: mvebu-dev...
108
109
110
111
  static int devbus_get_timing_params(struct devbus *devbus,
  				    struct device_node *node,
  				    struct devbus_read_params *r,
  				    struct devbus_write_params *w)
3edad321b   Ezequiel Garcia   drivers: memory: ...
112
  {
3edad321b   Ezequiel Garcia   drivers: memory: ...
113
  	int err;
30bd30b60   Thomas Petazzoni   memory: mvebu-dev...
114
  	err = of_property_read_u32(node, "devbus,bus-width", &r->bus_width);
3edad321b   Ezequiel Garcia   drivers: memory: ...
115
116
  	if (err < 0) {
  		dev_err(devbus->dev,
db749d17c   Rob Herring   memory: Convert t...
117
118
119
  			"%pOF has no 'devbus,bus-width' property
  ",
  			node);
3edad321b   Ezequiel Garcia   drivers: memory: ...
120
121
  		return err;
  	}
ce965c3d2   Thomas Petazzoni   memory: mvebu-dev...
122
123
124
125
126
  
  	/*
  	 * The bus width is encoded into the register as 0 for 8 bits,
  	 * and 1 for 16 bits, so we do the necessary conversion here.
  	 */
bf8fba459   Krzysztof Kozlowski   memory: mvebu-dev...
127
  	if (r->bus_width == 8) {
30bd30b60   Thomas Petazzoni   memory: mvebu-dev...
128
  		r->bus_width = 0;
bf8fba459   Krzysztof Kozlowski   memory: mvebu-dev...
129
  	} else if (r->bus_width == 16) {
30bd30b60   Thomas Petazzoni   memory: mvebu-dev...
130
  		r->bus_width = 1;
bf8fba459   Krzysztof Kozlowski   memory: mvebu-dev...
131
  	} else {
30bd30b60   Thomas Petazzoni   memory: mvebu-dev...
132
133
  		dev_err(devbus->dev, "invalid bus width %d
  ", r->bus_width);
ce965c3d2   Thomas Petazzoni   memory: mvebu-dev...
134
135
  		return -EINVAL;
  	}
3edad321b   Ezequiel Garcia   drivers: memory: ...
136
137
  
  	err = get_timing_param_ps(devbus, node, "devbus,badr-skew-ps",
0abbec7ee   Krzysztof Kozlowski   memory: mvebu-dev...
138
  				  &r->badr_skew);
3edad321b   Ezequiel Garcia   drivers: memory: ...
139
140
141
142
  	if (err < 0)
  		return err;
  
  	err = get_timing_param_ps(devbus, node, "devbus,turn-off-ps",
0abbec7ee   Krzysztof Kozlowski   memory: mvebu-dev...
143
  				  &r->turn_off);
3edad321b   Ezequiel Garcia   drivers: memory: ...
144
145
146
147
  	if (err < 0)
  		return err;
  
  	err = get_timing_param_ps(devbus, node, "devbus,acc-first-ps",
0abbec7ee   Krzysztof Kozlowski   memory: mvebu-dev...
148
  				  &r->acc_first);
3edad321b   Ezequiel Garcia   drivers: memory: ...
149
150
151
152
  	if (err < 0)
  		return err;
  
  	err = get_timing_param_ps(devbus, node, "devbus,acc-next-ps",
0abbec7ee   Krzysztof Kozlowski   memory: mvebu-dev...
153
  				  &r->acc_next);
3edad321b   Ezequiel Garcia   drivers: memory: ...
154
155
  	if (err < 0)
  		return err;
c4ec7430c   Thomas Petazzoni   memory: mvebu-dev...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  	if (of_device_is_compatible(devbus->dev->of_node, "marvell,mvebu-devbus")) {
  		err = get_timing_param_ps(devbus, node, "devbus,rd-setup-ps",
  					  &r->rd_setup);
  		if (err < 0)
  			return err;
  
  		err = get_timing_param_ps(devbus, node, "devbus,rd-hold-ps",
  					  &r->rd_hold);
  		if (err < 0)
  			return err;
  
  		err = of_property_read_u32(node, "devbus,sync-enable",
  					   &w->sync_enable);
  		if (err < 0) {
  			dev_err(devbus->dev,
db749d17c   Rob Herring   memory: Convert t...
171
172
173
  				"%pOF has no 'devbus,sync-enable' property
  ",
  				node);
c4ec7430c   Thomas Petazzoni   memory: mvebu-dev...
174
175
  			return err;
  		}
3edad321b   Ezequiel Garcia   drivers: memory: ...
176
177
178
  	}
  
  	err = get_timing_param_ps(devbus, node, "devbus,ale-wr-ps",
0abbec7ee   Krzysztof Kozlowski   memory: mvebu-dev...
179
  				  &w->ale_wr);
3edad321b   Ezequiel Garcia   drivers: memory: ...
180
181
182
183
  	if (err < 0)
  		return err;
  
  	err = get_timing_param_ps(devbus, node, "devbus,wr-low-ps",
0abbec7ee   Krzysztof Kozlowski   memory: mvebu-dev...
184
  				  &w->wr_low);
3edad321b   Ezequiel Garcia   drivers: memory: ...
185
186
187
188
  	if (err < 0)
  		return err;
  
  	err = get_timing_param_ps(devbus, node, "devbus,wr-high-ps",
0abbec7ee   Krzysztof Kozlowski   memory: mvebu-dev...
189
  				  &w->wr_high);
3edad321b   Ezequiel Garcia   drivers: memory: ...
190
191
  	if (err < 0)
  		return err;
30bd30b60   Thomas Petazzoni   memory: mvebu-dev...
192
193
  	return 0;
  }
c4ec7430c   Thomas Petazzoni   memory: mvebu-dev...
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
  static void devbus_orion_set_timing_params(struct devbus *devbus,
  					  struct device_node *node,
  					  struct devbus_read_params *r,
  					  struct devbus_write_params *w)
  {
  	u32 value;
  
  	/*
  	 * The hardware designers found it would be a good idea to
  	 * split most of the values in the register into two fields:
  	 * one containing all the low-order bits, and another one
  	 * containing just the high-order bit. For all of those
  	 * fields, we have to split the value into these two parts.
  	 */
  	value =	(r->turn_off   & ORION_TURN_OFF_MASK)  << ORION_TURN_OFF_SHIFT  |
  		(r->acc_first  & ORION_ACC_FIRST_MASK) << ORION_ACC_FIRST_SHIFT |
  		(r->acc_next   & ORION_ACC_NEXT_MASK)  << ORION_ACC_NEXT_SHIFT  |
  		(w->ale_wr     & ORION_ALE_WR_MASK)    << ORION_ALE_WR_SHIFT    |
  		(w->wr_low     & ORION_WR_LOW_MASK)    << ORION_WR_LOW_SHIFT    |
  		(w->wr_high    & ORION_WR_HIGH_MASK)   << ORION_WR_HIGH_SHIFT   |
  		r->bus_width                           << ORION_DEV_WIDTH_SHIFT |
  		((r->turn_off  & ORION_TURN_OFF_EXT_MASK)  ? ORION_TURN_OFF_EXT_BIT  : 0) |
  		((r->acc_first & ORION_ACC_FIRST_EXT_MASK) ? ORION_ACC_FIRST_EXT_BIT : 0) |
  		((r->acc_next  & ORION_ACC_NEXT_EXT_MASK)  ? ORION_ACC_NEXT_EXT_BIT  : 0) |
  		((w->ale_wr    & ORION_ALE_WR_EXT_MASK)    ? ORION_ALE_WR_EXT_BIT    : 0) |
  		((w->wr_low    & ORION_WR_LOW_EXT_MASK)    ? ORION_WR_LOW_EXT_BIT    : 0) |
  		((w->wr_high   & ORION_WR_HIGH_EXT_MASK)   ? ORION_WR_HIGH_EXT_BIT   : 0) |
  		(r->badr_skew << ORION_BADR_SKEW_SHIFT) |
  		ORION_RESERVED;
  
  	writel(value, devbus->base);
  }
30bd30b60   Thomas Petazzoni   memory: mvebu-dev...
226
227
228
229
230
231
  static void devbus_armada_set_timing_params(struct devbus *devbus,
  					   struct device_node *node,
  					   struct devbus_read_params *r,
  					   struct devbus_write_params *w)
  {
  	u32 value;
3edad321b   Ezequiel Garcia   drivers: memory: ...
232
  	/* Set read timings */
30bd30b60   Thomas Petazzoni   memory: mvebu-dev...
233
234
235
236
237
238
239
  	value = r->bus_width << ARMADA_DEV_WIDTH_SHIFT |
  		r->badr_skew << ARMADA_BADR_SKEW_SHIFT |
  		r->rd_hold   << ARMADA_RD_HOLD_SHIFT   |
  		r->acc_next  << ARMADA_ACC_NEXT_SHIFT  |
  		r->rd_setup  << ARMADA_RD_SETUP_SHIFT  |
  		r->acc_first << ARMADA_ACC_FIRST_SHIFT |
  		r->turn_off;
3edad321b   Ezequiel Garcia   drivers: memory: ...
240
241
242
  
  	dev_dbg(devbus->dev, "read parameters register 0x%p = 0x%x
  ",
71e2e5d39   Thomas Petazzoni   memory: mvebu-dev...
243
  		devbus->base + ARMADA_READ_PARAM_OFFSET,
3edad321b   Ezequiel Garcia   drivers: memory: ...
244
  		value);
71e2e5d39   Thomas Petazzoni   memory: mvebu-dev...
245
  	writel(value, devbus->base + ARMADA_READ_PARAM_OFFSET);
3edad321b   Ezequiel Garcia   drivers: memory: ...
246
247
  
  	/* Set write timings */
30bd30b60   Thomas Petazzoni   memory: mvebu-dev...
248
249
250
251
  	value = w->sync_enable  << ARMADA_SYNC_ENABLE_SHIFT |
  		w->wr_low       << ARMADA_WR_LOW_SHIFT      |
  		w->wr_high      << ARMADA_WR_HIGH_SHIFT     |
  		w->ale_wr;
3edad321b   Ezequiel Garcia   drivers: memory: ...
252
253
254
  
  	dev_dbg(devbus->dev, "write parameters register: 0x%p = 0x%x
  ",
71e2e5d39   Thomas Petazzoni   memory: mvebu-dev...
255
  		devbus->base + ARMADA_WRITE_PARAM_OFFSET,
3edad321b   Ezequiel Garcia   drivers: memory: ...
256
  		value);
71e2e5d39   Thomas Petazzoni   memory: mvebu-dev...
257
  	writel(value, devbus->base + ARMADA_WRITE_PARAM_OFFSET);
3edad321b   Ezequiel Garcia   drivers: memory: ...
258
259
260
261
262
263
  }
  
  static int mvebu_devbus_probe(struct platform_device *pdev)
  {
  	struct device *dev = &pdev->dev;
  	struct device_node *node = pdev->dev.of_node;
30bd30b60   Thomas Petazzoni   memory: mvebu-dev...
264
265
  	struct devbus_read_params r;
  	struct devbus_write_params w;
3edad321b   Ezequiel Garcia   drivers: memory: ...
266
  	struct devbus *devbus;
3edad321b   Ezequiel Garcia   drivers: memory: ...
267
268
  	struct clk *clk;
  	unsigned long rate;
9b6e4c0a5   Ezequiel Garcia   memory: mvebu-dev...
269
  	int err;
3edad321b   Ezequiel Garcia   drivers: memory: ...
270
271
272
273
274
275
  
  	devbus = devm_kzalloc(&pdev->dev, sizeof(struct devbus), GFP_KERNEL);
  	if (!devbus)
  		return -ENOMEM;
  
  	devbus->dev = dev;
f3ba1c86c   Yangtao Li   memory: mvebu-dev...
276
  	devbus->base = devm_platform_ioremap_resource(pdev, 0);
3edad321b   Ezequiel Garcia   drivers: memory: ...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  	if (IS_ERR(devbus->base))
  		return PTR_ERR(devbus->base);
  
  	clk = devm_clk_get(&pdev->dev, NULL);
  	if (IS_ERR(clk))
  		return PTR_ERR(clk);
  	clk_prepare_enable(clk);
  
  	/*
  	 * Obtain clock period in picoseconds,
  	 * we need this in order to convert timing
  	 * parameters from cycles to picoseconds.
  	 */
  	rate = clk_get_rate(clk) / 1000;
  	devbus->tick_ps = 1000000000 / rate;
30bd30b60   Thomas Petazzoni   memory: mvebu-dev...
292
293
294
  	dev_dbg(devbus->dev, "Setting timing parameter, tick is %lu ps
  ",
  		devbus->tick_ps);
0456d3300   Thomas Petazzoni   memory: mvebu-dev...
295
296
297
298
299
  	if (!of_property_read_bool(node, "devbus,keep-config")) {
  		/* Read the Device Tree node */
  		err = devbus_get_timing_params(devbus, node, &r, &w);
  		if (err < 0)
  			return err;
3edad321b   Ezequiel Garcia   drivers: memory: ...
300

0456d3300   Thomas Petazzoni   memory: mvebu-dev...
301
302
303
304
305
306
  		/* Set the new timing parameters */
  		if (of_device_is_compatible(node, "marvell,orion-devbus"))
  			devbus_orion_set_timing_params(devbus, node, &r, &w);
  		else
  			devbus_armada_set_timing_params(devbus, node, &r, &w);
  	}
30bd30b60   Thomas Petazzoni   memory: mvebu-dev...
307

3edad321b   Ezequiel Garcia   drivers: memory: ...
308
  	/*
3edad321b   Ezequiel Garcia   drivers: memory: ...
309
310
311
312
313
  	 * We need to create a child device explicitly from here to
  	 * guarantee that the child will be probed after the timing
  	 * parameters for the bus are written.
  	 */
  	err = of_platform_populate(node, NULL, NULL, dev);
9b6e4c0a5   Ezequiel Garcia   memory: mvebu-dev...
314
  	if (err < 0)
3edad321b   Ezequiel Garcia   drivers: memory: ...
315
  		return err;
3edad321b   Ezequiel Garcia   drivers: memory: ...
316
317
318
319
320
321
  
  	return 0;
  }
  
  static const struct of_device_id mvebu_devbus_of_match[] = {
  	{ .compatible = "marvell,mvebu-devbus" },
c4ec7430c   Thomas Petazzoni   memory: mvebu-dev...
322
  	{ .compatible = "marvell,orion-devbus" },
3edad321b   Ezequiel Garcia   drivers: memory: ...
323
324
325
326
327
328
329
330
  	{},
  };
  MODULE_DEVICE_TABLE(of, mvebu_devbus_of_match);
  
  static struct platform_driver mvebu_devbus_driver = {
  	.probe		= mvebu_devbus_probe,
  	.driver		= {
  		.name	= "mvebu-devbus",
3edad321b   Ezequiel Garcia   drivers: memory: ...
331
332
333
334
335
336
337
338
339
340
341
342
343
  		.of_match_table = mvebu_devbus_of_match,
  	},
  };
  
  static int __init mvebu_devbus_init(void)
  {
  	return platform_driver_register(&mvebu_devbus_driver);
  }
  module_init(mvebu_devbus_init);
  
  MODULE_LICENSE("GPL v2");
  MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");
  MODULE_DESCRIPTION("Marvell EBU SoC Device Bus controller");