1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * drivers/soc/tegra/flowctrl.c 4 * 5 * Functions and macros to control the flowcontroller 6 * 7 * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved. 8 */ 9 10 #include <linux/cpumask.h> 11 #include <linux/init.h> 12 #include <linux/io.h> 13 #include <linux/kernel.h> 14 #include <linux/of.h> 15 #include <linux/of_address.h> 16 #include <linux/platform_device.h> 17 18 #include <soc/tegra/common.h> 19 #include <soc/tegra/flowctrl.h> 20 #include <soc/tegra/fuse.h> 21 22 static u8 flowctrl_offset_halt_cpu[] = { 23 FLOW_CTRL_HALT_CPU0_EVENTS, 24 FLOW_CTRL_HALT_CPU1_EVENTS, 25 FLOW_CTRL_HALT_CPU1_EVENTS + 8, 26 FLOW_CTRL_HALT_CPU1_EVENTS + 16, 27 }; 28 29 static u8 flowctrl_offset_cpu_csr[] = { 30 FLOW_CTRL_CPU0_CSR, 31 FLOW_CTRL_CPU1_CSR, 32 FLOW_CTRL_CPU1_CSR + 8, 33 FLOW_CTRL_CPU1_CSR + 16, 34 }; 35 36 static void __iomem *tegra_flowctrl_base; 37 38 static void flowctrl_update(u8 offset, u32 value) 39 { 40 if (WARN_ONCE(IS_ERR_OR_NULL(tegra_flowctrl_base), 41 "Tegra flowctrl not initialised!\n")) 42 return; 43 44 writel(value, tegra_flowctrl_base + offset); 45 46 /* ensure the update has reached the flow controller */ 47 wmb(); 48 readl_relaxed(tegra_flowctrl_base + offset); 49 } 50 51 u32 flowctrl_read_cpu_csr(unsigned int cpuid) 52 { 53 u8 offset = flowctrl_offset_cpu_csr[cpuid]; 54 55 if (WARN_ONCE(IS_ERR_OR_NULL(tegra_flowctrl_base), 56 "Tegra flowctrl not initialised!\n")) 57 return 0; 58 59 return readl(tegra_flowctrl_base + offset); 60 } 61 62 void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value) 63 { 64 return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value); 65 } 66 67 void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value) 68 { 69 return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value); 70 } 71 72 void flowctrl_cpu_suspend_enter(unsigned int cpuid) 73 { 74 unsigned int reg; 75 int i; 76 77 reg = flowctrl_read_cpu_csr(cpuid); 78 switch (tegra_get_chip_id()) { 79 case TEGRA20: 80 /* clear wfe bitmap */ 81 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP; 82 /* clear wfi bitmap */ 83 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP; 84 /* pwr gating on wfe */ 85 reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid; 86 break; 87 case TEGRA30: 88 case TEGRA114: 89 case TEGRA124: 90 /* clear wfe bitmap */ 91 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP; 92 /* clear wfi bitmap */ 93 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP; 94 95 if (tegra_get_chip_id() == TEGRA30) { 96 /* 97 * The wfi doesn't work well on Tegra30 because 98 * CPU hangs under some odd circumstances after 99 * power-gating (like memory running off PLLP), 100 * hence use wfe that is working perfectly fine. 101 * Note that Tegra30 TRM doc clearly stands that 102 * wfi should be used for the "Cluster Switching", 103 * while wfe for the power-gating, just like it 104 * is done on Tegra20. 105 */ 106 reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid; 107 } else { 108 /* pwr gating on wfi */ 109 reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid; 110 } 111 break; 112 } 113 reg |= FLOW_CTRL_CSR_INTR_FLAG; /* clear intr flag */ 114 reg |= FLOW_CTRL_CSR_EVENT_FLAG; /* clear event flag */ 115 reg |= FLOW_CTRL_CSR_ENABLE; /* pwr gating */ 116 flowctrl_write_cpu_csr(cpuid, reg); 117 118 for (i = 0; i < num_possible_cpus(); i++) { 119 if (i == cpuid) 120 continue; 121 reg = flowctrl_read_cpu_csr(i); 122 reg |= FLOW_CTRL_CSR_EVENT_FLAG; 123 reg |= FLOW_CTRL_CSR_INTR_FLAG; 124 flowctrl_write_cpu_csr(i, reg); 125 } 126 } 127 128 void flowctrl_cpu_suspend_exit(unsigned int cpuid) 129 { 130 unsigned int reg; 131 132 /* Disable powergating via flow controller for CPU0 */ 133 reg = flowctrl_read_cpu_csr(cpuid); 134 switch (tegra_get_chip_id()) { 135 case TEGRA20: 136 /* clear wfe bitmap */ 137 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP; 138 /* clear wfi bitmap */ 139 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP; 140 break; 141 case TEGRA30: 142 case TEGRA114: 143 case TEGRA124: 144 /* clear wfe bitmap */ 145 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP; 146 /* clear wfi bitmap */ 147 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP; 148 break; 149 } 150 reg &= ~FLOW_CTRL_CSR_ENABLE; /* clear enable */ 151 reg |= FLOW_CTRL_CSR_INTR_FLAG; /* clear intr */ 152 reg |= FLOW_CTRL_CSR_EVENT_FLAG; /* clear event */ 153 flowctrl_write_cpu_csr(cpuid, reg); 154 } 155 156 static int tegra_flowctrl_probe(struct platform_device *pdev) 157 { 158 void __iomem *base = tegra_flowctrl_base; 159 160 tegra_flowctrl_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 161 if (IS_ERR(tegra_flowctrl_base)) 162 return PTR_ERR(tegra_flowctrl_base); 163 164 iounmap(base); 165 166 return 0; 167 } 168 169 static const struct of_device_id tegra_flowctrl_match[] = { 170 { .compatible = "nvidia,tegra210-flowctrl" }, 171 { .compatible = "nvidia,tegra124-flowctrl" }, 172 { .compatible = "nvidia,tegra114-flowctrl" }, 173 { .compatible = "nvidia,tegra30-flowctrl" }, 174 { .compatible = "nvidia,tegra20-flowctrl" }, 175 { } 176 }; 177 178 static struct platform_driver tegra_flowctrl_driver = { 179 .driver = { 180 .name = "tegra-flowctrl", 181 .suppress_bind_attrs = true, 182 .of_match_table = tegra_flowctrl_match, 183 }, 184 .probe = tegra_flowctrl_probe, 185 }; 186 builtin_platform_driver(tegra_flowctrl_driver); 187 188 static int __init tegra_flowctrl_init(void) 189 { 190 struct resource res; 191 struct device_node *np; 192 193 if (!soc_is_tegra()) 194 return 0; 195 196 np = of_find_matching_node(NULL, tegra_flowctrl_match); 197 if (np) { 198 if (of_address_to_resource(np, 0, &res) < 0) { 199 pr_err("failed to get flowctrl register\n"); 200 return -ENXIO; 201 } 202 of_node_put(np); 203 } else if (IS_ENABLED(CONFIG_ARM)) { 204 /* 205 * Hardcoded fallback for 32-bit Tegra 206 * devices if device tree node is missing. 207 */ 208 res.start = 0x60007000; 209 res.end = 0x60007fff; 210 res.flags = IORESOURCE_MEM; 211 } else { 212 /* 213 * At this point we're running on a Tegra, 214 * that doesn't support the flow controller 215 * (eg. Tegra186), so just return. 216 */ 217 return 0; 218 } 219 220 tegra_flowctrl_base = ioremap(res.start, resource_size(&res)); 221 if (!tegra_flowctrl_base) 222 return -ENXIO; 223 224 return 0; 225 } 226 early_initcall(tegra_flowctrl_init); 227