1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include <linux/cpumask.h>
22#include <linux/init.h>
23#include <linux/io.h>
24#include <linux/kernel.h>
25#include <linux/of.h>
26#include <linux/of_address.h>
27
28#include <soc/tegra/fuse.h>
29
30#include "flowctrl.h"
31
32static u8 flowctrl_offset_halt_cpu[] = {
33 FLOW_CTRL_HALT_CPU0_EVENTS,
34 FLOW_CTRL_HALT_CPU1_EVENTS,
35 FLOW_CTRL_HALT_CPU1_EVENTS + 8,
36 FLOW_CTRL_HALT_CPU1_EVENTS + 16,
37};
38
39static u8 flowctrl_offset_cpu_csr[] = {
40 FLOW_CTRL_CPU0_CSR,
41 FLOW_CTRL_CPU1_CSR,
42 FLOW_CTRL_CPU1_CSR + 8,
43 FLOW_CTRL_CPU1_CSR + 16,
44};
45
46static void __iomem *tegra_flowctrl_base;
47
48static void flowctrl_update(u8 offset, u32 value)
49{
50 writel(value, tegra_flowctrl_base + offset);
51
52
53 wmb();
54 readl_relaxed(tegra_flowctrl_base + offset);
55}
56
57u32 flowctrl_read_cpu_csr(unsigned int cpuid)
58{
59 u8 offset = flowctrl_offset_cpu_csr[cpuid];
60
61 return readl(tegra_flowctrl_base + offset);
62}
63
64void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)
65{
66 return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value);
67}
68
69void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)
70{
71 return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);
72}
73
74void flowctrl_cpu_suspend_enter(unsigned int cpuid)
75{
76 unsigned int reg;
77 int i;
78
79 reg = flowctrl_read_cpu_csr(cpuid);
80 switch (tegra_get_chip_id()) {
81 case TEGRA20:
82
83 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
84
85 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
86
87 reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid;
88 break;
89 case TEGRA30:
90 case TEGRA114:
91 case TEGRA124:
92
93 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
94
95 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
96
97 reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;
98 break;
99 }
100 reg |= FLOW_CTRL_CSR_INTR_FLAG;
101 reg |= FLOW_CTRL_CSR_EVENT_FLAG;
102 reg |= FLOW_CTRL_CSR_ENABLE;
103 flowctrl_write_cpu_csr(cpuid, reg);
104
105 for (i = 0; i < num_possible_cpus(); i++) {
106 if (i == cpuid)
107 continue;
108 reg = flowctrl_read_cpu_csr(i);
109 reg |= FLOW_CTRL_CSR_EVENT_FLAG;
110 reg |= FLOW_CTRL_CSR_INTR_FLAG;
111 flowctrl_write_cpu_csr(i, reg);
112 }
113}
114
115void flowctrl_cpu_suspend_exit(unsigned int cpuid)
116{
117 unsigned int reg;
118
119
120 reg = flowctrl_read_cpu_csr(cpuid);
121 switch (tegra_get_chip_id()) {
122 case TEGRA20:
123
124 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
125
126 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
127 break;
128 case TEGRA30:
129 case TEGRA114:
130 case TEGRA124:
131
132 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
133
134 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
135 break;
136 }
137 reg &= ~FLOW_CTRL_CSR_ENABLE;
138 reg |= FLOW_CTRL_CSR_INTR_FLAG;
139 reg |= FLOW_CTRL_CSR_EVENT_FLAG;
140 flowctrl_write_cpu_csr(cpuid, reg);
141}
142
143static const struct of_device_id matches[] __initconst = {
144 { .compatible = "nvidia,tegra124-flowctrl" },
145 { .compatible = "nvidia,tegra114-flowctrl" },
146 { .compatible = "nvidia,tegra30-flowctrl" },
147 { .compatible = "nvidia,tegra20-flowctrl" },
148 { }
149};
150
151void __init tegra_flowctrl_init(void)
152{
153
154 unsigned long base = 0x60007000;
155 unsigned long size = SZ_4K;
156 struct device_node *np;
157
158 np = of_find_matching_node(NULL, matches);
159 if (np) {
160 struct resource res;
161
162 if (of_address_to_resource(np, 0, &res) == 0) {
163 size = resource_size(&res);
164 base = res.start;
165 }
166
167 of_node_put(np);
168 }
169
170 tegra_flowctrl_base = ioremap_nocache(base, size);
171}
172