Commit | Line | Data |
---|---|---|
7232398a TR |
1 | /* |
2 | * drivers/soc/tegra/pmc.c | |
3 | * | |
4 | * Copyright (c) 2010 Google, Inc | |
5f84bb1a | 5 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. |
7232398a TR |
6 | * |
7 | * Author: | |
8 | * Colin Cross <ccross@google.com> | |
9 | * | |
10 | * This software is licensed under the terms of the GNU General Public | |
11 | * License version 2, as published by the Free Software Foundation, and | |
12 | * may be copied, distributed, and modified under those terms. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | */ | |
20 | ||
7d71e903 TR |
21 | #define pr_fmt(fmt) "tegra-pmc: " fmt |
22 | ||
7232398a TR |
23 | #include <linux/kernel.h> |
24 | #include <linux/clk.h> | |
25 | #include <linux/clk/tegra.h> | |
26 | #include <linux/debugfs.h> | |
27 | #include <linux/delay.h> | |
28 | #include <linux/err.h> | |
29 | #include <linux/export.h> | |
30 | #include <linux/init.h> | |
31 | #include <linux/io.h> | |
0a2d87e0 | 32 | #include <linux/iopoll.h> |
19906e6b TR |
33 | #include <linux/irq.h> |
34 | #include <linux/irqdomain.h> | |
7232398a TR |
35 | #include <linux/of.h> |
36 | #include <linux/of_address.h> | |
3fd0121b | 37 | #include <linux/of_clk.h> |
19906e6b | 38 | #include <linux/of_irq.h> |
a3804512 | 39 | #include <linux/of_platform.h> |
4a37f11c AV |
40 | #include <linux/pinctrl/pinctrl.h> |
41 | #include <linux/pinctrl/pinconf.h> | |
42 | #include <linux/pinctrl/pinconf-generic.h> | |
7232398a | 43 | #include <linux/platform_device.h> |
a3804512 | 44 | #include <linux/pm_domain.h> |
7232398a TR |
45 | #include <linux/reboot.h> |
46 | #include <linux/reset.h> | |
47 | #include <linux/seq_file.h> | |
a3804512 | 48 | #include <linux/slab.h> |
7232398a TR |
49 | #include <linux/spinlock.h> |
50 | ||
51 | #include <soc/tegra/common.h> | |
52 | #include <soc/tegra/fuse.h> | |
53 | #include <soc/tegra/pmc.h> | |
54 | ||
19906e6b | 55 | #include <dt-bindings/interrupt-controller/arm-gic.h> |
fccf0f76 | 56 | #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h> |
e59333c8 | 57 | #include <dt-bindings/gpio/tegra186-gpio.h> |
fccf0f76 | 58 | |
7232398a | 59 | #define PMC_CNTRL 0x0 |
6c0bd217 | 60 | #define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ |
95b780b3 TR |
61 | #define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */ |
62 | #define PMC_CNTRL_CPU_PWRREQ_POLARITY BIT(15) /* CPU pwr req polarity */ | |
63 | #define PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14) /* LP0 when CPU pwr gated */ | |
64 | #define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */ | |
65 | #define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */ | |
66 | #define PMC_CNTRL_MAIN_RST BIT(4) | |
7232398a TR |
67 | |
68 | #define DPD_SAMPLE 0x020 | |
6c0bd217 | 69 | #define DPD_SAMPLE_ENABLE BIT(0) |
7232398a TR |
70 | #define DPD_SAMPLE_DISABLE (0 << 0) |
71 | ||
72 | #define PWRGATE_TOGGLE 0x30 | |
6c0bd217 | 73 | #define PWRGATE_TOGGLE_START BIT(8) |
7232398a TR |
74 | |
75 | #define REMOVE_CLAMPING 0x34 | |
76 | ||
77 | #define PWRGATE_STATUS 0x38 | |
78 | ||
13136a47 AV |
79 | #define PMC_IMPL_E_33V_PWR 0x40 |
80 | ||
21b49910 LD |
81 | #define PMC_PWR_DET 0x48 |
82 | ||
5be22556 TR |
83 | #define PMC_SCRATCH0_MODE_RECOVERY BIT(31) |
84 | #define PMC_SCRATCH0_MODE_BOOTLOADER BIT(30) | |
85 | #define PMC_SCRATCH0_MODE_RCM BIT(1) | |
86 | #define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \ | |
7232398a TR |
87 | PMC_SCRATCH0_MODE_BOOTLOADER | \ |
88 | PMC_SCRATCH0_MODE_RCM) | |
89 | ||
90 | #define PMC_CPUPWRGOOD_TIMER 0xc8 | |
91 | #define PMC_CPUPWROFF_TIMER 0xcc | |
92 | ||
21b49910 LD |
93 | #define PMC_PWR_DET_VALUE 0xe4 |
94 | ||
7232398a TR |
95 | #define PMC_SCRATCH41 0x140 |
96 | ||
3568df3d | 97 | #define PMC_SENSOR_CTRL 0x1b0 |
6c0bd217 LD |
98 | #define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2) |
99 | #define PMC_SENSOR_CTRL_ENABLE_RST BIT(1) | |
3568df3d | 100 | |
f5353c60 TR |
101 | #define PMC_RST_STATUS_POR 0 |
102 | #define PMC_RST_STATUS_WATCHDOG 1 | |
103 | #define PMC_RST_STATUS_SENSOR 2 | |
104 | #define PMC_RST_STATUS_SW_MAIN 3 | |
105 | #define PMC_RST_STATUS_LP0 4 | |
106 | #define PMC_RST_STATUS_AOTAG 5 | |
107 | ||
7232398a | 108 | #define IO_DPD_REQ 0x1b8 |
6c0bd217 LD |
109 | #define IO_DPD_REQ_CODE_IDLE (0U << 30) |
110 | #define IO_DPD_REQ_CODE_OFF (1U << 30) | |
111 | #define IO_DPD_REQ_CODE_ON (2U << 30) | |
112 | #define IO_DPD_REQ_CODE_MASK (3U << 30) | |
7232398a TR |
113 | |
114 | #define IO_DPD_STATUS 0x1bc | |
115 | #define IO_DPD2_REQ 0x1c0 | |
116 | #define IO_DPD2_STATUS 0x1c4 | |
117 | #define SEL_DPD_TIM 0x1c8 | |
118 | ||
3568df3d | 119 | #define PMC_SCRATCH54 0x258 |
6c0bd217 LD |
120 | #define PMC_SCRATCH54_DATA_SHIFT 8 |
121 | #define PMC_SCRATCH54_ADDR_SHIFT 0 | |
3568df3d MP |
122 | |
123 | #define PMC_SCRATCH55 0x25c | |
6c0bd217 LD |
124 | #define PMC_SCRATCH55_RESET_TEGRA BIT(31) |
125 | #define PMC_SCRATCH55_CNTRL_ID_SHIFT 27 | |
126 | #define PMC_SCRATCH55_PINMUX_SHIFT 24 | |
127 | #define PMC_SCRATCH55_16BITOP BIT(15) | |
128 | #define PMC_SCRATCH55_CHECKSUM_SHIFT 16 | |
129 | #define PMC_SCRATCH55_I2CSLV1_SHIFT 0 | |
3568df3d | 130 | |
7232398a TR |
131 | #define GPU_RG_CNTRL 0x2d4 |
132 | ||
c641ec6e | 133 | /* Tegra186 and later */ |
19906e6b TR |
134 | #define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2)) |
135 | #define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3) | |
136 | #define WAKE_AOWAKE_MASK_W(x) (0x180 + ((x) << 2)) | |
137 | #define WAKE_AOWAKE_MASK_R(x) (0x300 + ((x) << 2)) | |
138 | #define WAKE_AOWAKE_STATUS_W(x) (0x30c + ((x) << 2)) | |
139 | #define WAKE_AOWAKE_STATUS_R(x) (0x48c + ((x) << 2)) | |
140 | #define WAKE_AOWAKE_TIER0_ROUTING(x) (0x4b4 + ((x) << 2)) | |
141 | #define WAKE_AOWAKE_TIER1_ROUTING(x) (0x4c0 + ((x) << 2)) | |
142 | #define WAKE_AOWAKE_TIER2_ROUTING(x) (0x4cc + ((x) << 2)) | |
143 | ||
c641ec6e TR |
144 | #define WAKE_AOWAKE_CTRL 0x4f4 |
145 | #define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) | |
146 | ||
a3804512 JH |
147 | struct tegra_powergate { |
148 | struct generic_pm_domain genpd; | |
149 | struct tegra_pmc *pmc; | |
150 | unsigned int id; | |
151 | struct clk **clks; | |
152 | unsigned int num_clks; | |
4c817ccf | 153 | struct reset_control *reset; |
a3804512 JH |
154 | }; |
155 | ||
21b49910 LD |
156 | struct tegra_io_pad_soc { |
157 | enum tegra_io_pad id; | |
158 | unsigned int dpd; | |
159 | unsigned int voltage; | |
437c4f26 | 160 | const char *name; |
21b49910 LD |
161 | }; |
162 | ||
5be22556 TR |
163 | struct tegra_pmc_regs { |
164 | unsigned int scratch0; | |
165 | unsigned int dpd_req; | |
166 | unsigned int dpd_status; | |
167 | unsigned int dpd2_req; | |
168 | unsigned int dpd2_status; | |
5f84bb1a SP |
169 | unsigned int rst_status; |
170 | unsigned int rst_source_shift; | |
171 | unsigned int rst_source_mask; | |
172 | unsigned int rst_level_shift; | |
173 | unsigned int rst_level_mask; | |
5be22556 TR |
174 | }; |
175 | ||
19906e6b TR |
176 | struct tegra_wake_event { |
177 | const char *name; | |
178 | unsigned int id; | |
179 | unsigned int irq; | |
180 | struct { | |
181 | unsigned int instance; | |
182 | unsigned int pin; | |
183 | } gpio; | |
184 | }; | |
185 | ||
186 | #define TEGRA_WAKE_IRQ(_name, _id, _irq) \ | |
187 | { \ | |
188 | .name = _name, \ | |
189 | .id = _id, \ | |
190 | .irq = _irq, \ | |
191 | .gpio = { \ | |
192 | .instance = UINT_MAX, \ | |
193 | .pin = UINT_MAX, \ | |
194 | }, \ | |
195 | } | |
196 | ||
197 | #define TEGRA_WAKE_GPIO(_name, _id, _instance, _pin) \ | |
198 | { \ | |
199 | .name = _name, \ | |
200 | .id = _id, \ | |
201 | .irq = 0, \ | |
202 | .gpio = { \ | |
203 | .instance = _instance, \ | |
204 | .pin = _pin, \ | |
205 | }, \ | |
206 | } | |
207 | ||
7232398a TR |
208 | struct tegra_pmc_soc { |
209 | unsigned int num_powergates; | |
210 | const char *const *powergates; | |
211 | unsigned int num_cpu_powergates; | |
212 | const u8 *cpu_powergates; | |
a9a40a4a | 213 | |
3568df3d | 214 | bool has_tsense_reset; |
a9a40a4a | 215 | bool has_gpu_clamps; |
a263394a | 216 | bool needs_mbist_war; |
13136a47 | 217 | bool has_impl_33v_pwr; |
21b49910 LD |
218 | |
219 | const struct tegra_io_pad_soc *io_pads; | |
220 | unsigned int num_io_pads; | |
5be22556 | 221 | |
4a37f11c AV |
222 | const struct pinctrl_pin_desc *pin_descs; |
223 | unsigned int num_pin_descs; | |
224 | ||
5be22556 TR |
225 | const struct tegra_pmc_regs *regs; |
226 | void (*init)(struct tegra_pmc *pmc); | |
227 | void (*setup_irq_polarity)(struct tegra_pmc *pmc, | |
228 | struct device_node *np, | |
229 | bool invert); | |
5f84bb1a SP |
230 | |
231 | const char * const *reset_sources; | |
232 | unsigned int num_reset_sources; | |
233 | const char * const *reset_levels; | |
234 | unsigned int num_reset_levels; | |
19906e6b TR |
235 | |
236 | const struct tegra_wake_event *wake_events; | |
237 | unsigned int num_wake_events; | |
5f84bb1a SP |
238 | }; |
239 | ||
240 | static const char * const tegra186_reset_sources[] = { | |
241 | "SYS_RESET", | |
242 | "AOWDT", | |
243 | "MCCPLEXWDT", | |
244 | "BPMPWDT", | |
245 | "SCEWDT", | |
246 | "SPEWDT", | |
247 | "APEWDT", | |
248 | "BCCPLEXWDT", | |
249 | "SENSOR", | |
250 | "AOTAG", | |
251 | "VFSENSOR", | |
252 | "SWREST", | |
253 | "SC7", | |
254 | "HSM", | |
255 | "CORESIGHT" | |
256 | }; | |
257 | ||
258 | static const char * const tegra186_reset_levels[] = { | |
259 | "L0", "L1", "L2", "WARM" | |
260 | }; | |
261 | ||
262 | static const char * const tegra30_reset_sources[] = { | |
263 | "POWER_ON_RESET", | |
264 | "WATCHDOG", | |
265 | "SENSOR", | |
266 | "SW_MAIN", | |
267 | "LP0", | |
268 | "AOTAG" | |
7232398a TR |
269 | }; |
270 | ||
271 | /** | |
272 | * struct tegra_pmc - NVIDIA Tegra PMC | |
35b67291 | 273 | * @dev: pointer to PMC device structure |
7232398a TR |
274 | * @base: pointer to I/O remapped register region |
275 | * @clk: pointer to pclk clock | |
35b67291 | 276 | * @soc: pointer to SoC data structure |
3195ac6d | 277 | * @debugfs: pointer to debugfs entry |
7232398a TR |
278 | * @rate: currently configured rate of pclk |
279 | * @suspend_mode: lowest suspend mode available | |
280 | * @cpu_good_time: CPU power good time (in microseconds) | |
281 | * @cpu_off_time: CPU power off time (in microsecends) | |
282 | * @core_osc_time: core power good OSC time (in microseconds) | |
283 | * @core_pmu_time: core power good PMU time (in microseconds) | |
284 | * @core_off_time: core power off time (in microseconds) | |
285 | * @corereq_high: core power request is active-high | |
286 | * @sysclkreq_high: system clock request is active-high | |
287 | * @combined_req: combined power request for CPU & core | |
288 | * @cpu_pwr_good_en: CPU power good signal is enabled | |
289 | * @lp0_vec_phys: physical base address of the LP0 warm boot code | |
290 | * @lp0_vec_size: size of the LP0 warm boot code | |
a3804512 | 291 | * @powergates_available: Bitmap of available power gates |
7232398a TR |
292 | * @powergates_lock: mutex for power gate register access |
293 | */ | |
294 | struct tegra_pmc { | |
3568df3d | 295 | struct device *dev; |
7232398a | 296 | void __iomem *base; |
c641ec6e TR |
297 | void __iomem *wake; |
298 | void __iomem *aotag; | |
5be22556 | 299 | void __iomem *scratch; |
7232398a | 300 | struct clk *clk; |
3195ac6d | 301 | struct dentry *debugfs; |
7232398a TR |
302 | |
303 | const struct tegra_pmc_soc *soc; | |
304 | ||
305 | unsigned long rate; | |
306 | ||
307 | enum tegra_suspend_mode suspend_mode; | |
308 | u32 cpu_good_time; | |
309 | u32 cpu_off_time; | |
310 | u32 core_osc_time; | |
311 | u32 core_pmu_time; | |
312 | u32 core_off_time; | |
313 | bool corereq_high; | |
314 | bool sysclkreq_high; | |
315 | bool combined_req; | |
316 | bool cpu_pwr_good_en; | |
317 | u32 lp0_vec_phys; | |
318 | u32 lp0_vec_size; | |
a3804512 | 319 | DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX); |
7232398a TR |
320 | |
321 | struct mutex powergates_lock; | |
4a37f11c AV |
322 | |
323 | struct pinctrl_dev *pctl_dev; | |
19906e6b TR |
324 | |
325 | struct irq_domain *domain; | |
326 | struct irq_chip irq; | |
7232398a TR |
327 | }; |
328 | ||
329 | static struct tegra_pmc *pmc = &(struct tegra_pmc) { | |
330 | .base = NULL, | |
331 | .suspend_mode = TEGRA_SUSPEND_NONE, | |
332 | }; | |
333 | ||
a3804512 JH |
334 | static inline struct tegra_powergate * |
335 | to_powergate(struct generic_pm_domain *domain) | |
336 | { | |
337 | return container_of(domain, struct tegra_powergate, genpd); | |
338 | } | |
339 | ||
7232398a TR |
340 | static u32 tegra_pmc_readl(unsigned long offset) |
341 | { | |
342 | return readl(pmc->base + offset); | |
343 | } | |
344 | ||
345 | static void tegra_pmc_writel(u32 value, unsigned long offset) | |
346 | { | |
347 | writel(value, pmc->base + offset); | |
348 | } | |
349 | ||
0ecf2d33 JH |
350 | static inline bool tegra_powergate_state(int id) |
351 | { | |
bc9af23d JH |
352 | if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps) |
353 | return (tegra_pmc_readl(GPU_RG_CNTRL) & 0x1) == 0; | |
354 | else | |
355 | return (tegra_pmc_readl(PWRGATE_STATUS) & BIT(id)) != 0; | |
0ecf2d33 JH |
356 | } |
357 | ||
0a243bd4 JH |
358 | static inline bool tegra_powergate_is_valid(int id) |
359 | { | |
360 | return (pmc->soc && pmc->soc->powergates[id]); | |
361 | } | |
362 | ||
a3804512 JH |
363 | static inline bool tegra_powergate_is_available(int id) |
364 | { | |
365 | return test_bit(id, pmc->powergates_available); | |
366 | } | |
367 | ||
368 | static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) | |
369 | { | |
370 | unsigned int i; | |
371 | ||
372 | if (!pmc || !pmc->soc || !name) | |
373 | return -EINVAL; | |
374 | ||
375 | for (i = 0; i < pmc->soc->num_powergates; i++) { | |
376 | if (!tegra_powergate_is_valid(i)) | |
377 | continue; | |
378 | ||
379 | if (!strcmp(name, pmc->soc->powergates[i])) | |
380 | return i; | |
381 | } | |
382 | ||
a3804512 JH |
383 | return -ENODEV; |
384 | } | |
385 | ||
7232398a TR |
386 | /** |
387 | * tegra_powergate_set() - set the state of a partition | |
388 | * @id: partition ID | |
389 | * @new_state: new state of the partition | |
390 | */ | |
70293ed0 | 391 | static int tegra_powergate_set(unsigned int id, bool new_state) |
7232398a | 392 | { |
0a2d87e0 JH |
393 | bool status; |
394 | int err; | |
395 | ||
bc9af23d JH |
396 | if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps) |
397 | return -EINVAL; | |
398 | ||
7232398a TR |
399 | mutex_lock(&pmc->powergates_lock); |
400 | ||
0ecf2d33 | 401 | if (tegra_powergate_state(id) == new_state) { |
7232398a TR |
402 | mutex_unlock(&pmc->powergates_lock); |
403 | return 0; | |
404 | } | |
405 | ||
406 | tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); | |
407 | ||
0a2d87e0 JH |
408 | err = readx_poll_timeout(tegra_powergate_state, id, status, |
409 | status == new_state, 10, 100000); | |
410 | ||
7232398a TR |
411 | mutex_unlock(&pmc->powergates_lock); |
412 | ||
0a2d87e0 | 413 | return err; |
7232398a TR |
414 | } |
415 | ||
a3804512 JH |
416 | static int __tegra_powergate_remove_clamping(unsigned int id) |
417 | { | |
418 | u32 mask; | |
419 | ||
420 | mutex_lock(&pmc->powergates_lock); | |
421 | ||
422 | /* | |
423 | * On Tegra124 and later, the clamps for the GPU are controlled by a | |
424 | * separate register (with different semantics). | |
425 | */ | |
426 | if (id == TEGRA_POWERGATE_3D) { | |
427 | if (pmc->soc->has_gpu_clamps) { | |
428 | tegra_pmc_writel(0, GPU_RG_CNTRL); | |
429 | goto out; | |
430 | } | |
431 | } | |
432 | ||
433 | /* | |
434 | * Tegra 2 has a bug where PCIE and VDE clamping masks are | |
435 | * swapped relatively to the partition ids | |
436 | */ | |
437 | if (id == TEGRA_POWERGATE_VDEC) | |
438 | mask = (1 << TEGRA_POWERGATE_PCIE); | |
439 | else if (id == TEGRA_POWERGATE_PCIE) | |
440 | mask = (1 << TEGRA_POWERGATE_VDEC); | |
441 | else | |
442 | mask = (1 << id); | |
443 | ||
444 | tegra_pmc_writel(mask, REMOVE_CLAMPING); | |
445 | ||
446 | out: | |
447 | mutex_unlock(&pmc->powergates_lock); | |
448 | ||
449 | return 0; | |
450 | } | |
451 | ||
452 | static void tegra_powergate_disable_clocks(struct tegra_powergate *pg) | |
453 | { | |
454 | unsigned int i; | |
455 | ||
456 | for (i = 0; i < pg->num_clks; i++) | |
457 | clk_disable_unprepare(pg->clks[i]); | |
458 | } | |
459 | ||
460 | static int tegra_powergate_enable_clocks(struct tegra_powergate *pg) | |
461 | { | |
462 | unsigned int i; | |
463 | int err; | |
464 | ||
465 | for (i = 0; i < pg->num_clks; i++) { | |
466 | err = clk_prepare_enable(pg->clks[i]); | |
467 | if (err) | |
468 | goto out; | |
469 | } | |
470 | ||
471 | return 0; | |
472 | ||
473 | out: | |
474 | while (i--) | |
475 | clk_disable_unprepare(pg->clks[i]); | |
476 | ||
477 | return err; | |
478 | } | |
479 | ||
a263394a PDS |
480 | int __weak tegra210_clk_handle_mbist_war(unsigned int id) |
481 | { | |
482 | return 0; | |
483 | } | |
484 | ||
a3804512 JH |
485 | static int tegra_powergate_power_up(struct tegra_powergate *pg, |
486 | bool disable_clocks) | |
487 | { | |
488 | int err; | |
489 | ||
4c817ccf | 490 | err = reset_control_assert(pg->reset); |
a3804512 JH |
491 | if (err) |
492 | return err; | |
493 | ||
494 | usleep_range(10, 20); | |
495 | ||
496 | err = tegra_powergate_set(pg->id, true); | |
497 | if (err < 0) | |
498 | return err; | |
499 | ||
500 | usleep_range(10, 20); | |
501 | ||
502 | err = tegra_powergate_enable_clocks(pg); | |
503 | if (err) | |
504 | goto disable_clks; | |
505 | ||
506 | usleep_range(10, 20); | |
507 | ||
508 | err = __tegra_powergate_remove_clamping(pg->id); | |
509 | if (err) | |
510 | goto disable_clks; | |
511 | ||
512 | usleep_range(10, 20); | |
513 | ||
4c817ccf | 514 | err = reset_control_deassert(pg->reset); |
a3804512 JH |
515 | if (err) |
516 | goto powergate_off; | |
517 | ||
518 | usleep_range(10, 20); | |
519 | ||
a263394a PDS |
520 | if (pg->pmc->soc->needs_mbist_war) |
521 | err = tegra210_clk_handle_mbist_war(pg->id); | |
522 | if (err) | |
523 | goto disable_clks; | |
524 | ||
a3804512 JH |
525 | if (disable_clocks) |
526 | tegra_powergate_disable_clocks(pg); | |
527 | ||
528 | return 0; | |
529 | ||
530 | disable_clks: | |
531 | tegra_powergate_disable_clocks(pg); | |
532 | usleep_range(10, 20); | |
da8f4b45 | 533 | |
a3804512 JH |
534 | powergate_off: |
535 | tegra_powergate_set(pg->id, false); | |
536 | ||
537 | return err; | |
538 | } | |
539 | ||
540 | static int tegra_powergate_power_down(struct tegra_powergate *pg) | |
541 | { | |
542 | int err; | |
543 | ||
544 | err = tegra_powergate_enable_clocks(pg); | |
545 | if (err) | |
546 | return err; | |
547 | ||
548 | usleep_range(10, 20); | |
549 | ||
4c817ccf | 550 | err = reset_control_assert(pg->reset); |
a3804512 JH |
551 | if (err) |
552 | goto disable_clks; | |
553 | ||
554 | usleep_range(10, 20); | |
555 | ||
556 | tegra_powergate_disable_clocks(pg); | |
557 | ||
558 | usleep_range(10, 20); | |
559 | ||
560 | err = tegra_powergate_set(pg->id, false); | |
561 | if (err) | |
562 | goto assert_resets; | |
563 | ||
564 | return 0; | |
565 | ||
566 | assert_resets: | |
567 | tegra_powergate_enable_clocks(pg); | |
568 | usleep_range(10, 20); | |
4c817ccf | 569 | reset_control_deassert(pg->reset); |
a3804512 | 570 | usleep_range(10, 20); |
da8f4b45 | 571 | |
a3804512 JH |
572 | disable_clks: |
573 | tegra_powergate_disable_clocks(pg); | |
574 | ||
575 | return err; | |
576 | } | |
577 | ||
578 | static int tegra_genpd_power_on(struct generic_pm_domain *domain) | |
579 | { | |
580 | struct tegra_powergate *pg = to_powergate(domain); | |
a3804512 JH |
581 | int err; |
582 | ||
583 | err = tegra_powergate_power_up(pg, true); | |
584 | if (err) | |
54e24721 TR |
585 | pr_err("failed to turn on PM domain %s: %d\n", pg->genpd.name, |
586 | err); | |
a3804512 JH |
587 | |
588 | return err; | |
589 | } | |
590 | ||
591 | static int tegra_genpd_power_off(struct generic_pm_domain *domain) | |
592 | { | |
593 | struct tegra_powergate *pg = to_powergate(domain); | |
a3804512 JH |
594 | int err; |
595 | ||
596 | err = tegra_powergate_power_down(pg); | |
597 | if (err) | |
54e24721 TR |
598 | pr_err("failed to turn off PM domain %s: %d\n", |
599 | pg->genpd.name, err); | |
a3804512 JH |
600 | |
601 | return err; | |
602 | } | |
603 | ||
7232398a TR |
604 | /** |
605 | * tegra_powergate_power_on() - power on partition | |
606 | * @id: partition ID | |
607 | */ | |
70293ed0 | 608 | int tegra_powergate_power_on(unsigned int id) |
7232398a | 609 | { |
a3804512 | 610 | if (!tegra_powergate_is_available(id)) |
7232398a TR |
611 | return -EINVAL; |
612 | ||
613 | return tegra_powergate_set(id, true); | |
614 | } | |
615 | ||
616 | /** | |
617 | * tegra_powergate_power_off() - power off partition | |
618 | * @id: partition ID | |
619 | */ | |
70293ed0 | 620 | int tegra_powergate_power_off(unsigned int id) |
7232398a | 621 | { |
a3804512 | 622 | if (!tegra_powergate_is_available(id)) |
7232398a TR |
623 | return -EINVAL; |
624 | ||
625 | return tegra_powergate_set(id, false); | |
626 | } | |
627 | EXPORT_SYMBOL(tegra_powergate_power_off); | |
628 | ||
629 | /** | |
630 | * tegra_powergate_is_powered() - check if partition is powered | |
631 | * @id: partition ID | |
632 | */ | |
70293ed0 | 633 | int tegra_powergate_is_powered(unsigned int id) |
7232398a | 634 | { |
0a243bd4 | 635 | if (!tegra_powergate_is_valid(id)) |
7232398a TR |
636 | return -EINVAL; |
637 | ||
b6e1fd17 | 638 | return tegra_powergate_state(id); |
7232398a TR |
639 | } |
640 | ||
641 | /** | |
642 | * tegra_powergate_remove_clamping() - remove power clamps for partition | |
643 | * @id: partition ID | |
644 | */ | |
70293ed0 | 645 | int tegra_powergate_remove_clamping(unsigned int id) |
7232398a | 646 | { |
a3804512 | 647 | if (!tegra_powergate_is_available(id)) |
7232398a TR |
648 | return -EINVAL; |
649 | ||
a3804512 | 650 | return __tegra_powergate_remove_clamping(id); |
7232398a TR |
651 | } |
652 | EXPORT_SYMBOL(tegra_powergate_remove_clamping); | |
653 | ||
654 | /** | |
655 | * tegra_powergate_sequence_power_up() - power up partition | |
656 | * @id: partition ID | |
657 | * @clk: clock for partition | |
658 | * @rst: reset for partition | |
659 | * | |
660 | * Must be called with clk disabled, and returns with clk enabled. | |
661 | */ | |
70293ed0 | 662 | int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, |
7232398a TR |
663 | struct reset_control *rst) |
664 | { | |
495ac33a | 665 | struct tegra_powergate *pg; |
a3804512 | 666 | int err; |
7232398a | 667 | |
403db2d2 JH |
668 | if (!tegra_powergate_is_available(id)) |
669 | return -EINVAL; | |
670 | ||
495ac33a VK |
671 | pg = kzalloc(sizeof(*pg), GFP_KERNEL); |
672 | if (!pg) | |
673 | return -ENOMEM; | |
7232398a | 674 | |
495ac33a VK |
675 | pg->id = id; |
676 | pg->clks = &clk; | |
677 | pg->num_clks = 1; | |
678 | pg->reset = rst; | |
679 | pg->pmc = pmc; | |
680 | ||
681 | err = tegra_powergate_power_up(pg, false); | |
a3804512 JH |
682 | if (err) |
683 | pr_err("failed to turn on partition %d: %d\n", id, err); | |
7232398a | 684 | |
495ac33a VK |
685 | kfree(pg); |
686 | ||
a3804512 | 687 | return err; |
7232398a TR |
688 | } |
689 | EXPORT_SYMBOL(tegra_powergate_sequence_power_up); | |
690 | ||
691 | #ifdef CONFIG_SMP | |
692 | /** | |
693 | * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID | |
694 | * @cpuid: CPU partition ID | |
695 | * | |
696 | * Returns the partition ID corresponding to the CPU partition ID or a | |
697 | * negative error code on failure. | |
698 | */ | |
70293ed0 | 699 | static int tegra_get_cpu_powergate_id(unsigned int cpuid) |
7232398a | 700 | { |
70293ed0 | 701 | if (pmc->soc && cpuid < pmc->soc->num_cpu_powergates) |
7232398a TR |
702 | return pmc->soc->cpu_powergates[cpuid]; |
703 | ||
704 | return -EINVAL; | |
705 | } | |
706 | ||
707 | /** | |
708 | * tegra_pmc_cpu_is_powered() - check if CPU partition is powered | |
709 | * @cpuid: CPU partition ID | |
710 | */ | |
70293ed0 | 711 | bool tegra_pmc_cpu_is_powered(unsigned int cpuid) |
7232398a TR |
712 | { |
713 | int id; | |
714 | ||
715 | id = tegra_get_cpu_powergate_id(cpuid); | |
716 | if (id < 0) | |
717 | return false; | |
718 | ||
719 | return tegra_powergate_is_powered(id); | |
720 | } | |
721 | ||
722 | /** | |
723 | * tegra_pmc_cpu_power_on() - power on CPU partition | |
724 | * @cpuid: CPU partition ID | |
725 | */ | |
70293ed0 | 726 | int tegra_pmc_cpu_power_on(unsigned int cpuid) |
7232398a TR |
727 | { |
728 | int id; | |
729 | ||
730 | id = tegra_get_cpu_powergate_id(cpuid); | |
731 | if (id < 0) | |
732 | return id; | |
733 | ||
734 | return tegra_powergate_set(id, true); | |
735 | } | |
736 | ||
737 | /** | |
738 | * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition | |
739 | * @cpuid: CPU partition ID | |
740 | */ | |
70293ed0 | 741 | int tegra_pmc_cpu_remove_clamping(unsigned int cpuid) |
7232398a TR |
742 | { |
743 | int id; | |
744 | ||
745 | id = tegra_get_cpu_powergate_id(cpuid); | |
746 | if (id < 0) | |
747 | return id; | |
748 | ||
749 | return tegra_powergate_remove_clamping(id); | |
750 | } | |
751 | #endif /* CONFIG_SMP */ | |
752 | ||
7892158a DR |
753 | static int tegra_pmc_restart_notify(struct notifier_block *this, |
754 | unsigned long action, void *data) | |
7232398a | 755 | { |
7892158a | 756 | const char *cmd = data; |
7232398a TR |
757 | u32 value; |
758 | ||
5be22556 | 759 | value = readl(pmc->scratch + pmc->soc->regs->scratch0); |
7232398a TR |
760 | value &= ~PMC_SCRATCH0_MODE_MASK; |
761 | ||
762 | if (cmd) { | |
763 | if (strcmp(cmd, "recovery") == 0) | |
764 | value |= PMC_SCRATCH0_MODE_RECOVERY; | |
765 | ||
766 | if (strcmp(cmd, "bootloader") == 0) | |
767 | value |= PMC_SCRATCH0_MODE_BOOTLOADER; | |
768 | ||
769 | if (strcmp(cmd, "forced-recovery") == 0) | |
770 | value |= PMC_SCRATCH0_MODE_RCM; | |
771 | } | |
772 | ||
5be22556 | 773 | writel(value, pmc->scratch + pmc->soc->regs->scratch0); |
7232398a | 774 | |
f5353c60 TR |
775 | /* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */ |
776 | value = tegra_pmc_readl(PMC_CNTRL); | |
777 | value |= PMC_CNTRL_MAIN_RST; | |
778 | tegra_pmc_writel(value, PMC_CNTRL); | |
7892158a DR |
779 | |
780 | return NOTIFY_DONE; | |
7232398a TR |
781 | } |
782 | ||
7892158a DR |
783 | static struct notifier_block tegra_pmc_restart_handler = { |
784 | .notifier_call = tegra_pmc_restart_notify, | |
785 | .priority = 128, | |
786 | }; | |
787 | ||
7232398a TR |
788 | static int powergate_show(struct seq_file *s, void *data) |
789 | { | |
790 | unsigned int i; | |
c3ea2972 | 791 | int status; |
7232398a TR |
792 | |
793 | seq_printf(s, " powergate powered\n"); | |
794 | seq_printf(s, "------------------\n"); | |
795 | ||
796 | for (i = 0; i < pmc->soc->num_powergates; i++) { | |
c3ea2972 JH |
797 | status = tegra_powergate_is_powered(i); |
798 | if (status < 0) | |
7232398a TR |
799 | continue; |
800 | ||
801 | seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i], | |
c3ea2972 | 802 | status ? "yes" : "no"); |
7232398a TR |
803 | } |
804 | ||
805 | return 0; | |
806 | } | |
807 | ||
57ba33d5 | 808 | DEFINE_SHOW_ATTRIBUTE(powergate); |
7232398a TR |
809 | |
810 | static int tegra_powergate_debugfs_init(void) | |
811 | { | |
3195ac6d JH |
812 | pmc->debugfs = debugfs_create_file("powergate", S_IRUGO, NULL, NULL, |
813 | &powergate_fops); | |
814 | if (!pmc->debugfs) | |
7232398a TR |
815 | return -ENOMEM; |
816 | ||
817 | return 0; | |
818 | } | |
819 | ||
a3804512 JH |
820 | static int tegra_powergate_of_get_clks(struct tegra_powergate *pg, |
821 | struct device_node *np) | |
822 | { | |
823 | struct clk *clk; | |
824 | unsigned int i, count; | |
825 | int err; | |
826 | ||
3fd0121b | 827 | count = of_clk_get_parent_count(np); |
a3804512 JH |
828 | if (count == 0) |
829 | return -ENODEV; | |
830 | ||
831 | pg->clks = kcalloc(count, sizeof(clk), GFP_KERNEL); | |
832 | if (!pg->clks) | |
833 | return -ENOMEM; | |
834 | ||
835 | for (i = 0; i < count; i++) { | |
836 | pg->clks[i] = of_clk_get(np, i); | |
837 | if (IS_ERR(pg->clks[i])) { | |
838 | err = PTR_ERR(pg->clks[i]); | |
839 | goto err; | |
840 | } | |
841 | } | |
842 | ||
843 | pg->num_clks = count; | |
844 | ||
845 | return 0; | |
846 | ||
847 | err: | |
848 | while (i--) | |
849 | clk_put(pg->clks[i]); | |
da8f4b45 | 850 | |
a3804512 JH |
851 | kfree(pg->clks); |
852 | ||
853 | return err; | |
854 | } | |
855 | ||
856 | static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, | |
05cfb988 | 857 | struct device_node *np, bool off) |
a3804512 | 858 | { |
a3804512 JH |
859 | int err; |
860 | ||
4c817ccf VG |
861 | pg->reset = of_reset_control_array_get_exclusive(np); |
862 | if (IS_ERR(pg->reset)) { | |
863 | err = PTR_ERR(pg->reset); | |
864 | pr_err("failed to get device resets: %d\n", err); | |
865 | return err; | |
a3804512 JH |
866 | } |
867 | ||
4c817ccf VG |
868 | if (off) |
869 | err = reset_control_assert(pg->reset); | |
870 | else | |
871 | err = reset_control_deassert(pg->reset); | |
da8f4b45 | 872 | |
4c817ccf VG |
873 | if (err) |
874 | reset_control_put(pg->reset); | |
a3804512 JH |
875 | |
876 | return err; | |
877 | } | |
878 | ||
879 | static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) | |
880 | { | |
881 | struct tegra_powergate *pg; | |
c2710ac9 | 882 | int id, err; |
a3804512 | 883 | bool off; |
a3804512 JH |
884 | |
885 | pg = kzalloc(sizeof(*pg), GFP_KERNEL); | |
886 | if (!pg) | |
c2710ac9 | 887 | return; |
a3804512 JH |
888 | |
889 | id = tegra_powergate_lookup(pmc, np->name); | |
c2710ac9 | 890 | if (id < 0) { |
dc37a252 | 891 | pr_err("powergate lookup failed for %pOFn: %d\n", np, id); |
a3804512 | 892 | goto free_mem; |
c2710ac9 | 893 | } |
a3804512 JH |
894 | |
895 | /* | |
896 | * Clear the bit for this powergate so it cannot be managed | |
897 | * directly via the legacy APIs for controlling powergates. | |
898 | */ | |
899 | clear_bit(id, pmc->powergates_available); | |
900 | ||
901 | pg->id = id; | |
902 | pg->genpd.name = np->name; | |
903 | pg->genpd.power_off = tegra_genpd_power_off; | |
904 | pg->genpd.power_on = tegra_genpd_power_on; | |
905 | pg->pmc = pmc; | |
906 | ||
05cfb988 JH |
907 | off = !tegra_powergate_is_powered(pg->id); |
908 | ||
c2710ac9 JH |
909 | err = tegra_powergate_of_get_clks(pg, np); |
910 | if (err < 0) { | |
dc37a252 | 911 | pr_err("failed to get clocks for %pOFn: %d\n", np, err); |
a3804512 | 912 | goto set_available; |
c2710ac9 | 913 | } |
a3804512 | 914 | |
c2710ac9 JH |
915 | err = tegra_powergate_of_get_resets(pg, np, off); |
916 | if (err < 0) { | |
dc37a252 | 917 | pr_err("failed to get resets for %pOFn: %d\n", np, err); |
a3804512 | 918 | goto remove_clks; |
c2710ac9 | 919 | } |
a3804512 | 920 | |
0b137340 JH |
921 | if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { |
922 | if (off) | |
923 | WARN_ON(tegra_powergate_power_up(pg, true)); | |
924 | ||
925 | goto remove_resets; | |
926 | } | |
e2d17960 | 927 | |
cd5ceda2 JH |
928 | err = pm_genpd_init(&pg->genpd, NULL, off); |
929 | if (err < 0) { | |
dc37a252 | 930 | pr_err("failed to initialise PM domain %pOFn: %d\n", np, |
cd5ceda2 JH |
931 | err); |
932 | goto remove_resets; | |
933 | } | |
a3804512 | 934 | |
c2710ac9 JH |
935 | err = of_genpd_add_provider_simple(np, &pg->genpd); |
936 | if (err < 0) { | |
dc37a252 RH |
937 | pr_err("failed to add PM domain provider for %pOFn: %d\n", |
938 | np, err); | |
0b137340 | 939 | goto remove_genpd; |
c2710ac9 | 940 | } |
a3804512 | 941 | |
45221120 | 942 | pr_debug("added PM domain %s\n", pg->genpd.name); |
a3804512 JH |
943 | |
944 | return; | |
945 | ||
0b137340 JH |
946 | remove_genpd: |
947 | pm_genpd_remove(&pg->genpd); | |
e2d17960 | 948 | |
a3804512 | 949 | remove_resets: |
4c817ccf | 950 | reset_control_put(pg->reset); |
a3804512 JH |
951 | |
952 | remove_clks: | |
953 | while (pg->num_clks--) | |
954 | clk_put(pg->clks[pg->num_clks]); | |
da8f4b45 | 955 | |
a3804512 JH |
956 | kfree(pg->clks); |
957 | ||
958 | set_available: | |
959 | set_bit(id, pmc->powergates_available); | |
960 | ||
961 | free_mem: | |
962 | kfree(pg); | |
a3804512 JH |
963 | } |
964 | ||
e2d17960 JH |
965 | static void tegra_powergate_init(struct tegra_pmc *pmc, |
966 | struct device_node *parent) | |
a3804512 JH |
967 | { |
968 | struct device_node *np, *child; | |
e2d17960 | 969 | unsigned int i; |
a3804512 | 970 | |
e2d17960 JH |
971 | /* Create a bitmap of the available and valid partitions */ |
972 | for (i = 0; i < pmc->soc->num_powergates; i++) | |
973 | if (pmc->soc->powergates[i]) | |
974 | set_bit(i, pmc->powergates_available); | |
975 | ||
976 | np = of_get_child_by_name(parent, "powergates"); | |
a3804512 JH |
977 | if (!np) |
978 | return; | |
979 | ||
0c106e57 | 980 | for_each_child_of_node(np, child) |
a3804512 | 981 | tegra_powergate_add(pmc, child); |
a3804512 JH |
982 | |
983 | of_node_put(np); | |
984 | } | |
985 | ||
21b49910 LD |
986 | static const struct tegra_io_pad_soc * |
987 | tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id) | |
988 | { | |
989 | unsigned int i; | |
990 | ||
991 | for (i = 0; i < pmc->soc->num_io_pads; i++) | |
992 | if (pmc->soc->io_pads[i].id == id) | |
993 | return &pmc->soc->io_pads[i]; | |
994 | ||
995 | return NULL; | |
996 | } | |
997 | ||
00ead3c9 AV |
998 | static int tegra_io_pad_get_dpd_register_bit(enum tegra_io_pad id, |
999 | unsigned long *request, | |
1000 | unsigned long *status, | |
1001 | u32 *mask) | |
7232398a | 1002 | { |
21b49910 | 1003 | const struct tegra_io_pad_soc *pad; |
7232398a | 1004 | |
21b49910 | 1005 | pad = tegra_io_pad_find(pmc, id); |
54e24721 TR |
1006 | if (!pad) { |
1007 | pr_err("invalid I/O pad ID %u\n", id); | |
21b49910 | 1008 | return -ENOENT; |
54e24721 | 1009 | } |
7232398a | 1010 | |
21b49910 LD |
1011 | if (pad->dpd == UINT_MAX) |
1012 | return -ENOTSUPP; | |
7232398a | 1013 | |
27b12b4e | 1014 | *mask = BIT(pad->dpd % 32); |
21b49910 LD |
1015 | |
1016 | if (pad->dpd < 32) { | |
5be22556 TR |
1017 | *status = pmc->soc->regs->dpd_status; |
1018 | *request = pmc->soc->regs->dpd_req; | |
7232398a | 1019 | } else { |
5be22556 TR |
1020 | *status = pmc->soc->regs->dpd2_status; |
1021 | *request = pmc->soc->regs->dpd2_req; | |
7232398a TR |
1022 | } |
1023 | ||
00ead3c9 AV |
1024 | return 0; |
1025 | } | |
1026 | ||
1027 | static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, | |
1028 | unsigned long *status, u32 *mask) | |
1029 | { | |
1030 | unsigned long rate, value; | |
1031 | int err; | |
1032 | ||
1033 | err = tegra_io_pad_get_dpd_register_bit(id, request, status, mask); | |
1034 | if (err) | |
1035 | return err; | |
1036 | ||
5be22556 TR |
1037 | if (pmc->clk) { |
1038 | rate = clk_get_rate(pmc->clk); | |
1039 | if (!rate) { | |
1040 | pr_err("failed to get clock rate\n"); | |
1041 | return -ENODEV; | |
1042 | } | |
7232398a | 1043 | |
5be22556 | 1044 | tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE); |
7232398a | 1045 | |
5be22556 TR |
1046 | /* must be at least 200 ns, in APB (PCLK) clock cycles */ |
1047 | value = DIV_ROUND_UP(1000000000, rate); | |
1048 | value = DIV_ROUND_UP(200, value); | |
1049 | tegra_pmc_writel(value, SEL_DPD_TIM); | |
1050 | } | |
7232398a TR |
1051 | |
1052 | return 0; | |
1053 | } | |
1054 | ||
21b49910 LD |
1055 | static int tegra_io_pad_poll(unsigned long offset, u32 mask, |
1056 | u32 val, unsigned long timeout) | |
7232398a | 1057 | { |
84cf85ea | 1058 | u32 value; |
7232398a TR |
1059 | |
1060 | timeout = jiffies + msecs_to_jiffies(timeout); | |
1061 | ||
1062 | while (time_after(timeout, jiffies)) { | |
1063 | value = tegra_pmc_readl(offset); | |
1064 | if ((value & mask) == val) | |
1065 | return 0; | |
1066 | ||
1067 | usleep_range(250, 1000); | |
1068 | } | |
1069 | ||
1070 | return -ETIMEDOUT; | |
1071 | } | |
1072 | ||
21b49910 | 1073 | static void tegra_io_pad_unprepare(void) |
7232398a | 1074 | { |
5be22556 TR |
1075 | if (pmc->clk) |
1076 | tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); | |
7232398a TR |
1077 | } |
1078 | ||
21b49910 LD |
1079 | /** |
1080 | * tegra_io_pad_power_enable() - enable power to I/O pad | |
1081 | * @id: Tegra I/O pad ID for which to enable power | |
1082 | * | |
1083 | * Returns: 0 on success or a negative error code on failure. | |
1084 | */ | |
1085 | int tegra_io_pad_power_enable(enum tegra_io_pad id) | |
7232398a | 1086 | { |
a9ccc123 | 1087 | unsigned long request, status; |
27b12b4e | 1088 | u32 mask; |
7232398a TR |
1089 | int err; |
1090 | ||
e8cf6616 JH |
1091 | mutex_lock(&pmc->powergates_lock); |
1092 | ||
27b12b4e | 1093 | err = tegra_io_pad_prepare(id, &request, &status, &mask); |
21b49910 | 1094 | if (err < 0) { |
54e24721 | 1095 | pr_err("failed to prepare I/O pad: %d\n", err); |
21b49910 LD |
1096 | goto unlock; |
1097 | } | |
7232398a | 1098 | |
27b12b4e | 1099 | tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | mask, request); |
7232398a | 1100 | |
27b12b4e | 1101 | err = tegra_io_pad_poll(status, mask, 0, 250); |
21b49910 | 1102 | if (err < 0) { |
54e24721 | 1103 | pr_err("failed to enable I/O pad: %d\n", err); |
21b49910 | 1104 | goto unlock; |
592431b0 | 1105 | } |
7232398a | 1106 | |
21b49910 | 1107 | tegra_io_pad_unprepare(); |
7232398a | 1108 | |
21b49910 | 1109 | unlock: |
e8cf6616 | 1110 | mutex_unlock(&pmc->powergates_lock); |
e8cf6616 | 1111 | return err; |
7232398a | 1112 | } |
21b49910 | 1113 | EXPORT_SYMBOL(tegra_io_pad_power_enable); |
7232398a | 1114 | |
21b49910 LD |
1115 | /** |
1116 | * tegra_io_pad_power_disable() - disable power to I/O pad | |
1117 | * @id: Tegra I/O pad ID for which to disable power | |
1118 | * | |
1119 | * Returns: 0 on success or a negative error code on failure. | |
1120 | */ | |
1121 | int tegra_io_pad_power_disable(enum tegra_io_pad id) | |
7232398a | 1122 | { |
a9ccc123 | 1123 | unsigned long request, status; |
27b12b4e | 1124 | u32 mask; |
7232398a TR |
1125 | int err; |
1126 | ||
e8cf6616 JH |
1127 | mutex_lock(&pmc->powergates_lock); |
1128 | ||
27b12b4e | 1129 | err = tegra_io_pad_prepare(id, &request, &status, &mask); |
21b49910 | 1130 | if (err < 0) { |
54e24721 | 1131 | pr_err("failed to prepare I/O pad: %d\n", err); |
21b49910 | 1132 | goto unlock; |
592431b0 | 1133 | } |
7232398a | 1134 | |
27b12b4e | 1135 | tegra_pmc_writel(IO_DPD_REQ_CODE_ON | mask, request); |
7232398a | 1136 | |
27b12b4e | 1137 | err = tegra_io_pad_poll(status, mask, mask, 250); |
21b49910 | 1138 | if (err < 0) { |
54e24721 | 1139 | pr_err("failed to disable I/O pad: %d\n", err); |
21b49910 LD |
1140 | goto unlock; |
1141 | } | |
7232398a | 1142 | |
21b49910 | 1143 | tegra_io_pad_unprepare(); |
7232398a | 1144 | |
21b49910 | 1145 | unlock: |
e8cf6616 | 1146 | mutex_unlock(&pmc->powergates_lock); |
e8cf6616 | 1147 | return err; |
7232398a | 1148 | } |
21b49910 LD |
1149 | EXPORT_SYMBOL(tegra_io_pad_power_disable); |
1150 | ||
f142b9d6 AV |
1151 | static int tegra_io_pad_is_powered(enum tegra_io_pad id) |
1152 | { | |
1153 | unsigned long request, status; | |
1154 | u32 mask, value; | |
1155 | int err; | |
1156 | ||
1157 | err = tegra_io_pad_get_dpd_register_bit(id, &request, &status, &mask); | |
1158 | if (err) | |
1159 | return err; | |
1160 | ||
1161 | value = tegra_pmc_readl(status); | |
1162 | ||
1163 | return !(value & mask); | |
1164 | } | |
1165 | ||
fccf0f76 | 1166 | static int tegra_io_pad_set_voltage(enum tegra_io_pad id, int voltage) |
21b49910 LD |
1167 | { |
1168 | const struct tegra_io_pad_soc *pad; | |
1169 | u32 value; | |
1170 | ||
1171 | pad = tegra_io_pad_find(pmc, id); | |
1172 | if (!pad) | |
1173 | return -ENOENT; | |
1174 | ||
1175 | if (pad->voltage == UINT_MAX) | |
1176 | return -ENOTSUPP; | |
1177 | ||
1178 | mutex_lock(&pmc->powergates_lock); | |
1179 | ||
13136a47 AV |
1180 | if (pmc->soc->has_impl_33v_pwr) { |
1181 | value = tegra_pmc_readl(PMC_IMPL_E_33V_PWR); | |
21b49910 | 1182 | |
fccf0f76 | 1183 | if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8) |
13136a47 AV |
1184 | value &= ~BIT(pad->voltage); |
1185 | else | |
1186 | value |= BIT(pad->voltage); | |
21b49910 | 1187 | |
13136a47 AV |
1188 | tegra_pmc_writel(value, PMC_IMPL_E_33V_PWR); |
1189 | } else { | |
1190 | /* write-enable PMC_PWR_DET_VALUE[pad->voltage] */ | |
1191 | value = tegra_pmc_readl(PMC_PWR_DET); | |
21b49910 | 1192 | value |= BIT(pad->voltage); |
13136a47 | 1193 | tegra_pmc_writel(value, PMC_PWR_DET); |
21b49910 | 1194 | |
13136a47 AV |
1195 | /* update I/O voltage */ |
1196 | value = tegra_pmc_readl(PMC_PWR_DET_VALUE); | |
21b49910 | 1197 | |
fccf0f76 | 1198 | if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8) |
13136a47 AV |
1199 | value &= ~BIT(pad->voltage); |
1200 | else | |
1201 | value |= BIT(pad->voltage); | |
1202 | ||
1203 | tegra_pmc_writel(value, PMC_PWR_DET_VALUE); | |
1204 | } | |
21b49910 LD |
1205 | |
1206 | mutex_unlock(&pmc->powergates_lock); | |
1207 | ||
1208 | usleep_range(100, 250); | |
1209 | ||
1210 | return 0; | |
1211 | } | |
21b49910 | 1212 | |
fccf0f76 | 1213 | static int tegra_io_pad_get_voltage(enum tegra_io_pad id) |
21b49910 LD |
1214 | { |
1215 | const struct tegra_io_pad_soc *pad; | |
1216 | u32 value; | |
1217 | ||
1218 | pad = tegra_io_pad_find(pmc, id); | |
1219 | if (!pad) | |
1220 | return -ENOENT; | |
1221 | ||
1222 | if (pad->voltage == UINT_MAX) | |
1223 | return -ENOTSUPP; | |
1224 | ||
13136a47 AV |
1225 | if (pmc->soc->has_impl_33v_pwr) |
1226 | value = tegra_pmc_readl(PMC_IMPL_E_33V_PWR); | |
1227 | else | |
1228 | value = tegra_pmc_readl(PMC_PWR_DET_VALUE); | |
21b49910 LD |
1229 | |
1230 | if ((value & BIT(pad->voltage)) == 0) | |
fccf0f76 | 1231 | return TEGRA_IO_PAD_VOLTAGE_1V8; |
21b49910 | 1232 | |
fccf0f76 | 1233 | return TEGRA_IO_PAD_VOLTAGE_3V3; |
21b49910 | 1234 | } |
21b49910 LD |
1235 | |
1236 | /** | |
1237 | * tegra_io_rail_power_on() - enable power to I/O rail | |
1238 | * @id: Tegra I/O pad ID for which to enable power | |
1239 | * | |
1240 | * See also: tegra_io_pad_power_enable() | |
1241 | */ | |
1242 | int tegra_io_rail_power_on(unsigned int id) | |
1243 | { | |
1244 | return tegra_io_pad_power_enable(id); | |
1245 | } | |
1246 | EXPORT_SYMBOL(tegra_io_rail_power_on); | |
1247 | ||
1248 | /** | |
1249 | * tegra_io_rail_power_off() - disable power to I/O rail | |
1250 | * @id: Tegra I/O pad ID for which to disable power | |
1251 | * | |
1252 | * See also: tegra_io_pad_power_disable() | |
1253 | */ | |
1254 | int tegra_io_rail_power_off(unsigned int id) | |
1255 | { | |
1256 | return tegra_io_pad_power_disable(id); | |
1257 | } | |
7232398a TR |
1258 | EXPORT_SYMBOL(tegra_io_rail_power_off); |
1259 | ||
1260 | #ifdef CONFIG_PM_SLEEP | |
1261 | enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void) | |
1262 | { | |
1263 | return pmc->suspend_mode; | |
1264 | } | |
1265 | ||
1266 | void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode) | |
1267 | { | |
1268 | if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE) | |
1269 | return; | |
1270 | ||
1271 | pmc->suspend_mode = mode; | |
1272 | } | |
1273 | ||
1274 | void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode) | |
1275 | { | |
1276 | unsigned long long rate = 0; | |
1277 | u32 value; | |
1278 | ||
1279 | switch (mode) { | |
1280 | case TEGRA_SUSPEND_LP1: | |
1281 | rate = 32768; | |
1282 | break; | |
1283 | ||
1284 | case TEGRA_SUSPEND_LP2: | |
1285 | rate = clk_get_rate(pmc->clk); | |
1286 | break; | |
1287 | ||
1288 | default: | |
1289 | break; | |
1290 | } | |
1291 | ||
1292 | if (WARN_ON_ONCE(rate == 0)) | |
1293 | rate = 100000000; | |
1294 | ||
1295 | if (rate != pmc->rate) { | |
1296 | u64 ticks; | |
1297 | ||
1298 | ticks = pmc->cpu_good_time * rate + USEC_PER_SEC - 1; | |
1299 | do_div(ticks, USEC_PER_SEC); | |
1300 | tegra_pmc_writel(ticks, PMC_CPUPWRGOOD_TIMER); | |
1301 | ||
1302 | ticks = pmc->cpu_off_time * rate + USEC_PER_SEC - 1; | |
1303 | do_div(ticks, USEC_PER_SEC); | |
1304 | tegra_pmc_writel(ticks, PMC_CPUPWROFF_TIMER); | |
1305 | ||
1306 | wmb(); | |
1307 | ||
1308 | pmc->rate = rate; | |
1309 | } | |
1310 | ||
1311 | value = tegra_pmc_readl(PMC_CNTRL); | |
1312 | value &= ~PMC_CNTRL_SIDE_EFFECT_LP0; | |
1313 | value |= PMC_CNTRL_CPU_PWRREQ_OE; | |
1314 | tegra_pmc_writel(value, PMC_CNTRL); | |
1315 | } | |
1316 | #endif | |
1317 | ||
1318 | static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np) | |
1319 | { | |
1320 | u32 value, values[2]; | |
1321 | ||
1322 | if (of_property_read_u32(np, "nvidia,suspend-mode", &value)) { | |
1323 | } else { | |
1324 | switch (value) { | |
1325 | case 0: | |
1326 | pmc->suspend_mode = TEGRA_SUSPEND_LP0; | |
1327 | break; | |
1328 | ||
1329 | case 1: | |
1330 | pmc->suspend_mode = TEGRA_SUSPEND_LP1; | |
1331 | break; | |
1332 | ||
1333 | case 2: | |
1334 | pmc->suspend_mode = TEGRA_SUSPEND_LP2; | |
1335 | break; | |
1336 | ||
1337 | default: | |
1338 | pmc->suspend_mode = TEGRA_SUSPEND_NONE; | |
1339 | break; | |
1340 | } | |
1341 | } | |
1342 | ||
1343 | pmc->suspend_mode = tegra_pm_validate_suspend_mode(pmc->suspend_mode); | |
1344 | ||
1345 | if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &value)) | |
1346 | pmc->suspend_mode = TEGRA_SUSPEND_NONE; | |
1347 | ||
1348 | pmc->cpu_good_time = value; | |
1349 | ||
1350 | if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &value)) | |
1351 | pmc->suspend_mode = TEGRA_SUSPEND_NONE; | |
1352 | ||
1353 | pmc->cpu_off_time = value; | |
1354 | ||
1355 | if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time", | |
1356 | values, ARRAY_SIZE(values))) | |
1357 | pmc->suspend_mode = TEGRA_SUSPEND_NONE; | |
1358 | ||
1359 | pmc->core_osc_time = values[0]; | |
1360 | pmc->core_pmu_time = values[1]; | |
1361 | ||
1362 | if (of_property_read_u32(np, "nvidia,core-pwr-off-time", &value)) | |
1363 | pmc->suspend_mode = TEGRA_SUSPEND_NONE; | |
1364 | ||
1365 | pmc->core_off_time = value; | |
1366 | ||
1367 | pmc->corereq_high = of_property_read_bool(np, | |
1368 | "nvidia,core-power-req-active-high"); | |
1369 | ||
1370 | pmc->sysclkreq_high = of_property_read_bool(np, | |
1371 | "nvidia,sys-clock-req-active-high"); | |
1372 | ||
1373 | pmc->combined_req = of_property_read_bool(np, | |
1374 | "nvidia,combined-power-req"); | |
1375 | ||
1376 | pmc->cpu_pwr_good_en = of_property_read_bool(np, | |
1377 | "nvidia,cpu-pwr-good-en"); | |
1378 | ||
1379 | if (of_property_read_u32_array(np, "nvidia,lp0-vec", values, | |
1380 | ARRAY_SIZE(values))) | |
1381 | if (pmc->suspend_mode == TEGRA_SUSPEND_LP0) | |
1382 | pmc->suspend_mode = TEGRA_SUSPEND_LP1; | |
1383 | ||
1384 | pmc->lp0_vec_phys = values[0]; | |
1385 | pmc->lp0_vec_size = values[1]; | |
1386 | ||
1387 | return 0; | |
1388 | } | |
1389 | ||
1390 | static void tegra_pmc_init(struct tegra_pmc *pmc) | |
1391 | { | |
5be22556 TR |
1392 | if (pmc->soc->init) |
1393 | pmc->soc->init(pmc); | |
7232398a TR |
1394 | } |
1395 | ||
1e52efdf | 1396 | static void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc) |
3568df3d MP |
1397 | { |
1398 | static const char disabled[] = "emergency thermal reset disabled"; | |
1399 | u32 pmu_addr, ctrl_id, reg_addr, reg_data, pinmux; | |
1400 | struct device *dev = pmc->dev; | |
1401 | struct device_node *np; | |
1402 | u32 value, checksum; | |
1403 | ||
1404 | if (!pmc->soc->has_tsense_reset) | |
95169cd2 | 1405 | return; |
3568df3d | 1406 | |
1dc6bd5e | 1407 | np = of_get_child_by_name(pmc->dev->of_node, "i2c-thermtrip"); |
3568df3d MP |
1408 | if (!np) { |
1409 | dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled); | |
95169cd2 | 1410 | return; |
3568df3d MP |
1411 | } |
1412 | ||
1413 | if (of_property_read_u32(np, "nvidia,i2c-controller-id", &ctrl_id)) { | |
1414 | dev_err(dev, "I2C controller ID missing, %s.\n", disabled); | |
1415 | goto out; | |
1416 | } | |
1417 | ||
1418 | if (of_property_read_u32(np, "nvidia,bus-addr", &pmu_addr)) { | |
1419 | dev_err(dev, "nvidia,bus-addr missing, %s.\n", disabled); | |
1420 | goto out; | |
1421 | } | |
1422 | ||
1423 | if (of_property_read_u32(np, "nvidia,reg-addr", ®_addr)) { | |
1424 | dev_err(dev, "nvidia,reg-addr missing, %s.\n", disabled); | |
1425 | goto out; | |
1426 | } | |
1427 | ||
1428 | if (of_property_read_u32(np, "nvidia,reg-data", ®_data)) { | |
1429 | dev_err(dev, "nvidia,reg-data missing, %s.\n", disabled); | |
1430 | goto out; | |
1431 | } | |
1432 | ||
1433 | if (of_property_read_u32(np, "nvidia,pinmux-id", &pinmux)) | |
1434 | pinmux = 0; | |
1435 | ||
1436 | value = tegra_pmc_readl(PMC_SENSOR_CTRL); | |
1437 | value |= PMC_SENSOR_CTRL_SCRATCH_WRITE; | |
1438 | tegra_pmc_writel(value, PMC_SENSOR_CTRL); | |
1439 | ||
1440 | value = (reg_data << PMC_SCRATCH54_DATA_SHIFT) | | |
1441 | (reg_addr << PMC_SCRATCH54_ADDR_SHIFT); | |
1442 | tegra_pmc_writel(value, PMC_SCRATCH54); | |
1443 | ||
1444 | value = PMC_SCRATCH55_RESET_TEGRA; | |
1445 | value |= ctrl_id << PMC_SCRATCH55_CNTRL_ID_SHIFT; | |
1446 | value |= pinmux << PMC_SCRATCH55_PINMUX_SHIFT; | |
1447 | value |= pmu_addr << PMC_SCRATCH55_I2CSLV1_SHIFT; | |
1448 | ||
1449 | /* | |
1450 | * Calculate checksum of SCRATCH54, SCRATCH55 fields. Bits 23:16 will | |
1451 | * contain the checksum and are currently zero, so they are not added. | |
1452 | */ | |
1453 | checksum = reg_addr + reg_data + (value & 0xff) + ((value >> 8) & 0xff) | |
1454 | + ((value >> 24) & 0xff); | |
1455 | checksum &= 0xff; | |
1456 | checksum = 0x100 - checksum; | |
1457 | ||
1458 | value |= checksum << PMC_SCRATCH55_CHECKSUM_SHIFT; | |
1459 | ||
1460 | tegra_pmc_writel(value, PMC_SCRATCH55); | |
1461 | ||
1462 | value = tegra_pmc_readl(PMC_SENSOR_CTRL); | |
1463 | value |= PMC_SENSOR_CTRL_ENABLE_RST; | |
1464 | tegra_pmc_writel(value, PMC_SENSOR_CTRL); | |
1465 | ||
1466 | dev_info(pmc->dev, "emergency thermal reset enabled\n"); | |
1467 | ||
1468 | out: | |
1469 | of_node_put(np); | |
3568df3d MP |
1470 | } |
1471 | ||
4a37f11c AV |
1472 | static int tegra_io_pad_pinctrl_get_groups_count(struct pinctrl_dev *pctl_dev) |
1473 | { | |
1474 | return pmc->soc->num_io_pads; | |
1475 | } | |
1476 | ||
1477 | static const char *tegra_io_pad_pinctrl_get_group_name( | |
1478 | struct pinctrl_dev *pctl, unsigned int group) | |
1479 | { | |
1480 | return pmc->soc->io_pads[group].name; | |
1481 | } | |
1482 | ||
1483 | static int tegra_io_pad_pinctrl_get_group_pins(struct pinctrl_dev *pctl_dev, | |
1484 | unsigned int group, | |
1485 | const unsigned int **pins, | |
1486 | unsigned int *num_pins) | |
1487 | { | |
1488 | *pins = &pmc->soc->io_pads[group].id; | |
1489 | *num_pins = 1; | |
1490 | return 0; | |
1491 | } | |
1492 | ||
1493 | static const struct pinctrl_ops tegra_io_pad_pinctrl_ops = { | |
1494 | .get_groups_count = tegra_io_pad_pinctrl_get_groups_count, | |
1495 | .get_group_name = tegra_io_pad_pinctrl_get_group_name, | |
1496 | .get_group_pins = tegra_io_pad_pinctrl_get_group_pins, | |
1497 | .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, | |
1498 | .dt_free_map = pinconf_generic_dt_free_map, | |
1499 | }; | |
1500 | ||
1501 | static int tegra_io_pad_pinconf_get(struct pinctrl_dev *pctl_dev, | |
1502 | unsigned int pin, unsigned long *config) | |
1503 | { | |
1504 | const struct tegra_io_pad_soc *pad = tegra_io_pad_find(pmc, pin); | |
1505 | enum pin_config_param param = pinconf_to_config_param(*config); | |
1506 | int ret; | |
1507 | u32 arg; | |
1508 | ||
1509 | if (!pad) | |
1510 | return -EINVAL; | |
1511 | ||
1512 | switch (param) { | |
1513 | case PIN_CONFIG_POWER_SOURCE: | |
1514 | ret = tegra_io_pad_get_voltage(pad->id); | |
1515 | if (ret < 0) | |
1516 | return ret; | |
1517 | arg = ret; | |
1518 | break; | |
1519 | case PIN_CONFIG_LOW_POWER_MODE: | |
1520 | ret = tegra_io_pad_is_powered(pad->id); | |
1521 | if (ret < 0) | |
1522 | return ret; | |
1523 | arg = !ret; | |
1524 | break; | |
1525 | default: | |
1526 | return -EINVAL; | |
1527 | } | |
1528 | ||
1529 | *config = pinconf_to_config_packed(param, arg); | |
1530 | ||
1531 | return 0; | |
1532 | } | |
1533 | ||
1534 | static int tegra_io_pad_pinconf_set(struct pinctrl_dev *pctl_dev, | |
1535 | unsigned int pin, unsigned long *configs, | |
1536 | unsigned int num_configs) | |
1537 | { | |
1538 | const struct tegra_io_pad_soc *pad = tegra_io_pad_find(pmc, pin); | |
1539 | enum pin_config_param param; | |
1540 | unsigned int i; | |
1541 | int err; | |
1542 | u32 arg; | |
1543 | ||
1544 | if (!pad) | |
1545 | return -EINVAL; | |
1546 | ||
1547 | for (i = 0; i < num_configs; ++i) { | |
1548 | param = pinconf_to_config_param(configs[i]); | |
1549 | arg = pinconf_to_config_argument(configs[i]); | |
1550 | ||
1551 | switch (param) { | |
1552 | case PIN_CONFIG_LOW_POWER_MODE: | |
1553 | if (arg) | |
1554 | err = tegra_io_pad_power_disable(pad->id); | |
1555 | else | |
1556 | err = tegra_io_pad_power_enable(pad->id); | |
1557 | if (err) | |
1558 | return err; | |
1559 | break; | |
1560 | case PIN_CONFIG_POWER_SOURCE: | |
1561 | if (arg != TEGRA_IO_PAD_VOLTAGE_1V8 && | |
1562 | arg != TEGRA_IO_PAD_VOLTAGE_3V3) | |
1563 | return -EINVAL; | |
1564 | err = tegra_io_pad_set_voltage(pad->id, arg); | |
1565 | if (err) | |
1566 | return err; | |
1567 | break; | |
1568 | default: | |
1569 | return -EINVAL; | |
1570 | } | |
1571 | } | |
1572 | ||
1573 | return 0; | |
1574 | } | |
1575 | ||
1576 | static const struct pinconf_ops tegra_io_pad_pinconf_ops = { | |
1577 | .pin_config_get = tegra_io_pad_pinconf_get, | |
1578 | .pin_config_set = tegra_io_pad_pinconf_set, | |
1579 | .is_generic = true, | |
1580 | }; | |
1581 | ||
1582 | static struct pinctrl_desc tegra_pmc_pctl_desc = { | |
1583 | .pctlops = &tegra_io_pad_pinctrl_ops, | |
1584 | .confops = &tegra_io_pad_pinconf_ops, | |
1585 | }; | |
1586 | ||
1587 | static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc) | |
1588 | { | |
1589 | int err = 0; | |
1590 | ||
1591 | if (!pmc->soc->num_pin_descs) | |
1592 | return 0; | |
1593 | ||
1594 | tegra_pmc_pctl_desc.name = dev_name(pmc->dev); | |
1595 | tegra_pmc_pctl_desc.pins = pmc->soc->pin_descs; | |
1596 | tegra_pmc_pctl_desc.npins = pmc->soc->num_pin_descs; | |
1597 | ||
1598 | pmc->pctl_dev = devm_pinctrl_register(pmc->dev, &tegra_pmc_pctl_desc, | |
1599 | pmc); | |
1600 | if (IS_ERR(pmc->pctl_dev)) { | |
1601 | err = PTR_ERR(pmc->pctl_dev); | |
1602 | dev_err(pmc->dev, "unable to register pinctrl, %d\n", err); | |
1603 | } | |
1604 | ||
1605 | return err; | |
1606 | } | |
1607 | ||
5f84bb1a SP |
1608 | static ssize_t reset_reason_show(struct device *dev, |
1609 | struct device_attribute *attr, char *buf) | |
1610 | { | |
1611 | u32 value, rst_src; | |
1612 | ||
1613 | value = tegra_pmc_readl(pmc->soc->regs->rst_status); | |
1614 | rst_src = (value & pmc->soc->regs->rst_source_mask) >> | |
1615 | pmc->soc->regs->rst_source_shift; | |
1616 | ||
1617 | return sprintf(buf, "%s\n", pmc->soc->reset_sources[rst_src]); | |
1618 | } | |
1619 | ||
1620 | static DEVICE_ATTR_RO(reset_reason); | |
1621 | ||
1622 | static ssize_t reset_level_show(struct device *dev, | |
1623 | struct device_attribute *attr, char *buf) | |
1624 | { | |
1625 | u32 value, rst_lvl; | |
1626 | ||
1627 | value = tegra_pmc_readl(pmc->soc->regs->rst_status); | |
1628 | rst_lvl = (value & pmc->soc->regs->rst_level_mask) >> | |
1629 | pmc->soc->regs->rst_level_shift; | |
1630 | ||
1631 | return sprintf(buf, "%s\n", pmc->soc->reset_levels[rst_lvl]); | |
1632 | } | |
1633 | ||
1634 | static DEVICE_ATTR_RO(reset_level); | |
1635 | ||
1636 | static void tegra_pmc_reset_sysfs_init(struct tegra_pmc *pmc) | |
1637 | { | |
1638 | struct device *dev = pmc->dev; | |
1639 | int err = 0; | |
1640 | ||
1641 | if (pmc->soc->reset_sources) { | |
1642 | err = device_create_file(dev, &dev_attr_reset_reason); | |
1643 | if (err < 0) | |
1644 | dev_warn(dev, | |
1645 | "failed to create attr \"reset_reason\": %d\n", | |
1646 | err); | |
1647 | } | |
1648 | ||
1649 | if (pmc->soc->reset_levels) { | |
1650 | err = device_create_file(dev, &dev_attr_reset_level); | |
1651 | if (err < 0) | |
1652 | dev_warn(dev, | |
1653 | "failed to create attr \"reset_level\": %d\n", | |
1654 | err); | |
1655 | } | |
1656 | } | |
1657 | ||
19906e6b TR |
1658 | static int tegra_pmc_irq_translate(struct irq_domain *domain, |
1659 | struct irq_fwspec *fwspec, | |
1660 | unsigned long *hwirq, | |
1661 | unsigned int *type) | |
1662 | { | |
1663 | if (WARN_ON(fwspec->param_count < 2)) | |
1664 | return -EINVAL; | |
1665 | ||
1666 | *hwirq = fwspec->param[0]; | |
1667 | *type = fwspec->param[1]; | |
1668 | ||
1669 | return 0; | |
1670 | } | |
1671 | ||
1672 | static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, | |
1673 | unsigned int num_irqs, void *data) | |
1674 | { | |
1675 | struct tegra_pmc *pmc = domain->host_data; | |
1676 | const struct tegra_pmc_soc *soc = pmc->soc; | |
1677 | struct irq_fwspec *fwspec = data; | |
1678 | unsigned int i; | |
1679 | int err = 0; | |
1680 | ||
1681 | for (i = 0; i < soc->num_wake_events; i++) { | |
1682 | const struct tegra_wake_event *event = &soc->wake_events[i]; | |
1683 | ||
1684 | if (fwspec->param_count == 2) { | |
1685 | struct irq_fwspec spec; | |
1686 | ||
1687 | if (event->id != fwspec->param[0]) | |
1688 | continue; | |
1689 | ||
1690 | err = irq_domain_set_hwirq_and_chip(domain, virq, | |
1691 | event->id, | |
1692 | &pmc->irq, pmc); | |
1693 | if (err < 0) | |
1694 | break; | |
1695 | ||
1696 | spec.fwnode = &pmc->dev->of_node->fwnode; | |
1697 | spec.param_count = 3; | |
1698 | spec.param[0] = GIC_SPI; | |
1699 | spec.param[1] = event->irq; | |
1700 | spec.param[2] = fwspec->param[1]; | |
1701 | ||
1702 | err = irq_domain_alloc_irqs_parent(domain, virq, | |
1703 | num_irqs, &spec); | |
1704 | ||
1705 | break; | |
1706 | } | |
1707 | ||
1708 | if (fwspec->param_count == 3) { | |
1709 | if (event->gpio.instance != fwspec->param[0] || | |
1710 | event->gpio.pin != fwspec->param[1]) | |
1711 | continue; | |
1712 | ||
1713 | err = irq_domain_set_hwirq_and_chip(domain, virq, | |
1714 | event->id, | |
1715 | &pmc->irq, pmc); | |
1716 | ||
1717 | break; | |
1718 | } | |
1719 | } | |
1720 | ||
1721 | if (i == soc->num_wake_events) | |
1722 | err = irq_domain_set_hwirq_and_chip(domain, virq, ULONG_MAX, | |
1723 | &pmc->irq, pmc); | |
1724 | ||
1725 | return err; | |
1726 | } | |
1727 | ||
1728 | static const struct irq_domain_ops tegra_pmc_irq_domain_ops = { | |
1729 | .translate = tegra_pmc_irq_translate, | |
1730 | .alloc = tegra_pmc_irq_alloc, | |
1731 | }; | |
1732 | ||
1733 | static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on) | |
1734 | { | |
1735 | struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); | |
1736 | unsigned int offset, bit; | |
1737 | u32 value; | |
1738 | ||
1739 | offset = data->hwirq / 32; | |
1740 | bit = data->hwirq % 32; | |
1741 | ||
1742 | /* clear wake status */ | |
1743 | writel(0x1, pmc->wake + WAKE_AOWAKE_STATUS_W(data->hwirq)); | |
1744 | ||
1745 | /* route wake to tier 2 */ | |
1746 | value = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset)); | |
1747 | ||
1748 | if (!on) | |
1749 | value &= ~(1 << bit); | |
1750 | else | |
1751 | value |= 1 << bit; | |
1752 | ||
1753 | writel(value, pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset)); | |
1754 | ||
1755 | /* enable wakeup event */ | |
1756 | writel(!!on, pmc->wake + WAKE_AOWAKE_MASK_W(data->hwirq)); | |
1757 | ||
1758 | return 0; | |
1759 | } | |
1760 | ||
1761 | static int tegra_pmc_irq_set_type(struct irq_data *data, unsigned int type) | |
1762 | { | |
1763 | struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); | |
1764 | u32 value; | |
1765 | ||
1766 | if (data->hwirq == ULONG_MAX) | |
1767 | return 0; | |
1768 | ||
1769 | value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq)); | |
1770 | ||
1771 | switch (type) { | |
1772 | case IRQ_TYPE_EDGE_RISING: | |
1773 | case IRQ_TYPE_LEVEL_HIGH: | |
1774 | value |= WAKE_AOWAKE_CNTRL_LEVEL; | |
1775 | break; | |
1776 | ||
1777 | case IRQ_TYPE_EDGE_FALLING: | |
1778 | case IRQ_TYPE_LEVEL_LOW: | |
1779 | value &= ~WAKE_AOWAKE_CNTRL_LEVEL; | |
1780 | break; | |
1781 | ||
1782 | case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING: | |
1783 | value ^= WAKE_AOWAKE_CNTRL_LEVEL; | |
1784 | break; | |
1785 | ||
1786 | default: | |
1787 | return -EINVAL; | |
1788 | } | |
1789 | ||
1790 | writel(value, pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq)); | |
1791 | ||
1792 | return 0; | |
1793 | } | |
1794 | ||
1795 | static int tegra_pmc_irq_init(struct tegra_pmc *pmc) | |
1796 | { | |
1797 | struct irq_domain *parent = NULL; | |
1798 | struct device_node *np; | |
1799 | ||
1800 | np = of_irq_find_parent(pmc->dev->of_node); | |
1801 | if (np) { | |
1802 | parent = irq_find_host(np); | |
1803 | of_node_put(np); | |
1804 | } | |
1805 | ||
1806 | if (!parent) | |
1807 | return 0; | |
1808 | ||
1809 | pmc->irq.name = dev_name(pmc->dev); | |
1810 | pmc->irq.irq_mask = irq_chip_mask_parent; | |
1811 | pmc->irq.irq_unmask = irq_chip_unmask_parent; | |
1812 | pmc->irq.irq_eoi = irq_chip_eoi_parent; | |
1813 | pmc->irq.irq_set_affinity = irq_chip_set_affinity_parent; | |
1814 | pmc->irq.irq_set_type = tegra_pmc_irq_set_type; | |
1815 | pmc->irq.irq_set_wake = tegra_pmc_irq_set_wake; | |
1816 | ||
1817 | pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node, | |
1818 | &tegra_pmc_irq_domain_ops, pmc); | |
1819 | if (!pmc->domain) { | |
1820 | dev_err(pmc->dev, "failed to allocate domain\n"); | |
1821 | return -ENOMEM; | |
1822 | } | |
1823 | ||
1824 | return 0; | |
1825 | } | |
1826 | ||
7232398a TR |
1827 | static int tegra_pmc_probe(struct platform_device *pdev) |
1828 | { | |
e8cf6616 | 1829 | void __iomem *base; |
7232398a TR |
1830 | struct resource *res; |
1831 | int err; | |
1832 | ||
a83f1fc3 JH |
1833 | /* |
1834 | * Early initialisation should have configured an initial | |
1835 | * register mapping and setup the soc data pointer. If these | |
1836 | * are not valid then something went badly wrong! | |
1837 | */ | |
1838 | if (WARN_ON(!pmc->base || !pmc->soc)) | |
1839 | return -ENODEV; | |
1840 | ||
7232398a TR |
1841 | err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node); |
1842 | if (err < 0) | |
1843 | return err; | |
1844 | ||
1845 | /* take over the memory region from the early initialization */ | |
1846 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
0259f522 JH |
1847 | base = devm_ioremap_resource(&pdev->dev, res); |
1848 | if (IS_ERR(base)) | |
1849 | return PTR_ERR(base); | |
7232398a | 1850 | |
c641ec6e TR |
1851 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake"); |
1852 | if (res) { | |
1853 | pmc->wake = devm_ioremap_resource(&pdev->dev, res); | |
1854 | if (IS_ERR(pmc->wake)) | |
1855 | return PTR_ERR(pmc->wake); | |
1856 | } else { | |
1857 | pmc->wake = base; | |
1858 | } | |
1859 | ||
1860 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag"); | |
1861 | if (res) { | |
1862 | pmc->aotag = devm_ioremap_resource(&pdev->dev, res); | |
1863 | if (IS_ERR(pmc->aotag)) | |
1864 | return PTR_ERR(pmc->aotag); | |
1865 | } else { | |
1866 | pmc->aotag = base; | |
1867 | } | |
1868 | ||
1869 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch"); | |
1870 | if (res) { | |
1871 | pmc->scratch = devm_ioremap_resource(&pdev->dev, res); | |
1872 | if (IS_ERR(pmc->scratch)) | |
1873 | return PTR_ERR(pmc->scratch); | |
1874 | } else { | |
1875 | pmc->scratch = base; | |
1876 | } | |
5be22556 | 1877 | |
7232398a TR |
1878 | pmc->clk = devm_clk_get(&pdev->dev, "pclk"); |
1879 | if (IS_ERR(pmc->clk)) { | |
1880 | err = PTR_ERR(pmc->clk); | |
5be22556 TR |
1881 | |
1882 | if (err != -ENOENT) { | |
1883 | dev_err(&pdev->dev, "failed to get pclk: %d\n", err); | |
1884 | return err; | |
1885 | } | |
1886 | ||
1887 | pmc->clk = NULL; | |
7232398a TR |
1888 | } |
1889 | ||
3568df3d MP |
1890 | pmc->dev = &pdev->dev; |
1891 | ||
7232398a TR |
1892 | tegra_pmc_init(pmc); |
1893 | ||
3568df3d MP |
1894 | tegra_pmc_init_tsense_reset(pmc); |
1895 | ||
5f84bb1a SP |
1896 | tegra_pmc_reset_sysfs_init(pmc); |
1897 | ||
7232398a TR |
1898 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { |
1899 | err = tegra_powergate_debugfs_init(); | |
1900 | if (err < 0) | |
1901 | return err; | |
7892158a DR |
1902 | } |
1903 | ||
1904 | err = register_restart_handler(&tegra_pmc_restart_handler); | |
1905 | if (err) { | |
1906 | dev_err(&pdev->dev, "unable to register restart handler, %d\n", | |
1907 | err); | |
4a37f11c | 1908 | goto cleanup_debugfs; |
7232398a TR |
1909 | } |
1910 | ||
4a37f11c AV |
1911 | err = tegra_pmc_pinctrl_init(pmc); |
1912 | if (err) | |
1913 | goto cleanup_restart_handler; | |
1914 | ||
19906e6b TR |
1915 | err = tegra_pmc_irq_init(pmc); |
1916 | if (err < 0) | |
1917 | goto cleanup_restart_handler; | |
1918 | ||
e8cf6616 JH |
1919 | mutex_lock(&pmc->powergates_lock); |
1920 | iounmap(pmc->base); | |
0259f522 | 1921 | pmc->base = base; |
e8cf6616 | 1922 | mutex_unlock(&pmc->powergates_lock); |
0259f522 | 1923 | |
7232398a | 1924 | return 0; |
4a37f11c AV |
1925 | |
1926 | cleanup_restart_handler: | |
1927 | unregister_restart_handler(&tegra_pmc_restart_handler); | |
1928 | cleanup_debugfs: | |
1929 | debugfs_remove(pmc->debugfs); | |
1930 | return err; | |
7232398a TR |
1931 | } |
1932 | ||
2b20b616 | 1933 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) |
7232398a TR |
1934 | static int tegra_pmc_suspend(struct device *dev) |
1935 | { | |
1936 | tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41); | |
1937 | ||
1938 | return 0; | |
1939 | } | |
1940 | ||
1941 | static int tegra_pmc_resume(struct device *dev) | |
1942 | { | |
1943 | tegra_pmc_writel(0x0, PMC_SCRATCH41); | |
1944 | ||
1945 | return 0; | |
1946 | } | |
7232398a TR |
1947 | |
1948 | static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume); | |
1949 | ||
2b20b616 PW |
1950 | #endif |
1951 | ||
7232398a TR |
1952 | static const char * const tegra20_powergates[] = { |
1953 | [TEGRA_POWERGATE_CPU] = "cpu", | |
1954 | [TEGRA_POWERGATE_3D] = "3d", | |
1955 | [TEGRA_POWERGATE_VENC] = "venc", | |
1956 | [TEGRA_POWERGATE_VDEC] = "vdec", | |
1957 | [TEGRA_POWERGATE_PCIE] = "pcie", | |
1958 | [TEGRA_POWERGATE_L2] = "l2", | |
1959 | [TEGRA_POWERGATE_MPE] = "mpe", | |
1960 | }; | |
1961 | ||
5be22556 TR |
1962 | static const struct tegra_pmc_regs tegra20_pmc_regs = { |
1963 | .scratch0 = 0x50, | |
1964 | .dpd_req = 0x1b8, | |
1965 | .dpd_status = 0x1bc, | |
1966 | .dpd2_req = 0x1c0, | |
1967 | .dpd2_status = 0x1c4, | |
5f84bb1a SP |
1968 | .rst_status = 0x1b4, |
1969 | .rst_source_shift = 0x0, | |
1970 | .rst_source_mask = 0x7, | |
1971 | .rst_level_shift = 0x0, | |
1972 | .rst_level_mask = 0x0, | |
5be22556 TR |
1973 | }; |
1974 | ||
1975 | static void tegra20_pmc_init(struct tegra_pmc *pmc) | |
1976 | { | |
1977 | u32 value; | |
1978 | ||
1979 | /* Always enable CPU power request */ | |
1980 | value = tegra_pmc_readl(PMC_CNTRL); | |
1981 | value |= PMC_CNTRL_CPU_PWRREQ_OE; | |
1982 | tegra_pmc_writel(value, PMC_CNTRL); | |
1983 | ||
1984 | value = tegra_pmc_readl(PMC_CNTRL); | |
1985 | ||
1986 | if (pmc->sysclkreq_high) | |
1987 | value &= ~PMC_CNTRL_SYSCLK_POLARITY; | |
1988 | else | |
1989 | value |= PMC_CNTRL_SYSCLK_POLARITY; | |
1990 | ||
1991 | /* configure the output polarity while the request is tristated */ | |
1992 | tegra_pmc_writel(value, PMC_CNTRL); | |
1993 | ||
1994 | /* now enable the request */ | |
1995 | value = tegra_pmc_readl(PMC_CNTRL); | |
1996 | value |= PMC_CNTRL_SYSCLK_OE; | |
1997 | tegra_pmc_writel(value, PMC_CNTRL); | |
1998 | } | |
1999 | ||
2000 | static void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc, | |
2001 | struct device_node *np, | |
2002 | bool invert) | |
2003 | { | |
2004 | u32 value; | |
2005 | ||
2006 | value = tegra_pmc_readl(PMC_CNTRL); | |
2007 | ||
2008 | if (invert) | |
2009 | value |= PMC_CNTRL_INTR_POLARITY; | |
2010 | else | |
2011 | value &= ~PMC_CNTRL_INTR_POLARITY; | |
2012 | ||
2013 | tegra_pmc_writel(value, PMC_CNTRL); | |
2014 | } | |
2015 | ||
7232398a TR |
2016 | static const struct tegra_pmc_soc tegra20_pmc_soc = { |
2017 | .num_powergates = ARRAY_SIZE(tegra20_powergates), | |
2018 | .powergates = tegra20_powergates, | |
2019 | .num_cpu_powergates = 0, | |
2020 | .cpu_powergates = NULL, | |
3568df3d | 2021 | .has_tsense_reset = false, |
a9a40a4a | 2022 | .has_gpu_clamps = false, |
5be22556 TR |
2023 | .num_io_pads = 0, |
2024 | .io_pads = NULL, | |
4a37f11c AV |
2025 | .num_pin_descs = 0, |
2026 | .pin_descs = NULL, | |
5be22556 TR |
2027 | .regs = &tegra20_pmc_regs, |
2028 | .init = tegra20_pmc_init, | |
2029 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | |
5f84bb1a SP |
2030 | .reset_sources = NULL, |
2031 | .num_reset_sources = 0, | |
2032 | .reset_levels = NULL, | |
2033 | .num_reset_levels = 0, | |
7232398a TR |
2034 | }; |
2035 | ||
2036 | static const char * const tegra30_powergates[] = { | |
2037 | [TEGRA_POWERGATE_CPU] = "cpu0", | |
2038 | [TEGRA_POWERGATE_3D] = "3d0", | |
2039 | [TEGRA_POWERGATE_VENC] = "venc", | |
2040 | [TEGRA_POWERGATE_VDEC] = "vdec", | |
2041 | [TEGRA_POWERGATE_PCIE] = "pcie", | |
2042 | [TEGRA_POWERGATE_L2] = "l2", | |
2043 | [TEGRA_POWERGATE_MPE] = "mpe", | |
2044 | [TEGRA_POWERGATE_HEG] = "heg", | |
2045 | [TEGRA_POWERGATE_SATA] = "sata", | |
2046 | [TEGRA_POWERGATE_CPU1] = "cpu1", | |
2047 | [TEGRA_POWERGATE_CPU2] = "cpu2", | |
2048 | [TEGRA_POWERGATE_CPU3] = "cpu3", | |
2049 | [TEGRA_POWERGATE_CELP] = "celp", | |
2050 | [TEGRA_POWERGATE_3D1] = "3d1", | |
2051 | }; | |
2052 | ||
2053 | static const u8 tegra30_cpu_powergates[] = { | |
2054 | TEGRA_POWERGATE_CPU, | |
2055 | TEGRA_POWERGATE_CPU1, | |
2056 | TEGRA_POWERGATE_CPU2, | |
2057 | TEGRA_POWERGATE_CPU3, | |
2058 | }; | |
2059 | ||
2060 | static const struct tegra_pmc_soc tegra30_pmc_soc = { | |
2061 | .num_powergates = ARRAY_SIZE(tegra30_powergates), | |
2062 | .powergates = tegra30_powergates, | |
2063 | .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates), | |
2064 | .cpu_powergates = tegra30_cpu_powergates, | |
3568df3d | 2065 | .has_tsense_reset = true, |
a9a40a4a | 2066 | .has_gpu_clamps = false, |
13136a47 | 2067 | .has_impl_33v_pwr = false, |
5be22556 TR |
2068 | .num_io_pads = 0, |
2069 | .io_pads = NULL, | |
4a37f11c AV |
2070 | .num_pin_descs = 0, |
2071 | .pin_descs = NULL, | |
5be22556 TR |
2072 | .regs = &tegra20_pmc_regs, |
2073 | .init = tegra20_pmc_init, | |
2074 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | |
5f84bb1a SP |
2075 | .reset_sources = tegra30_reset_sources, |
2076 | .num_reset_sources = 5, | |
2077 | .reset_levels = NULL, | |
2078 | .num_reset_levels = 0, | |
7232398a TR |
2079 | }; |
2080 | ||
2081 | static const char * const tegra114_powergates[] = { | |
2082 | [TEGRA_POWERGATE_CPU] = "crail", | |
2083 | [TEGRA_POWERGATE_3D] = "3d", | |
2084 | [TEGRA_POWERGATE_VENC] = "venc", | |
2085 | [TEGRA_POWERGATE_VDEC] = "vdec", | |
2086 | [TEGRA_POWERGATE_MPE] = "mpe", | |
2087 | [TEGRA_POWERGATE_HEG] = "heg", | |
2088 | [TEGRA_POWERGATE_CPU1] = "cpu1", | |
2089 | [TEGRA_POWERGATE_CPU2] = "cpu2", | |
2090 | [TEGRA_POWERGATE_CPU3] = "cpu3", | |
2091 | [TEGRA_POWERGATE_CELP] = "celp", | |
2092 | [TEGRA_POWERGATE_CPU0] = "cpu0", | |
2093 | [TEGRA_POWERGATE_C0NC] = "c0nc", | |
2094 | [TEGRA_POWERGATE_C1NC] = "c1nc", | |
2095 | [TEGRA_POWERGATE_DIS] = "dis", | |
2096 | [TEGRA_POWERGATE_DISB] = "disb", | |
2097 | [TEGRA_POWERGATE_XUSBA] = "xusba", | |
2098 | [TEGRA_POWERGATE_XUSBB] = "xusbb", | |
2099 | [TEGRA_POWERGATE_XUSBC] = "xusbc", | |
2100 | }; | |
2101 | ||
2102 | static const u8 tegra114_cpu_powergates[] = { | |
2103 | TEGRA_POWERGATE_CPU0, | |
2104 | TEGRA_POWERGATE_CPU1, | |
2105 | TEGRA_POWERGATE_CPU2, | |
2106 | TEGRA_POWERGATE_CPU3, | |
2107 | }; | |
2108 | ||
2109 | static const struct tegra_pmc_soc tegra114_pmc_soc = { | |
2110 | .num_powergates = ARRAY_SIZE(tegra114_powergates), | |
2111 | .powergates = tegra114_powergates, | |
2112 | .num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates), | |
2113 | .cpu_powergates = tegra114_cpu_powergates, | |
3568df3d | 2114 | .has_tsense_reset = true, |
a9a40a4a | 2115 | .has_gpu_clamps = false, |
13136a47 | 2116 | .has_impl_33v_pwr = false, |
5be22556 TR |
2117 | .num_io_pads = 0, |
2118 | .io_pads = NULL, | |
4a37f11c AV |
2119 | .num_pin_descs = 0, |
2120 | .pin_descs = NULL, | |
5be22556 TR |
2121 | .regs = &tegra20_pmc_regs, |
2122 | .init = tegra20_pmc_init, | |
2123 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | |
5f84bb1a SP |
2124 | .reset_sources = tegra30_reset_sources, |
2125 | .num_reset_sources = 5, | |
2126 | .reset_levels = NULL, | |
2127 | .num_reset_levels = 0, | |
7232398a TR |
2128 | }; |
2129 | ||
2130 | static const char * const tegra124_powergates[] = { | |
2131 | [TEGRA_POWERGATE_CPU] = "crail", | |
2132 | [TEGRA_POWERGATE_3D] = "3d", | |
2133 | [TEGRA_POWERGATE_VENC] = "venc", | |
2134 | [TEGRA_POWERGATE_PCIE] = "pcie", | |
2135 | [TEGRA_POWERGATE_VDEC] = "vdec", | |
7232398a TR |
2136 | [TEGRA_POWERGATE_MPE] = "mpe", |
2137 | [TEGRA_POWERGATE_HEG] = "heg", | |
2138 | [TEGRA_POWERGATE_SATA] = "sata", | |
2139 | [TEGRA_POWERGATE_CPU1] = "cpu1", | |
2140 | [TEGRA_POWERGATE_CPU2] = "cpu2", | |
2141 | [TEGRA_POWERGATE_CPU3] = "cpu3", | |
2142 | [TEGRA_POWERGATE_CELP] = "celp", | |
2143 | [TEGRA_POWERGATE_CPU0] = "cpu0", | |
2144 | [TEGRA_POWERGATE_C0NC] = "c0nc", | |
2145 | [TEGRA_POWERGATE_C1NC] = "c1nc", | |
2146 | [TEGRA_POWERGATE_SOR] = "sor", | |
2147 | [TEGRA_POWERGATE_DIS] = "dis", | |
2148 | [TEGRA_POWERGATE_DISB] = "disb", | |
2149 | [TEGRA_POWERGATE_XUSBA] = "xusba", | |
2150 | [TEGRA_POWERGATE_XUSBB] = "xusbb", | |
2151 | [TEGRA_POWERGATE_XUSBC] = "xusbc", | |
2152 | [TEGRA_POWERGATE_VIC] = "vic", | |
2153 | [TEGRA_POWERGATE_IRAM] = "iram", | |
2154 | }; | |
2155 | ||
2156 | static const u8 tegra124_cpu_powergates[] = { | |
2157 | TEGRA_POWERGATE_CPU0, | |
2158 | TEGRA_POWERGATE_CPU1, | |
2159 | TEGRA_POWERGATE_CPU2, | |
2160 | TEGRA_POWERGATE_CPU3, | |
2161 | }; | |
2162 | ||
437c4f26 AV |
2163 | #define TEGRA_IO_PAD(_id, _dpd, _voltage, _name) \ |
2164 | ((struct tegra_io_pad_soc) { \ | |
2165 | .id = (_id), \ | |
2166 | .dpd = (_dpd), \ | |
2167 | .voltage = (_voltage), \ | |
2168 | .name = (_name), \ | |
2169 | }) | |
2170 | ||
4a37f11c AV |
2171 | #define TEGRA_IO_PIN_DESC(_id, _dpd, _voltage, _name) \ |
2172 | ((struct pinctrl_pin_desc) { \ | |
2173 | .number = (_id), \ | |
2174 | .name = (_name) \ | |
2175 | }) | |
2176 | ||
437c4f26 AV |
2177 | #define TEGRA124_IO_PAD_TABLE(_pad) \ |
2178 | /* .id .dpd .voltage .name */ \ | |
2179 | _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ | |
2180 | _pad(TEGRA_IO_PAD_BB, 15, UINT_MAX, "bb"), \ | |
2181 | _pad(TEGRA_IO_PAD_CAM, 36, UINT_MAX, "cam"), \ | |
2182 | _pad(TEGRA_IO_PAD_COMP, 22, UINT_MAX, "comp"), \ | |
2183 | _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ | |
2184 | _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csb"), \ | |
2185 | _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "cse"), \ | |
2186 | _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ | |
2187 | _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \ | |
2188 | _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \ | |
2189 | _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \ | |
2190 | _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \ | |
2191 | _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ | |
2192 | _pad(TEGRA_IO_PAD_HV, 38, UINT_MAX, "hv"), \ | |
2193 | _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \ | |
2194 | _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ | |
2195 | _pad(TEGRA_IO_PAD_NAND, 13, UINT_MAX, "nand"), \ | |
2196 | _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \ | |
2197 | _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \ | |
2198 | _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ | |
2199 | _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ | |
2200 | _pad(TEGRA_IO_PAD_SDMMC1, 33, UINT_MAX, "sdmmc1"), \ | |
2201 | _pad(TEGRA_IO_PAD_SDMMC3, 34, UINT_MAX, "sdmmc3"), \ | |
2202 | _pad(TEGRA_IO_PAD_SDMMC4, 35, UINT_MAX, "sdmmc4"), \ | |
2203 | _pad(TEGRA_IO_PAD_SYS_DDC, 58, UINT_MAX, "sys_ddc"), \ | |
2204 | _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ | |
2205 | _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ | |
2206 | _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ | |
2207 | _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ | |
2208 | _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb_bias") | |
2209 | ||
21b49910 | 2210 | static const struct tegra_io_pad_soc tegra124_io_pads[] = { |
437c4f26 | 2211 | TEGRA124_IO_PAD_TABLE(TEGRA_IO_PAD) |
21b49910 LD |
2212 | }; |
2213 | ||
4a37f11c AV |
2214 | static const struct pinctrl_pin_desc tegra124_pin_descs[] = { |
2215 | TEGRA124_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) | |
21b49910 LD |
2216 | }; |
2217 | ||
7232398a TR |
2218 | static const struct tegra_pmc_soc tegra124_pmc_soc = { |
2219 | .num_powergates = ARRAY_SIZE(tegra124_powergates), | |
2220 | .powergates = tegra124_powergates, | |
2221 | .num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates), | |
2222 | .cpu_powergates = tegra124_cpu_powergates, | |
3568df3d | 2223 | .has_tsense_reset = true, |
a9a40a4a | 2224 | .has_gpu_clamps = true, |
13136a47 | 2225 | .has_impl_33v_pwr = false, |
21b49910 LD |
2226 | .num_io_pads = ARRAY_SIZE(tegra124_io_pads), |
2227 | .io_pads = tegra124_io_pads, | |
4a37f11c AV |
2228 | .num_pin_descs = ARRAY_SIZE(tegra124_pin_descs), |
2229 | .pin_descs = tegra124_pin_descs, | |
5be22556 TR |
2230 | .regs = &tegra20_pmc_regs, |
2231 | .init = tegra20_pmc_init, | |
2232 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | |
5f84bb1a SP |
2233 | .reset_sources = tegra30_reset_sources, |
2234 | .num_reset_sources = 5, | |
2235 | .reset_levels = NULL, | |
2236 | .num_reset_levels = 0, | |
7232398a TR |
2237 | }; |
2238 | ||
c2fe4694 TR |
2239 | static const char * const tegra210_powergates[] = { |
2240 | [TEGRA_POWERGATE_CPU] = "crail", | |
2241 | [TEGRA_POWERGATE_3D] = "3d", | |
2242 | [TEGRA_POWERGATE_VENC] = "venc", | |
2243 | [TEGRA_POWERGATE_PCIE] = "pcie", | |
c2fe4694 | 2244 | [TEGRA_POWERGATE_MPE] = "mpe", |
c2fe4694 TR |
2245 | [TEGRA_POWERGATE_SATA] = "sata", |
2246 | [TEGRA_POWERGATE_CPU1] = "cpu1", | |
2247 | [TEGRA_POWERGATE_CPU2] = "cpu2", | |
2248 | [TEGRA_POWERGATE_CPU3] = "cpu3", | |
c2fe4694 TR |
2249 | [TEGRA_POWERGATE_CPU0] = "cpu0", |
2250 | [TEGRA_POWERGATE_C0NC] = "c0nc", | |
c2fe4694 TR |
2251 | [TEGRA_POWERGATE_SOR] = "sor", |
2252 | [TEGRA_POWERGATE_DIS] = "dis", | |
2253 | [TEGRA_POWERGATE_DISB] = "disb", | |
2254 | [TEGRA_POWERGATE_XUSBA] = "xusba", | |
2255 | [TEGRA_POWERGATE_XUSBB] = "xusbb", | |
2256 | [TEGRA_POWERGATE_XUSBC] = "xusbc", | |
2257 | [TEGRA_POWERGATE_VIC] = "vic", | |
2258 | [TEGRA_POWERGATE_IRAM] = "iram", | |
2259 | [TEGRA_POWERGATE_NVDEC] = "nvdec", | |
2260 | [TEGRA_POWERGATE_NVJPG] = "nvjpg", | |
2261 | [TEGRA_POWERGATE_AUD] = "aud", | |
2262 | [TEGRA_POWERGATE_DFD] = "dfd", | |
2263 | [TEGRA_POWERGATE_VE2] = "ve2", | |
2264 | }; | |
2265 | ||
2266 | static const u8 tegra210_cpu_powergates[] = { | |
2267 | TEGRA_POWERGATE_CPU0, | |
2268 | TEGRA_POWERGATE_CPU1, | |
2269 | TEGRA_POWERGATE_CPU2, | |
2270 | TEGRA_POWERGATE_CPU3, | |
2271 | }; | |
2272 | ||
437c4f26 AV |
2273 | #define TEGRA210_IO_PAD_TABLE(_pad) \ |
2274 | /* .id .dpd .voltage .name */ \ | |
2275 | _pad(TEGRA_IO_PAD_AUDIO, 17, 5, "audio"), \ | |
2276 | _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 18, "audio-hv"), \ | |
2277 | _pad(TEGRA_IO_PAD_CAM, 36, 10, "cam"), \ | |
2278 | _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ | |
2279 | _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ | |
2280 | _pad(TEGRA_IO_PAD_CSIC, 42, UINT_MAX, "csic"), \ | |
2281 | _pad(TEGRA_IO_PAD_CSID, 43, UINT_MAX, "csid"), \ | |
2282 | _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "csie"), \ | |
2283 | _pad(TEGRA_IO_PAD_CSIF, 45, UINT_MAX, "csif"), \ | |
2284 | _pad(TEGRA_IO_PAD_DBG, 25, 19, "dbg"), \ | |
2285 | _pad(TEGRA_IO_PAD_DEBUG_NONAO, 26, UINT_MAX, "debug-nonao"), \ | |
2286 | _pad(TEGRA_IO_PAD_DMIC, 50, 20, "dmic"), \ | |
2287 | _pad(TEGRA_IO_PAD_DP, 51, UINT_MAX, "dp"), \ | |
2288 | _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ | |
2289 | _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \ | |
2290 | _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \ | |
2291 | _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \ | |
2292 | _pad(TEGRA_IO_PAD_EMMC, 35, UINT_MAX, "emmc"), \ | |
2293 | _pad(TEGRA_IO_PAD_EMMC2, 37, UINT_MAX, "emmc2"), \ | |
2294 | _pad(TEGRA_IO_PAD_GPIO, 27, 21, "gpio"), \ | |
2295 | _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \ | |
2296 | _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ | |
2297 | _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \ | |
2298 | _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ | |
2299 | _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \ | |
2300 | _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \ | |
2301 | _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ | |
2302 | _pad(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, 11, "pex-cntrl"), \ | |
2303 | _pad(TEGRA_IO_PAD_SDMMC1, 33, 12, "sdmmc1"), \ | |
2304 | _pad(TEGRA_IO_PAD_SDMMC3, 34, 13, "sdmmc3"), \ | |
2305 | _pad(TEGRA_IO_PAD_SPI, 46, 22, "spi"), \ | |
2306 | _pad(TEGRA_IO_PAD_SPI_HV, 47, 23, "spi-hv"), \ | |
2307 | _pad(TEGRA_IO_PAD_UART, 14, 2, "uart"), \ | |
2308 | _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ | |
2309 | _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ | |
2310 | _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ | |
2311 | _pad(TEGRA_IO_PAD_USB3, 18, UINT_MAX, "usb3"), \ | |
2312 | _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias") | |
2313 | ||
21b49910 | 2314 | static const struct tegra_io_pad_soc tegra210_io_pads[] = { |
437c4f26 | 2315 | TEGRA210_IO_PAD_TABLE(TEGRA_IO_PAD) |
21b49910 LD |
2316 | }; |
2317 | ||
4a37f11c AV |
2318 | static const struct pinctrl_pin_desc tegra210_pin_descs[] = { |
2319 | TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) | |
21b49910 LD |
2320 | }; |
2321 | ||
c2fe4694 TR |
2322 | static const struct tegra_pmc_soc tegra210_pmc_soc = { |
2323 | .num_powergates = ARRAY_SIZE(tegra210_powergates), | |
2324 | .powergates = tegra210_powergates, | |
2325 | .num_cpu_powergates = ARRAY_SIZE(tegra210_cpu_powergates), | |
2326 | .cpu_powergates = tegra210_cpu_powergates, | |
2327 | .has_tsense_reset = true, | |
2328 | .has_gpu_clamps = true, | |
13136a47 | 2329 | .has_impl_33v_pwr = false, |
a263394a | 2330 | .needs_mbist_war = true, |
21b49910 LD |
2331 | .num_io_pads = ARRAY_SIZE(tegra210_io_pads), |
2332 | .io_pads = tegra210_io_pads, | |
4a37f11c AV |
2333 | .num_pin_descs = ARRAY_SIZE(tegra210_pin_descs), |
2334 | .pin_descs = tegra210_pin_descs, | |
5be22556 TR |
2335 | .regs = &tegra20_pmc_regs, |
2336 | .init = tegra20_pmc_init, | |
2337 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | |
5f84bb1a SP |
2338 | .reset_sources = tegra30_reset_sources, |
2339 | .num_reset_sources = 5, | |
2340 | .reset_levels = NULL, | |
2341 | .num_reset_levels = 0, | |
c2fe4694 TR |
2342 | }; |
2343 | ||
437c4f26 AV |
2344 | #define TEGRA186_IO_PAD_TABLE(_pad) \ |
2345 | /* .id .dpd .voltage .name */ \ | |
2346 | _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ | |
2347 | _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ | |
2348 | _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ | |
2349 | _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ | |
2350 | _pad(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, UINT_MAX, "pex-clk-bias"), \ | |
2351 | _pad(TEGRA_IO_PAD_PEX_CLK3, 5, UINT_MAX, "pex-clk3"), \ | |
2352 | _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ | |
2353 | _pad(TEGRA_IO_PAD_PEX_CLK1, 7, UINT_MAX, "pex-clk1"), \ | |
2354 | _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ | |
2355 | _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ | |
2356 | _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ | |
2357 | _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias"), \ | |
2358 | _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ | |
2359 | _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ | |
2360 | _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ | |
2361 | _pad(TEGRA_IO_PAD_DBG, 25, UINT_MAX, "dbg"), \ | |
2362 | _pad(TEGRA_IO_PAD_HDMI_DP0, 28, UINT_MAX, "hdmi-dp0"), \ | |
2363 | _pad(TEGRA_IO_PAD_HDMI_DP1, 29, UINT_MAX, "hdmi-dp1"), \ | |
2364 | _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ | |
2365 | _pad(TEGRA_IO_PAD_SDMMC2_HV, 34, 5, "sdmmc2-hv"), \ | |
2366 | _pad(TEGRA_IO_PAD_SDMMC4, 36, UINT_MAX, "sdmmc4"), \ | |
2367 | _pad(TEGRA_IO_PAD_CAM, 38, UINT_MAX, "cam"), \ | |
2368 | _pad(TEGRA_IO_PAD_DSIB, 40, UINT_MAX, "dsib"), \ | |
2369 | _pad(TEGRA_IO_PAD_DSIC, 41, UINT_MAX, "dsic"), \ | |
2370 | _pad(TEGRA_IO_PAD_DSID, 42, UINT_MAX, "dsid"), \ | |
2371 | _pad(TEGRA_IO_PAD_CSIC, 43, UINT_MAX, "csic"), \ | |
2372 | _pad(TEGRA_IO_PAD_CSID, 44, UINT_MAX, "csid"), \ | |
2373 | _pad(TEGRA_IO_PAD_CSIE, 45, UINT_MAX, "csie"), \ | |
2374 | _pad(TEGRA_IO_PAD_CSIF, 46, UINT_MAX, "csif"), \ | |
2375 | _pad(TEGRA_IO_PAD_SPI, 47, UINT_MAX, "spi"), \ | |
2376 | _pad(TEGRA_IO_PAD_UFS, 49, UINT_MAX, "ufs"), \ | |
2377 | _pad(TEGRA_IO_PAD_DMIC_HV, 52, 2, "dmic-hv"), \ | |
2378 | _pad(TEGRA_IO_PAD_EDP, 53, UINT_MAX, "edp"), \ | |
2379 | _pad(TEGRA_IO_PAD_SDMMC1_HV, 55, 4, "sdmmc1-hv"), \ | |
2380 | _pad(TEGRA_IO_PAD_SDMMC3_HV, 56, 6, "sdmmc3-hv"), \ | |
2381 | _pad(TEGRA_IO_PAD_CONN, 60, UINT_MAX, "conn"), \ | |
2382 | _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 1, "audio-hv"), \ | |
2383 | _pad(TEGRA_IO_PAD_AO_HV, UINT_MAX, 0, "ao-hv") | |
2384 | ||
c641ec6e | 2385 | static const struct tegra_io_pad_soc tegra186_io_pads[] = { |
437c4f26 | 2386 | TEGRA186_IO_PAD_TABLE(TEGRA_IO_PAD) |
c641ec6e TR |
2387 | }; |
2388 | ||
4a37f11c AV |
2389 | static const struct pinctrl_pin_desc tegra186_pin_descs[] = { |
2390 | TEGRA186_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) | |
c641ec6e TR |
2391 | }; |
2392 | ||
2393 | static const struct tegra_pmc_regs tegra186_pmc_regs = { | |
2394 | .scratch0 = 0x2000, | |
2395 | .dpd_req = 0x74, | |
2396 | .dpd_status = 0x78, | |
2397 | .dpd2_req = 0x7c, | |
2398 | .dpd2_status = 0x80, | |
5f84bb1a SP |
2399 | .rst_status = 0x70, |
2400 | .rst_source_shift = 0x2, | |
2401 | .rst_source_mask = 0x3C, | |
2402 | .rst_level_shift = 0x0, | |
2403 | .rst_level_mask = 0x3, | |
c641ec6e TR |
2404 | }; |
2405 | ||
2406 | static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, | |
2407 | struct device_node *np, | |
2408 | bool invert) | |
2409 | { | |
2410 | struct resource regs; | |
2411 | void __iomem *wake; | |
2412 | u32 value; | |
2413 | int index; | |
2414 | ||
2415 | index = of_property_match_string(np, "reg-names", "wake"); | |
2416 | if (index < 0) { | |
2417 | pr_err("failed to find PMC wake registers\n"); | |
2418 | return; | |
2419 | } | |
2420 | ||
2421 | of_address_to_resource(np, index, ®s); | |
2422 | ||
2423 | wake = ioremap_nocache(regs.start, resource_size(®s)); | |
2424 | if (!wake) { | |
2425 | pr_err("failed to map PMC wake registers\n"); | |
2426 | return; | |
2427 | } | |
2428 | ||
2429 | value = readl(wake + WAKE_AOWAKE_CTRL); | |
2430 | ||
2431 | if (invert) | |
2432 | value |= WAKE_AOWAKE_CTRL_INTR_POLARITY; | |
2433 | else | |
2434 | value &= ~WAKE_AOWAKE_CTRL_INTR_POLARITY; | |
2435 | ||
2436 | writel(value, wake + WAKE_AOWAKE_CTRL); | |
2437 | ||
2438 | iounmap(wake); | |
2439 | } | |
2440 | ||
e59333c8 TR |
2441 | static const struct tegra_wake_event tegra186_wake_events[] = { |
2442 | TEGRA_WAKE_GPIO("power", 29, 1, TEGRA_AON_GPIO(FF, 0)), | |
2443 | TEGRA_WAKE_IRQ("rtc", 73, 10), | |
2444 | }; | |
2445 | ||
c641ec6e TR |
2446 | static const struct tegra_pmc_soc tegra186_pmc_soc = { |
2447 | .num_powergates = 0, | |
2448 | .powergates = NULL, | |
2449 | .num_cpu_powergates = 0, | |
2450 | .cpu_powergates = NULL, | |
2451 | .has_tsense_reset = false, | |
2452 | .has_gpu_clamps = false, | |
13136a47 | 2453 | .has_impl_33v_pwr = true, |
c641ec6e TR |
2454 | .num_io_pads = ARRAY_SIZE(tegra186_io_pads), |
2455 | .io_pads = tegra186_io_pads, | |
4a37f11c AV |
2456 | .num_pin_descs = ARRAY_SIZE(tegra186_pin_descs), |
2457 | .pin_descs = tegra186_pin_descs, | |
c641ec6e TR |
2458 | .regs = &tegra186_pmc_regs, |
2459 | .init = NULL, | |
2460 | .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, | |
5f84bb1a SP |
2461 | .reset_sources = tegra186_reset_sources, |
2462 | .num_reset_sources = 14, | |
2463 | .reset_levels = tegra186_reset_levels, | |
2464 | .num_reset_levels = 3, | |
e59333c8 TR |
2465 | .num_wake_events = ARRAY_SIZE(tegra186_wake_events), |
2466 | .wake_events = tegra186_wake_events, | |
c641ec6e TR |
2467 | }; |
2468 | ||
eac9c48a TR |
2469 | static const struct tegra_io_pad_soc tegra194_io_pads[] = { |
2470 | { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, | |
2471 | { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX }, | |
2472 | { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX }, | |
2473 | { .id = TEGRA_IO_PAD_PEX_CLK_BIAS, .dpd = 4, .voltage = UINT_MAX }, | |
2474 | { .id = TEGRA_IO_PAD_PEX_CLK3, .dpd = 5, .voltage = UINT_MAX }, | |
2475 | { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX }, | |
2476 | { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 7, .voltage = UINT_MAX }, | |
2477 | { .id = TEGRA_IO_PAD_EQOS, .dpd = 8, .voltage = UINT_MAX }, | |
2478 | { .id = TEGRA_IO_PAD_PEX_CLK2_BIAS, .dpd = 9, .voltage = UINT_MAX }, | |
2479 | { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 10, .voltage = UINT_MAX }, | |
2480 | { .id = TEGRA_IO_PAD_DAP3, .dpd = 11, .voltage = UINT_MAX }, | |
2481 | { .id = TEGRA_IO_PAD_DAP5, .dpd = 12, .voltage = UINT_MAX }, | |
2482 | { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX }, | |
2483 | { .id = TEGRA_IO_PAD_PWR_CTL, .dpd = 15, .voltage = UINT_MAX }, | |
2484 | { .id = TEGRA_IO_PAD_SOC_GPIO53, .dpd = 16, .voltage = UINT_MAX }, | |
2485 | { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX }, | |
2486 | { .id = TEGRA_IO_PAD_GP_PWM2, .dpd = 18, .voltage = UINT_MAX }, | |
2487 | { .id = TEGRA_IO_PAD_GP_PWM3, .dpd = 19, .voltage = UINT_MAX }, | |
2488 | { .id = TEGRA_IO_PAD_SOC_GPIO12, .dpd = 20, .voltage = UINT_MAX }, | |
2489 | { .id = TEGRA_IO_PAD_SOC_GPIO13, .dpd = 21, .voltage = UINT_MAX }, | |
2490 | { .id = TEGRA_IO_PAD_SOC_GPIO10, .dpd = 22, .voltage = UINT_MAX }, | |
2491 | { .id = TEGRA_IO_PAD_UART4, .dpd = 23, .voltage = UINT_MAX }, | |
2492 | { .id = TEGRA_IO_PAD_UART5, .dpd = 24, .voltage = UINT_MAX }, | |
2493 | { .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = UINT_MAX }, | |
2494 | { .id = TEGRA_IO_PAD_HDMI_DP3, .dpd = 26, .voltage = UINT_MAX }, | |
2495 | { .id = TEGRA_IO_PAD_HDMI_DP2, .dpd = 27, .voltage = UINT_MAX }, | |
2496 | { .id = TEGRA_IO_PAD_HDMI_DP0, .dpd = 28, .voltage = UINT_MAX }, | |
2497 | { .id = TEGRA_IO_PAD_HDMI_DP1, .dpd = 29, .voltage = UINT_MAX }, | |
2498 | { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX }, | |
2499 | { .id = TEGRA_IO_PAD_PEX_CTL2, .dpd = 33, .voltage = UINT_MAX }, | |
2500 | { .id = TEGRA_IO_PAD_PEX_L0_RST_N, .dpd = 34, .voltage = UINT_MAX }, | |
2501 | { .id = TEGRA_IO_PAD_PEX_L1_RST_N, .dpd = 35, .voltage = UINT_MAX }, | |
2502 | { .id = TEGRA_IO_PAD_SDMMC4, .dpd = 36, .voltage = UINT_MAX }, | |
2503 | { .id = TEGRA_IO_PAD_PEX_L5_RST_N, .dpd = 37, .voltage = UINT_MAX }, | |
2504 | { .id = TEGRA_IO_PAD_CSIC, .dpd = 43, .voltage = UINT_MAX }, | |
2505 | { .id = TEGRA_IO_PAD_CSID, .dpd = 44, .voltage = UINT_MAX }, | |
2506 | { .id = TEGRA_IO_PAD_CSIE, .dpd = 45, .voltage = UINT_MAX }, | |
2507 | { .id = TEGRA_IO_PAD_CSIF, .dpd = 46, .voltage = UINT_MAX }, | |
2508 | { .id = TEGRA_IO_PAD_SPI, .dpd = 47, .voltage = UINT_MAX }, | |
2509 | { .id = TEGRA_IO_PAD_UFS, .dpd = 49, .voltage = UINT_MAX }, | |
2510 | { .id = TEGRA_IO_PAD_CSIG, .dpd = 50, .voltage = UINT_MAX }, | |
2511 | { .id = TEGRA_IO_PAD_CSIH, .dpd = 51, .voltage = UINT_MAX }, | |
2512 | { .id = TEGRA_IO_PAD_EDP, .dpd = 53, .voltage = UINT_MAX }, | |
2513 | { .id = TEGRA_IO_PAD_SDMMC1_HV, .dpd = 55, .voltage = UINT_MAX }, | |
2514 | { .id = TEGRA_IO_PAD_SDMMC3_HV, .dpd = 56, .voltage = UINT_MAX }, | |
2515 | { .id = TEGRA_IO_PAD_CONN, .dpd = 60, .voltage = UINT_MAX }, | |
2516 | { .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = UINT_MAX }, | |
2517 | }; | |
2518 | ||
2519 | static const struct tegra_pmc_soc tegra194_pmc_soc = { | |
2520 | .num_powergates = 0, | |
2521 | .powergates = NULL, | |
2522 | .num_cpu_powergates = 0, | |
2523 | .cpu_powergates = NULL, | |
2524 | .has_tsense_reset = false, | |
2525 | .has_gpu_clamps = false, | |
2526 | .num_io_pads = ARRAY_SIZE(tegra194_io_pads), | |
2527 | .io_pads = tegra194_io_pads, | |
2528 | .regs = &tegra186_pmc_regs, | |
2529 | .init = NULL, | |
2530 | .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, | |
2531 | }; | |
2532 | ||
7232398a | 2533 | static const struct of_device_id tegra_pmc_match[] = { |
eac9c48a | 2534 | { .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc }, |
c641ec6e | 2535 | { .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc }, |
c2fe4694 | 2536 | { .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc }, |
7d71e903 | 2537 | { .compatible = "nvidia,tegra132-pmc", .data = &tegra124_pmc_soc }, |
7232398a TR |
2538 | { .compatible = "nvidia,tegra124-pmc", .data = &tegra124_pmc_soc }, |
2539 | { .compatible = "nvidia,tegra114-pmc", .data = &tegra114_pmc_soc }, | |
2540 | { .compatible = "nvidia,tegra30-pmc", .data = &tegra30_pmc_soc }, | |
2541 | { .compatible = "nvidia,tegra20-pmc", .data = &tegra20_pmc_soc }, | |
2542 | { } | |
2543 | }; | |
2544 | ||
2545 | static struct platform_driver tegra_pmc_driver = { | |
2546 | .driver = { | |
2547 | .name = "tegra-pmc", | |
2548 | .suppress_bind_attrs = true, | |
2549 | .of_match_table = tegra_pmc_match, | |
2b20b616 | 2550 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) |
7232398a | 2551 | .pm = &tegra_pmc_pm_ops, |
2b20b616 | 2552 | #endif |
7232398a TR |
2553 | }, |
2554 | .probe = tegra_pmc_probe, | |
2555 | }; | |
7d4d9ed6 | 2556 | builtin_platform_driver(tegra_pmc_driver); |
7232398a TR |
2557 | |
2558 | /* | |
2559 | * Early initialization to allow access to registers in the very early boot | |
2560 | * process. | |
2561 | */ | |
2562 | static int __init tegra_pmc_early_init(void) | |
2563 | { | |
2564 | const struct of_device_id *match; | |
2565 | struct device_node *np; | |
2566 | struct resource regs; | |
2567 | bool invert; | |
7232398a | 2568 | |
61fd284b JH |
2569 | mutex_init(&pmc->powergates_lock); |
2570 | ||
7232398a TR |
2571 | np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match); |
2572 | if (!np) { | |
7d71e903 TR |
2573 | /* |
2574 | * Fall back to legacy initialization for 32-bit ARM only. All | |
2575 | * 64-bit ARM device tree files for Tegra are required to have | |
2576 | * a PMC node. | |
2577 | * | |
2578 | * This is for backwards-compatibility with old device trees | |
2579 | * that didn't contain a PMC node. Note that in this case the | |
2580 | * SoC data can't be matched and therefore powergating is | |
2581 | * disabled. | |
2582 | */ | |
2583 | if (IS_ENABLED(CONFIG_ARM) && soc_is_tegra()) { | |
2584 | pr_warn("DT node not found, powergating disabled\n"); | |
2585 | ||
2586 | regs.start = 0x7000e400; | |
2587 | regs.end = 0x7000e7ff; | |
2588 | regs.flags = IORESOURCE_MEM; | |
2589 | ||
2590 | pr_warn("Using memory region %pR\n", ®s); | |
2591 | } else { | |
2592 | /* | |
2593 | * At this point we're not running on Tegra, so play | |
2594 | * nice with multi-platform kernels. | |
2595 | */ | |
2596 | return 0; | |
2597 | } | |
7232398a | 2598 | } else { |
7d71e903 TR |
2599 | /* |
2600 | * Extract information from the device tree if we've found a | |
2601 | * matching node. | |
2602 | */ | |
2603 | if (of_address_to_resource(np, 0, ®s) < 0) { | |
2604 | pr_err("failed to get PMC registers\n"); | |
b69a6258 | 2605 | of_node_put(np); |
7d71e903 TR |
2606 | return -ENXIO; |
2607 | } | |
7232398a TR |
2608 | } |
2609 | ||
2610 | pmc->base = ioremap_nocache(regs.start, resource_size(®s)); | |
2611 | if (!pmc->base) { | |
2612 | pr_err("failed to map PMC registers\n"); | |
b69a6258 | 2613 | of_node_put(np); |
7232398a TR |
2614 | return -ENXIO; |
2615 | } | |
2616 | ||
11131895 | 2617 | if (np) { |
718a2426 JH |
2618 | pmc->soc = match->data; |
2619 | ||
e2d17960 | 2620 | tegra_powergate_init(pmc, np); |
7232398a | 2621 | |
11131895 JH |
2622 | /* |
2623 | * Invert the interrupt polarity if a PMC device tree node | |
2624 | * exists and contains the nvidia,invert-interrupt property. | |
2625 | */ | |
2626 | invert = of_property_read_bool(np, "nvidia,invert-interrupt"); | |
7232398a | 2627 | |
5be22556 | 2628 | pmc->soc->setup_irq_polarity(pmc, np, invert); |
b69a6258 JH |
2629 | |
2630 | of_node_put(np); | |
11131895 | 2631 | } |
7232398a TR |
2632 | |
2633 | return 0; | |
2634 | } | |
2635 | early_initcall(tegra_pmc_early_init); |