Commit a3dc838d authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'tegra-for-4.16-soc-2' of...

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
parents 7294f2fc ccf15184
NVIDIA Tegra186 MISC register block
The MISC register block found on Tegra186 SoCs contains registers that can be
used to identify a given chip and various strapping options.
Required properties:
- compatible: Must be:
- Tegra186: "nvidia,tegra186-misc"
- reg: Should contain 2 entries: The first entry gives the physical address
and length of the register region which contains revision and debug
features. The second entry specifies the physical address and length
of the register region indicating the strapping options.
...@@ -95,7 +95,7 @@ config ARCH_TEGRA_186_SOC ...@@ -95,7 +95,7 @@ config ARCH_TEGRA_186_SOC
select TEGRA_BPMP select TEGRA_BPMP
select TEGRA_HSP_MBOX select TEGRA_HSP_MBOX
select TEGRA_IVC select TEGRA_IVC
select SOC_TEGRA_PMC_TEGRA186 select SOC_TEGRA_PMC
help help
Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a
combination of Denver and Cortex-A57 CPU cores and a GPU based on combination of Denver and Cortex-A57 CPU cores and a GPU based on
...@@ -118,9 +118,6 @@ config SOC_TEGRA_FLOWCTRL ...@@ -118,9 +118,6 @@ config SOC_TEGRA_FLOWCTRL
config SOC_TEGRA_PMC config SOC_TEGRA_PMC
bool bool
config SOC_TEGRA_PMC_TEGRA186
bool
config SOC_TEGRA_POWERGATE_BPMP config SOC_TEGRA_POWERGATE_BPMP
def_bool y def_bool y
depends on PM_GENERIC_DOMAINS depends on PM_GENERIC_DOMAINS
......
...@@ -4,5 +4,4 @@ obj-y += fuse/ ...@@ -4,5 +4,4 @@ obj-y += fuse/
obj-y += common.o obj-y += common.o
obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o
obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.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 obj-$(CONFIG_SOC_TEGRA_POWERGATE_BPMP) += powergate-bpmp.o
...@@ -103,6 +103,9 @@ static struct tegra_fuse *fuse = &(struct tegra_fuse) { ...@@ -103,6 +103,9 @@ static struct tegra_fuse *fuse = &(struct tegra_fuse) {
}; };
static const struct of_device_id tegra_fuse_match[] = { 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 #ifdef CONFIG_ARCH_TEGRA_210_SOC
{ .compatible = "nvidia,tegra210-efuse", .data = &tegra210_fuse_soc }, { .compatible = "nvidia,tegra210-efuse", .data = &tegra210_fuse_soc },
#endif #endif
...@@ -132,6 +135,7 @@ static int tegra_fuse_probe(struct platform_device *pdev) ...@@ -132,6 +135,7 @@ static int tegra_fuse_probe(struct platform_device *pdev)
/* take over the memory region from the early initialization */ /* take over the memory region from the early initialization */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
fuse->phys = res->start;
fuse->base = devm_ioremap_resource(&pdev->dev, res); fuse->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(fuse->base)) if (IS_ERR(fuse->base))
return PTR_ERR(fuse->base); return PTR_ERR(fuse->base);
......
...@@ -59,7 +59,7 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset) ...@@ -59,7 +59,7 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
mutex_lock(&fuse->apbdma.lock); 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); err = dmaengine_slave_config(fuse->apbdma.chan, &fuse->apbdma.config);
if (err) if (err)
...@@ -96,6 +96,13 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset) ...@@ -96,6 +96,13 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
return value; 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) static int tegra20_fuse_probe(struct tegra_fuse *fuse)
{ {
dma_cap_mask_t mask; dma_cap_mask_t mask;
...@@ -103,7 +110,7 @@ static int tegra20_fuse_probe(struct tegra_fuse *fuse) ...@@ -103,7 +110,7 @@ static int tegra20_fuse_probe(struct tegra_fuse *fuse)
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, 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) if (!fuse->apbdma.chan)
return -EPROBE_DEFER; return -EPROBE_DEFER;
...@@ -119,6 +126,8 @@ static int tegra20_fuse_probe(struct tegra_fuse *fuse) ...@@ -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.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
fuse->apbdma.config.src_maxburst = 1; fuse->apbdma.config.src_maxburst = 1;
fuse->apbdma.config.dst_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); init_completion(&fuse->apbdma.wait);
mutex_init(&fuse->apbdma.lock); mutex_init(&fuse->apbdma.lock);
......
...@@ -46,9 +46,13 @@ ...@@ -46,9 +46,13 @@
defined(CONFIG_ARCH_TEGRA_114_SOC) || \ defined(CONFIG_ARCH_TEGRA_114_SOC) || \
defined(CONFIG_ARCH_TEGRA_124_SOC) || \ defined(CONFIG_ARCH_TEGRA_124_SOC) || \
defined(CONFIG_ARCH_TEGRA_132_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) 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); return readl_relaxed(fuse->base + FUSE_BEGIN + offset);
} }
...@@ -98,7 +102,10 @@ static void __init tegra30_fuse_init(struct tegra_fuse *fuse) ...@@ -98,7 +102,10 @@ static void __init tegra30_fuse_init(struct tegra_fuse *fuse)
fuse->read = tegra30_fuse_read; fuse->read = tegra30_fuse_read;
tegra_init_revision(); 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(); tegra30_fuse_add_randomness();
} }
#endif #endif
...@@ -158,3 +165,16 @@ const struct tegra_fuse_soc tegra210_fuse_soc = { ...@@ -158,3 +165,16 @@ const struct tegra_fuse_soc tegra210_fuse_soc = {
.info = &tegra210_fuse_info, .info = &tegra210_fuse_info,
}; };
#endif #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
...@@ -105,4 +105,8 @@ extern const struct tegra_fuse_soc tegra124_fuse_soc; ...@@ -105,4 +105,8 @@ extern const struct tegra_fuse_soc tegra124_fuse_soc;
extern const struct tegra_fuse_soc tegra210_fuse_soc; extern const struct tegra_fuse_soc tegra210_fuse_soc;
#endif #endif
#ifdef CONFIG_ARCH_TEGRA_186_SOC
extern const struct tegra_fuse_soc tegra186_fuse_soc;
#endif
#endif #endif
...@@ -38,17 +38,17 @@ static void __iomem *strapping_base; ...@@ -38,17 +38,17 @@ static void __iomem *strapping_base;
static bool long_ram_code; static bool long_ram_code;
u32 tegra_read_chipid(void) u32 tegra_read_chipid(void)
{
return readl_relaxed(apbmisc_base + 4);
}
u8 tegra_get_chip_id(void)
{ {
if (!apbmisc_base) { if (!apbmisc_base) {
WARN(1, "Tegra Chip ID not yet available\n"); WARN(1, "Tegra Chip ID not yet available\n");
return 0; return 0;
} }
return readl_relaxed(apbmisc_base + 4);
}
u8 tegra_get_chip_id(void)
{
return (tegra_read_chipid() >> 8) & 0xff; return (tegra_read_chipid() >> 8) & 0xff;
} }
...@@ -74,6 +74,7 @@ u32 tegra_read_ram_code(void) ...@@ -74,6 +74,7 @@ u32 tegra_read_ram_code(void)
static const struct of_device_id apbmisc_match[] __initconst = { static const struct of_device_id apbmisc_match[] __initconst = {
{ .compatible = "nvidia,tegra20-apbmisc", }, { .compatible = "nvidia,tegra20-apbmisc", },
{ .compatible = "nvidia,tegra186-misc", },
{}, {},
}; };
......
/*
* 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);
This diff is collapsed.
...@@ -83,6 +83,7 @@ enum tegra_io_pad { ...@@ -83,6 +83,7 @@ enum tegra_io_pad {
TEGRA_IO_PAD_BB, TEGRA_IO_PAD_BB,
TEGRA_IO_PAD_CAM, TEGRA_IO_PAD_CAM,
TEGRA_IO_PAD_COMP, TEGRA_IO_PAD_COMP,
TEGRA_IO_PAD_CONN,
TEGRA_IO_PAD_CSIA, TEGRA_IO_PAD_CSIA,
TEGRA_IO_PAD_CSIB, TEGRA_IO_PAD_CSIB,
TEGRA_IO_PAD_CSIC, TEGRA_IO_PAD_CSIC,
...@@ -92,31 +93,42 @@ enum tegra_io_pad { ...@@ -92,31 +93,42 @@ enum tegra_io_pad {
TEGRA_IO_PAD_DBG, TEGRA_IO_PAD_DBG,
TEGRA_IO_PAD_DEBUG_NONAO, TEGRA_IO_PAD_DEBUG_NONAO,
TEGRA_IO_PAD_DMIC, TEGRA_IO_PAD_DMIC,
TEGRA_IO_PAD_DMIC_HV,
TEGRA_IO_PAD_DP, TEGRA_IO_PAD_DP,
TEGRA_IO_PAD_DSI, TEGRA_IO_PAD_DSI,
TEGRA_IO_PAD_DSIB, TEGRA_IO_PAD_DSIB,
TEGRA_IO_PAD_DSIC, TEGRA_IO_PAD_DSIC,
TEGRA_IO_PAD_DSID, TEGRA_IO_PAD_DSID,
TEGRA_IO_PAD_EDP,
TEGRA_IO_PAD_EMMC, TEGRA_IO_PAD_EMMC,
TEGRA_IO_PAD_EMMC2, TEGRA_IO_PAD_EMMC2,
TEGRA_IO_PAD_GPIO, TEGRA_IO_PAD_GPIO,
TEGRA_IO_PAD_HDMI, TEGRA_IO_PAD_HDMI,
TEGRA_IO_PAD_HDMI_DP0,
TEGRA_IO_PAD_HDMI_DP1,
TEGRA_IO_PAD_HSIC, TEGRA_IO_PAD_HSIC,
TEGRA_IO_PAD_HV, TEGRA_IO_PAD_HV,
TEGRA_IO_PAD_LVDS, TEGRA_IO_PAD_LVDS,
TEGRA_IO_PAD_MIPI_BIAS, TEGRA_IO_PAD_MIPI_BIAS,
TEGRA_IO_PAD_NAND, TEGRA_IO_PAD_NAND,
TEGRA_IO_PAD_PEX_BIAS, TEGRA_IO_PAD_PEX_BIAS,
TEGRA_IO_PAD_PEX_CLK_BIAS,
TEGRA_IO_PAD_PEX_CLK1, TEGRA_IO_PAD_PEX_CLK1,
TEGRA_IO_PAD_PEX_CLK2, TEGRA_IO_PAD_PEX_CLK2,
TEGRA_IO_PAD_PEX_CLK3,
TEGRA_IO_PAD_PEX_CNTRL, TEGRA_IO_PAD_PEX_CNTRL,
TEGRA_IO_PAD_SDMMC1, 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,
TEGRA_IO_PAD_SDMMC3_HV,
TEGRA_IO_PAD_SDMMC4, TEGRA_IO_PAD_SDMMC4,
TEGRA_IO_PAD_SPI, TEGRA_IO_PAD_SPI,
TEGRA_IO_PAD_SPI_HV, TEGRA_IO_PAD_SPI_HV,
TEGRA_IO_PAD_SYS_DDC, TEGRA_IO_PAD_SYS_DDC,
TEGRA_IO_PAD_UART, TEGRA_IO_PAD_UART,
TEGRA_IO_PAD_UFS,
TEGRA_IO_PAD_USB0, TEGRA_IO_PAD_USB0,
TEGRA_IO_PAD_USB1, TEGRA_IO_PAD_USB1,
TEGRA_IO_PAD_USB2, TEGRA_IO_PAD_USB2,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment