1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <device/mmio.h>
4 #include <assert.h>
5 #include <console/console.h>
6 #include <soc/addressmap.h>
7 #include <soc/pmc.h>
8 #include <soc/power.h>
9
10 static struct tegra_pmc_regs *const pmc = (void *)TEGRA_PMC_BASE;
11
12 enum {
13 POWER_GATE = 0,
14 POWER_UNGATE = 1,
15 };
16
partition_powered(int id)17 static int partition_powered(int id)
18 {
19 if (read32(&pmc->pwrgate_status) & (0x1 << id))
20 return POWER_UNGATE;
21
22 return POWER_GATE;
23 }
24
25 static const char *const power_gate_string[] = {
26 [POWER_GATE] = "Gat",
27 [POWER_UNGATE] = "Ungat",
28 };
29
power_gate_toggle_request(uint32_t id,int request)30 static void power_gate_toggle_request(uint32_t id, int request)
31 {
32 printk(BIOS_INFO, "%sing power partition %d.\n",
33 power_gate_string[request], id);
34
35 int part_powered = partition_powered(id);
36
37 if (request == part_powered) {
38 printk(BIOS_INFO, "Partition %d already %sed.\n", id,
39 power_gate_string[request]);
40 return;
41 }
42
43 uint32_t pwrgate_toggle = read32(&pmc->pwrgate_toggle);
44 pwrgate_toggle &= ~(PMC_PWRGATE_TOGGLE_PARTID_MASK);
45 pwrgate_toggle |= (id << PMC_PWRGATE_TOGGLE_PARTID_SHIFT);
46 pwrgate_toggle |= PMC_PWRGATE_TOGGLE_START;
47 write32(&pmc->pwrgate_toggle, pwrgate_toggle);
48
49 // Wait for the request to be accepted.
50 while (read32(&pmc->pwrgate_toggle) & PMC_PWRGATE_TOGGLE_START)
51 ;
52 printk(BIOS_INFO, "Power gate toggle request accepted.\n");
53
54 while (1) {
55 part_powered = partition_powered(id);
56 if (request == part_powered) {
57 printk(BIOS_INFO, "Partition %d %sed.\n", id,
58 power_gate_string[request]);
59 return;
60 }
61 }
62 }
63
power_gate_partition(uint32_t id)64 void power_gate_partition(uint32_t id)
65 {
66 power_gate_toggle_request(id, POWER_GATE);
67 }
68
power_ungate_partition(uint32_t id)69 void power_ungate_partition(uint32_t id)
70 {
71 power_gate_toggle_request(id, POWER_UNGATE);
72 }
73
pmc_rst_status(void)74 uint8_t pmc_rst_status(void)
75 {
76 return read32(&pmc->rst_status) & PMC_RST_STATUS_SOURCE_MASK;
77 }
78
79 static const char *pmc_rst_status_str[PMC_RST_STATUS_NUM_SOURCES] = {
80 [PMC_RST_STATUS_SOURCE_POR] = "POR",
81 [PMC_RST_STATUS_SOURCE_WATCHDOG] = "Watchdog",
82 [PMC_RST_STATUS_SOURCE_SENSOR] = "Sensor",
83 [PMC_RST_STATUS_SOURCE_SW_MAIN] = "SW Main",
84 [PMC_RST_STATUS_SOURCE_LP0] = "LP0",
85 };
86
pmc_print_rst_status(void)87 void pmc_print_rst_status(void)
88 {
89 uint8_t rst_status = pmc_rst_status();
90 assert(rst_status < PMC_RST_STATUS_NUM_SOURCES);
91 printk(BIOS_INFO, "PMC Reset Status: %s\n",
92 pmc_rst_status_str[rst_status]);
93 }
94
partition_clamp_on(int id)95 static int partition_clamp_on(int id)
96 {
97 return read32(&pmc->clamp_status) & (1 << id);
98 }
99
remove_clamps(int id)100 void remove_clamps(int id)
101 {
102 if (!partition_clamp_on(id))
103 return;
104
105 /* Remove clamp */
106 write32(&pmc->remove_clamping_cmd, (1 << id));
107
108 /* Wait for clamp off */
109 while (partition_clamp_on(id))
110 ;
111 }
112
pmc_override_pwr_det(uint32_t bits,uint32_t override)113 void pmc_override_pwr_det(uint32_t bits, uint32_t override)
114 {
115 uint32_t val = read32(&pmc->pwr_det_val);
116 val &= ~bits;
117 val |= (override & bits);
118 write32(&pmc->pwr_det_val, val);
119 }
120