0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/cpumask.h>
0011 #include <linux/init.h>
0012 #include <linux/io.h>
0013 #include <linux/kernel.h>
0014 #include <linux/of.h>
0015 #include <linux/of_address.h>
0016 #include <linux/platform_device.h>
0017
0018 #include <soc/tegra/common.h>
0019 #include <soc/tegra/flowctrl.h>
0020 #include <soc/tegra/fuse.h>
0021
0022 static u8 flowctrl_offset_halt_cpu[] = {
0023 FLOW_CTRL_HALT_CPU0_EVENTS,
0024 FLOW_CTRL_HALT_CPU1_EVENTS,
0025 FLOW_CTRL_HALT_CPU1_EVENTS + 8,
0026 FLOW_CTRL_HALT_CPU1_EVENTS + 16,
0027 };
0028
0029 static u8 flowctrl_offset_cpu_csr[] = {
0030 FLOW_CTRL_CPU0_CSR,
0031 FLOW_CTRL_CPU1_CSR,
0032 FLOW_CTRL_CPU1_CSR + 8,
0033 FLOW_CTRL_CPU1_CSR + 16,
0034 };
0035
0036 static void __iomem *tegra_flowctrl_base;
0037
0038 static void flowctrl_update(u8 offset, u32 value)
0039 {
0040 if (WARN_ONCE(IS_ERR_OR_NULL(tegra_flowctrl_base),
0041 "Tegra flowctrl not initialised!\n"))
0042 return;
0043
0044 writel(value, tegra_flowctrl_base + offset);
0045
0046
0047 wmb();
0048 readl_relaxed(tegra_flowctrl_base + offset);
0049 }
0050
0051 u32 flowctrl_read_cpu_csr(unsigned int cpuid)
0052 {
0053 u8 offset = flowctrl_offset_cpu_csr[cpuid];
0054
0055 if (WARN_ONCE(IS_ERR_OR_NULL(tegra_flowctrl_base),
0056 "Tegra flowctrl not initialised!\n"))
0057 return 0;
0058
0059 return readl(tegra_flowctrl_base + offset);
0060 }
0061
0062 void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)
0063 {
0064 return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value);
0065 }
0066
0067 void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)
0068 {
0069 return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);
0070 }
0071
0072 void flowctrl_cpu_suspend_enter(unsigned int cpuid)
0073 {
0074 unsigned int reg;
0075 int i;
0076
0077 reg = flowctrl_read_cpu_csr(cpuid);
0078 switch (tegra_get_chip_id()) {
0079 case TEGRA20:
0080
0081 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
0082
0083 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
0084
0085 reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid;
0086 break;
0087 case TEGRA30:
0088 case TEGRA114:
0089 case TEGRA124:
0090
0091 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
0092
0093 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
0094
0095 if (tegra_get_chip_id() == TEGRA30) {
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106 reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid;
0107 } else {
0108
0109 reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;
0110 }
0111 break;
0112 }
0113 reg |= FLOW_CTRL_CSR_INTR_FLAG;
0114 reg |= FLOW_CTRL_CSR_EVENT_FLAG;
0115 reg |= FLOW_CTRL_CSR_ENABLE;
0116 flowctrl_write_cpu_csr(cpuid, reg);
0117
0118 for (i = 0; i < num_possible_cpus(); i++) {
0119 if (i == cpuid)
0120 continue;
0121 reg = flowctrl_read_cpu_csr(i);
0122 reg |= FLOW_CTRL_CSR_EVENT_FLAG;
0123 reg |= FLOW_CTRL_CSR_INTR_FLAG;
0124 flowctrl_write_cpu_csr(i, reg);
0125 }
0126 }
0127
0128 void flowctrl_cpu_suspend_exit(unsigned int cpuid)
0129 {
0130 unsigned int reg;
0131
0132
0133 reg = flowctrl_read_cpu_csr(cpuid);
0134 switch (tegra_get_chip_id()) {
0135 case TEGRA20:
0136
0137 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
0138
0139 reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
0140 break;
0141 case TEGRA30:
0142 case TEGRA114:
0143 case TEGRA124:
0144
0145 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
0146
0147 reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
0148 break;
0149 }
0150 reg &= ~FLOW_CTRL_CSR_ENABLE;
0151 reg |= FLOW_CTRL_CSR_INTR_FLAG;
0152 reg |= FLOW_CTRL_CSR_EVENT_FLAG;
0153 flowctrl_write_cpu_csr(cpuid, reg);
0154 }
0155
0156 static int tegra_flowctrl_probe(struct platform_device *pdev)
0157 {
0158 void __iomem *base = tegra_flowctrl_base;
0159 struct resource *res;
0160
0161 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0162 tegra_flowctrl_base = devm_ioremap_resource(&pdev->dev, res);
0163 if (IS_ERR(tegra_flowctrl_base))
0164 return PTR_ERR(tegra_flowctrl_base);
0165
0166 iounmap(base);
0167
0168 return 0;
0169 }
0170
0171 static const struct of_device_id tegra_flowctrl_match[] = {
0172 { .compatible = "nvidia,tegra210-flowctrl" },
0173 { .compatible = "nvidia,tegra124-flowctrl" },
0174 { .compatible = "nvidia,tegra114-flowctrl" },
0175 { .compatible = "nvidia,tegra30-flowctrl" },
0176 { .compatible = "nvidia,tegra20-flowctrl" },
0177 { }
0178 };
0179
0180 static struct platform_driver tegra_flowctrl_driver = {
0181 .driver = {
0182 .name = "tegra-flowctrl",
0183 .suppress_bind_attrs = true,
0184 .of_match_table = tegra_flowctrl_match,
0185 },
0186 .probe = tegra_flowctrl_probe,
0187 };
0188 builtin_platform_driver(tegra_flowctrl_driver);
0189
0190 static int __init tegra_flowctrl_init(void)
0191 {
0192 struct resource res;
0193 struct device_node *np;
0194
0195 if (!soc_is_tegra())
0196 return 0;
0197
0198 np = of_find_matching_node(NULL, tegra_flowctrl_match);
0199 if (np) {
0200 if (of_address_to_resource(np, 0, &res) < 0) {
0201 pr_err("failed to get flowctrl register\n");
0202 return -ENXIO;
0203 }
0204 of_node_put(np);
0205 } else if (IS_ENABLED(CONFIG_ARM)) {
0206
0207
0208
0209
0210 res.start = 0x60007000;
0211 res.end = 0x60007fff;
0212 res.flags = IORESOURCE_MEM;
0213 } else {
0214
0215
0216
0217
0218
0219 return 0;
0220 }
0221
0222 tegra_flowctrl_base = ioremap(res.start, resource_size(&res));
0223 if (!tegra_flowctrl_base)
0224 return -ENXIO;
0225
0226 return 0;
0227 }
0228 early_initcall(tegra_flowctrl_init);