Blame view

drivers/memory/of_memory.c 9.61 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
e6b42eb6a   Aneesh V   memory: emif: add...
2
3
4
5
  /*
   * OpenFirmware helpers for memory drivers
   *
   * Copyright (C) 2012 Texas Instruments, Inc.
976897dd9   Lukasz Luba   memory: Extend of...
6
   * Copyright (C) 2019 Samsung Electronics Co., Ltd.
efc464632   Krzysztof Kozlowski   memory: of: Remov...
7
   * Copyright (C) 2020 Krzysztof Kozlowski <krzk@kernel.org>
e6b42eb6a   Aneesh V   memory: emif: add...
8
9
10
   */
  
  #include <linux/device.h>
e6b42eb6a   Aneesh V   memory: emif: add...
11
12
  #include <linux/of.h>
  #include <linux/gfp.h>
e6b42eb6a   Aneesh V   memory: emif: add...
13
  #include <linux/export.h>
5ec47cda7   Masahiro Yamada   memory: move jede...
14
15
  
  #include "jedec_ddr.h"
aeb83d705   Baoyou Xie   fix:memory:of_mem...
16
  #include "of_memory.h"
e6b42eb6a   Aneesh V   memory: emif: add...
17
18
19
20
  
  /**
   * of_get_min_tck() - extract min timing values for ddr
   * @np: pointer to ddr device tree node
46c711187   Krzysztof Kozlowski   memory: of: Corre...
21
   * @dev: device requesting for min timing values
e6b42eb6a   Aneesh V   memory: emif: add...
22
23
24
25
26
27
28
   *
   * Populates the lpddr2_min_tck structure by extracting data
   * from device tree node. Returns a pointer to the populated
   * structure. If any error in populating the structure, returns
   * default min timings provided by JEDEC.
   */
  const struct lpddr2_min_tck *of_get_min_tck(struct device_node *np,
9825095a0   Krzysztof Kozlowski   memory: of: Corre...
29
  					    struct device *dev)
e6b42eb6a   Aneesh V   memory: emif: add...
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  {
  	int			ret = 0;
  	struct lpddr2_min_tck	*min;
  
  	min = devm_kzalloc(dev, sizeof(*min), GFP_KERNEL);
  	if (!min)
  		goto default_min_tck;
  
  	ret |= of_property_read_u32(np, "tRPab-min-tck", &min->tRPab);
  	ret |= of_property_read_u32(np, "tRCD-min-tck", &min->tRCD);
  	ret |= of_property_read_u32(np, "tWR-min-tck", &min->tWR);
  	ret |= of_property_read_u32(np, "tRASmin-min-tck", &min->tRASmin);
  	ret |= of_property_read_u32(np, "tRRD-min-tck", &min->tRRD);
  	ret |= of_property_read_u32(np, "tWTR-min-tck", &min->tWTR);
  	ret |= of_property_read_u32(np, "tXP-min-tck", &min->tXP);
  	ret |= of_property_read_u32(np, "tRTP-min-tck", &min->tRTP);
  	ret |= of_property_read_u32(np, "tCKE-min-tck", &min->tCKE);
  	ret |= of_property_read_u32(np, "tCKESR-min-tck", &min->tCKESR);
  	ret |= of_property_read_u32(np, "tFAW-min-tck", &min->tFAW);
  
  	if (ret) {
  		devm_kfree(dev, min);
  		goto default_min_tck;
  	}
  
  	return min;
  
  default_min_tck:
efc464632   Krzysztof Kozlowski   memory: of: Remov...
58
59
  	dev_warn(dev, "Using default min-tck values
  ");
e6b42eb6a   Aneesh V   memory: emif: add...
60
61
62
63
64
  	return &lpddr2_jedec_min_tck;
  }
  EXPORT_SYMBOL(of_get_min_tck);
  
  static int of_do_get_timings(struct device_node *np,
9825095a0   Krzysztof Kozlowski   memory: of: Corre...
65
  			     struct lpddr2_timings *tim)
e6b42eb6a   Aneesh V   memory: emif: add...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  {
  	int ret;
  
  	ret = of_property_read_u32(np, "max-freq", &tim->max_freq);
  	ret |= of_property_read_u32(np, "min-freq", &tim->min_freq);
  	ret |= of_property_read_u32(np, "tRPab", &tim->tRPab);
  	ret |= of_property_read_u32(np, "tRCD", &tim->tRCD);
  	ret |= of_property_read_u32(np, "tWR", &tim->tWR);
  	ret |= of_property_read_u32(np, "tRAS-min", &tim->tRAS_min);
  	ret |= of_property_read_u32(np, "tRRD", &tim->tRRD);
  	ret |= of_property_read_u32(np, "tWTR", &tim->tWTR);
  	ret |= of_property_read_u32(np, "tXP", &tim->tXP);
  	ret |= of_property_read_u32(np, "tRTP", &tim->tRTP);
  	ret |= of_property_read_u32(np, "tCKESR", &tim->tCKESR);
  	ret |= of_property_read_u32(np, "tDQSCK-max", &tim->tDQSCK_max);
  	ret |= of_property_read_u32(np, "tFAW", &tim->tFAW);
  	ret |= of_property_read_u32(np, "tZQCS", &tim->tZQCS);
  	ret |= of_property_read_u32(np, "tZQCL", &tim->tZQCL);
  	ret |= of_property_read_u32(np, "tZQinit", &tim->tZQinit);
  	ret |= of_property_read_u32(np, "tRAS-max-ns", &tim->tRAS_max_ns);
  	ret |= of_property_read_u32(np, "tDQSCK-max-derated",
9825095a0   Krzysztof Kozlowski   memory: of: Corre...
87
  				    &tim->tDQSCK_max_derated);
e6b42eb6a   Aneesh V   memory: emif: add...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  
  	return ret;
  }
  
  /**
   * of_get_ddr_timings() - extracts the ddr timings and updates no of
   * frequencies available.
   * @np_ddr: Pointer to ddr device tree node
   * @dev: Device requesting for ddr timings
   * @device_type: Type of ddr(LPDDR2 S2/S4)
   * @nr_frequencies: No of frequencies available for ddr
   * (updated by this function)
   *
   * Populates lpddr2_timings structure by extracting data from device
   * tree node. Returns pointer to populated structure. If any error
   * while populating, returns default timings provided by JEDEC.
   */
  const struct lpddr2_timings *of_get_ddr_timings(struct device_node *np_ddr,
9825095a0   Krzysztof Kozlowski   memory: of: Corre...
106
107
108
  						struct device *dev,
  						u32 device_type,
  						u32 *nr_frequencies)
e6b42eb6a   Aneesh V   memory: emif: add...
109
110
111
112
  {
  	struct lpddr2_timings	*timings = NULL;
  	u32			arr_sz = 0, i = 0;
  	struct device_node	*np_tim;
ae53e3740   Dan Carpenter   memory: of_memory...
113
  	char			*tim_compat = NULL;
e6b42eb6a   Aneesh V   memory: emif: add...
114
115
116
117
118
119
120
  
  	switch (device_type) {
  	case DDR_TYPE_LPDDR2_S2:
  	case DDR_TYPE_LPDDR2_S4:
  		tim_compat = "jedec,lpddr2-timings";
  		break;
  	default:
efc464632   Krzysztof Kozlowski   memory: of: Remov...
121
122
  		dev_warn(dev, "Unsupported memory type
  ");
e6b42eb6a   Aneesh V   memory: emif: add...
123
124
125
126
127
128
129
  	}
  
  	for_each_child_of_node(np_ddr, np_tim)
  		if (of_device_is_compatible(np_tim, tim_compat))
  			arr_sz++;
  
  	if (arr_sz)
a86854d0c   Kees Cook   treewide: devm_kz...
130
131
  		timings = devm_kcalloc(dev, arr_sz, sizeof(*timings),
  				       GFP_KERNEL);
e6b42eb6a   Aneesh V   memory: emif: add...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  
  	if (!timings)
  		goto default_timings;
  
  	for_each_child_of_node(np_ddr, np_tim) {
  		if (of_device_is_compatible(np_tim, tim_compat)) {
  			if (of_do_get_timings(np_tim, &timings[i])) {
  				devm_kfree(dev, timings);
  				goto default_timings;
  			}
  			i++;
  		}
  	}
  
  	*nr_frequencies = arr_sz;
  
  	return timings;
  
  default_timings:
efc464632   Krzysztof Kozlowski   memory: of: Remov...
151
152
  	dev_warn(dev, "Using default memory timings
  ");
e6b42eb6a   Aneesh V   memory: emif: add...
153
154
155
156
  	*nr_frequencies = ARRAY_SIZE(lpddr2_jedec_timings);
  	return lpddr2_jedec_timings;
  }
  EXPORT_SYMBOL(of_get_ddr_timings);
976897dd9   Lukasz Luba   memory: Extend of...
157
158
159
160
  
  /**
   * of_lpddr3_get_min_tck() - extract min timing values for lpddr3
   * @np: pointer to ddr device tree node
46c711187   Krzysztof Kozlowski   memory: of: Corre...
161
   * @dev: device requesting for min timing values
976897dd9   Lukasz Luba   memory: Extend of...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
   *
   * Populates the lpddr3_min_tck structure by extracting data
   * from device tree node. Returns a pointer to the populated
   * structure. If any error in populating the structure, returns NULL.
   */
  const struct lpddr3_min_tck *of_lpddr3_get_min_tck(struct device_node *np,
  						   struct device *dev)
  {
  	int			ret = 0;
  	struct lpddr3_min_tck	*min;
  
  	min = devm_kzalloc(dev, sizeof(*min), GFP_KERNEL);
  	if (!min)
  		goto default_min_tck;
  
  	ret |= of_property_read_u32(np, "tRFC-min-tck", &min->tRFC);
  	ret |= of_property_read_u32(np, "tRRD-min-tck", &min->tRRD);
  	ret |= of_property_read_u32(np, "tRPab-min-tck", &min->tRPab);
  	ret |= of_property_read_u32(np, "tRPpb-min-tck", &min->tRPpb);
  	ret |= of_property_read_u32(np, "tRCD-min-tck", &min->tRCD);
  	ret |= of_property_read_u32(np, "tRC-min-tck", &min->tRC);
  	ret |= of_property_read_u32(np, "tRAS-min-tck", &min->tRAS);
  	ret |= of_property_read_u32(np, "tWTR-min-tck", &min->tWTR);
  	ret |= of_property_read_u32(np, "tWR-min-tck", &min->tWR);
  	ret |= of_property_read_u32(np, "tRTP-min-tck", &min->tRTP);
  	ret |= of_property_read_u32(np, "tW2W-C2C-min-tck", &min->tW2W_C2C);
  	ret |= of_property_read_u32(np, "tR2R-C2C-min-tck", &min->tR2R_C2C);
  	ret |= of_property_read_u32(np, "tWL-min-tck", &min->tWL);
  	ret |= of_property_read_u32(np, "tDQSCK-min-tck", &min->tDQSCK);
  	ret |= of_property_read_u32(np, "tRL-min-tck", &min->tRL);
  	ret |= of_property_read_u32(np, "tFAW-min-tck", &min->tFAW);
  	ret |= of_property_read_u32(np, "tXSR-min-tck", &min->tXSR);
  	ret |= of_property_read_u32(np, "tXP-min-tck", &min->tXP);
  	ret |= of_property_read_u32(np, "tCKE-min-tck", &min->tCKE);
  	ret |= of_property_read_u32(np, "tCKESR-min-tck", &min->tCKESR);
  	ret |= of_property_read_u32(np, "tMRD-min-tck", &min->tMRD);
  
  	if (ret) {
efc464632   Krzysztof Kozlowski   memory: of: Remov...
200
201
  		dev_warn(dev, "Errors while parsing min-tck values
  ");
976897dd9   Lukasz Luba   memory: Extend of...
202
203
204
205
206
207
208
  		devm_kfree(dev, min);
  		goto default_min_tck;
  	}
  
  	return min;
  
  default_min_tck:
efc464632   Krzysztof Kozlowski   memory: of: Remov...
209
210
  	dev_warn(dev, "Using default min-tck values
  ");
976897dd9   Lukasz Luba   memory: Extend of...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
  	return NULL;
  }
  EXPORT_SYMBOL(of_lpddr3_get_min_tck);
  
  static int of_lpddr3_do_get_timings(struct device_node *np,
  				    struct lpddr3_timings *tim)
  {
  	int ret;
  
  	/* The 'reg' param required since DT has changed, used as 'max-freq' */
  	ret = of_property_read_u32(np, "reg", &tim->max_freq);
  	ret |= of_property_read_u32(np, "min-freq", &tim->min_freq);
  	ret |= of_property_read_u32(np, "tRFC", &tim->tRFC);
  	ret |= of_property_read_u32(np, "tRRD", &tim->tRRD);
  	ret |= of_property_read_u32(np, "tRPab", &tim->tRPab);
  	ret |= of_property_read_u32(np, "tRPpb", &tim->tRPpb);
  	ret |= of_property_read_u32(np, "tRCD", &tim->tRCD);
  	ret |= of_property_read_u32(np, "tRC", &tim->tRC);
  	ret |= of_property_read_u32(np, "tRAS", &tim->tRAS);
  	ret |= of_property_read_u32(np, "tWTR", &tim->tWTR);
  	ret |= of_property_read_u32(np, "tWR", &tim->tWR);
  	ret |= of_property_read_u32(np, "tRTP", &tim->tRTP);
  	ret |= of_property_read_u32(np, "tW2W-C2C", &tim->tW2W_C2C);
  	ret |= of_property_read_u32(np, "tR2R-C2C", &tim->tR2R_C2C);
  	ret |= of_property_read_u32(np, "tFAW", &tim->tFAW);
  	ret |= of_property_read_u32(np, "tXSR", &tim->tXSR);
  	ret |= of_property_read_u32(np, "tXP", &tim->tXP);
  	ret |= of_property_read_u32(np, "tCKE", &tim->tCKE);
  	ret |= of_property_read_u32(np, "tCKESR", &tim->tCKESR);
  	ret |= of_property_read_u32(np, "tMRD", &tim->tMRD);
  
  	return ret;
  }
  
  /**
   * of_lpddr3_get_ddr_timings() - extracts the lpddr3 timings and updates no of
   * frequencies available.
   * @np_ddr: Pointer to ddr device tree node
   * @dev: Device requesting for ddr timings
   * @device_type: Type of ddr
   * @nr_frequencies: No of frequencies available for ddr
   * (updated by this function)
   *
   * Populates lpddr3_timings structure by extracting data from device
   * tree node. Returns pointer to populated structure. If any error
   * while populating, returns NULL.
   */
  const struct lpddr3_timings
  *of_lpddr3_get_ddr_timings(struct device_node *np_ddr, struct device *dev,
  			   u32 device_type, u32 *nr_frequencies)
  {
  	struct lpddr3_timings	*timings = NULL;
  	u32			arr_sz = 0, i = 0;
  	struct device_node	*np_tim;
  	char			*tim_compat = NULL;
  
  	switch (device_type) {
  	case DDR_TYPE_LPDDR3:
  		tim_compat = "jedec,lpddr3-timings";
  		break;
  	default:
efc464632   Krzysztof Kozlowski   memory: of: Remov...
272
273
  		dev_warn(dev, "Unsupported memory type
  ");
976897dd9   Lukasz Luba   memory: Extend of...
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
  	}
  
  	for_each_child_of_node(np_ddr, np_tim)
  		if (of_device_is_compatible(np_tim, tim_compat))
  			arr_sz++;
  
  	if (arr_sz)
  		timings = devm_kcalloc(dev, arr_sz, sizeof(*timings),
  				       GFP_KERNEL);
  
  	if (!timings)
  		goto default_timings;
  
  	for_each_child_of_node(np_ddr, np_tim) {
  		if (of_device_is_compatible(np_tim, tim_compat)) {
  			if (of_lpddr3_do_get_timings(np_tim, &timings[i])) {
  				devm_kfree(dev, timings);
  				goto default_timings;
  			}
  			i++;
  		}
  	}
  
  	*nr_frequencies = arr_sz;
  
  	return timings;
  
  default_timings:
efc464632   Krzysztof Kozlowski   memory: of: Remov...
302
303
  	dev_warn(dev, "Failed to get timings
  ");
976897dd9   Lukasz Luba   memory: Extend of...
304
305
306
307
  	*nr_frequencies = 0;
  	return NULL;
  }
  EXPORT_SYMBOL(of_lpddr3_get_ddr_timings);