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); 225