diff options
author | Arnd Bergmann <arnd@arndb.de> | 2017-12-21 19:57:04 +0300 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2017-12-21 19:57:04 +0300 |
commit | a3dc838d7aa045c5b601f88ea1eab7b788b58e64 (patch) | |
tree | ec97d0a672f10d9fa21ce38ec63ce96efac5db35 /drivers/soc | |
parent | 7294f2fc1903231951165152e2f8237fb95ab50d (diff) | |
parent | ccf151847b81a3ad779b64f5f71f0632f2009eb6 (diff) | |
download | linux-a3dc838d7aa045c5b601f88ea1eab7b788b58e64.tar.xz |
Merge tag 'tegra-for-4.16-soc-2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/soc
Pull "soc/tegra: Changes for v4.16-rc1" from Thierry Reding:
Fuse and chip ID support for Tegra186 is added in this set of changes,
followed by some unification work for the PMC driver in order to avoid
code duplication between Tegra186 and prior chips.
This also contains a couple of fixes for reading fuses on Tegra20.
* tag 'tegra-for-4.16-soc-2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
soc/tegra: fuse: Explicitly request DMA channel from APB DMA driver
soc/tegra: fuse: Fix reading registers using DMA on Tegra20
soc/tegra: pmc: Consolidate Tegra186 support
soc/tegra: pmc: Parameterize driver
soc/tegra: fuse: Add Tegra186 chip ID support
soc/tegra: fuse: Warn if accessing unmapped registers
soc/tegra: fuse: Move register mapping check
soc/tegra: fuse: Add Tegra186 support
dt-bindings: misc: Add Tegra186 MISC registers bindings
Diffstat (limited to 'drivers/soc')
-rw-r--r-- | drivers/soc/tegra/Kconfig | 5 | ||||
-rw-r--r-- | drivers/soc/tegra/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra.c | 4 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra20.c | 13 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra30.c | 24 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/fuse.h | 4 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/tegra-apbmisc.c | 11 | ||||
-rw-r--r-- | drivers/soc/tegra/pmc-tegra186.c | 169 | ||||
-rw-r--r-- | drivers/soc/tegra/pmc.c | 304 |
9 files changed, 298 insertions, 237 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/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index b7c552e3133c..a33ee8ef8b6b 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -103,6 +103,9 @@ static struct tegra_fuse *fuse = &(struct tegra_fuse) { }; static const struct of_device_id tegra_fuse_match[] = { +#ifdef CONFIG_ARCH_TEGRA_186_SOC + { .compatible = "nvidia,tegra186-efuse", .data = &tegra186_fuse_soc }, +#endif #ifdef CONFIG_ARCH_TEGRA_210_SOC { .compatible = "nvidia,tegra210-efuse", .data = &tegra210_fuse_soc }, #endif @@ -132,6 +135,7 @@ static int tegra_fuse_probe(struct platform_device *pdev) /* take over the memory region from the early initialization */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fuse->phys = res->start; fuse->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(fuse->base)) return PTR_ERR(fuse->base); diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c index 294413a969a0..49ff017f3ded 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra20.c +++ b/drivers/soc/tegra/fuse/fuse-tegra20.c @@ -59,7 +59,7 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset) mutex_lock(&fuse->apbdma.lock); - fuse->apbdma.config.src_addr = fuse->apbdma.phys + FUSE_BEGIN + offset; + fuse->apbdma.config.src_addr = fuse->phys + FUSE_BEGIN + offset; err = dmaengine_slave_config(fuse->apbdma.chan, &fuse->apbdma.config); if (err) @@ -96,6 +96,13 @@ out: return value; } +static bool dma_filter(struct dma_chan *chan, void *filter_param) +{ + struct device_node *np = chan->device->dev->of_node; + + return of_device_is_compatible(np, "nvidia,tegra20-apbdma"); +} + static int tegra20_fuse_probe(struct tegra_fuse *fuse) { dma_cap_mask_t mask; @@ -103,7 +110,7 @@ static int tegra20_fuse_probe(struct tegra_fuse *fuse) dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - fuse->apbdma.chan = dma_request_channel(mask, NULL, NULL); + fuse->apbdma.chan = __dma_request_channel(&mask, dma_filter, NULL); if (!fuse->apbdma.chan) return -EPROBE_DEFER; @@ -119,6 +126,8 @@ static int tegra20_fuse_probe(struct tegra_fuse *fuse) fuse->apbdma.config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; fuse->apbdma.config.src_maxburst = 1; fuse->apbdma.config.dst_maxburst = 1; + fuse->apbdma.config.direction = DMA_DEV_TO_MEM; + fuse->apbdma.config.device_fc = false; init_completion(&fuse->apbdma.wait); mutex_init(&fuse->apbdma.lock); diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 882607bcaa6c..257e254c6137 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -46,9 +46,13 @@ defined(CONFIG_ARCH_TEGRA_114_SOC) || \ defined(CONFIG_ARCH_TEGRA_124_SOC) || \ defined(CONFIG_ARCH_TEGRA_132_SOC) || \ - defined(CONFIG_ARCH_TEGRA_210_SOC) + defined(CONFIG_ARCH_TEGRA_210_SOC) || \ + defined(CONFIG_ARCH_TEGRA_186_SOC) static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) { + if (WARN_ON(!fuse->base)) + return 0; + return readl_relaxed(fuse->base + FUSE_BEGIN + offset); } @@ -98,7 +102,10 @@ static void __init tegra30_fuse_init(struct tegra_fuse *fuse) fuse->read = tegra30_fuse_read; tegra_init_revision(); - fuse->soc->speedo_init(&tegra_sku_info); + + if (fuse->soc->speedo_init) + fuse->soc->speedo_init(&tegra_sku_info); + tegra30_fuse_add_randomness(); } #endif @@ -158,3 +165,16 @@ const struct tegra_fuse_soc tegra210_fuse_soc = { .info = &tegra210_fuse_info, }; #endif + +#if defined(CONFIG_ARCH_TEGRA_186_SOC) +static const struct tegra_fuse_info tegra186_fuse_info = { + .read = tegra30_fuse_read, + .size = 0x300, + .spare = 0x280, +}; + +const struct tegra_fuse_soc tegra186_fuse_soc = { + .init = tegra30_fuse_init, + .info = &tegra186_fuse_info, +}; +#endif diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h index 10c2076d5089..f355b9d54915 100644 --- a/drivers/soc/tegra/fuse/fuse.h +++ b/drivers/soc/tegra/fuse/fuse.h @@ -105,4 +105,8 @@ extern const struct tegra_fuse_soc tegra124_fuse_soc; extern const struct tegra_fuse_soc tegra210_fuse_soc; #endif +#ifdef CONFIG_ARCH_TEGRA_186_SOC +extern const struct tegra_fuse_soc tegra186_fuse_soc; +#endif + #endif diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c index 5b18f6ffa45c..e5a4d8f98b10 100644 --- a/drivers/soc/tegra/fuse/tegra-apbmisc.c +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c @@ -39,16 +39,16 @@ static bool long_ram_code; u32 tegra_read_chipid(void) { - return readl_relaxed(apbmisc_base + 4); -} - -u8 tegra_get_chip_id(void) -{ if (!apbmisc_base) { WARN(1, "Tegra Chip ID not yet available\n"); return 0; } + return readl_relaxed(apbmisc_base + 4); +} + +u8 tegra_get_chip_id(void) +{ return (tegra_read_chipid() >> 8) & 0xff; } @@ -74,6 +74,7 @@ u32 tegra_read_ram_code(void) static const struct of_device_id apbmisc_match[] __initconst = { { .compatible = "nvidia,tegra20-apbmisc", }, + { .compatible = "nvidia,tegra186-misc", }, {}, }; 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 0453ff6839a7..ce62a47a6647 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -66,11 +66,10 @@ #define PMC_PWR_DET 0x48 -#define PMC_SCRATCH0 0x50 -#define PMC_SCRATCH0_MODE_RECOVERY BIT(31) -#define PMC_SCRATCH0_MODE_BOOTLOADER BIT(30) -#define PMC_SCRATCH0_MODE_RCM BIT(1) -#define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \ +#define PMC_SCRATCH0_MODE_RECOVERY BIT(31) +#define PMC_SCRATCH0_MODE_BOOTLOADER BIT(30) +#define PMC_SCRATCH0_MODE_RCM BIT(1) +#define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \ PMC_SCRATCH0_MODE_BOOTLOADER | \ PMC_SCRATCH0_MODE_RCM) @@ -118,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; @@ -134,6 +137,14 @@ struct tegra_io_pad_soc { unsigned int voltage; }; +struct tegra_pmc_regs { + unsigned int scratch0; + unsigned int dpd_req; + unsigned int dpd_status; + unsigned int dpd2_req; + unsigned int dpd2_status; +}; + struct tegra_pmc_soc { unsigned int num_powergates; const char *const *powergates; @@ -145,6 +156,12 @@ struct tegra_pmc_soc { const struct tegra_io_pad_soc *io_pads; unsigned int num_io_pads; + + const struct tegra_pmc_regs *regs; + void (*init)(struct tegra_pmc *pmc); + void (*setup_irq_polarity)(struct tegra_pmc *pmc, + struct device_node *np, + bool invert); }; /** @@ -173,6 +190,9 @@ 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; @@ -645,7 +665,7 @@ static int tegra_pmc_restart_notify(struct notifier_block *this, const char *cmd = data; u32 value; - value = tegra_pmc_readl(PMC_SCRATCH0); + value = readl(pmc->scratch + pmc->soc->regs->scratch0); value &= ~PMC_SCRATCH0_MODE_MASK; if (cmd) { @@ -659,7 +679,7 @@ static int tegra_pmc_restart_notify(struct notifier_block *this, value |= PMC_SCRATCH0_MODE_RCM; } - tegra_pmc_writel(value, PMC_SCRATCH0); + writel(value, pmc->scratch + pmc->soc->regs->scratch0); /* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */ value = tegra_pmc_readl(PMC_CNTRL); @@ -954,25 +974,27 @@ static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, *mask = BIT(pad->dpd % 32); if (pad->dpd < 32) { - *status = IO_DPD_STATUS; - *request = IO_DPD_REQ; + *status = pmc->soc->regs->dpd_status; + *request = pmc->soc->regs->dpd_req; } else { - *status = IO_DPD2_STATUS; - *request = IO_DPD2_REQ; + *status = pmc->soc->regs->dpd2_status; + *request = pmc->soc->regs->dpd2_req; } - rate = clk_get_rate(pmc->clk); - if (!rate) { - pr_err("failed to get clock rate\n"); - return -ENODEV; - } + if (pmc->clk) { + rate = clk_get_rate(pmc->clk); + if (!rate) { + pr_err("failed to get clock rate\n"); + return -ENODEV; + } - tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE); + tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE); - /* must be at least 200 ns, in APB (PCLK) clock cycles */ - value = DIV_ROUND_UP(1000000000, rate); - value = DIV_ROUND_UP(200, value); - tegra_pmc_writel(value, SEL_DPD_TIM); + /* must be at least 200 ns, in APB (PCLK) clock cycles */ + value = DIV_ROUND_UP(1000000000, rate); + value = DIV_ROUND_UP(200, value); + tegra_pmc_writel(value, SEL_DPD_TIM); + } return 0; } @@ -997,7 +1019,8 @@ static int tegra_io_pad_poll(unsigned long offset, u32 mask, static void tegra_io_pad_unprepare(void) { - tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); + if (pmc->clk) + tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); } /** @@ -1287,27 +1310,8 @@ static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np) static void tegra_pmc_init(struct tegra_pmc *pmc) { - u32 value; - - /* Always enable CPU power request */ - value = tegra_pmc_readl(PMC_CNTRL); - value |= PMC_CNTRL_CPU_PWRREQ_OE; - tegra_pmc_writel(value, PMC_CNTRL); - - value = tegra_pmc_readl(PMC_CNTRL); - - if (pmc->sysclkreq_high) - value &= ~PMC_CNTRL_SYSCLK_POLARITY; - else - value |= PMC_CNTRL_SYSCLK_POLARITY; - - /* configure the output polarity while the request is tristated */ - tegra_pmc_writel(value, PMC_CNTRL); - - /* now enable the request */ - value = tegra_pmc_readl(PMC_CNTRL); - value |= PMC_CNTRL_SYSCLK_OE; - tegra_pmc_writel(value, PMC_CNTRL); + if (pmc->soc->init) + pmc->soc->init(pmc); } static void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc) @@ -1410,11 +1414,43 @@ static int tegra_pmc_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(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)) { err = PTR_ERR(pmc->clk); - dev_err(&pdev->dev, "failed to get pclk: %d\n", err); - return err; + + if (err != -ENOENT) { + dev_err(&pdev->dev, "failed to get pclk: %d\n", err); + return err; + } + + pmc->clk = NULL; } pmc->dev = &pdev->dev; @@ -1474,6 +1510,55 @@ static const char * const tegra20_powergates[] = { [TEGRA_POWERGATE_MPE] = "mpe", }; +static const struct tegra_pmc_regs tegra20_pmc_regs = { + .scratch0 = 0x50, + .dpd_req = 0x1b8, + .dpd_status = 0x1bc, + .dpd2_req = 0x1c0, + .dpd2_status = 0x1c4, +}; + +static void tegra20_pmc_init(struct tegra_pmc *pmc) +{ + u32 value; + + /* Always enable CPU power request */ + value = tegra_pmc_readl(PMC_CNTRL); + value |= PMC_CNTRL_CPU_PWRREQ_OE; + tegra_pmc_writel(value, PMC_CNTRL); + + value = tegra_pmc_readl(PMC_CNTRL); + + if (pmc->sysclkreq_high) + value &= ~PMC_CNTRL_SYSCLK_POLARITY; + else + value |= PMC_CNTRL_SYSCLK_POLARITY; + + /* configure the output polarity while the request is tristated */ + tegra_pmc_writel(value, PMC_CNTRL); + + /* now enable the request */ + value = tegra_pmc_readl(PMC_CNTRL); + value |= PMC_CNTRL_SYSCLK_OE; + tegra_pmc_writel(value, PMC_CNTRL); +} + +static void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc, + struct device_node *np, + bool invert) +{ + u32 value; + + value = tegra_pmc_readl(PMC_CNTRL); + + if (invert) + value |= PMC_CNTRL_INTR_POLARITY; + else + value &= ~PMC_CNTRL_INTR_POLARITY; + + tegra_pmc_writel(value, PMC_CNTRL); +} + static const struct tegra_pmc_soc tegra20_pmc_soc = { .num_powergates = ARRAY_SIZE(tegra20_powergates), .powergates = tegra20_powergates, @@ -1481,6 +1566,11 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { .cpu_powergates = NULL, .has_tsense_reset = false, .has_gpu_clamps = false, + .num_io_pads = 0, + .io_pads = NULL, + .regs = &tegra20_pmc_regs, + .init = tegra20_pmc_init, + .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, }; static const char * const tegra30_powergates[] = { @@ -1514,6 +1604,11 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { .cpu_powergates = tegra30_cpu_powergates, .has_tsense_reset = true, .has_gpu_clamps = false, + .num_io_pads = 0, + .io_pads = NULL, + .regs = &tegra20_pmc_regs, + .init = tegra20_pmc_init, + .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, }; static const char * const tegra114_powergates[] = { @@ -1551,6 +1646,11 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { .cpu_powergates = tegra114_cpu_powergates, .has_tsense_reset = true, .has_gpu_clamps = false, + .num_io_pads = 0, + .io_pads = NULL, + .regs = &tegra20_pmc_regs, + .init = tegra20_pmc_init, + .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, }; static const char * const tegra124_powergates[] = { @@ -1628,6 +1728,9 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .has_gpu_clamps = true, .num_io_pads = ARRAY_SIZE(tegra124_io_pads), .io_pads = tegra124_io_pads, + .regs = &tegra20_pmc_regs, + .init = tegra20_pmc_init, + .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, }; static const char * const tegra210_powergates[] = { @@ -1714,9 +1817,110 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .has_gpu_clamps = true, .num_io_pads = ARRAY_SIZE(tegra210_io_pads), .io_pads = tegra210_io_pads, + .regs = &tegra20_pmc_regs, + .init = tegra20_pmc_init, + .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 }, @@ -1749,7 +1953,6 @@ static int __init tegra_pmc_early_init(void) struct device_node *np; struct resource regs; bool invert; - u32 value; mutex_init(&pmc->powergates_lock); @@ -1810,14 +2013,7 @@ static int __init tegra_pmc_early_init(void) */ invert = of_property_read_bool(np, "nvidia,invert-interrupt"); - value = tegra_pmc_readl(PMC_CNTRL); - - if (invert) - value |= PMC_CNTRL_INTR_POLARITY; - else - value &= ~PMC_CNTRL_INTR_POLARITY; - - tegra_pmc_writel(value, PMC_CNTRL); + pmc->soc->setup_irq_polarity(pmc, np, invert); of_node_put(np); } |