2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright 2020 Michal Meloun <mmel@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/param.h>
29 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/module.h>
33 #include <sys/malloc.h>
34 #include <sys/mutex.h>
37 #include <machine/bus.h>
39 #include <dev/clk/clk.h>
40 #include <dev/hwreset/hwreset.h>
41 #include <dev/ofw/ofw_bus.h>
42 #include <dev/ofw/ofw_bus_subr.h>
43 #include <dev/psci/smccc.h>
45 #include <arm/nvidia/tegra_pmc.h>
47 #define PMC_CNTRL 0x000
48 #define PMC_CNTRL_SHUTDOWN_OE (1 << 22)
49 #define PMC_CNTRL_CPUPWRGOOD_SEL_MASK (0x3 << 20)
50 #define PMC_CNTRL_CPUPWRGOOD_SEL_SHIFT 20
51 #define PMC_CNTRL_CPUPWRGOOD_EN (1 << 19)
52 #define PMC_CNTRL_FUSE_OVERRIDE (1 << 18)
53 #define PMC_CNTRL_INTR_POLARITY (1 << 17)
54 #define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16)
55 #define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15)
56 #define PMC_CNTRL_SIDE_EFFECT_LP0 (1 << 14)
57 #define PMC_CNTRL_AOINIT (1 << 13)
58 #define PMC_CNTRL_PWRGATE_DIS (1 << 12)
59 #define PMC_CNTRL_SYSCLK_OE (1 << 11)
60 #define PMC_CNTRL_SYSCLK_POLARITY (1 << 10)
61 #define PMC_CNTRL_PWRREQ_OE (1 << 9)
62 #define PMC_CNTRL_PWRREQ_POLARITY (1 << 8)
63 #define PMC_CNTRL_BLINK_EN (1 << 7)
64 #define PMC_CNTRL_GLITCHDET_DIS (1 << 6)
65 #define PMC_CNTRL_LATCHWAKE_EN (1 << 5)
66 #define PMC_CNTRL_MAIN_RST (1 << 4)
67 #define PMC_CNTRL_KBC_RST (1 << 3)
68 #define PMC_CNTRL_RTC_RST (1 << 2)
69 #define PMC_CNTRL_RTC_CLK_DIS (1 << 1)
70 #define PMC_CNTRL_KBC_CLK_DIS (1 << 0)
72 #define PMC_DPD_SAMPLE 0x020
74 #define PMC_CLAMP_STATUS 0x02C
75 #define PMC_CLAMP_STATUS_PARTID(x) (1 << ((x) & 0x1F))
77 #define PMC_PWRGATE_TOGGLE 0x030
78 #define PMC_PWRGATE_TOGGLE_START (1 << 8)
79 #define PMC_PWRGATE_TOGGLE_PARTID(x) (((x) & 0x1F) << 0)
81 #define PMC_REMOVE_CLAMPING_CMD 0x034
82 #define PMC_REMOVE_CLAMPING_CMD_PARTID(x) (1 << ((x) & 0x1F))
84 #define PMC_PWRGATE_STATUS 0x038
85 #define PMC_PWRGATE_STATUS_PARTID(x) (1 << ((x) & 0x1F))
87 #define PMC_SCRATCH0 0x050
88 #define PMC_SCRATCH0_MODE_RECOVERY (1 << 31)
89 #define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30)
90 #define PMC_SCRATCH0_MODE_RCM (1 << 1)
91 #define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \
92 PMC_SCRATCH0_MODE_BOOTLOADER | \
93 PMC_SCRATCH0_MODE_RCM)
95 #define PMC_CPUPWRGOOD_TIMER 0x0c8
96 #define PMC_CPUPWROFF_TIMER 0x0cc
98 #define PMC_SCRATCH41 0x140
100 #define PMC_SENSOR_CTRL 0x1b0
101 #define PMC_SENSOR_CTRL_BLOCK_SCRATCH_WRITE (1 << 2)
102 #define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1)
103 #define PMC_SENSOR_CTRL_ENABLE_PG (1 << 0)
105 #define PMC_IO_DPD_REQ 0x1b8
106 #define PMC_IO_DPD_REQ_CODE_IDLE (0 << 30)
107 #define PMC_IO_DPD_REQ_CODE_OFF (1 << 30)
108 #define PMC_IO_DPD_REQ_CODE_ON (2 << 30)
109 #define PMC_IO_DPD_REQ_CODE_MASK (3 << 30)
111 #define PMC_IO_DPD_STATUS 0x1bc
112 #define PMC_IO_DPD_STATUS_HDMI (1 << 28)
113 #define PMC_IO_DPD2_REQ 0x1c0
114 #define PMC_IO_DPD2_STATUS 0x1c4
115 #define PMC_IO_DPD2_STATUS_HV (1 << 6)
116 #define PMC_SEL_DPD_TIM 0x1c8
118 #define PMC_SCRATCH54 0x258
119 #define PMC_SCRATCH54_DATA_SHIFT 8
120 #define PMC_SCRATCH54_ADDR_SHIFT 0
122 #define PMC_SCRATCH55 0x25c
123 #define PMC_SCRATCH55_RST_ENABLE (1 << 31)
124 #define PMC_SCRATCH55_CNTRL_TYPE (1 << 30)
125 #define PMC_SCRATCH55_CNTRL_ID_SHIFT 27
126 #define PMC_SCRATCH55_CNTRL_ID_MASK 0x07
127 #define PMC_SCRATCH55_PINMUX_SHIFT 24
128 #define PMC_SCRATCH55_PINMUX_MASK 0x07
129 #define PMC_SCRATCH55_CHECKSUM_SHIFT 16
130 #define PMC_SCRATCH55_CHECKSUM_MASK 0xFF
131 #define PMC_SCRATCH55_16BITOP (1 << 15)
132 #define PMC_SCRATCH55_I2CSLV1_SHIFT 0
133 #define PMC_SCRATCH55_I2CSLV1_MASK 0x7F
135 #define PMC_GPU_RG_CNTRL 0x2d4
138 #define PMC_SMC 0xc2fffe00
139 #define PMC_SMC_READ 0xaa
140 #define PMC_SMC_WRITE 0xbb
142 #define PMC_LOCK(_sc) mtx_lock(&(_sc)->mtx)
143 #define PMC_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
144 #define PMC_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \
145 device_get_nameunit(_sc->dev), "tegra210_pmc", MTX_DEF)
146 #define PMC_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx);
147 #define PMC_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED);
148 #define PMC_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED);
150 struct tegra210_pmc_softc
{
152 struct resource
*mem_res
;
158 enum tegra_suspend_mode suspend_mode
;
159 uint32_t cpu_good_time
;
160 uint32_t cpu_off_time
;
161 uint32_t core_osc_time
;
162 uint32_t core_pmu_time
;
163 uint32_t core_off_time
;
168 uint32_t lp0_vec_phys
;
169 uint32_t lp0_vec_size
;
172 static struct ofw_compat_data compat_data
[] = {
173 {"nvidia,tegra210-pmc", 1},
177 static struct tegra210_pmc_softc
*pmc_sc
;
179 static inline struct tegra210_pmc_softc
*
180 tegra210_pmc_get_sc(void)
183 panic("To early call to Tegra PMC driver.\n");
188 WR4(struct tegra210_pmc_softc
*sc
, bus_size_t r
, uint32_t v
)
190 struct arm_smccc_res res
;
192 if (sc
->secure_access
) {
193 arm_smccc_invoke_smc(PMC_SMC
, PMC_SMC_WRITE
, r
, v
, &res
);
195 device_printf(sc
->dev
," PMC SMC write failed: %lu\n",
199 bus_write_4(sc
->mem_res
, r
, v
);
203 RD4(struct tegra210_pmc_softc
*sc
, bus_size_t r
)
205 struct arm_smccc_res res
;
207 if (sc
->secure_access
) {
208 arm_smccc_invoke_smc(PMC_SMC
, PMC_SMC_READ
, r
, &res
);
210 device_printf(sc
->dev
," PMC SMC write failed: %lu\n",
212 return((uint32_t)res
.a1
);
215 return(bus_read_4(sc
->mem_res
, r
));
219 tegra210_pmc_set_powergate(struct tegra210_pmc_softc
*sc
,
220 enum tegra_powergate_id id
, int ena
)
227 reg
= RD4(sc
, PMC_PWRGATE_STATUS
) & PMC_PWRGATE_STATUS_PARTID(id
);
228 if (((reg
!= 0) && ena
) || ((reg
== 0) && !ena
)) {
233 for (i
= 100; i
> 0; i
--) {
234 reg
= RD4(sc
, PMC_PWRGATE_TOGGLE
);
235 if ((reg
& PMC_PWRGATE_TOGGLE_START
) == 0)
240 device_printf(sc
->dev
,
241 "Timeout when waiting for TOGGLE_START\n");
243 WR4(sc
, PMC_PWRGATE_TOGGLE
,
244 PMC_PWRGATE_TOGGLE_START
| PMC_PWRGATE_TOGGLE_PARTID(id
));
246 for (i
= 100; i
> 0; i
--) {
247 reg
= RD4(sc
, PMC_PWRGATE_TOGGLE
);
248 if ((reg
& PMC_PWRGATE_TOGGLE_START
) == 0)
253 device_printf(sc
->dev
,
254 "Timeout when waiting for TOGGLE_START\n");
260 tegra_powergate_remove_clamping(enum tegra_powergate_id id
)
262 struct tegra210_pmc_softc
*sc
;
264 enum tegra_powergate_id swid
;
267 sc
= tegra210_pmc_get_sc();
269 if (id
== TEGRA_POWERGATE_3D
) {
270 WR4(sc
, PMC_GPU_RG_CNTRL
, 0);
274 reg
= RD4(sc
, PMC_PWRGATE_STATUS
);
275 if ((reg
& PMC_PWRGATE_STATUS_PARTID(id
)) == 0)
276 panic("Attempt to remove clamping for unpowered partition.\n");
278 if (id
== TEGRA_POWERGATE_PCX
)
279 swid
= TEGRA_POWERGATE_VDE
;
280 else if (id
== TEGRA_POWERGATE_VDE
)
281 swid
= TEGRA_POWERGATE_PCX
;
284 WR4(sc
, PMC_REMOVE_CLAMPING_CMD
, PMC_REMOVE_CLAMPING_CMD_PARTID(swid
));
286 for (i
= 100; i
> 0; i
--) {
287 reg
= RD4(sc
, PMC_REMOVE_CLAMPING_CMD
);
288 if ((reg
& PMC_REMOVE_CLAMPING_CMD_PARTID(swid
)) == 0)
293 device_printf(sc
->dev
, "Timeout when remove clamping\n");
295 reg
= RD4(sc
, PMC_CLAMP_STATUS
);
296 if ((reg
& PMC_CLAMP_STATUS_PARTID(id
)) != 0)
297 panic("Cannot remove clamping\n");
303 tegra_powergate_is_powered(enum tegra_powergate_id id
)
305 struct tegra210_pmc_softc
*sc
;
308 sc
= tegra210_pmc_get_sc();
310 reg
= RD4(sc
, PMC_PWRGATE_STATUS
);
311 return ((reg
& PMC_PWRGATE_STATUS_PARTID(id
)) ? 1 : 0);
315 tegra_powergate_power_on(enum tegra_powergate_id id
)
317 struct tegra210_pmc_softc
*sc
;
320 sc
= tegra210_pmc_get_sc();
322 rv
= tegra210_pmc_set_powergate(sc
, id
, 1);
324 device_printf(sc
->dev
, "Cannot set powergate: %d\n", id
);
328 for (i
= 100; i
> 0; i
--) {
329 if (tegra_powergate_is_powered(id
))
334 device_printf(sc
->dev
, "Timeout when waiting on power up\n");
342 tegra_powergate_power_off(enum tegra_powergate_id id
)
344 struct tegra210_pmc_softc
*sc
;
347 sc
= tegra210_pmc_get_sc();
349 rv
= tegra210_pmc_set_powergate(sc
, id
, 0);
351 device_printf(sc
->dev
, "Cannot set powergate: %d\n", id
);
354 for (i
= 100; i
> 0; i
--) {
355 if (!tegra_powergate_is_powered(id
))
360 device_printf(sc
->dev
, "Timeout when waiting on power off\n");
366 tegra_powergate_sequence_power_up(enum tegra_powergate_id id
, clk_t clk
,
369 struct tegra210_pmc_softc
*sc
;
372 sc
= tegra210_pmc_get_sc();
374 rv
= hwreset_assert(rst
);
376 device_printf(sc
->dev
, "Cannot assert reset\n");
382 device_printf(sc
->dev
, "Cannot stop clock\n");
386 rv
= tegra_powergate_power_on(id
);
388 device_printf(sc
->dev
, "Cannot power on powergate\n");
392 rv
= clk_enable(clk
);
394 device_printf(sc
->dev
, "Cannot enable clock\n");
399 rv
= tegra_powergate_remove_clamping(id
);
401 device_printf(sc
->dev
, "Cannot remove clamping\n");
404 rv
= hwreset_deassert(rst
);
406 device_printf(sc
->dev
, "Cannot unreset reset\n");
415 tegra_powergate_power_off(id
);
420 tegra210_pmc_parse_fdt(struct tegra210_pmc_softc
*sc
, phandle_t node
)
426 rv
= OF_getencprop(node
, "nvidia,suspend-mode", &tmp
, sizeof(tmp
));
430 sc
->suspend_mode
= TEGRA_SUSPEND_LP0
;
434 sc
->suspend_mode
= TEGRA_SUSPEND_LP1
;
438 sc
->suspend_mode
= TEGRA_SUSPEND_LP2
;
442 sc
->suspend_mode
= TEGRA_SUSPEND_NONE
;
447 rv
= OF_getencprop(node
, "nvidia,cpu-pwr-good-time", &tmp
, sizeof(tmp
));
449 sc
->cpu_good_time
= tmp
;
450 sc
->suspend_mode
= TEGRA_SUSPEND_NONE
;
453 rv
= OF_getencprop(node
, "nvidia,cpu-pwr-off-time", &tmp
, sizeof(tmp
));
455 sc
->cpu_off_time
= tmp
;
456 sc
->suspend_mode
= TEGRA_SUSPEND_NONE
;
459 rv
= OF_getencprop(node
, "nvidia,core-pwr-good-time", tmparr
,
461 if (rv
== sizeof(tmparr
)) {
462 sc
->core_osc_time
= tmparr
[0];
463 sc
->core_pmu_time
= tmparr
[1];
464 sc
->suspend_mode
= TEGRA_SUSPEND_NONE
;
467 rv
= OF_getencprop(node
, "nvidia,core-pwr-off-time", &tmp
, sizeof(tmp
));
469 sc
->core_off_time
= tmp
;
470 sc
->suspend_mode
= TEGRA_SUSPEND_NONE
;
474 OF_hasprop(node
, "nvidia,core-power-req-active-high");
476 OF_hasprop(node
, "nvidia,sys-clock-req-active-high");
478 OF_hasprop(node
, "nvidia,combined-power-req");
479 sc
->cpu_pwr_good_en
=
480 OF_hasprop(node
, "nvidia,cpu-pwr-good-en");
482 rv
= OF_getencprop(node
, "nvidia,lp0-vec", tmparr
, sizeof(tmparr
));
483 if (rv
== sizeof(tmparr
)) {
485 sc
->lp0_vec_phys
= tmparr
[0];
486 sc
->core_pmu_time
= tmparr
[1];
487 sc
->lp0_vec_size
= TEGRA_SUSPEND_NONE
;
488 if (sc
->suspend_mode
== TEGRA_SUSPEND_LP0
)
489 sc
->suspend_mode
= TEGRA_SUSPEND_LP1
;
495 tegra210_pmc_check_secure(struct tegra210_pmc_softc
*sc
)
499 sc
->secure_access
= false;
502 * If PMC is coverd by secure trust zone, all reads returns 0,
503 * Use scratch0 register acvcess test
505 orig
= RD4(sc
, PMC_SCRATCH0
);
506 WR4(sc
, PMC_SCRATCH0
, 0xDEADBEEF);
507 if (RD4(sc
, PMC_SCRATCH0
) == 0) {
508 sc
->secure_access
= true;
511 WR4(sc
, PMC_SCRATCH0
, 0xBADC0DE);
512 if (RD4(sc
, PMC_SCRATCH0
) == 0) {
513 sc
->secure_access
= true;
516 WR4(sc
, PMC_SCRATCH0
, orig
);
520 tegra210_pmc_probe(device_t dev
)
523 if (!ofw_bus_status_okay(dev
))
526 if (!ofw_bus_search_compatible(dev
, compat_data
)->ocd_data
)
529 device_set_desc(dev
, "Tegra PMC");
530 return (BUS_PROBE_DEFAULT
);
534 tegra210_pmc_detach(device_t dev
)
537 /* This device is always present. */
542 tegra210_pmc_attach(device_t dev
)
544 struct tegra210_pmc_softc
*sc
;
549 sc
= device_get_softc(dev
);
551 node
= ofw_bus_get_node(dev
);
554 rv
= tegra210_pmc_parse_fdt(sc
, node
);
556 device_printf(sc
->dev
, "Cannot parse FDT data\n");
560 rv
= clk_get_by_ofw_name(sc
->dev
, 0, "pclk", &sc
->clk
);
562 device_printf(sc
->dev
, "Cannot get \"pclk\" clock\n");
567 sc
->mem_res
= bus_alloc_resource_any(dev
, SYS_RES_MEMORY
, &rid
,
569 if (sc
->mem_res
== NULL
) {
570 device_printf(dev
, "Cannot allocate memory resources\n");
574 tegra210_pmc_check_secure(sc
);
576 /* Enable CPU power request. */
577 reg
= RD4(sc
, PMC_CNTRL
);
578 reg
|= PMC_CNTRL_CPU_PWRREQ_OE
;
579 WR4(sc
, PMC_CNTRL
, reg
);
581 /* Set sysclk output polarity */
582 reg
= RD4(sc
, PMC_CNTRL
);
583 if (sc
->sysclkreq_high
)
584 reg
&= ~PMC_CNTRL_SYSCLK_POLARITY
;
586 reg
|= PMC_CNTRL_SYSCLK_POLARITY
;
587 WR4(sc
, PMC_CNTRL
, reg
);
589 /* Enable sysclk request. */
590 reg
= RD4(sc
, PMC_CNTRL
);
591 reg
|= PMC_CNTRL_SYSCLK_OE
;
592 WR4(sc
, PMC_CNTRL
, reg
);
595 * Remove HDMI from deep power down mode.
596 * XXX mote this to HDMI driver
598 reg
= RD4(sc
, PMC_IO_DPD_STATUS
);
599 reg
&= ~ PMC_IO_DPD_STATUS_HDMI
;
600 WR4(sc
, PMC_IO_DPD_STATUS
, reg
);
602 reg
= RD4(sc
, PMC_IO_DPD2_STATUS
);
603 reg
&= ~ PMC_IO_DPD2_STATUS_HV
;
604 WR4(sc
, PMC_IO_DPD2_STATUS
, reg
);
607 panic("tegra210_pmc: double driver attach");
612 static device_method_t tegra210_pmc_methods
[] = {
613 /* Device interface */
614 DEVMETHOD(device_probe
, tegra210_pmc_probe
),
615 DEVMETHOD(device_attach
, tegra210_pmc_attach
),
616 DEVMETHOD(device_detach
, tegra210_pmc_detach
),
621 static DEFINE_CLASS_0(pmc
, tegra210_pmc_driver
, tegra210_pmc_methods
,
622 sizeof(struct tegra210_pmc_softc
));
623 EARLY_DRIVER_MODULE(tegra210_pmc
, simplebus
, tegra210_pmc_driver
, NULL
, NULL
,