diff options
-rw-r--r-- | drivers/soc/tegra/Kconfig | 5 | ||||
-rw-r--r-- | drivers/soc/tegra/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/tegra/pmc-tegra186.c | 169 | ||||
-rw-r--r-- | drivers/soc/tegra/pmc.c | 131 | ||||
-rw-r--r-- | include/soc/tegra/pmc.h | 12 |
5 files changed, 143 insertions, 175 deletions
diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig index e9e277178c94..89ebe22a3e27 100644 --- a/drivers/soc/tegra/Kconfig +++ b/drivers/soc/tegra/Kconfig @@ -95,7 +95,7 @@ config ARCH_TEGRA_186_SOC select TEGRA_BPMP select TEGRA_HSP_MBOX select TEGRA_IVC - select SOC_TEGRA_PMC_TEGRA186 + select SOC_TEGRA_PMC help Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a combination of Denver and Cortex-A57 CPU cores and a GPU based on @@ -118,9 +118,6 @@ config SOC_TEGRA_FLOWCTRL config SOC_TEGRA_PMC bool -config SOC_TEGRA_PMC_TEGRA186 - bool - config SOC_TEGRA_POWERGATE_BPMP def_bool y depends on PM_GENERIC_DOMAINS diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile index 482e108d28aa..902759fe5f4d 100644 --- a/drivers/soc/tegra/Makefile +++ b/drivers/soc/tegra/Makefile @@ -4,5 +4,4 @@ obj-y += fuse/ obj-y += common.o obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o -obj-$(CONFIG_SOC_TEGRA_PMC_TEGRA186) += pmc-tegra186.o obj-$(CONFIG_SOC_TEGRA_POWERGATE_BPMP) += powergate-bpmp.o diff --git a/drivers/soc/tegra/pmc-tegra186.c b/drivers/soc/tegra/pmc-tegra186.c deleted file mode 100644 index 6f5c6f98ba92..000000000000 --- a/drivers/soc/tegra/pmc-tegra186.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#define pr_fmt(fmt) "tegra-pmc: " fmt - -#include <linux/io.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/reboot.h> - -#include <asm/system_misc.h> - -#define PMC_CNTRL 0x000 -#define PMC_CNTRL_MAIN_RST BIT(4) - -#define PMC_RST_STATUS 0x070 - -#define WAKE_AOWAKE_CTRL 0x4f4 -#define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) - -#define SCRATCH_SCRATCH0 0x2000 -#define SCRATCH_SCRATCH0_MODE_RECOVERY BIT(31) -#define SCRATCH_SCRATCH0_MODE_BOOTLOADER BIT(30) -#define SCRATCH_SCRATCH0_MODE_RCM BIT(1) -#define SCRATCH_SCRATCH0_MODE_MASK (SCRATCH_SCRATCH0_MODE_RECOVERY | \ - SCRATCH_SCRATCH0_MODE_BOOTLOADER | \ - SCRATCH_SCRATCH0_MODE_RCM) - -struct tegra_pmc { - struct device *dev; - void __iomem *regs; - void __iomem *wake; - void __iomem *aotag; - void __iomem *scratch; - - void (*system_restart)(enum reboot_mode mode, const char *cmd); - struct notifier_block restart; -}; - -static int tegra186_pmc_restart_notify(struct notifier_block *nb, - unsigned long action, - void *data) -{ - struct tegra_pmc *pmc = container_of(nb, struct tegra_pmc, restart); - const char *cmd = data; - u32 value; - - value = readl(pmc->scratch + SCRATCH_SCRATCH0); - value &= ~SCRATCH_SCRATCH0_MODE_MASK; - - if (cmd) { - if (strcmp(cmd, "recovery") == 0) - value |= SCRATCH_SCRATCH0_MODE_RECOVERY; - - if (strcmp(cmd, "bootloader") == 0) - value |= SCRATCH_SCRATCH0_MODE_BOOTLOADER; - - if (strcmp(cmd, "forced-recovery") == 0) - value |= SCRATCH_SCRATCH0_MODE_RCM; - } - - writel(value, pmc->scratch + SCRATCH_SCRATCH0); - - /* - * If available, call the system restart implementation that was - * registered earlier (typically PSCI). - */ - if (pmc->system_restart) { - pmc->system_restart(reboot_mode, cmd); - return NOTIFY_DONE; - } - - /* reset everything but SCRATCH0_SCRATCH0 and PMC_RST_STATUS */ - value = readl(pmc->regs + PMC_CNTRL); - value |= PMC_CNTRL_MAIN_RST; - writel(value, pmc->regs + PMC_CNTRL); - - return NOTIFY_DONE; -} - -static int tegra186_pmc_setup(struct tegra_pmc *pmc) -{ - struct device_node *np = pmc->dev->of_node; - bool invert; - u32 value; - - invert = of_property_read_bool(np, "nvidia,invert-interrupt"); - - value = readl(pmc->wake + WAKE_AOWAKE_CTRL); - - if (invert) - value |= WAKE_AOWAKE_CTRL_INTR_POLARITY; - else - value &= ~WAKE_AOWAKE_CTRL_INTR_POLARITY; - - writel(value, pmc->wake + WAKE_AOWAKE_CTRL); - - /* - * We need to hook any system restart implementation registered - * previously so we can write SCRATCH_SCRATCH0 before reset. - */ - pmc->system_restart = arm_pm_restart; - arm_pm_restart = NULL; - - pmc->restart.notifier_call = tegra186_pmc_restart_notify; - pmc->restart.priority = 128; - - return register_restart_handler(&pmc->restart); -} - -static int tegra186_pmc_probe(struct platform_device *pdev) -{ - struct tegra_pmc *pmc; - struct resource *res; - - pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL); - if (!pmc) - return -ENOMEM; - - pmc->dev = &pdev->dev; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmc"); - pmc->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pmc->regs)) - return PTR_ERR(pmc->regs); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake"); - pmc->wake = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pmc->wake)) - return PTR_ERR(pmc->wake); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag"); - pmc->aotag = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pmc->aotag)) - return PTR_ERR(pmc->aotag); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch"); - pmc->scratch = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pmc->scratch)) - return PTR_ERR(pmc->scratch); - - return tegra186_pmc_setup(pmc); -} - -static const struct of_device_id tegra186_pmc_of_match[] = { - { .compatible = "nvidia,tegra186-pmc" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, tegra186_pmc_of_match); - -static struct platform_driver tegra186_pmc_driver = { - .driver = { - .name = "tegra186-pmc", - .of_match_table = tegra186_pmc_of_match, - }, - .probe = tegra186_pmc_probe, -}; -builtin_platform_driver(tegra186_pmc_driver); diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 363b4b9c3aaf..ce62a47a6647 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -117,6 +117,10 @@ #define GPU_RG_CNTRL 0x2d4 +/* Tegra186 and later */ +#define WAKE_AOWAKE_CTRL 0x4f4 +#define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) + struct tegra_powergate { struct generic_pm_domain genpd; struct tegra_pmc *pmc; @@ -186,6 +190,8 @@ struct tegra_pmc_soc { struct tegra_pmc { struct device *dev; void __iomem *base; + void __iomem *wake; + void __iomem *aotag; void __iomem *scratch; struct clk *clk; struct dentry *debugfs; @@ -1408,7 +1414,32 @@ static int tegra_pmc_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - pmc->scratch = base; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake"); + if (res) { + pmc->wake = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmc->wake)) + return PTR_ERR(pmc->wake); + } else { + pmc->wake = base; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag"); + if (res) { + pmc->aotag = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmc->aotag)) + return PTR_ERR(pmc->aotag); + } else { + pmc->aotag = base; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch"); + if (res) { + pmc->scratch = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmc->scratch)) + return PTR_ERR(pmc->scratch); + } else { + pmc->scratch = base; + } pmc->clk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(pmc->clk)) { @@ -1791,7 +1822,105 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, }; +static const struct tegra_io_pad_soc tegra186_io_pads[] = { + { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK_BIAS, .dpd = 4, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK3, .dpd = 5, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 7, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HDMI_DP0, .dpd = 28, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HDMI_DP1, .dpd = 29, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC2_HV, .dpd = 34, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC4, .dpd = 36, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CAM, .dpd = 38, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIB, .dpd = 40, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIC, .dpd = 41, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSID, .dpd = 42, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIC, .dpd = 43, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSID, .dpd = 44, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIE, .dpd = 45, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIF, .dpd = 46, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SPI, .dpd = 47, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_UFS, .dpd = 49, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DMIC_HV, .dpd = 52, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_EDP, .dpd = 53, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC1_HV, .dpd = 55, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC3_HV, .dpd = 56, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CONN, .dpd = 60, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = UINT_MAX }, +}; + +static const struct tegra_pmc_regs tegra186_pmc_regs = { + .scratch0 = 0x2000, + .dpd_req = 0x74, + .dpd_status = 0x78, + .dpd2_req = 0x7c, + .dpd2_status = 0x80, +}; + +static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, + struct device_node *np, + bool invert) +{ + struct resource regs; + void __iomem *wake; + u32 value; + int index; + + index = of_property_match_string(np, "reg-names", "wake"); + if (index < 0) { + pr_err("failed to find PMC wake registers\n"); + return; + } + + of_address_to_resource(np, index, ®s); + + wake = ioremap_nocache(regs.start, resource_size(®s)); + if (!wake) { + pr_err("failed to map PMC wake registers\n"); + return; + } + + value = readl(wake + WAKE_AOWAKE_CTRL); + + if (invert) + value |= WAKE_AOWAKE_CTRL_INTR_POLARITY; + else + value &= ~WAKE_AOWAKE_CTRL_INTR_POLARITY; + + writel(value, wake + WAKE_AOWAKE_CTRL); + + iounmap(wake); +} + +static const struct tegra_pmc_soc tegra186_pmc_soc = { + .num_powergates = 0, + .powergates = NULL, + .num_cpu_powergates = 0, + .cpu_powergates = NULL, + .has_tsense_reset = false, + .has_gpu_clamps = false, + .num_io_pads = ARRAY_SIZE(tegra186_io_pads), + .io_pads = tegra186_io_pads, + .regs = &tegra186_pmc_regs, + .init = NULL, + .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, +}; + static const struct of_device_id tegra_pmc_match[] = { + { .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc }, { .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc }, { .compatible = "nvidia,tegra132-pmc", .data = &tegra124_pmc_soc }, { .compatible = "nvidia,tegra124-pmc", .data = &tegra124_pmc_soc }, diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h index 1c3982bc558f..c32bf91c23e6 100644 --- a/include/soc/tegra/pmc.h +++ b/include/soc/tegra/pmc.h @@ -83,6 +83,7 @@ enum tegra_io_pad { TEGRA_IO_PAD_BB, TEGRA_IO_PAD_CAM, TEGRA_IO_PAD_COMP, + TEGRA_IO_PAD_CONN, TEGRA_IO_PAD_CSIA, TEGRA_IO_PAD_CSIB, TEGRA_IO_PAD_CSIC, @@ -92,31 +93,42 @@ enum tegra_io_pad { TEGRA_IO_PAD_DBG, TEGRA_IO_PAD_DEBUG_NONAO, TEGRA_IO_PAD_DMIC, + TEGRA_IO_PAD_DMIC_HV, TEGRA_IO_PAD_DP, TEGRA_IO_PAD_DSI, TEGRA_IO_PAD_DSIB, TEGRA_IO_PAD_DSIC, TEGRA_IO_PAD_DSID, + TEGRA_IO_PAD_EDP, TEGRA_IO_PAD_EMMC, TEGRA_IO_PAD_EMMC2, TEGRA_IO_PAD_GPIO, TEGRA_IO_PAD_HDMI, + TEGRA_IO_PAD_HDMI_DP0, + TEGRA_IO_PAD_HDMI_DP1, TEGRA_IO_PAD_HSIC, TEGRA_IO_PAD_HV, TEGRA_IO_PAD_LVDS, TEGRA_IO_PAD_MIPI_BIAS, TEGRA_IO_PAD_NAND, TEGRA_IO_PAD_PEX_BIAS, + TEGRA_IO_PAD_PEX_CLK_BIAS, TEGRA_IO_PAD_PEX_CLK1, TEGRA_IO_PAD_PEX_CLK2, + TEGRA_IO_PAD_PEX_CLK3, TEGRA_IO_PAD_PEX_CNTRL, TEGRA_IO_PAD_SDMMC1, + TEGRA_IO_PAD_SDMMC1_HV, + TEGRA_IO_PAD_SDMMC2, + TEGRA_IO_PAD_SDMMC2_HV, TEGRA_IO_PAD_SDMMC3, + TEGRA_IO_PAD_SDMMC3_HV, TEGRA_IO_PAD_SDMMC4, TEGRA_IO_PAD_SPI, TEGRA_IO_PAD_SPI_HV, TEGRA_IO_PAD_SYS_DDC, TEGRA_IO_PAD_UART, + TEGRA_IO_PAD_UFS, TEGRA_IO_PAD_USB0, TEGRA_IO_PAD_USB1, TEGRA_IO_PAD_USB2, |