Commit | Line | Data |
---|---|---|
89184651 TR |
1 | /* |
2 | * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License version 2 as | |
6 | * published by the Free Software Foundation. | |
7 | */ | |
8 | ||
9 | #include <linux/clk.h> | |
10 | #include <linux/interrupt.h> | |
11 | #include <linux/kernel.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/of.h> | |
14 | #include <linux/platform_device.h> | |
15 | #include <linux/slab.h> | |
3d9dd6fd MP |
16 | #include <linux/sort.h> |
17 | ||
18 | #include <soc/tegra/fuse.h> | |
89184651 TR |
19 | |
20 | #include "mc.h" | |
21 | ||
22 | #define MC_INTSTATUS 0x000 | |
23 | #define MC_INT_DECERR_MTS (1 << 16) | |
24 | #define MC_INT_SECERR_SEC (1 << 13) | |
25 | #define MC_INT_DECERR_VPR (1 << 12) | |
26 | #define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11) | |
27 | #define MC_INT_INVALID_SMMU_PAGE (1 << 10) | |
28 | #define MC_INT_ARBITRATION_EMEM (1 << 9) | |
29 | #define MC_INT_SECURITY_VIOLATION (1 << 8) | |
30 | #define MC_INT_DECERR_EMEM (1 << 6) | |
31 | ||
32 | #define MC_INTMASK 0x004 | |
33 | ||
34 | #define MC_ERR_STATUS 0x08 | |
35 | #define MC_ERR_STATUS_TYPE_SHIFT 28 | |
36 | #define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (6 << MC_ERR_STATUS_TYPE_SHIFT) | |
37 | #define MC_ERR_STATUS_TYPE_MASK (0x7 << MC_ERR_STATUS_TYPE_SHIFT) | |
38 | #define MC_ERR_STATUS_READABLE (1 << 27) | |
39 | #define MC_ERR_STATUS_WRITABLE (1 << 26) | |
40 | #define MC_ERR_STATUS_NONSECURE (1 << 25) | |
41 | #define MC_ERR_STATUS_ADR_HI_SHIFT 20 | |
42 | #define MC_ERR_STATUS_ADR_HI_MASK 0x3 | |
43 | #define MC_ERR_STATUS_SECURITY (1 << 17) | |
44 | #define MC_ERR_STATUS_RW (1 << 16) | |
89184651 TR |
45 | |
46 | #define MC_ERR_ADR 0x0c | |
47 | ||
48 | #define MC_EMEM_ARB_CFG 0x90 | |
49 | #define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) (((x) & 0x1ff) << 0) | |
50 | #define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff | |
51 | #define MC_EMEM_ARB_MISC0 0xd8 | |
52 | ||
3d9dd6fd MP |
53 | #define MC_EMEM_ADR_CFG 0x54 |
54 | #define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0) | |
55 | ||
89184651 TR |
56 | static const struct of_device_id tegra_mc_of_match[] = { |
57 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | |
58 | { .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc }, | |
59 | #endif | |
60 | #ifdef CONFIG_ARCH_TEGRA_114_SOC | |
61 | { .compatible = "nvidia,tegra114-mc", .data = &tegra114_mc_soc }, | |
62 | #endif | |
63 | #ifdef CONFIG_ARCH_TEGRA_124_SOC | |
64 | { .compatible = "nvidia,tegra124-mc", .data = &tegra124_mc_soc }, | |
242b1d71 TR |
65 | #endif |
66 | #ifdef CONFIG_ARCH_TEGRA_132_SOC | |
67 | { .compatible = "nvidia,tegra132-mc", .data = &tegra132_mc_soc }, | |
89184651 TR |
68 | #endif |
69 | { } | |
70 | }; | |
71 | MODULE_DEVICE_TABLE(of, tegra_mc_of_match); | |
72 | ||
73 | static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc) | |
74 | { | |
75 | unsigned long long tick; | |
76 | unsigned int i; | |
77 | u32 value; | |
78 | ||
79 | /* compute the number of MC clock cycles per tick */ | |
80 | tick = mc->tick * clk_get_rate(mc->clk); | |
81 | do_div(tick, NSEC_PER_SEC); | |
82 | ||
83 | value = readl(mc->regs + MC_EMEM_ARB_CFG); | |
84 | value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK; | |
85 | value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick); | |
86 | writel(value, mc->regs + MC_EMEM_ARB_CFG); | |
87 | ||
88 | /* write latency allowance defaults */ | |
89 | for (i = 0; i < mc->soc->num_clients; i++) { | |
90 | const struct tegra_mc_la *la = &mc->soc->clients[i].la; | |
91 | u32 value; | |
92 | ||
93 | value = readl(mc->regs + la->reg); | |
94 | value &= ~(la->mask << la->shift); | |
95 | value |= (la->def & la->mask) << la->shift; | |
96 | writel(value, mc->regs + la->reg); | |
97 | } | |
98 | ||
99 | return 0; | |
100 | } | |
101 | ||
3d9dd6fd MP |
102 | void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate) |
103 | { | |
104 | unsigned int i; | |
105 | struct tegra_mc_timing *timing = NULL; | |
106 | ||
107 | for (i = 0; i < mc->num_timings; i++) { | |
108 | if (mc->timings[i].rate == rate) { | |
109 | timing = &mc->timings[i]; | |
110 | break; | |
111 | } | |
112 | } | |
113 | ||
114 | if (!timing) { | |
115 | dev_err(mc->dev, "no memory timing registered for rate %lu\n", | |
116 | rate); | |
117 | return; | |
118 | } | |
119 | ||
120 | for (i = 0; i < mc->soc->num_emem_regs; ++i) | |
121 | mc_writel(mc, timing->emem_data[i], mc->soc->emem_regs[i]); | |
122 | } | |
123 | ||
124 | unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc) | |
125 | { | |
126 | u8 dram_count; | |
127 | ||
128 | dram_count = mc_readl(mc, MC_EMEM_ADR_CFG); | |
129 | dram_count &= MC_EMEM_ADR_CFG_EMEM_NUMDEV; | |
130 | dram_count++; | |
131 | ||
132 | return dram_count; | |
133 | } | |
134 | ||
135 | static int load_one_timing(struct tegra_mc *mc, | |
136 | struct tegra_mc_timing *timing, | |
137 | struct device_node *node) | |
138 | { | |
139 | int err; | |
140 | u32 tmp; | |
141 | ||
142 | err = of_property_read_u32(node, "clock-frequency", &tmp); | |
143 | if (err) { | |
144 | dev_err(mc->dev, | |
145 | "timing %s: failed to read rate\n", node->name); | |
146 | return err; | |
147 | } | |
148 | ||
149 | timing->rate = tmp; | |
150 | timing->emem_data = devm_kcalloc(mc->dev, mc->soc->num_emem_regs, | |
151 | sizeof(u32), GFP_KERNEL); | |
152 | if (!timing->emem_data) | |
153 | return -ENOMEM; | |
154 | ||
155 | err = of_property_read_u32_array(node, "nvidia,emem-configuration", | |
156 | timing->emem_data, | |
157 | mc->soc->num_emem_regs); | |
158 | if (err) { | |
159 | dev_err(mc->dev, | |
160 | "timing %s: failed to read EMEM configuration\n", | |
161 | node->name); | |
162 | return err; | |
163 | } | |
164 | ||
165 | return 0; | |
166 | } | |
167 | ||
168 | static int load_timings(struct tegra_mc *mc, struct device_node *node) | |
169 | { | |
170 | struct device_node *child; | |
171 | struct tegra_mc_timing *timing; | |
172 | int child_count = of_get_child_count(node); | |
173 | int i = 0, err; | |
174 | ||
175 | mc->timings = devm_kcalloc(mc->dev, child_count, sizeof(*timing), | |
176 | GFP_KERNEL); | |
177 | if (!mc->timings) | |
178 | return -ENOMEM; | |
179 | ||
180 | mc->num_timings = child_count; | |
181 | ||
182 | for_each_child_of_node(node, child) { | |
183 | timing = &mc->timings[i++]; | |
184 | ||
185 | err = load_one_timing(mc, timing, child); | |
186 | if (err) | |
187 | return err; | |
188 | } | |
189 | ||
190 | return 0; | |
191 | } | |
192 | ||
193 | static int tegra_mc_setup_timings(struct tegra_mc *mc) | |
194 | { | |
195 | struct device_node *node; | |
196 | u32 ram_code, node_ram_code; | |
197 | int err; | |
198 | ||
199 | ram_code = tegra_read_ram_code(); | |
200 | ||
201 | mc->num_timings = 0; | |
202 | ||
203 | for_each_child_of_node(mc->dev->of_node, node) { | |
204 | err = of_property_read_u32(node, "nvidia,ram-code", | |
205 | &node_ram_code); | |
206 | if (err || (node_ram_code != ram_code)) { | |
207 | of_node_put(node); | |
208 | continue; | |
209 | } | |
210 | ||
211 | err = load_timings(mc, node); | |
212 | if (err) | |
213 | return err; | |
214 | of_node_put(node); | |
215 | break; | |
216 | } | |
217 | ||
218 | if (mc->num_timings == 0) | |
219 | dev_warn(mc->dev, | |
220 | "no memory timings for RAM code %u registered\n", | |
221 | ram_code); | |
222 | ||
223 | return 0; | |
224 | } | |
225 | ||
89184651 TR |
226 | static const char *const status_names[32] = { |
227 | [ 1] = "External interrupt", | |
228 | [ 6] = "EMEM address decode error", | |
229 | [ 8] = "Security violation", | |
230 | [ 9] = "EMEM arbitration error", | |
231 | [10] = "Page fault", | |
232 | [11] = "Invalid APB ASID update", | |
233 | [12] = "VPR violation", | |
234 | [13] = "Secure carveout violation", | |
235 | [16] = "MTS carveout violation", | |
236 | }; | |
237 | ||
238 | static const char *const error_names[8] = { | |
239 | [2] = "EMEM decode error", | |
240 | [3] = "TrustZone violation", | |
241 | [4] = "Carveout violation", | |
242 | [6] = "SMMU translation error", | |
243 | }; | |
244 | ||
245 | static irqreturn_t tegra_mc_irq(int irq, void *data) | |
246 | { | |
247 | struct tegra_mc *mc = data; | |
248 | unsigned long status, mask; | |
249 | unsigned int bit; | |
250 | ||
251 | /* mask all interrupts to avoid flooding */ | |
252 | status = mc_readl(mc, MC_INTSTATUS); | |
253 | mask = mc_readl(mc, MC_INTMASK); | |
254 | ||
255 | for_each_set_bit(bit, &status, 32) { | |
256 | const char *error = status_names[bit] ?: "unknown"; | |
257 | const char *client = "unknown", *desc; | |
258 | const char *direction, *secure; | |
259 | phys_addr_t addr = 0; | |
260 | unsigned int i; | |
261 | char perm[7]; | |
262 | u8 id, type; | |
263 | u32 value; | |
264 | ||
265 | value = mc_readl(mc, MC_ERR_STATUS); | |
266 | ||
267 | #ifdef CONFIG_PHYS_ADDR_T_64BIT | |
268 | if (mc->soc->num_address_bits > 32) { | |
269 | addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) & | |
270 | MC_ERR_STATUS_ADR_HI_MASK); | |
271 | addr <<= 32; | |
272 | } | |
273 | #endif | |
274 | ||
275 | if (value & MC_ERR_STATUS_RW) | |
276 | direction = "write"; | |
277 | else | |
278 | direction = "read"; | |
279 | ||
280 | if (value & MC_ERR_STATUS_SECURITY) | |
281 | secure = "secure "; | |
282 | else | |
283 | secure = ""; | |
284 | ||
3c01cf3b | 285 | id = value & mc->soc->client_id_mask; |
89184651 TR |
286 | |
287 | for (i = 0; i < mc->soc->num_clients; i++) { | |
288 | if (mc->soc->clients[i].id == id) { | |
289 | client = mc->soc->clients[i].name; | |
290 | break; | |
291 | } | |
292 | } | |
293 | ||
294 | type = (value & MC_ERR_STATUS_TYPE_MASK) >> | |
295 | MC_ERR_STATUS_TYPE_SHIFT; | |
296 | desc = error_names[type]; | |
297 | ||
298 | switch (value & MC_ERR_STATUS_TYPE_MASK) { | |
299 | case MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE: | |
300 | perm[0] = ' '; | |
301 | perm[1] = '['; | |
302 | ||
303 | if (value & MC_ERR_STATUS_READABLE) | |
304 | perm[2] = 'R'; | |
305 | else | |
306 | perm[2] = '-'; | |
307 | ||
308 | if (value & MC_ERR_STATUS_WRITABLE) | |
309 | perm[3] = 'W'; | |
310 | else | |
311 | perm[3] = '-'; | |
312 | ||
313 | if (value & MC_ERR_STATUS_NONSECURE) | |
314 | perm[4] = '-'; | |
315 | else | |
316 | perm[4] = 'S'; | |
317 | ||
318 | perm[5] = ']'; | |
319 | perm[6] = '\0'; | |
320 | break; | |
321 | ||
322 | default: | |
323 | perm[0] = '\0'; | |
324 | break; | |
325 | } | |
326 | ||
327 | value = mc_readl(mc, MC_ERR_ADR); | |
328 | addr |= value; | |
329 | ||
330 | dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s%s)\n", | |
331 | client, secure, direction, &addr, error, | |
332 | desc, perm); | |
333 | } | |
334 | ||
335 | /* clear interrupts */ | |
336 | mc_writel(mc, status, MC_INTSTATUS); | |
337 | ||
338 | return IRQ_HANDLED; | |
339 | } | |
340 | ||
341 | static int tegra_mc_probe(struct platform_device *pdev) | |
342 | { | |
343 | const struct of_device_id *match; | |
344 | struct resource *res; | |
345 | struct tegra_mc *mc; | |
346 | u32 value; | |
347 | int err; | |
348 | ||
349 | match = of_match_node(tegra_mc_of_match, pdev->dev.of_node); | |
350 | if (!match) | |
351 | return -ENODEV; | |
352 | ||
353 | mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); | |
354 | if (!mc) | |
355 | return -ENOMEM; | |
356 | ||
357 | platform_set_drvdata(pdev, mc); | |
358 | mc->soc = match->data; | |
359 | mc->dev = &pdev->dev; | |
360 | ||
361 | /* length of MC tick in nanoseconds */ | |
362 | mc->tick = 30; | |
363 | ||
364 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
365 | mc->regs = devm_ioremap_resource(&pdev->dev, res); | |
366 | if (IS_ERR(mc->regs)) | |
367 | return PTR_ERR(mc->regs); | |
368 | ||
369 | mc->clk = devm_clk_get(&pdev->dev, "mc"); | |
370 | if (IS_ERR(mc->clk)) { | |
371 | dev_err(&pdev->dev, "failed to get MC clock: %ld\n", | |
372 | PTR_ERR(mc->clk)); | |
373 | return PTR_ERR(mc->clk); | |
374 | } | |
375 | ||
376 | err = tegra_mc_setup_latency_allowance(mc); | |
377 | if (err < 0) { | |
378 | dev_err(&pdev->dev, "failed to setup latency allowance: %d\n", | |
379 | err); | |
380 | return err; | |
381 | } | |
382 | ||
3d9dd6fd MP |
383 | err = tegra_mc_setup_timings(mc); |
384 | if (err < 0) { | |
385 | dev_err(&pdev->dev, "failed to setup timings: %d\n", err); | |
386 | return err; | |
387 | } | |
388 | ||
89184651 TR |
389 | if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) { |
390 | mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc); | |
391 | if (IS_ERR(mc->smmu)) { | |
392 | dev_err(&pdev->dev, "failed to probe SMMU: %ld\n", | |
393 | PTR_ERR(mc->smmu)); | |
394 | return PTR_ERR(mc->smmu); | |
395 | } | |
396 | } | |
397 | ||
398 | mc->irq = platform_get_irq(pdev, 0); | |
399 | if (mc->irq < 0) { | |
400 | dev_err(&pdev->dev, "interrupt not specified\n"); | |
401 | return mc->irq; | |
402 | } | |
403 | ||
404 | err = devm_request_irq(&pdev->dev, mc->irq, tegra_mc_irq, IRQF_SHARED, | |
405 | dev_name(&pdev->dev), mc); | |
406 | if (err < 0) { | |
407 | dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq, | |
408 | err); | |
409 | return err; | |
410 | } | |
411 | ||
3c01cf3b PW |
412 | WARN(!mc->soc->client_id_mask, "Missing client ID mask for this SoC\n"); |
413 | ||
89184651 TR |
414 | value = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | |
415 | MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | | |
6f0a4d0c TV |
416 | MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM; |
417 | ||
89184651 TR |
418 | mc_writel(mc, value, MC_INTMASK); |
419 | ||
420 | return 0; | |
421 | } | |
422 | ||
423 | static struct platform_driver tegra_mc_driver = { | |
424 | .driver = { | |
425 | .name = "tegra-mc", | |
426 | .of_match_table = tegra_mc_of_match, | |
427 | .suppress_bind_attrs = true, | |
428 | }, | |
429 | .prevent_deferred_probe = true, | |
430 | .probe = tegra_mc_probe, | |
431 | }; | |
432 | ||
433 | static int tegra_mc_init(void) | |
434 | { | |
435 | return platform_driver_register(&tegra_mc_driver); | |
436 | } | |
437 | arch_initcall(tegra_mc_init); | |
438 | ||
439 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); | |
440 | MODULE_DESCRIPTION("NVIDIA Tegra Memory Controller driver"); | |
441 | MODULE_LICENSE("GPL v2"); |