GNU Linux-libre 4.19.263-gnu1
[releases.git] / drivers / soc / tegra / flowctrl.c
1 /*
2  * drivers/soc/tegra/flowctrl.c
3  *
4  * Functions and macros to control the flowcontroller
5  *
6  * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU General Public License,
10  * version 2, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
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 #include <linux/platform_device.h>
28
29 #include <soc/tegra/common.h>
30 #include <soc/tegra/flowctrl.h>
31 #include <soc/tegra/fuse.h>
32
33 static u8 flowctrl_offset_halt_cpu[] = {
34         FLOW_CTRL_HALT_CPU0_EVENTS,
35         FLOW_CTRL_HALT_CPU1_EVENTS,
36         FLOW_CTRL_HALT_CPU1_EVENTS + 8,
37         FLOW_CTRL_HALT_CPU1_EVENTS + 16,
38 };
39
40 static u8 flowctrl_offset_cpu_csr[] = {
41         FLOW_CTRL_CPU0_CSR,
42         FLOW_CTRL_CPU1_CSR,
43         FLOW_CTRL_CPU1_CSR + 8,
44         FLOW_CTRL_CPU1_CSR + 16,
45 };
46
47 static void __iomem *tegra_flowctrl_base;
48
49 static void flowctrl_update(u8 offset, u32 value)
50 {
51         if (WARN_ONCE(IS_ERR_OR_NULL(tegra_flowctrl_base),
52                       "Tegra flowctrl not initialised!\n"))
53                 return;
54
55         writel(value, tegra_flowctrl_base + offset);
56
57         /* ensure the update has reached the flow controller */
58         wmb();
59         readl_relaxed(tegra_flowctrl_base + offset);
60 }
61
62 u32 flowctrl_read_cpu_csr(unsigned int cpuid)
63 {
64         u8 offset = flowctrl_offset_cpu_csr[cpuid];
65
66         if (WARN_ONCE(IS_ERR_OR_NULL(tegra_flowctrl_base),
67                       "Tegra flowctrl not initialised!\n"))
68                 return 0;
69
70         return readl(tegra_flowctrl_base + offset);
71 }
72
73 void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)
74 {
75         return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value);
76 }
77
78 void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)
79 {
80         return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);
81 }
82
83 void flowctrl_cpu_suspend_enter(unsigned int cpuid)
84 {
85         unsigned int reg;
86         int i;
87
88         reg = flowctrl_read_cpu_csr(cpuid);
89         switch (tegra_get_chip_id()) {
90         case TEGRA20:
91                 /* clear wfe bitmap */
92                 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
93                 /* clear wfi bitmap */
94                 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
95                 /* pwr gating on wfe */
96                 reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid;
97                 break;
98         case TEGRA30:
99         case TEGRA114:
100         case TEGRA124:
101                 /* clear wfe bitmap */
102                 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
103                 /* clear wfi bitmap */
104                 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
105                 /* pwr gating on wfi */
106                 reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;
107                 break;
108         }
109         reg |= FLOW_CTRL_CSR_INTR_FLAG;                 /* clear intr flag */
110         reg |= FLOW_CTRL_CSR_EVENT_FLAG;                /* clear event flag */
111         reg |= FLOW_CTRL_CSR_ENABLE;                    /* pwr gating */
112         flowctrl_write_cpu_csr(cpuid, reg);
113
114         for (i = 0; i < num_possible_cpus(); i++) {
115                 if (i == cpuid)
116                         continue;
117                 reg = flowctrl_read_cpu_csr(i);
118                 reg |= FLOW_CTRL_CSR_EVENT_FLAG;
119                 reg |= FLOW_CTRL_CSR_INTR_FLAG;
120                 flowctrl_write_cpu_csr(i, reg);
121         }
122 }
123
124 void flowctrl_cpu_suspend_exit(unsigned int cpuid)
125 {
126         unsigned int reg;
127
128         /* Disable powergating via flow controller for CPU0 */
129         reg = flowctrl_read_cpu_csr(cpuid);
130         switch (tegra_get_chip_id()) {
131         case TEGRA20:
132                 /* clear wfe bitmap */
133                 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
134                 /* clear wfi bitmap */
135                 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
136                 break;
137         case TEGRA30:
138         case TEGRA114:
139         case TEGRA124:
140                 /* clear wfe bitmap */
141                 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
142                 /* clear wfi bitmap */
143                 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
144                 break;
145         }
146         reg &= ~FLOW_CTRL_CSR_ENABLE;                   /* clear enable */
147         reg |= FLOW_CTRL_CSR_INTR_FLAG;                 /* clear intr */
148         reg |= FLOW_CTRL_CSR_EVENT_FLAG;                /* clear event */
149         flowctrl_write_cpu_csr(cpuid, reg);
150 }
151
152 static int tegra_flowctrl_probe(struct platform_device *pdev)
153 {
154         void __iomem *base = tegra_flowctrl_base;
155         struct resource *res;
156
157         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
158         tegra_flowctrl_base = devm_ioremap_resource(&pdev->dev, res);
159         if (IS_ERR(tegra_flowctrl_base))
160                 return PTR_ERR(tegra_flowctrl_base);
161
162         iounmap(base);
163
164         return 0;
165 }
166
167 static const struct of_device_id tegra_flowctrl_match[] = {
168         { .compatible = "nvidia,tegra210-flowctrl" },
169         { .compatible = "nvidia,tegra124-flowctrl" },
170         { .compatible = "nvidia,tegra114-flowctrl" },
171         { .compatible = "nvidia,tegra30-flowctrl" },
172         { .compatible = "nvidia,tegra20-flowctrl" },
173         { }
174 };
175
176 static struct platform_driver tegra_flowctrl_driver = {
177         .driver = {
178                 .name = "tegra-flowctrl",
179                 .suppress_bind_attrs = true,
180                 .of_match_table = tegra_flowctrl_match,
181         },
182         .probe = tegra_flowctrl_probe,
183 };
184 builtin_platform_driver(tegra_flowctrl_driver);
185
186 static int __init tegra_flowctrl_init(void)
187 {
188         struct resource res;
189         struct device_node *np;
190
191         if (!soc_is_tegra())
192                 return 0;
193
194         np = of_find_matching_node(NULL, tegra_flowctrl_match);
195         if (np) {
196                 if (of_address_to_resource(np, 0, &res) < 0) {
197                         pr_err("failed to get flowctrl register\n");
198                         return -ENXIO;
199                 }
200                 of_node_put(np);
201         } else if (IS_ENABLED(CONFIG_ARM)) {
202                 /*
203                  * Hardcoded fallback for 32-bit Tegra
204                  * devices if device tree node is missing.
205                  */
206                 res.start = 0x60007000;
207                 res.end = 0x60007fff;
208                 res.flags = IORESOURCE_MEM;
209         } else {
210                 /*
211                  * At this point we're running on a Tegra,
212                  * that doesn't support the flow controller
213                  * (eg. Tegra186), so just return.
214                  */
215                 return 0;
216         }
217
218         tegra_flowctrl_base = ioremap_nocache(res.start, resource_size(&res));
219         if (!tegra_flowctrl_base)
220                 return -ENXIO;
221
222         return 0;
223 }
224 early_initcall(tegra_flowctrl_init);