289 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.4 * Copyright (C) 2011 Google, Inc.5 *6 * Author:7 * Jay Cheng <jacheng@nvidia.com>8 * James Wylder <james.wylder@motorola.com>9 * Benoit Goby <benoit@android.com>10 * Colin Cross <ccross@android.com>11 * Hiroshi DOYU <hdoyu@nvidia.com>12 */13 14#include <linux/err.h>15#include <linux/kernel.h>16#include <linux/module.h>17#include <linux/platform_device.h>18#include <linux/io.h>19#include <linux/of.h>20 21#include <soc/tegra/ahb.h>22 23#define DRV_NAME "tegra-ahb"24 25#define AHB_ARBITRATION_DISABLE 0x0426#define AHB_ARBITRATION_PRIORITY_CTRL 0x0827#define AHB_PRIORITY_WEIGHT(x) (((x) & 0x7) << 29)28#define PRIORITY_SELECT_USB BIT(6)29#define PRIORITY_SELECT_USB2 BIT(18)30#define PRIORITY_SELECT_USB3 BIT(17)31 32#define AHB_GIZMO_AHB_MEM 0x1033#define ENB_FAST_REARBITRATE BIT(2)34#define DONT_SPLIT_AHB_WR BIT(7)35 36#define AHB_GIZMO_APB_DMA 0x1437#define AHB_GIZMO_IDE 0x1c38#define AHB_GIZMO_USB 0x2039#define AHB_GIZMO_AHB_XBAR_BRIDGE 0x2440#define AHB_GIZMO_CPU_AHB_BRIDGE 0x2841#define AHB_GIZMO_COP_AHB_BRIDGE 0x2c42#define AHB_GIZMO_XBAR_APB_CTLR 0x3043#define AHB_GIZMO_VCP_AHB_BRIDGE 0x3444#define AHB_GIZMO_NAND 0x4045#define AHB_GIZMO_SDMMC4 0x4846#define AHB_GIZMO_XIO 0x4c47#define AHB_GIZMO_BSEV 0x6448#define AHB_GIZMO_BSEA 0x7449#define AHB_GIZMO_NOR 0x7850#define AHB_GIZMO_USB2 0x7c51#define AHB_GIZMO_USB3 0x8052#define IMMEDIATE BIT(18)53 54#define AHB_GIZMO_SDMMC1 0x8455#define AHB_GIZMO_SDMMC2 0x8856#define AHB_GIZMO_SDMMC3 0x8c57#define AHB_MEM_PREFETCH_CFG_X 0xdc58#define AHB_ARBITRATION_XBAR_CTRL 0xe059#define AHB_MEM_PREFETCH_CFG3 0xe460#define AHB_MEM_PREFETCH_CFG4 0xe861#define AHB_MEM_PREFETCH_CFG1 0xf062#define AHB_MEM_PREFETCH_CFG2 0xf463#define PREFETCH_ENB BIT(31)64#define MST_ID(x) (((x) & 0x1f) << 26)65#define AHBDMA_MST_ID MST_ID(5)66#define USB_MST_ID MST_ID(6)67#define USB2_MST_ID MST_ID(18)68#define USB3_MST_ID MST_ID(17)69#define ADDR_BNDRY(x) (((x) & 0xf) << 21)70#define INACTIVITY_TIMEOUT(x) (((x) & 0xffff) << 0)71 72#define AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID 0xfc73 74#define AHB_ARBITRATION_XBAR_CTRL_SMMU_INIT_DONE BIT(17)75 76/*77 * INCORRECT_BASE_ADDR_LOW_BYTE: Legacy kernel DT files for Tegra SoCs78 * prior to Tegra124 generally use a physical base address ending in79 * 0x4 for the AHB IP block. According to the TRM, the low byte80 * should be 0x0. During device probing, this macro is used to detect81 * whether the passed-in physical address is incorrect, and if so, to82 * correct it.83 */84#define INCORRECT_BASE_ADDR_LOW_BYTE 0x485 86static struct platform_driver tegra_ahb_driver;87 88static const u32 tegra_ahb_gizmo[] = {89 AHB_ARBITRATION_DISABLE,90 AHB_ARBITRATION_PRIORITY_CTRL,91 AHB_GIZMO_AHB_MEM,92 AHB_GIZMO_APB_DMA,93 AHB_GIZMO_IDE,94 AHB_GIZMO_USB,95 AHB_GIZMO_AHB_XBAR_BRIDGE,96 AHB_GIZMO_CPU_AHB_BRIDGE,97 AHB_GIZMO_COP_AHB_BRIDGE,98 AHB_GIZMO_XBAR_APB_CTLR,99 AHB_GIZMO_VCP_AHB_BRIDGE,100 AHB_GIZMO_NAND,101 AHB_GIZMO_SDMMC4,102 AHB_GIZMO_XIO,103 AHB_GIZMO_BSEV,104 AHB_GIZMO_BSEA,105 AHB_GIZMO_NOR,106 AHB_GIZMO_USB2,107 AHB_GIZMO_USB3,108 AHB_GIZMO_SDMMC1,109 AHB_GIZMO_SDMMC2,110 AHB_GIZMO_SDMMC3,111 AHB_MEM_PREFETCH_CFG_X,112 AHB_ARBITRATION_XBAR_CTRL,113 AHB_MEM_PREFETCH_CFG3,114 AHB_MEM_PREFETCH_CFG4,115 AHB_MEM_PREFETCH_CFG1,116 AHB_MEM_PREFETCH_CFG2,117 AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID,118};119 120struct tegra_ahb {121 void __iomem *regs;122 struct device *dev;123 u32 ctx[];124};125 126static inline u32 gizmo_readl(struct tegra_ahb *ahb, u32 offset)127{128 return readl(ahb->regs + offset);129}130 131static inline void gizmo_writel(struct tegra_ahb *ahb, u32 value, u32 offset)132{133 writel(value, ahb->regs + offset);134}135 136#ifdef CONFIG_TEGRA_IOMMU_SMMU137int tegra_ahb_enable_smmu(struct device_node *dn)138{139 struct device *dev;140 u32 val;141 struct tegra_ahb *ahb;142 143 dev = driver_find_device_by_of_node(&tegra_ahb_driver.driver, dn);144 if (!dev)145 return -EPROBE_DEFER;146 ahb = dev_get_drvdata(dev);147 val = gizmo_readl(ahb, AHB_ARBITRATION_XBAR_CTRL);148 val |= AHB_ARBITRATION_XBAR_CTRL_SMMU_INIT_DONE;149 gizmo_writel(ahb, val, AHB_ARBITRATION_XBAR_CTRL);150 return 0;151}152EXPORT_SYMBOL(tegra_ahb_enable_smmu);153#endif154 155static int __maybe_unused tegra_ahb_suspend(struct device *dev)156{157 int i;158 struct tegra_ahb *ahb = dev_get_drvdata(dev);159 160 for (i = 0; i < ARRAY_SIZE(tegra_ahb_gizmo); i++)161 ahb->ctx[i] = gizmo_readl(ahb, tegra_ahb_gizmo[i]);162 return 0;163}164 165static int __maybe_unused tegra_ahb_resume(struct device *dev)166{167 int i;168 struct tegra_ahb *ahb = dev_get_drvdata(dev);169 170 for (i = 0; i < ARRAY_SIZE(tegra_ahb_gizmo); i++)171 gizmo_writel(ahb, ahb->ctx[i], tegra_ahb_gizmo[i]);172 return 0;173}174 175static UNIVERSAL_DEV_PM_OPS(tegra_ahb_pm,176 tegra_ahb_suspend,177 tegra_ahb_resume, NULL);178 179static void tegra_ahb_gizmo_init(struct tegra_ahb *ahb)180{181 u32 val;182 183 val = gizmo_readl(ahb, AHB_GIZMO_AHB_MEM);184 val |= ENB_FAST_REARBITRATE | IMMEDIATE | DONT_SPLIT_AHB_WR;185 gizmo_writel(ahb, val, AHB_GIZMO_AHB_MEM);186 187 val = gizmo_readl(ahb, AHB_GIZMO_USB);188 val |= IMMEDIATE;189 gizmo_writel(ahb, val, AHB_GIZMO_USB);190 191 val = gizmo_readl(ahb, AHB_GIZMO_USB2);192 val |= IMMEDIATE;193 gizmo_writel(ahb, val, AHB_GIZMO_USB2);194 195 val = gizmo_readl(ahb, AHB_GIZMO_USB3);196 val |= IMMEDIATE;197 gizmo_writel(ahb, val, AHB_GIZMO_USB3);198 199 val = gizmo_readl(ahb, AHB_ARBITRATION_PRIORITY_CTRL);200 val |= PRIORITY_SELECT_USB |201 PRIORITY_SELECT_USB2 |202 PRIORITY_SELECT_USB3 |203 AHB_PRIORITY_WEIGHT(7);204 gizmo_writel(ahb, val, AHB_ARBITRATION_PRIORITY_CTRL);205 206 val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG1);207 val &= ~MST_ID(~0);208 val |= PREFETCH_ENB |209 AHBDMA_MST_ID |210 ADDR_BNDRY(0xc) |211 INACTIVITY_TIMEOUT(0x1000);212 gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG1);213 214 val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG2);215 val &= ~MST_ID(~0);216 val |= PREFETCH_ENB |217 USB_MST_ID |218 ADDR_BNDRY(0xc) |219 INACTIVITY_TIMEOUT(0x1000);220 gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG2);221 222 val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG3);223 val &= ~MST_ID(~0);224 val |= PREFETCH_ENB |225 USB3_MST_ID |226 ADDR_BNDRY(0xc) |227 INACTIVITY_TIMEOUT(0x1000);228 gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG3);229 230 val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG4);231 val &= ~MST_ID(~0);232 val |= PREFETCH_ENB |233 USB2_MST_ID |234 ADDR_BNDRY(0xc) |235 INACTIVITY_TIMEOUT(0x1000);236 gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG4);237}238 239static int tegra_ahb_probe(struct platform_device *pdev)240{241 struct resource *res;242 struct tegra_ahb *ahb;243 size_t bytes;244 245 bytes = sizeof(*ahb) + sizeof(u32) * ARRAY_SIZE(tegra_ahb_gizmo);246 ahb = devm_kzalloc(&pdev->dev, bytes, GFP_KERNEL);247 if (!ahb)248 return -ENOMEM;249 250 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);251 252 /* Correct the IP block base address if necessary */253 if (res &&254 (res->start & INCORRECT_BASE_ADDR_LOW_BYTE) ==255 INCORRECT_BASE_ADDR_LOW_BYTE) {256 dev_warn(&pdev->dev, "incorrect AHB base address in DT data - enabling workaround\n");257 res->start -= INCORRECT_BASE_ADDR_LOW_BYTE;258 }259 260 ahb->regs = devm_ioremap_resource(&pdev->dev, res);261 if (IS_ERR(ahb->regs))262 return PTR_ERR(ahb->regs);263 264 ahb->dev = &pdev->dev;265 platform_set_drvdata(pdev, ahb);266 tegra_ahb_gizmo_init(ahb);267 return 0;268}269 270static const struct of_device_id tegra_ahb_of_match[] = {271 { .compatible = "nvidia,tegra30-ahb", },272 { .compatible = "nvidia,tegra20-ahb", },273 {},274};275 276static struct platform_driver tegra_ahb_driver = {277 .probe = tegra_ahb_probe,278 .driver = {279 .name = DRV_NAME,280 .of_match_table = tegra_ahb_of_match,281 .pm = &tegra_ahb_pm,282 },283};284module_platform_driver(tegra_ahb_driver);285 286MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");287MODULE_DESCRIPTION("Tegra AHB driver");288MODULE_ALIAS("platform:" DRV_NAME);289