diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-02 03:17:40 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-02 03:17:40 +0300 |
commit | adbc128fa8b4e9ecfdd11d5dd0a7d9845c6ea510 (patch) | |
tree | 55137f446ffd127530fdcbe86dafdfb436fe1c20 /drivers | |
parent | 537433b6241e067de2d9da3bed5f4fed9c9eac58 (diff) | |
parent | 0ca14cdea789f70c4dc7ef5844aad52cb9675aee (diff) | |
download | linux-adbc128fa8b4e9ecfdd11d5dd0a7d9845c6ea510.tar.xz |
Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform updates from Arnd Bergmann:
"These are mostly minor bugfixes, cleanup and many defconfig updates to
support added drivers. In particular OMAP and PXA keep cleaning up the
legacy code base, as usual.
Nvidia adds some more SoC support code for Tegra 186.
For the first time on years, we are actually adding a non-DT platform
for the EP93xx based Liebherr controller BK3.1. It's a minor variation
of the EP93xx reference design and in active use, while EP93xx
apparently doesn't have enough new development to have any device tree
support"
* tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (73 commits)
ARM: omap: hwmod: fix section mismatch warnings
ARM: pxa/tosa-bt: add MODULE_LICENSE tag
arm64: defconfig: enable CONFIG_ACPI_APEI_EINJ
arm64: defconfig: enable EDAC GHES option
arm64: defconfig: enable CONFIG_ACPI_APEI_MEMORY_FAILURE
ARM: imx_v6_v7_defconfig: enable CONFIG_CPU_FREQ_STAT
Wind down ARM/TANGO port
ARM: davinci: constify gpio_led
ARM: davinci: drop unneeded newline
soc: Add SoC driver for Gemini
ARM: SAMSUNG: Add SPDX license identifiers
ARM: S5PV210: Add SPDX license identifiers
ARM: S3C64XX: Add SPDX license identifiers
ARM: S3C24XX: Add SPDX license identifiers
ARM: EXYNOS: Add SPDX license identifiers
ARM: imx: remove unused imx3 pm definitions
ARM: imx: don't abort MMDC probe if power saving status doesn't match
ARM: imx_v6_v7_defconfig: enable RTC_DRV_MXC_V2
ARM: imx_v6_v7_defconfig: Add missing config for DART-MX6 SoM
ARM: davinci: Use PTR_ERR_OR_ZERO()
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/busses/i2c-pxa-pci.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 2 | ||||
-rw-r--r-- | drivers/soc/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/gemini/Makefile | 2 | ||||
-rw-r--r-- | drivers/soc/gemini/soc-gemini.c | 71 | ||||
-rw-r--r-- | drivers/soc/mediatek/mtk-infracfg.c | 26 | ||||
-rw-r--r-- | drivers/soc/mediatek/mtk-scpsys.c | 140 | ||||
-rw-r--r-- | drivers/soc/renesas/rcar-sysc.c | 2 | ||||
-rw-r--r-- | drivers/soc/renesas/renesas-soc.c | 3 | ||||
-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 |
18 files changed, 525 insertions, 259 deletions
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 004deb96afe3..72ea8f4c61aa 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -10,7 +10,7 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/platform_device.h> -#include <linux/i2c/pxa-i2c.h> +#include <linux/platform_data/i2c-pxa.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_address.h> diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 600d264e080c..fbf91d383b40 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -36,7 +36,7 @@ #include <linux/clk.h> #include <linux/slab.h> #include <linux/io.h> -#include <linux/i2c/pxa-i2c.h> +#include <linux/platform_data/i2c-pxa.h> #include <asm/irq.h> diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index deecb16e7256..342768df3530 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -9,6 +9,7 @@ obj-y += bcm/ obj-$(CONFIG_ARCH_DOVE) += dove/ obj-$(CONFIG_MACH_DOVE) += dove/ obj-y += fsl/ +obj-$(CONFIG_ARCH_GEMINI) += gemini/ obj-$(CONFIG_ARCH_MXC) += imx/ obj-$(CONFIG_SOC_XWAY) += lantiq/ obj-y += mediatek/ diff --git a/drivers/soc/gemini/Makefile b/drivers/soc/gemini/Makefile new file mode 100644 index 000000000000..8cbd1e45db78 --- /dev/null +++ b/drivers/soc/gemini/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-y += soc-gemini.o diff --git a/drivers/soc/gemini/soc-gemini.c b/drivers/soc/gemini/soc-gemini.c new file mode 100644 index 000000000000..642b96c91ad6 --- /dev/null +++ b/drivers/soc/gemini/soc-gemini.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Linaro Ltd. + * + * Author: Linus Walleij <linus.walleij@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/of.h> + +#define GLOBAL_WORD_ID 0x00 +#define GEMINI_GLOBAL_ARB1_CTRL 0x2c +#define GEMINI_ARB1_BURST_MASK GENMASK(21, 16) +#define GEMINI_ARB1_BURST_SHIFT 16 +/* These all define the priority on the BUS2 backplane */ +#define GEMINI_ARB1_PRIO_MASK GENMASK(9, 0) +#define GEMINI_ARB1_DMAC_HIGH_PRIO BIT(0) +#define GEMINI_ARB1_IDE_HIGH_PRIO BIT(1) +#define GEMINI_ARB1_RAID_HIGH_PRIO BIT(2) +#define GEMINI_ARB1_SECURITY_HIGH_PRIO BIT(3) +#define GEMINI_ARB1_GMAC0_HIGH_PRIO BIT(4) +#define GEMINI_ARB1_GMAC1_HIGH_PRIO BIT(5) +#define GEMINI_ARB1_USB0_HIGH_PRIO BIT(6) +#define GEMINI_ARB1_USB1_HIGH_PRIO BIT(7) +#define GEMINI_ARB1_PCI_HIGH_PRIO BIT(8) +#define GEMINI_ARB1_TVE_HIGH_PRIO BIT(9) + +#define GEMINI_DEFAULT_BURST_SIZE 0x20 +#define GEMINI_DEFAULT_PRIO (GEMINI_ARB1_GMAC0_HIGH_PRIO | \ + GEMINI_ARB1_GMAC1_HIGH_PRIO) + +static int __init gemini_soc_init(void) +{ + struct regmap *map; + u32 rev; + u32 val; + int ret; + + /* Multiplatform guard, only proceed on Gemini */ + if (!of_machine_is_compatible("cortina,gemini")) + return 0; + + map = syscon_regmap_lookup_by_compatible("cortina,gemini-syscon"); + if (IS_ERR(map)) + return PTR_ERR(map); + ret = regmap_read(map, GLOBAL_WORD_ID, &rev); + if (ret) + return ret; + + val = (GEMINI_DEFAULT_BURST_SIZE << GEMINI_ARB1_BURST_SHIFT) | + GEMINI_DEFAULT_PRIO; + + /* Set up system arbitration */ + regmap_update_bits(map, + GEMINI_GLOBAL_ARB1_CTRL, + GEMINI_ARB1_BURST_MASK | GEMINI_ARB1_PRIO_MASK, + val); + + pr_info("Gemini SoC %04x revision %02x, set arbitration %08x\n", + rev >> 8, rev & 0xff, val); + + return 0; +} +subsys_initcall(gemini_soc_init); diff --git a/drivers/soc/mediatek/mtk-infracfg.c b/drivers/soc/mediatek/mtk-infracfg.c index dba3055a9493..8c310de01e93 100644 --- a/drivers/soc/mediatek/mtk-infracfg.c +++ b/drivers/soc/mediatek/mtk-infracfg.c @@ -19,23 +19,33 @@ #define INFRA_TOPAXI_PROTECTEN 0x0220 #define INFRA_TOPAXI_PROTECTSTA1 0x0228 +#define INFRA_TOPAXI_PROTECTEN_SET 0x0260 +#define INFRA_TOPAXI_PROTECTEN_CLR 0x0264 /** * mtk_infracfg_set_bus_protection - enable bus protection * @regmap: The infracfg regmap * @mask: The mask containing the protection bits to be enabled. + * @reg_update: The boolean flag determines to set the protection bits + * by regmap_update_bits with enable register(PROTECTEN) or + * by regmap_write with set register(PROTECTEN_SET). * * This function enables the bus protection bits for disabled power * domains so that the system does not hang when some unit accesses the * bus while in power down. */ -int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask) +int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask, + bool reg_update) { unsigned long expired; u32 val; int ret; - regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, mask); + if (reg_update) + regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, + mask); + else + regmap_write(infracfg, INFRA_TOPAXI_PROTECTEN_SET, mask); expired = jiffies + HZ; @@ -59,16 +69,24 @@ int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask) * mtk_infracfg_clear_bus_protection - disable bus protection * @regmap: The infracfg regmap * @mask: The mask containing the protection bits to be disabled. + * @reg_update: The boolean flag determines to clear the protection bits + * by regmap_update_bits with enable register(PROTECTEN) or + * by regmap_write with clear register(PROTECTEN_CLR). * * This function disables the bus protection bits previously enabled with * mtk_infracfg_set_bus_protection. */ -int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask) + +int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask, + bool reg_update) { unsigned long expired; int ret; - regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, 0); + if (reg_update) + regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, 0); + else + regmap_write(infracfg, INFRA_TOPAXI_PROTECTEN_CLR, mask); expired = jiffies + HZ; diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index e570b6af2e6f..435ce5ec648a 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -21,6 +21,7 @@ #include <linux/soc/mediatek/infracfg.h> #include <dt-bindings/power/mt2701-power.h> +#include <dt-bindings/power/mt2712-power.h> #include <dt-bindings/power/mt6797-power.h> #include <dt-bindings/power/mt7622-power.h> #include <dt-bindings/power/mt8173-power.h> @@ -32,7 +33,7 @@ #define SPM_DIS_PWR_CON 0x023c #define SPM_CONN_PWR_CON 0x0280 #define SPM_VEN2_PWR_CON 0x0298 -#define SPM_AUDIO_PWR_CON 0x029c /* MT8173 */ +#define SPM_AUDIO_PWR_CON 0x029c /* MT8173, MT2712 */ #define SPM_BDP_PWR_CON 0x029c /* MT2701 */ #define SPM_ETH_PWR_CON 0x02a0 #define SPM_HIF_PWR_CON 0x02a4 @@ -40,12 +41,12 @@ #define SPM_MFG_2D_PWR_CON 0x02c0 #define SPM_MFG_ASYNC_PWR_CON 0x02c4 #define SPM_USB_PWR_CON 0x02cc +#define SPM_USB2_PWR_CON 0x02d4 /* MT2712 */ #define SPM_ETHSYS_PWR_CON 0x02e0 /* MT7622 */ #define SPM_HIF0_PWR_CON 0x02e4 /* MT7622 */ #define SPM_HIF1_PWR_CON 0x02e8 /* MT7622 */ #define SPM_WB_PWR_CON 0x02ec /* MT7622 */ - #define SPM_PWR_STATUS 0x060c #define SPM_PWR_STATUS_2ND 0x0610 @@ -64,12 +65,13 @@ #define PWR_STATUS_ETH BIT(15) #define PWR_STATUS_HIF BIT(16) #define PWR_STATUS_IFR_MSC BIT(17) +#define PWR_STATUS_USB2 BIT(19) /* MT2712 */ #define PWR_STATUS_VENC_LT BIT(20) #define PWR_STATUS_VENC BIT(21) -#define PWR_STATUS_MFG_2D BIT(22) -#define PWR_STATUS_MFG_ASYNC BIT(23) -#define PWR_STATUS_AUDIO BIT(24) -#define PWR_STATUS_USB BIT(25) +#define PWR_STATUS_MFG_2D BIT(22) /* MT8173 */ +#define PWR_STATUS_MFG_ASYNC BIT(23) /* MT8173 */ +#define PWR_STATUS_AUDIO BIT(24) /* MT8173, MT2712 */ +#define PWR_STATUS_USB BIT(25) /* MT8173, MT2712 */ #define PWR_STATUS_ETHSYS BIT(24) /* MT7622 */ #define PWR_STATUS_HIF0 BIT(25) /* MT7622 */ #define PWR_STATUS_HIF1 BIT(26) /* MT7622 */ @@ -84,6 +86,8 @@ enum clk_id { CLK_ETHIF, CLK_VDEC, CLK_HIFSEL, + CLK_JPGDEC, + CLK_AUDIO, CLK_MAX, }; @@ -96,10 +100,12 @@ static const char * const clk_names[] = { "ethif", "vdec", "hif_sel", + "jpgdec", + "audio", NULL, }; -#define MAX_CLKS 2 +#define MAX_CLKS 3 struct scp_domain_data { const char *name; @@ -134,6 +140,7 @@ struct scp { void __iomem *base; struct regmap *infracfg; struct scp_ctrl_reg ctrl_reg; + bool bus_prot_reg_update; }; struct scp_subdomain { @@ -147,6 +154,7 @@ struct scp_soc_data { const struct scp_subdomain *subdomains; int num_subdomains; const struct scp_ctrl_reg regs; + bool bus_prot_reg_update; }; static int scpsys_domain_is_on(struct scp_domain *scpd) @@ -254,7 +262,8 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) if (scpd->data->bus_prot_mask) { ret = mtk_infracfg_clear_bus_protection(scp->infracfg, - scpd->data->bus_prot_mask); + scpd->data->bus_prot_mask, + scp->bus_prot_reg_update); if (ret) goto err_pwr_ack; } @@ -289,7 +298,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) if (scpd->data->bus_prot_mask) { ret = mtk_infracfg_set_bus_protection(scp->infracfg, - scpd->data->bus_prot_mask); + scpd->data->bus_prot_mask, + scp->bus_prot_reg_update); if (ret) goto out; } @@ -371,7 +381,8 @@ static void init_clks(struct platform_device *pdev, struct clk **clk) static struct scp *init_scp(struct platform_device *pdev, const struct scp_domain_data *scp_domain_data, int num, - const struct scp_ctrl_reg *scp_ctrl_reg) + const struct scp_ctrl_reg *scp_ctrl_reg, + bool bus_prot_reg_update) { struct genpd_onecell_data *pd_data; struct resource *res; @@ -386,6 +397,8 @@ static struct scp *init_scp(struct platform_device *pdev, scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs; scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs; + scp->bus_prot_reg_update = bus_prot_reg_update; + scp->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -581,6 +594,85 @@ static const struct scp_domain_data scp_domain_data_mt2701[] = { }; /* + * MT2712 power domain support + */ +static const struct scp_domain_data scp_domain_data_mt2712[] = { + [MT2712_POWER_DOMAIN_MM] = { + .name = "mm", + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM}, + .active_wakeup = true, + }, + [MT2712_POWER_DOMAIN_VDEC] = { + .name = "vdec", + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM, CLK_VDEC}, + .active_wakeup = true, + }, + [MT2712_POWER_DOMAIN_VENC] = { + .name = "venc", + .sta_mask = PWR_STATUS_VENC, + .ctl_offs = SPM_VEN_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_MM, CLK_VENC, CLK_JPGDEC}, + .active_wakeup = true, + }, + [MT2712_POWER_DOMAIN_ISP] = { + .name = "isp", + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = {CLK_MM}, + .active_wakeup = true, + }, + [MT2712_POWER_DOMAIN_AUDIO] = { + .name = "audio", + .sta_mask = PWR_STATUS_AUDIO, + .ctl_offs = SPM_AUDIO_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_AUDIO}, + .active_wakeup = true, + }, + [MT2712_POWER_DOMAIN_USB] = { + .name = "usb", + .sta_mask = PWR_STATUS_USB, + .ctl_offs = SPM_USB_PWR_CON, + .sram_pdn_bits = GENMASK(10, 8), + .sram_pdn_ack_bits = GENMASK(14, 12), + .clk_id = {CLK_NONE}, + .active_wakeup = true, + }, + [MT2712_POWER_DOMAIN_USB2] = { + .name = "usb2", + .sta_mask = PWR_STATUS_USB2, + .ctl_offs = SPM_USB2_PWR_CON, + .sram_pdn_bits = GENMASK(10, 8), + .sram_pdn_ack_bits = GENMASK(14, 12), + .clk_id = {CLK_NONE}, + .active_wakeup = true, + }, + [MT2712_POWER_DOMAIN_MFG] = { + .name = "mfg", + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(19, 16), + .clk_id = {CLK_MFG}, + .bus_prot_mask = BIT(14) | BIT(21) | BIT(23), + .active_wakeup = true, + }, +}; + +/* * MT6797 power domain support */ @@ -806,7 +898,18 @@ static const struct scp_soc_data mt2701_data = { .regs = { .pwr_sta_offs = SPM_PWR_STATUS, .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND - } + }, + .bus_prot_reg_update = true, +}; + +static const struct scp_soc_data mt2712_data = { + .domains = scp_domain_data_mt2712, + .num_domains = ARRAY_SIZE(scp_domain_data_mt2712), + .regs = { + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND + }, + .bus_prot_reg_update = false, }; static const struct scp_soc_data mt6797_data = { @@ -817,7 +920,8 @@ static const struct scp_soc_data mt6797_data = { .regs = { .pwr_sta_offs = SPM_PWR_STATUS_MT6797, .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND_MT6797 - } + }, + .bus_prot_reg_update = true, }; static const struct scp_soc_data mt7622_data = { @@ -826,7 +930,8 @@ static const struct scp_soc_data mt7622_data = { .regs = { .pwr_sta_offs = SPM_PWR_STATUS, .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND - } + }, + .bus_prot_reg_update = true, }; static const struct scp_soc_data mt8173_data = { @@ -837,7 +942,8 @@ static const struct scp_soc_data mt8173_data = { .regs = { .pwr_sta_offs = SPM_PWR_STATUS, .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND - } + }, + .bus_prot_reg_update = true, }; /* @@ -849,6 +955,9 @@ static const struct of_device_id of_scpsys_match_tbl[] = { .compatible = "mediatek,mt2701-scpsys", .data = &mt2701_data, }, { + .compatible = "mediatek,mt2712-scpsys", + .data = &mt2712_data, + }, { .compatible = "mediatek,mt6797-scpsys", .data = &mt6797_data, }, { @@ -874,7 +983,8 @@ static int scpsys_probe(struct platform_device *pdev) match = of_match_device(of_scpsys_match_tbl, &pdev->dev); soc = (const struct scp_soc_data *)match->data; - scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs); + scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs, + soc->bus_prot_reg_update); if (IS_ERR(scp)) return PTR_ERR(scp); diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 55a47e509e49..52c25a5e2646 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -224,7 +224,7 @@ static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd) if (!(pd->flags & (PD_CPU | PD_SCU))) { /* Enable Clock Domain for I/O devices */ - genpd->flags |= GENPD_FLAG_PM_CLK; + genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP; if (has_cpg_mstp) { genpd->attach_dev = cpg_mstp_attach_dev; genpd->detach_dev = cpg_mstp_detach_dev; diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index 9f4ee2567c72..926b7fd6db2d 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c @@ -250,6 +250,9 @@ static int __init renesas_soc_init(void) if (chipid) { product = readl(chipid); iounmap(chipid); + /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */ + if ((product & 0x7fff) == 0x5210) + product ^= 0x11; if (soc->id && ((product >> 8) & 0xff) != soc->id) { pr_warn("SoC mismatch (product = 0x%x)\n", product); return -ENODEV; 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); } |