1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <device/mmio.h>
4 #include <soc/addressmap.h>
5 #include <soc/flow_ctrl.h>
6
7 #define FLOW_CTRL_HALT_CPU0_EVENTS 0x0
8 #define FLOW_CTRL_WAITEVENT (2 << 29)
9 #define FLOW_CTRL_WAIT_FOR_INTERRUPT (4 << 29)
10 #define FLOW_CTRL_HALT_SCLK (1 << 27)
11 #define FLOW_CTRL_HALT_LIC_IRQ (1 << 11)
12 #define FLOW_CTRL_HALT_LIC_FIQ (1 << 10)
13 #define FLOW_CTRL_HALT_GIC_IRQ (1 << 9)
14 #define FLOW_CTRL_HALT_GIC_FIQ (1 << 8)
15 #define FLOW_CTRL_CPU0_CSR 0x8
16 #define FLOW_CTRL_CSR_INTR_FLAG (1 << 15)
17 #define FLOW_CTRL_CSR_EVENT_FLAG (1 << 14)
18 #define FLOW_CTRL_CSR_WFI_CPU0 (1 << 8)
19 #define FLOW_CTRL_CSR_WFI_BITMAP (0xF << 8)
20 #define FLOW_CTRL_CSR_WFE_BITMAP (0xF << 4)
21 #define FLOW_CTRL_CSR_ENABLE (1 << 0)
22 #define FLOW_CTRL_HALT_CPU1_EVENTS 0x14
23 #define FLOW_CTRL_CPU1_CSR 0x18
24 #define FLOW_CTRL_CC4_CORE0_CTRL 0x6c
25
26 static void *tegra_flowctrl_base = (void *)TEGRA_FLOW_BASE;
27
28 static const uint8_t flowctrl_offset_halt_cpu[] = {
29 FLOW_CTRL_HALT_CPU0_EVENTS,
30 FLOW_CTRL_HALT_CPU1_EVENTS,
31 FLOW_CTRL_HALT_CPU1_EVENTS + 8,
32 FLOW_CTRL_HALT_CPU1_EVENTS + 16
33 };
34
35 static const uint8_t flowctrl_offset_cpu_csr[] = {
36 FLOW_CTRL_CPU0_CSR,
37 FLOW_CTRL_CPU1_CSR,
38 FLOW_CTRL_CPU1_CSR + 8,
39 FLOW_CTRL_CPU1_CSR + 16
40 };
41
42 static const uint8_t flowctrl_offset_cc4_ctrl[] = {
43 FLOW_CTRL_CC4_CORE0_CTRL,
44 FLOW_CTRL_CC4_CORE0_CTRL + 4,
45 FLOW_CTRL_CC4_CORE0_CTRL + 8,
46 FLOW_CTRL_CC4_CORE0_CTRL + 12
47 };
48
flowctrl_write_cpu_csr(int cpu,uint32_t val)49 void flowctrl_write_cpu_csr(int cpu, uint32_t val)
50 {
51 write32(tegra_flowctrl_base + flowctrl_offset_cpu_csr[cpu], val);
52 val = read32(tegra_flowctrl_base + flowctrl_offset_cpu_csr[cpu]);
53 }
54
flowctrl_write_cpu_halt(int cpu,uint32_t val)55 void flowctrl_write_cpu_halt(int cpu, uint32_t val)
56 {
57 write32(tegra_flowctrl_base + flowctrl_offset_halt_cpu[cpu], val);
58 val = read32(tegra_flowctrl_base + flowctrl_offset_halt_cpu[cpu]);
59 }
60
flowctrl_write_cc4_ctrl(int cpu,uint32_t val)61 void flowctrl_write_cc4_ctrl(int cpu, uint32_t val)
62 {
63 write32(tegra_flowctrl_base + flowctrl_offset_cc4_ctrl[cpu], val);
64 val = read32(tegra_flowctrl_base + flowctrl_offset_cc4_ctrl[cpu]);
65 }
66
flowctrl_cpu_off(int cpu)67 void flowctrl_cpu_off(int cpu)
68 {
69 uint32_t val = FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG |
70 FLOW_CTRL_CSR_ENABLE | (FLOW_CTRL_CSR_WFI_CPU0 << cpu);
71
72 flowctrl_write_cpu_csr(cpu, val);
73 flowctrl_write_cpu_halt(cpu, FLOW_CTRL_WAITEVENT);
74 flowctrl_write_cc4_ctrl(cpu, 0);
75 }
76
flowctrl_cpu_on(int cpu)77 void flowctrl_cpu_on(int cpu)
78 {
79 flowctrl_write_cpu_csr(cpu, FLOW_CTRL_CSR_ENABLE);
80 flowctrl_write_cpu_halt(cpu, FLOW_CTRL_WAITEVENT |
81 FLOW_CTRL_HALT_SCLK);
82 }
83
flowctrl_cpu_suspend(int cpu)84 void flowctrl_cpu_suspend(int cpu)
85 {
86 uint32_t val;
87
88 val = FLOW_CTRL_HALT_GIC_IRQ | FLOW_CTRL_HALT_GIC_FIQ |
89 FLOW_CTRL_HALT_LIC_IRQ | FLOW_CTRL_HALT_LIC_FIQ |
90 FLOW_CTRL_WAITEVENT;
91 flowctrl_write_cpu_halt(cpu, val);
92
93 val = FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG |
94 FLOW_CTRL_CSR_ENABLE | (FLOW_CTRL_CSR_WFI_CPU0 << cpu);
95 flowctrl_write_cpu_csr(cpu, val);
96 }
97