diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-04-04 01:02:35 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-04-04 01:02:35 +0300 |
commit | 0e8fb69f287bcf61fb93990f6bb1496ef0122499 (patch) | |
tree | 276b8bd5339141109e2fa3590f369c731128c2e8 /drivers | |
parent | de3c913c6e9d8bbf8b2d3caaed55ff3e40a62e56 (diff) | |
parent | f125e2d4339dda6937865f975470b29c84714c9b (diff) | |
download | linux-0e8fb69f287bcf61fb93990f6bb1496ef0122499.tar.xz |
Merge tag 'arm-soc-5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull ARM SoC updates from Arnd Bergmann:
"The code changes are mostly for 32-bit platforms and include:
- Lots of updates for the Nvidia Tegra platform, including cpuidle,
pmc, and dt-binding changes
- Microchip at91 power management updates for the recently added
sam9x60 SoC
- Treewide setup_irq deprecation by afzal mohammed
- STMicroelectronics stm32 gains earlycon support
- Renesas platforms with Cortex-A9 can now use the global timer
- Some TI OMAP2+ platforms gain cpuidle support
- Various cleanups for the i.MX6 and Orion platforms, as well as
Kconfig files across all platforms"
* tag 'arm-soc-5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (75 commits)
ARM: qcom: Add support for IPQ40xx
ARM: mmp: replace setup_irq() by request_irq()
ARM: cns3xxx: replace setup_irq() by request_irq()
ARM: spear: replace setup_irq() by request_irq()
ARM: ep93xx: Replace setup_irq() by request_irq()
ARM: iop32x: replace setup_irq() by request_irq()
arm: mach-dove: Mark dove_io_desc as __maybe_unused
ARM: orion: replace setup_irq() by request_irq()
ARM: debug: stm32: add UART early console support for STM32MP1
ARM: debug: stm32: add UART early console support for STM32H7
ARM: debug: stm32: add UART early console configuration for STM32F7
ARM: debug: stm32: add UART early console configuration for STM32F4
cpuidle: tegra: Disable CC6 state if LP2 unavailable
cpuidle: tegra: Squash Tegra114 driver into the common driver
cpuidle: tegra: Squash Tegra30 driver into the common driver
cpuidle: Refactor and move out NVIDIA Tegra20 driver into drivers/cpuidle
ARM: tegra: cpuidle: Remove unnecessary memory barrier
ARM: tegra: cpuidle: Make abort_flag atomic
ARM: tegra: cpuidle: Handle case where secondary CPU hangs on entering LP2
ARM: tegra: Make outer_disable() open-coded
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/at91/clk-sam9x60-pll.c | 91 | ||||
-rw-r--r-- | drivers/cpuidle/Kconfig.arm | 8 | ||||
-rw-r--r-- | drivers/cpuidle/Makefile | 1 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-tegra.c | 392 | ||||
-rw-r--r-- | drivers/firmware/xilinx/Kconfig | 2 | ||||
-rw-r--r-- | drivers/soc/mediatek/mtk-cmdq-helper.c | 1 | ||||
-rw-r--r-- | drivers/soc/mediatek/mtk-pmic-wrap.c | 128 | ||||
-rw-r--r-- | drivers/soc/renesas/Kconfig | 2 | ||||
-rw-r--r-- | drivers/soc/tegra/pmc.c | 688 | ||||
-rw-r--r-- | drivers/soc/ti/pm33xx.c | 21 |
10 files changed, 1118 insertions, 216 deletions
diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c index dfb354a5ff18..e699803986e5 100644 --- a/drivers/clk/at91/clk-sam9x60-pll.c +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -14,27 +14,8 @@ #include "pmc.h" -#define PMC_PLL_CTRL0 0xc -#define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0) -#define PMC_PLL_CTRL0_ENPLL BIT(28) -#define PMC_PLL_CTRL0_ENPLLCK BIT(29) -#define PMC_PLL_CTRL0_ENLOCK BIT(31) - -#define PMC_PLL_CTRL1 0x10 -#define PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0) -#define PMC_PLL_CTRL1_MUL_MSK GENMASK(30, 24) - -#define PMC_PLL_ACR 0x18 -#define PMC_PLL_ACR_DEFAULT_UPLL 0x12020010UL -#define PMC_PLL_ACR_DEFAULT_PLLA 0x00020010UL -#define PMC_PLL_ACR_UTMIVR BIT(12) -#define PMC_PLL_ACR_UTMIBG BIT(13) -#define PMC_PLL_ACR_LOOP_FILTER_MSK GENMASK(31, 24) - -#define PMC_PLL_UPDT 0x1c -#define PMC_PLL_UPDT_UPDATE BIT(8) - -#define PMC_PLL_ISR0 0xec +#define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0) +#define PMC_PLL_CTRL1_MUL_MSK GENMASK(30, 24) #define PLL_DIV_MAX (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1) #define UPLL_DIV 2 @@ -59,7 +40,7 @@ static inline bool sam9x60_pll_ready(struct regmap *regmap, int id) { unsigned int status; - regmap_read(regmap, PMC_PLL_ISR0, &status); + regmap_read(regmap, AT91_PMC_PLL_ISR0, &status); return !!(status & BIT(id)); } @@ -74,12 +55,12 @@ static int sam9x60_pll_prepare(struct clk_hw *hw) u32 val; spin_lock_irqsave(pll->lock, flags); - regmap_write(regmap, PMC_PLL_UPDT, pll->id); + regmap_write(regmap, AT91_PMC_PLL_UPDT, pll->id); - regmap_read(regmap, PMC_PLL_CTRL0, &val); + regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val); div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val); - regmap_read(regmap, PMC_PLL_CTRL1, &val); + regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val); mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val); if (sam9x60_pll_ready(regmap, pll->id) && @@ -88,39 +69,39 @@ static int sam9x60_pll_prepare(struct clk_hw *hw) return 0; } - /* Recommended value for PMC_PLL_ACR */ + /* Recommended value for AT91_PMC_PLL_ACR */ if (pll->characteristics->upll) - val = PMC_PLL_ACR_DEFAULT_UPLL; + val = AT91_PMC_PLL_ACR_DEFAULT_UPLL; else - val = PMC_PLL_ACR_DEFAULT_PLLA; - regmap_write(regmap, PMC_PLL_ACR, val); + val = AT91_PMC_PLL_ACR_DEFAULT_PLLA; + regmap_write(regmap, AT91_PMC_PLL_ACR, val); - regmap_write(regmap, PMC_PLL_CTRL1, + regmap_write(regmap, AT91_PMC_PLL_CTRL1, FIELD_PREP(PMC_PLL_CTRL1_MUL_MSK, pll->mul)); if (pll->characteristics->upll) { /* Enable the UTMI internal bandgap */ - val |= PMC_PLL_ACR_UTMIBG; - regmap_write(regmap, PMC_PLL_ACR, val); + val |= AT91_PMC_PLL_ACR_UTMIBG; + regmap_write(regmap, AT91_PMC_PLL_ACR, val); udelay(10); /* Enable the UTMI internal regulator */ - val |= PMC_PLL_ACR_UTMIVR; - regmap_write(regmap, PMC_PLL_ACR, val); + val |= AT91_PMC_PLL_ACR_UTMIVR; + regmap_write(regmap, AT91_PMC_PLL_ACR, val); udelay(10); } - regmap_update_bits(regmap, PMC_PLL_UPDT, - PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE, AT91_PMC_PLL_UPDT_UPDATE); - regmap_write(regmap, PMC_PLL_CTRL0, - PMC_PLL_CTRL0_ENLOCK | PMC_PLL_CTRL0_ENPLL | - PMC_PLL_CTRL0_ENPLLCK | pll->div); + regmap_write(regmap, AT91_PMC_PLL_CTRL0, + AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL | + AT91_PMC_PLL_CTRL0_ENPLLCK | pll->div); - regmap_update_bits(regmap, PMC_PLL_UPDT, - PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE, AT91_PMC_PLL_UPDT_UPDATE); while (!sam9x60_pll_ready(regmap, pll->id)) cpu_relax(); @@ -144,22 +125,24 @@ static void sam9x60_pll_unprepare(struct clk_hw *hw) spin_lock_irqsave(pll->lock, flags); - regmap_write(pll->regmap, PMC_PLL_UPDT, pll->id); + regmap_write(pll->regmap, AT91_PMC_PLL_UPDT, pll->id); - regmap_update_bits(pll->regmap, PMC_PLL_CTRL0, - PMC_PLL_CTRL0_ENPLLCK, 0); + regmap_update_bits(pll->regmap, AT91_PMC_PLL_CTRL0, + AT91_PMC_PLL_CTRL0_ENPLLCK, 0); - regmap_update_bits(pll->regmap, PMC_PLL_UPDT, - PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + regmap_update_bits(pll->regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE, AT91_PMC_PLL_UPDT_UPDATE); - regmap_update_bits(pll->regmap, PMC_PLL_CTRL0, PMC_PLL_CTRL0_ENPLL, 0); + regmap_update_bits(pll->regmap, AT91_PMC_PLL_CTRL0, + AT91_PMC_PLL_CTRL0_ENPLL, 0); if (pll->characteristics->upll) - regmap_update_bits(pll->regmap, PMC_PLL_ACR, - PMC_PLL_ACR_UTMIBG | PMC_PLL_ACR_UTMIVR, 0); + regmap_update_bits(pll->regmap, AT91_PMC_PLL_ACR, + AT91_PMC_PLL_ACR_UTMIBG | + AT91_PMC_PLL_ACR_UTMIVR, 0); - regmap_update_bits(pll->regmap, PMC_PLL_UPDT, - PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + regmap_update_bits(pll->regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE, AT91_PMC_PLL_UPDT_UPDATE); spin_unlock_irqrestore(pll->lock, flags); } @@ -316,10 +299,10 @@ sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock, pll->regmap = regmap; pll->lock = lock; - regmap_write(regmap, PMC_PLL_UPDT, id); - regmap_read(regmap, PMC_PLL_CTRL0, &pllr); + regmap_write(regmap, AT91_PMC_PLL_UPDT, id); + regmap_read(regmap, AT91_PMC_PLL_CTRL0, &pllr); pll->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, pllr); - regmap_read(regmap, PMC_PLL_CTRL1, &pllr); + regmap_read(regmap, AT91_PMC_PLL_CTRL1, &pllr); pll->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, pllr); hw = &pll->hw; diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index 62272ecfa771..99a2d72ac02b 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -86,3 +86,11 @@ config ARM_MVEBU_V7_CPUIDLE depends on (ARCH_MVEBU || COMPILE_TEST) && !ARM64 help Select this to enable cpuidle on Armada 370, 38x and XP processors. + +config ARM_TEGRA_CPUIDLE + bool "CPU Idle Driver for NVIDIA Tegra SoCs" + depends on ARCH_TEGRA && !ARM64 + select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP + select ARM_CPU_SUSPEND + help + Select this to enable cpuidle for NVIDIA Tegra20/30/114/124 SoCs. diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index cc8c769d7fa9..55a464f6a78b 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_ARM_CPUIDLE) += cpuidle-arm.o obj-$(CONFIG_ARM_PSCI_CPUIDLE) += cpuidle_psci.o cpuidle_psci-y := cpuidle-psci.o cpuidle_psci-$(CONFIG_PM_GENERIC_DOMAINS_OF) += cpuidle-psci-domain.o +obj-$(CONFIG_ARM_TEGRA_CPUIDLE) += cpuidle-tegra.o ############################################################################### # MIPS drivers diff --git a/drivers/cpuidle/cpuidle-tegra.c b/drivers/cpuidle/cpuidle-tegra.c new file mode 100644 index 000000000000..313b0290e97b --- /dev/null +++ b/drivers/cpuidle/cpuidle-tegra.c @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * CPU idle driver for Tegra CPUs + * + * Copyright (c) 2010-2013, NVIDIA Corporation. + * Copyright (c) 2011 Google, Inc. + * Author: Colin Cross <ccross@android.com> + * Gary King <gking@nvidia.com> + * + * Rework for 3.3 by Peter De Schrijver <pdeschrijver@nvidia.com> + * + * Tegra20/124 driver unification by Dmitry Osipenko <digetx@gmail.com> + */ + +#define pr_fmt(fmt) "tegra-cpuidle: " fmt + +#include <linux/atomic.h> +#include <linux/cpuidle.h> +#include <linux/cpumask.h> +#include <linux/cpu_pm.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/platform_device.h> +#include <linux/types.h> + +#include <linux/clk/tegra.h> +#include <linux/firmware/trusted_foundations.h> + +#include <soc/tegra/cpuidle.h> +#include <soc/tegra/flowctrl.h> +#include <soc/tegra/fuse.h> +#include <soc/tegra/irq.h> +#include <soc/tegra/pm.h> +#include <soc/tegra/pmc.h> + +#include <asm/cpuidle.h> +#include <asm/firmware.h> +#include <asm/smp_plat.h> +#include <asm/suspend.h> + +enum tegra_state { + TEGRA_C1, + TEGRA_C7, + TEGRA_CC6, + TEGRA_STATE_COUNT, +}; + +static atomic_t tegra_idle_barrier; +static atomic_t tegra_abort_flag; + +static inline bool tegra_cpuidle_using_firmware(void) +{ + return firmware_ops->prepare_idle && firmware_ops->do_idle; +} + +static void tegra_cpuidle_report_cpus_state(void) +{ + unsigned long cpu, lcpu, csr; + + for_each_cpu(lcpu, cpu_possible_mask) { + cpu = cpu_logical_map(lcpu); + csr = flowctrl_read_cpu_csr(cpu); + + pr_err("cpu%lu: online=%d flowctrl_csr=0x%08lx\n", + cpu, cpu_online(lcpu), csr); + } +} + +static int tegra_cpuidle_wait_for_secondary_cpus_parking(void) +{ + unsigned int retries = 3; + + while (retries--) { + unsigned int delay_us = 10; + unsigned int timeout_us = 500 * 1000 / delay_us; + + /* + * The primary CPU0 core shall wait for the secondaries + * shutdown in order to power-off CPU's cluster safely. + * The timeout value depends on the current CPU frequency, + * it takes about 40-150us in average and over 1000us in + * a worst case scenario. + */ + do { + if (tegra_cpu_rail_off_ready()) + return 0; + + udelay(delay_us); + + } while (timeout_us--); + + pr_err("secondary CPU taking too long to park\n"); + + tegra_cpuidle_report_cpus_state(); + } + + pr_err("timed out waiting secondaries to park\n"); + + return -ETIMEDOUT; +} + +static void tegra_cpuidle_unpark_secondary_cpus(void) +{ + unsigned int cpu, lcpu; + + for_each_cpu(lcpu, cpu_online_mask) { + cpu = cpu_logical_map(lcpu); + + if (cpu > 0) { + tegra_enable_cpu_clock(cpu); + tegra_cpu_out_of_reset(cpu); + flowctrl_write_cpu_halt(cpu, 0); + } + } +} + +static int tegra_cpuidle_cc6_enter(unsigned int cpu) +{ + int ret; + + if (cpu > 0) { + ret = cpu_suspend(cpu, tegra_pm_park_secondary_cpu); + } else { + ret = tegra_cpuidle_wait_for_secondary_cpus_parking(); + if (!ret) + ret = tegra_pm_enter_lp2(); + + tegra_cpuidle_unpark_secondary_cpus(); + } + + return ret; +} + +static int tegra_cpuidle_c7_enter(void) +{ + int err; + + if (tegra_cpuidle_using_firmware()) { + err = call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2); + if (err) + return err; + + return call_firmware_op(do_idle, 0); + } + + return cpu_suspend(0, tegra30_pm_secondary_cpu_suspend); +} + +static int tegra_cpuidle_coupled_barrier(struct cpuidle_device *dev) +{ + if (tegra_pending_sgi()) { + /* + * CPU got local interrupt that will be lost after GIC's + * shutdown because GIC driver doesn't save/restore the + * pending SGI state across CPU cluster PM. Abort and retry + * next time. + */ + atomic_set(&tegra_abort_flag, 1); + } + + cpuidle_coupled_parallel_barrier(dev, &tegra_idle_barrier); + + if (atomic_read(&tegra_abort_flag)) { + cpuidle_coupled_parallel_barrier(dev, &tegra_idle_barrier); + atomic_set(&tegra_abort_flag, 0); + return -EINTR; + } + + return 0; +} + +static int tegra_cpuidle_state_enter(struct cpuidle_device *dev, + int index, unsigned int cpu) +{ + int ret; + + /* + * CC6 state is the "CPU cluster power-off" state. In order to + * enter this state, at first the secondary CPU cores need to be + * parked into offline mode, then the last CPU should clean out + * remaining dirty cache lines into DRAM and trigger Flow Controller + * logic that turns off the cluster's power domain (which includes + * CPU cores, GIC and L2 cache). + */ + if (index == TEGRA_CC6) { + ret = tegra_cpuidle_coupled_barrier(dev); + if (ret) + return ret; + } + + local_fiq_disable(); + tegra_pm_set_cpu_in_lp2(); + cpu_pm_enter(); + + switch (index) { + case TEGRA_C7: + ret = tegra_cpuidle_c7_enter(); + break; + + case TEGRA_CC6: + ret = tegra_cpuidle_cc6_enter(cpu); + break; + + default: + ret = -EINVAL; + break; + } + + cpu_pm_exit(); + tegra_pm_clear_cpu_in_lp2(); + local_fiq_enable(); + + return ret; +} + +static int tegra_cpuidle_adjust_state_index(int index, unsigned int cpu) +{ + /* + * On Tegra30 CPU0 can't be power-gated separately from secondary + * cores because it gates the whole CPU cluster. + */ + if (cpu > 0 || index != TEGRA_C7 || tegra_get_chip_id() != TEGRA30) + return index; + + /* put CPU0 into C1 if C7 is requested and secondaries are online */ + if (!IS_ENABLED(CONFIG_PM_SLEEP) || num_online_cpus() > 1) + index = TEGRA_C1; + else + index = TEGRA_CC6; + + return index; +} + +static int tegra_cpuidle_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + unsigned int cpu = cpu_logical_map(dev->cpu); + int err; + + index = tegra_cpuidle_adjust_state_index(index, cpu); + if (dev->states_usage[index].disable) + return -1; + + if (index == TEGRA_C1) + err = arm_cpuidle_simple_enter(dev, drv, index); + else + err = tegra_cpuidle_state_enter(dev, index, cpu); + + if (err && (err != -EINTR || index != TEGRA_CC6)) + pr_err_once("failed to enter state %d err: %d\n", index, err); + + return err ? -1 : index; +} + +static void tegra114_enter_s2idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + tegra_cpuidle_enter(dev, drv, index); +} + +/* + * The previous versions of Tegra CPUIDLE driver used a different "legacy" + * terminology for naming of the idling states, while this driver uses the + * new terminology. + * + * Mapping of the old terms into the new ones: + * + * Old | New + * --------- + * LP3 | C1 (CPU core clock gating) + * LP2 | C7 (CPU core power gating) + * LP2 | CC6 (CPU cluster power gating) + * + * Note that that the older CPUIDLE driver versions didn't explicitly + * differentiate the LP2 states because these states either used the same + * code path or because CC6 wasn't supported. + */ +static struct cpuidle_driver tegra_idle_driver = { + .name = "tegra_idle", + .states = { + [TEGRA_C1] = ARM_CPUIDLE_WFI_STATE_PWR(600), + [TEGRA_C7] = { + .enter = tegra_cpuidle_enter, + .exit_latency = 2000, + .target_residency = 2200, + .power_usage = 100, + .flags = CPUIDLE_FLAG_TIMER_STOP, + .name = "C7", + .desc = "CPU core powered off", + }, + [TEGRA_CC6] = { + .enter = tegra_cpuidle_enter, + .exit_latency = 5000, + .target_residency = 10000, + .power_usage = 0, + .flags = CPUIDLE_FLAG_TIMER_STOP | + CPUIDLE_FLAG_COUPLED, + .name = "CC6", + .desc = "CPU cluster powered off", + }, + }, + .state_count = TEGRA_STATE_COUNT, + .safe_state_index = TEGRA_C1, +}; + +static inline void tegra_cpuidle_disable_state(enum tegra_state state) +{ + cpuidle_driver_state_disabled(&tegra_idle_driver, state, true); +} + +/* + * Tegra20 HW appears to have a bug such that PCIe device interrupts, whether + * they are legacy IRQs or MSI, are lost when CC6 is enabled. To work around + * this, simply disable CC6 if the PCI driver and DT node are both enabled. + */ +void tegra_cpuidle_pcie_irqs_in_use(void) +{ + struct cpuidle_state *state_cc6 = &tegra_idle_driver.states[TEGRA_CC6]; + + if ((state_cc6->flags & CPUIDLE_FLAG_UNUSABLE) || + tegra_get_chip_id() != TEGRA20) + return; + + pr_info("disabling CC6 state, since PCIe IRQs are in use\n"); + tegra_cpuidle_disable_state(TEGRA_CC6); +} + +static void tegra_cpuidle_setup_tegra114_c7_state(void) +{ + struct cpuidle_state *s = &tegra_idle_driver.states[TEGRA_C7]; + + s->enter_s2idle = tegra114_enter_s2idle; + s->target_residency = 1000; + s->exit_latency = 500; +} + +static int tegra_cpuidle_probe(struct platform_device *pdev) +{ + /* LP2 could be disabled in device-tree */ + if (tegra_pmc_get_suspend_mode() < TEGRA_SUSPEND_LP2) + tegra_cpuidle_disable_state(TEGRA_CC6); + + /* + * Required suspend-resume functionality, which is provided by the + * Tegra-arch core and PMC driver, is unavailable if PM-sleep option + * is disabled. + */ + if (!IS_ENABLED(CONFIG_PM_SLEEP)) { + if (!tegra_cpuidle_using_firmware()) + tegra_cpuidle_disable_state(TEGRA_C7); + + tegra_cpuidle_disable_state(TEGRA_CC6); + } + + /* + * Generic WFI state (also known as C1 or LP3) and the coupled CPU + * cluster power-off (CC6 or LP2) states are common for all Tegra SoCs. + */ + switch (tegra_get_chip_id()) { + case TEGRA20: + /* Tegra20 isn't capable to power-off individual CPU cores */ + tegra_cpuidle_disable_state(TEGRA_C7); + break; + + case TEGRA30: + tegra_cpuidle_disable_state(TEGRA_CC6); + break; + + case TEGRA114: + case TEGRA124: + tegra_cpuidle_setup_tegra114_c7_state(); + + /* coupled CC6 (LP2) state isn't implemented yet */ + tegra_cpuidle_disable_state(TEGRA_CC6); + break; + + default: + return -EINVAL; + } + + return cpuidle_register(&tegra_idle_driver, cpu_possible_mask); +} + +static struct platform_driver tegra_cpuidle_driver = { + .probe = tegra_cpuidle_probe, + .driver = { + .name = "tegra-cpuidle", + }, +}; +builtin_platform_driver(tegra_cpuidle_driver); diff --git a/drivers/firmware/xilinx/Kconfig b/drivers/firmware/xilinx/Kconfig index bd33bbf70daf..9a9bd190888e 100644 --- a/drivers/firmware/xilinx/Kconfig +++ b/drivers/firmware/xilinx/Kconfig @@ -6,6 +6,8 @@ menu "Zynq MPSoC Firmware Drivers" config ZYNQMP_FIRMWARE bool "Enable Xilinx Zynq MPSoC firmware interface" + depends on ARCH_ZYNQMP + default y if ARCH_ZYNQMP select MFD_CORE help Firmware interface driver is used by different diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c index de20e6cba83b..db37144ae98c 100644 --- a/drivers/soc/mediatek/mtk-cmdq-helper.c +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c @@ -78,6 +78,7 @@ struct cmdq_client *cmdq_mbox_create(struct device *dev, int index, u32 timeout) client->pkt_cnt = 0; client->client.dev = dev; client->client.tx_block = false; + client->client.knows_txdone = true; client->chan = mbox_request_channel(&client->client, index); if (IS_ERR(client->chan)) { diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index c725315cf6a8..5d34e8b9c988 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -111,6 +111,28 @@ enum dew_regs { PWRAP_RG_SPI_CON13, PWRAP_SPISLV_KEY, + /* MT6359 only regs */ + PWRAP_DEW_CRC_SWRST, + PWRAP_DEW_RG_EN_RECORD, + PWRAP_DEW_RECORD_CMD0, + PWRAP_DEW_RECORD_CMD1, + PWRAP_DEW_RECORD_CMD2, + PWRAP_DEW_RECORD_CMD3, + PWRAP_DEW_RECORD_CMD4, + PWRAP_DEW_RECORD_CMD5, + PWRAP_DEW_RECORD_WDATA0, + PWRAP_DEW_RECORD_WDATA1, + PWRAP_DEW_RECORD_WDATA2, + PWRAP_DEW_RECORD_WDATA3, + PWRAP_DEW_RECORD_WDATA4, + PWRAP_DEW_RECORD_WDATA5, + PWRAP_DEW_RG_ADDR_TARGET, + PWRAP_DEW_RG_ADDR_MASK, + PWRAP_DEW_RG_WDATA_TARGET, + PWRAP_DEW_RG_WDATA_MASK, + PWRAP_DEW_RG_SPI_RECORD_CLR, + PWRAP_DEW_RG_CMD_ALERT_CLR, + /* MT6397 only regs */ PWRAP_DEW_EVENT_OUT_EN, PWRAP_DEW_EVENT_SRC_EN, @@ -197,6 +219,42 @@ static const u32 mt6358_regs[] = { [PWRAP_SPISLV_KEY] = 0x044a, }; +static const u32 mt6359_regs[] = { + [PWRAP_DEW_RG_EN_RECORD] = 0x040a, + [PWRAP_DEW_DIO_EN] = 0x040c, + [PWRAP_DEW_READ_TEST] = 0x040e, + [PWRAP_DEW_WRITE_TEST] = 0x0410, + [PWRAP_DEW_CRC_SWRST] = 0x0412, + [PWRAP_DEW_CRC_EN] = 0x0414, + [PWRAP_DEW_CRC_VAL] = 0x0416, + [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0418, + [PWRAP_DEW_CIPHER_IV_SEL] = 0x041a, + [PWRAP_DEW_CIPHER_EN] = 0x041c, + [PWRAP_DEW_CIPHER_RDY] = 0x041e, + [PWRAP_DEW_CIPHER_MODE] = 0x0420, + [PWRAP_DEW_CIPHER_SWRST] = 0x0422, + [PWRAP_DEW_RDDMY_NO] = 0x0424, + [PWRAP_DEW_RECORD_CMD0] = 0x0428, + [PWRAP_DEW_RECORD_CMD1] = 0x042a, + [PWRAP_DEW_RECORD_CMD2] = 0x042c, + [PWRAP_DEW_RECORD_CMD3] = 0x042e, + [PWRAP_DEW_RECORD_CMD4] = 0x0430, + [PWRAP_DEW_RECORD_CMD5] = 0x0432, + [PWRAP_DEW_RECORD_WDATA0] = 0x0434, + [PWRAP_DEW_RECORD_WDATA1] = 0x0436, + [PWRAP_DEW_RECORD_WDATA2] = 0x0438, + [PWRAP_DEW_RECORD_WDATA3] = 0x043a, + [PWRAP_DEW_RECORD_WDATA4] = 0x043c, + [PWRAP_DEW_RECORD_WDATA5] = 0x043e, + [PWRAP_DEW_RG_ADDR_TARGET] = 0x0440, + [PWRAP_DEW_RG_ADDR_MASK] = 0x0442, + [PWRAP_DEW_RG_WDATA_TARGET] = 0x0444, + [PWRAP_DEW_RG_WDATA_MASK] = 0x0446, + [PWRAP_DEW_RG_SPI_RECORD_CLR] = 0x0448, + [PWRAP_DEW_RG_CMD_ALERT_CLR] = 0x0448, + [PWRAP_SPISLV_KEY] = 0x044a, +}; + static const u32 mt6397_regs[] = { [PWRAP_DEW_BASE] = 0xbc00, [PWRAP_DEW_EVENT_OUT_EN] = 0xbc00, @@ -497,6 +555,45 @@ static int mt6765_regs[] = { [PWRAP_DCM_DBC_PRD] = 0x1E0, }; +static int mt6779_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_RDDMY] = 0x20, + [PWRAP_CSHEXT_WRITE] = 0x24, + [PWRAP_CSHEXT_READ] = 0x28, + [PWRAP_CSLEXT_WRITE] = 0x2C, + [PWRAP_CSLEXT_READ] = 0x30, + [PWRAP_EXT_CK_WRITE] = 0x34, + [PWRAP_STAUPD_CTRL] = 0x3C, + [PWRAP_STAUPD_GRPEN] = 0x40, + [PWRAP_EINT_STA0_ADR] = 0x44, + [PWRAP_HARB_HPRIO] = 0x68, + [PWRAP_HIPRIO_ARB_EN] = 0x6C, + [PWRAP_MAN_EN] = 0x7C, + [PWRAP_MAN_CMD] = 0x80, + [PWRAP_WACS0_EN] = 0x8C, + [PWRAP_INIT_DONE0] = 0x90, + [PWRAP_WACS1_EN] = 0x94, + [PWRAP_WACS2_EN] = 0x9C, + [PWRAP_INIT_DONE1] = 0x98, + [PWRAP_INIT_DONE2] = 0xA0, + [PWRAP_INT_EN] = 0xBC, + [PWRAP_INT_FLG_RAW] = 0xC0, + [PWRAP_INT_FLG] = 0xC4, + [PWRAP_INT_CLR] = 0xC8, + [PWRAP_INT1_EN] = 0xCC, + [PWRAP_INT1_FLG] = 0xD4, + [PWRAP_INT1_CLR] = 0xD8, + [PWRAP_TIMER_EN] = 0xF0, + [PWRAP_WDT_UNIT] = 0xF8, + [PWRAP_WDT_SRC_EN] = 0xFC, + [PWRAP_WDT_SRC_EN_1] = 0x100, + [PWRAP_WACS2_CMD] = 0xC20, + [PWRAP_WACS2_RDATA] = 0xC24, + [PWRAP_WACS2_VLDCLR] = 0xC28, +}; + static int mt6797_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, @@ -938,6 +1035,7 @@ enum pmic_type { PMIC_MT6351, PMIC_MT6357, PMIC_MT6358, + PMIC_MT6359, PMIC_MT6380, PMIC_MT6397, }; @@ -945,6 +1043,7 @@ enum pmic_type { enum pwrap_type { PWRAP_MT2701, PWRAP_MT6765, + PWRAP_MT6779, PWRAP_MT6797, PWRAP_MT7622, PWRAP_MT8135, @@ -1377,6 +1476,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) break; case PWRAP_MT2701: case PWRAP_MT6765: + case PWRAP_MT6779: case PWRAP_MT6797: case PWRAP_MT8173: case PWRAP_MT8516: @@ -1711,6 +1811,15 @@ static const struct pwrap_slv_type pmic_mt6358 = { .pwrap_write = pwrap_write16, }; +static const struct pwrap_slv_type pmic_mt6359 = { + .dew_regs = mt6359_regs, + .type = PMIC_MT6359, + .regmap = &pwrap_regmap_config16, + .caps = PWRAP_SLV_CAP_DUALIO, + .pwrap_read = pwrap_read16, + .pwrap_write = pwrap_write16, +}; + static const struct pwrap_slv_type pmic_mt6380 = { .dew_regs = NULL, .type = PMIC_MT6380, @@ -1744,6 +1853,9 @@ static const struct of_device_id of_slave_match_tbl[] = { .compatible = "mediatek,mt6358", .data = &pmic_mt6358, }, { + .compatible = "mediatek,mt6359", + .data = &pmic_mt6359, + }, { /* The MT6380 PMIC only implements a regulator, so we bind it * directly instead of using a MFD. */ @@ -1783,6 +1895,19 @@ static const struct pmic_wrapper_type pwrap_mt6765 = { .init_soc_specific = NULL, }; +static const struct pmic_wrapper_type pwrap_mt6779 = { + .regs = mt6779_regs, + .type = PWRAP_MT6779, + .arb_en_all = 0xfbb7f, + .int_en_all = 0xfffffffe, + .int1_en_all = 0, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = 0, + .init_reg_clock = pwrap_common_init_reg_clock, + .init_soc_specific = NULL, +}; + static const struct pmic_wrapper_type pwrap_mt6797 = { .regs = mt6797_regs, .type = PWRAP_MT6797, @@ -1868,6 +1993,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = { .compatible = "mediatek,mt6765-pwrap", .data = &pwrap_mt6765, }, { + .compatible = "mediatek,mt6779-pwrap", + .data = &pwrap_mt6779, + }, { .compatible = "mediatek,mt6797-pwrap", .data = &pwrap_mt6797, }, { diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index ba2b8b51d2d9..de5cfe3fddd3 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -116,6 +116,7 @@ config ARCH_R8A7779 bool "R-Car H1 (R8A77790)" select ARCH_RCAR_GEN1 select ARM_ERRATA_754322 + select ARM_GLOBAL_TIMER select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP select SYSC_R8A7779 @@ -163,6 +164,7 @@ config ARCH_SH73A0 bool "SH-Mobile AG5 (R8A73A00)" select ARCH_RMOBILE select ARM_ERRATA_754322 + select ARM_GLOBAL_TIMER select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP select RENESAS_INTC_IRQPIN diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 1699dda6b393..1c533a969f54 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -3,7 +3,7 @@ * drivers/soc/tegra/pmc.c * * Copyright (c) 2010 Google, Inc - * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved. * * Author: * Colin Cross <ccross@google.com> @@ -13,9 +13,13 @@ #include <linux/arm-smccc.h> #include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/clk-conf.h> #include <linux/clk/tegra.h> #include <linux/debugfs.h> #include <linux/delay.h> +#include <linux/device.h> #include <linux/err.h> #include <linux/export.h> #include <linux/init.h> @@ -48,6 +52,7 @@ #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h> #include <dt-bindings/gpio/tegra186-gpio.h> #include <dt-bindings/gpio/tegra194-gpio.h> +#include <dt-bindings/soc/tegra-pmc.h> #define PMC_CNTRL 0x0 #define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ @@ -57,12 +62,15 @@ #define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */ #define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */ #define PMC_CNTRL_PWRREQ_POLARITY BIT(8) +#define PMC_CNTRL_BLINK_EN 7 #define PMC_CNTRL_MAIN_RST BIT(4) #define PMC_WAKE_MASK 0x0c #define PMC_WAKE_LEVEL 0x10 #define PMC_WAKE_STATUS 0x14 #define PMC_SW_WAKE_STATUS 0x18 +#define PMC_DPD_PADS_ORIDE 0x1c +#define PMC_DPD_PADS_ORIDE_BLINK 20 #define DPD_SAMPLE 0x020 #define DPD_SAMPLE_ENABLE BIT(0) @@ -75,6 +83,7 @@ #define PWRGATE_STATUS 0x38 +#define PMC_BLINK_TIMER 0x40 #define PMC_IMPL_E_33V_PWR 0x40 #define PMC_PWR_DET 0x48 @@ -100,6 +109,8 @@ #define PMC_WAKE2_STATUS 0x168 #define PMC_SW_WAKE2_STATUS 0x16c +#define PMC_CLK_OUT_CNTRL 0x1a8 +#define PMC_CLK_OUT_MUX_MASK GENMASK(1, 0) #define PMC_SENSOR_CTRL 0x1b0 #define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2) #define PMC_SENSOR_CTRL_ENABLE_RST BIT(1) @@ -155,6 +166,71 @@ #define TEGRA_SMC_PMC_READ 0xaa #define TEGRA_SMC_PMC_WRITE 0xbb +struct pmc_clk { + struct clk_hw hw; + unsigned long offs; + u32 mux_shift; + u32 force_en_shift; +}; + +#define to_pmc_clk(_hw) container_of(_hw, struct pmc_clk, hw) + +struct pmc_clk_gate { + struct clk_hw hw; + unsigned long offs; + u32 shift; +}; + +#define to_pmc_clk_gate(_hw) container_of(_hw, struct pmc_clk_gate, hw) + +struct pmc_clk_init_data { + char *name; + const char *const *parents; + int num_parents; + int clk_id; + u8 mux_shift; + u8 force_en_shift; +}; + +static const char * const clk_out1_parents[] = { "osc", "osc_div2", + "osc_div4", "extern1", +}; + +static const char * const clk_out2_parents[] = { "osc", "osc_div2", + "osc_div4", "extern2", +}; + +static const char * const clk_out3_parents[] = { "osc", "osc_div2", + "osc_div4", "extern3", +}; + +static const struct pmc_clk_init_data tegra_pmc_clks_data[] = { + { + .name = "pmc_clk_out_1", + .parents = clk_out1_parents, + .num_parents = ARRAY_SIZE(clk_out1_parents), + .clk_id = TEGRA_PMC_CLK_OUT_1, + .mux_shift = 6, + .force_en_shift = 2, + }, + { + .name = "pmc_clk_out_2", + .parents = clk_out2_parents, + .num_parents = ARRAY_SIZE(clk_out2_parents), + .clk_id = TEGRA_PMC_CLK_OUT_2, + .mux_shift = 14, + .force_en_shift = 10, + }, + { + .name = "pmc_clk_out_3", + .parents = clk_out3_parents, + .num_parents = ARRAY_SIZE(clk_out3_parents), + .clk_id = TEGRA_PMC_CLK_OUT_3, + .mux_shift = 22, + .force_en_shift = 18, + }, +}; + struct tegra_powergate { struct generic_pm_domain genpd; struct tegra_pmc *pmc; @@ -254,6 +330,10 @@ struct tegra_pmc_soc { */ const struct tegra_wake_event *wake_events; unsigned int num_wake_events; + + const struct pmc_clk_init_data *pmc_clks_data; + unsigned int num_pmc_clks; + bool has_blink_output; }; static const char * const tegra186_reset_sources[] = { @@ -2163,6 +2243,258 @@ static int tegra_pmc_clk_notify_cb(struct notifier_block *nb, return NOTIFY_OK; } +static void pmc_clk_fence_udelay(u32 offset) +{ + tegra_pmc_readl(pmc, offset); + /* pmc clk propagation delay 2 us */ + udelay(2); +} + +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw) +{ + struct pmc_clk *clk = to_pmc_clk(hw); + u32 val; + + val = tegra_pmc_readl(pmc, clk->offs) >> clk->mux_shift; + val &= PMC_CLK_OUT_MUX_MASK; + + return val; +} + +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct pmc_clk *clk = to_pmc_clk(hw); + u32 val; + + val = tegra_pmc_readl(pmc, clk->offs); + val &= ~(PMC_CLK_OUT_MUX_MASK << clk->mux_shift); + val |= index << clk->mux_shift; + tegra_pmc_writel(pmc, val, clk->offs); + pmc_clk_fence_udelay(clk->offs); + + return 0; +} + +static int pmc_clk_is_enabled(struct clk_hw *hw) +{ + struct pmc_clk *clk = to_pmc_clk(hw); + u32 val; + + val = tegra_pmc_readl(pmc, clk->offs) & BIT(clk->force_en_shift); + + return val ? 1 : 0; +} + +static void pmc_clk_set_state(unsigned long offs, u32 shift, int state) +{ + u32 val; + + val = tegra_pmc_readl(pmc, offs); + val = state ? (val | BIT(shift)) : (val & ~BIT(shift)); + tegra_pmc_writel(pmc, val, offs); + pmc_clk_fence_udelay(offs); +} + +static int pmc_clk_enable(struct clk_hw *hw) +{ + struct pmc_clk *clk = to_pmc_clk(hw); + + pmc_clk_set_state(clk->offs, clk->force_en_shift, 1); + + return 0; +} + +static void pmc_clk_disable(struct clk_hw *hw) +{ + struct pmc_clk *clk = to_pmc_clk(hw); + + pmc_clk_set_state(clk->offs, clk->force_en_shift, 0); +} + +static const struct clk_ops pmc_clk_ops = { + .get_parent = pmc_clk_mux_get_parent, + .set_parent = pmc_clk_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, + .is_enabled = pmc_clk_is_enabled, + .enable = pmc_clk_enable, + .disable = pmc_clk_disable, +}; + +static struct clk * +tegra_pmc_clk_out_register(struct tegra_pmc *pmc, + const struct pmc_clk_init_data *data, + unsigned long offset) +{ + struct clk_init_data init; + struct pmc_clk *pmc_clk; + + pmc_clk = devm_kzalloc(pmc->dev, sizeof(*pmc_clk), GFP_KERNEL); + if (!pmc_clk) + return ERR_PTR(-ENOMEM); + + init.name = data->name; + init.ops = &pmc_clk_ops; + init.parent_names = data->parents; + init.num_parents = data->num_parents; + init.flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT | + CLK_SET_PARENT_GATE; + + pmc_clk->hw.init = &init; + pmc_clk->offs = offset; + pmc_clk->mux_shift = data->mux_shift; + pmc_clk->force_en_shift = data->force_en_shift; + + return clk_register(NULL, &pmc_clk->hw); +} + +static int pmc_clk_gate_is_enabled(struct clk_hw *hw) +{ + struct pmc_clk_gate *gate = to_pmc_clk_gate(hw); + + return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1 : 0; +} + +static int pmc_clk_gate_enable(struct clk_hw *hw) +{ + struct pmc_clk_gate *gate = to_pmc_clk_gate(hw); + + pmc_clk_set_state(gate->offs, gate->shift, 1); + + return 0; +} + +static void pmc_clk_gate_disable(struct clk_hw *hw) +{ + struct pmc_clk_gate *gate = to_pmc_clk_gate(hw); + + pmc_clk_set_state(gate->offs, gate->shift, 0); +} + +static const struct clk_ops pmc_clk_gate_ops = { + .is_enabled = pmc_clk_gate_is_enabled, + .enable = pmc_clk_gate_enable, + .disable = pmc_clk_gate_disable, +}; + +static struct clk * +tegra_pmc_clk_gate_register(struct tegra_pmc *pmc, const char *name, + const char *parent_name, unsigned long offset, + u32 shift) +{ + struct clk_init_data init; + struct pmc_clk_gate *gate; + + gate = devm_kzalloc(pmc->dev, sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &pmc_clk_gate_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = 0; + + gate->hw.init = &init; + gate->offs = offset; + gate->shift = shift; + + return clk_register(NULL, &gate->hw); +} + +static void tegra_pmc_clock_register(struct tegra_pmc *pmc, + struct device_node *np) +{ + struct clk *clk; + struct clk_onecell_data *clk_data; + unsigned int num_clks; + int i, err; + + num_clks = pmc->soc->num_pmc_clks; + if (pmc->soc->has_blink_output) + num_clks += 1; + + if (!num_clks) + return; + + clk_data = devm_kmalloc(pmc->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return; + + clk_data->clks = devm_kcalloc(pmc->dev, TEGRA_PMC_CLK_MAX, + sizeof(*clk_data->clks), GFP_KERNEL); + if (!clk_data->clks) + return; + + clk_data->clk_num = TEGRA_PMC_CLK_MAX; + + for (i = 0; i < TEGRA_PMC_CLK_MAX; i++) + clk_data->clks[i] = ERR_PTR(-ENOENT); + + for (i = 0; i < pmc->soc->num_pmc_clks; i++) { + const struct pmc_clk_init_data *data; + + data = pmc->soc->pmc_clks_data + i; + + clk = tegra_pmc_clk_out_register(pmc, data, PMC_CLK_OUT_CNTRL); + if (IS_ERR(clk)) { + dev_warn(pmc->dev, "unable to register clock %s: %d\n", + data->name, PTR_ERR_OR_ZERO(clk)); + return; + } + + err = clk_register_clkdev(clk, data->name, NULL); + if (err) { + dev_warn(pmc->dev, + "unable to register %s clock lookup: %d\n", + data->name, err); + return; + } + + clk_data->clks[data->clk_id] = clk; + } + + if (pmc->soc->has_blink_output) { + tegra_pmc_writel(pmc, 0x0, PMC_BLINK_TIMER); + clk = tegra_pmc_clk_gate_register(pmc, + "pmc_blink_override", + "clk_32k", + PMC_DPD_PADS_ORIDE, + PMC_DPD_PADS_ORIDE_BLINK); + if (IS_ERR(clk)) { + dev_warn(pmc->dev, + "unable to register pmc_blink_override: %d\n", + PTR_ERR_OR_ZERO(clk)); + return; + } + + clk = tegra_pmc_clk_gate_register(pmc, "pmc_blink", + "pmc_blink_override", + PMC_CNTRL, + PMC_CNTRL_BLINK_EN); + if (IS_ERR(clk)) { + dev_warn(pmc->dev, + "unable to register pmc_blink: %d\n", + PTR_ERR_OR_ZERO(clk)); + return; + } + + err = clk_register_clkdev(clk, "pmc_blink", NULL); + if (err) { + dev_warn(pmc->dev, + "unable to register pmc_blink lookup: %d\n", + err); + return; + } + + clk_data->clks[TEGRA_PMC_CLK_BLINK] = clk; + } + + err = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); + if (err) + dev_warn(pmc->dev, "failed to add pmc clock provider: %d\n", + err); +} + static int tegra_pmc_probe(struct platform_device *pdev) { void __iomem *base; @@ -2281,6 +2613,7 @@ static int tegra_pmc_probe(struct platform_device *pdev) pmc->base = base; mutex_unlock(&pmc->powergates_lock); + tegra_pmc_clock_register(pmc, pdev->dev.of_node); platform_set_drvdata(pdev, pmc); return 0; @@ -2422,6 +2755,9 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { .num_reset_sources = 0, .reset_levels = NULL, .num_reset_levels = 0, + .pmc_clks_data = NULL, + .num_pmc_clks = 0, + .has_blink_output = true, }; static const char * const tegra30_powergates[] = { @@ -2469,6 +2805,9 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, .num_reset_levels = 0, + .pmc_clks_data = tegra_pmc_clks_data, + .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), + .has_blink_output = true, }; static const char * const tegra114_powergates[] = { @@ -2520,6 +2859,9 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, .num_reset_levels = 0, + .pmc_clks_data = tegra_pmc_clks_data, + .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), + .has_blink_output = true, }; static const char * const tegra124_powergates[] = { @@ -2569,38 +2911,38 @@ static const u8 tegra124_cpu_powergates[] = { .name = (_name) \ }) -#define TEGRA124_IO_PAD_TABLE(_pad) \ - /* .id .dpd .voltage .name */ \ - _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ - _pad(TEGRA_IO_PAD_BB, 15, UINT_MAX, "bb"), \ - _pad(TEGRA_IO_PAD_CAM, 36, UINT_MAX, "cam"), \ - _pad(TEGRA_IO_PAD_COMP, 22, UINT_MAX, "comp"), \ - _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ - _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csb"), \ - _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "cse"), \ - _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ - _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \ - _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \ - _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \ - _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \ - _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ - _pad(TEGRA_IO_PAD_HV, 38, UINT_MAX, "hv"), \ - _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \ - _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ - _pad(TEGRA_IO_PAD_NAND, 13, UINT_MAX, "nand"), \ - _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \ - _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \ - _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ - _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ - _pad(TEGRA_IO_PAD_SDMMC1, 33, UINT_MAX, "sdmmc1"), \ - _pad(TEGRA_IO_PAD_SDMMC3, 34, UINT_MAX, "sdmmc3"), \ - _pad(TEGRA_IO_PAD_SDMMC4, 35, UINT_MAX, "sdmmc4"), \ - _pad(TEGRA_IO_PAD_SYS_DDC, 58, UINT_MAX, "sys_ddc"), \ - _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ - _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ - _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ - _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ - _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb_bias") +#define TEGRA124_IO_PAD_TABLE(_pad) \ + /* .id .dpd .voltage .name */ \ + _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ + _pad(TEGRA_IO_PAD_BB, 15, UINT_MAX, "bb"), \ + _pad(TEGRA_IO_PAD_CAM, 36, UINT_MAX, "cam"), \ + _pad(TEGRA_IO_PAD_COMP, 22, UINT_MAX, "comp"), \ + _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ + _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csb"), \ + _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "cse"), \ + _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ + _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \ + _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \ + _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \ + _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \ + _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ + _pad(TEGRA_IO_PAD_HV, 38, UINT_MAX, "hv"), \ + _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \ + _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ + _pad(TEGRA_IO_PAD_NAND, 13, UINT_MAX, "nand"), \ + _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \ + _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \ + _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ + _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ + _pad(TEGRA_IO_PAD_SDMMC1, 33, UINT_MAX, "sdmmc1"), \ + _pad(TEGRA_IO_PAD_SDMMC3, 34, UINT_MAX, "sdmmc3"), \ + _pad(TEGRA_IO_PAD_SDMMC4, 35, UINT_MAX, "sdmmc4"), \ + _pad(TEGRA_IO_PAD_SYS_DDC, 58, UINT_MAX, "sys_ddc"), \ + _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ + _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ + _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ + _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ + _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb_bias") static const struct tegra_io_pad_soc tegra124_io_pads[] = { TEGRA124_IO_PAD_TABLE(TEGRA_IO_PAD) @@ -2631,6 +2973,9 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, .num_reset_levels = 0, + .pmc_clks_data = tegra_pmc_clks_data, + .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), + .has_blink_output = true, }; static const char * const tegra210_powergates[] = { @@ -2667,46 +3012,46 @@ static const u8 tegra210_cpu_powergates[] = { TEGRA_POWERGATE_CPU3, }; -#define TEGRA210_IO_PAD_TABLE(_pad) \ - /* .id .dpd .voltage .name */ \ - _pad(TEGRA_IO_PAD_AUDIO, 17, 5, "audio"), \ - _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 18, "audio-hv"), \ - _pad(TEGRA_IO_PAD_CAM, 36, 10, "cam"), \ - _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ - _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ - _pad(TEGRA_IO_PAD_CSIC, 42, UINT_MAX, "csic"), \ - _pad(TEGRA_IO_PAD_CSID, 43, UINT_MAX, "csid"), \ - _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "csie"), \ - _pad(TEGRA_IO_PAD_CSIF, 45, UINT_MAX, "csif"), \ - _pad(TEGRA_IO_PAD_DBG, 25, 19, "dbg"), \ - _pad(TEGRA_IO_PAD_DEBUG_NONAO, 26, UINT_MAX, "debug-nonao"), \ - _pad(TEGRA_IO_PAD_DMIC, 50, 20, "dmic"), \ - _pad(TEGRA_IO_PAD_DP, 51, UINT_MAX, "dp"), \ - _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ - _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \ - _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \ - _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \ - _pad(TEGRA_IO_PAD_EMMC, 35, UINT_MAX, "emmc"), \ - _pad(TEGRA_IO_PAD_EMMC2, 37, UINT_MAX, "emmc2"), \ - _pad(TEGRA_IO_PAD_GPIO, 27, 21, "gpio"), \ - _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \ - _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ - _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \ - _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ - _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \ - _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \ - _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ - _pad(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, 11, "pex-cntrl"), \ - _pad(TEGRA_IO_PAD_SDMMC1, 33, 12, "sdmmc1"), \ - _pad(TEGRA_IO_PAD_SDMMC3, 34, 13, "sdmmc3"), \ - _pad(TEGRA_IO_PAD_SPI, 46, 22, "spi"), \ - _pad(TEGRA_IO_PAD_SPI_HV, 47, 23, "spi-hv"), \ - _pad(TEGRA_IO_PAD_UART, 14, 2, "uart"), \ - _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ - _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ - _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ - _pad(TEGRA_IO_PAD_USB3, 18, UINT_MAX, "usb3"), \ - _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias") +#define TEGRA210_IO_PAD_TABLE(_pad) \ + /* .id .dpd .voltage .name */ \ + _pad(TEGRA_IO_PAD_AUDIO, 17, 5, "audio"), \ + _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 18, "audio-hv"), \ + _pad(TEGRA_IO_PAD_CAM, 36, 10, "cam"), \ + _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ + _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ + _pad(TEGRA_IO_PAD_CSIC, 42, UINT_MAX, "csic"), \ + _pad(TEGRA_IO_PAD_CSID, 43, UINT_MAX, "csid"), \ + _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "csie"), \ + _pad(TEGRA_IO_PAD_CSIF, 45, UINT_MAX, "csif"), \ + _pad(TEGRA_IO_PAD_DBG, 25, 19, "dbg"), \ + _pad(TEGRA_IO_PAD_DEBUG_NONAO, 26, UINT_MAX, "debug-nonao"), \ + _pad(TEGRA_IO_PAD_DMIC, 50, 20, "dmic"), \ + _pad(TEGRA_IO_PAD_DP, 51, UINT_MAX, "dp"), \ + _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ + _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \ + _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \ + _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \ + _pad(TEGRA_IO_PAD_EMMC, 35, UINT_MAX, "emmc"), \ + _pad(TEGRA_IO_PAD_EMMC2, 37, UINT_MAX, "emmc2"), \ + _pad(TEGRA_IO_PAD_GPIO, 27, 21, "gpio"), \ + _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \ + _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ + _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \ + _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ + _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \ + _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \ + _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ + _pad(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, 11, "pex-cntrl"), \ + _pad(TEGRA_IO_PAD_SDMMC1, 33, 12, "sdmmc1"), \ + _pad(TEGRA_IO_PAD_SDMMC3, 34, 13, "sdmmc3"), \ + _pad(TEGRA_IO_PAD_SPI, 46, 22, "spi"), \ + _pad(TEGRA_IO_PAD_SPI_HV, 47, 23, "spi-hv"), \ + _pad(TEGRA_IO_PAD_UART, 14, 2, "uart"), \ + _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ + _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ + _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ + _pad(TEGRA_IO_PAD_USB3, 18, UINT_MAX, "usb3"), \ + _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias") static const struct tegra_io_pad_soc tegra210_io_pads[] = { TEGRA210_IO_PAD_TABLE(TEGRA_IO_PAD) @@ -2745,48 +3090,51 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .num_reset_levels = 0, .num_wake_events = ARRAY_SIZE(tegra210_wake_events), .wake_events = tegra210_wake_events, + .pmc_clks_data = tegra_pmc_clks_data, + .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), + .has_blink_output = true, }; -#define TEGRA186_IO_PAD_TABLE(_pad) \ - /* .id .dpd .voltage .name */ \ - _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ - _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ - _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ - _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ - _pad(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, UINT_MAX, "pex-clk-bias"), \ - _pad(TEGRA_IO_PAD_PEX_CLK3, 5, UINT_MAX, "pex-clk3"), \ - _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ - _pad(TEGRA_IO_PAD_PEX_CLK1, 7, UINT_MAX, "pex-clk1"), \ - _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ - _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ - _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ - _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias"), \ - _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ - _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ - _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ - _pad(TEGRA_IO_PAD_DBG, 25, UINT_MAX, "dbg"), \ - _pad(TEGRA_IO_PAD_HDMI_DP0, 28, UINT_MAX, "hdmi-dp0"), \ - _pad(TEGRA_IO_PAD_HDMI_DP1, 29, UINT_MAX, "hdmi-dp1"), \ - _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ - _pad(TEGRA_IO_PAD_SDMMC2_HV, 34, 5, "sdmmc2-hv"), \ - _pad(TEGRA_IO_PAD_SDMMC4, 36, UINT_MAX, "sdmmc4"), \ - _pad(TEGRA_IO_PAD_CAM, 38, UINT_MAX, "cam"), \ - _pad(TEGRA_IO_PAD_DSIB, 40, UINT_MAX, "dsib"), \ - _pad(TEGRA_IO_PAD_DSIC, 41, UINT_MAX, "dsic"), \ - _pad(TEGRA_IO_PAD_DSID, 42, UINT_MAX, "dsid"), \ - _pad(TEGRA_IO_PAD_CSIC, 43, UINT_MAX, "csic"), \ - _pad(TEGRA_IO_PAD_CSID, 44, UINT_MAX, "csid"), \ - _pad(TEGRA_IO_PAD_CSIE, 45, UINT_MAX, "csie"), \ - _pad(TEGRA_IO_PAD_CSIF, 46, UINT_MAX, "csif"), \ - _pad(TEGRA_IO_PAD_SPI, 47, UINT_MAX, "spi"), \ - _pad(TEGRA_IO_PAD_UFS, 49, UINT_MAX, "ufs"), \ - _pad(TEGRA_IO_PAD_DMIC_HV, 52, 2, "dmic-hv"), \ - _pad(TEGRA_IO_PAD_EDP, 53, UINT_MAX, "edp"), \ - _pad(TEGRA_IO_PAD_SDMMC1_HV, 55, 4, "sdmmc1-hv"), \ - _pad(TEGRA_IO_PAD_SDMMC3_HV, 56, 6, "sdmmc3-hv"), \ - _pad(TEGRA_IO_PAD_CONN, 60, UINT_MAX, "conn"), \ - _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 1, "audio-hv"), \ - _pad(TEGRA_IO_PAD_AO_HV, UINT_MAX, 0, "ao-hv") +#define TEGRA186_IO_PAD_TABLE(_pad) \ + /* .id .dpd .voltage .name */ \ + _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ + _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ + _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \ + _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ + _pad(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, UINT_MAX, "pex-clk-bias"), \ + _pad(TEGRA_IO_PAD_PEX_CLK3, 5, UINT_MAX, "pex-clk3"), \ + _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ + _pad(TEGRA_IO_PAD_PEX_CLK1, 7, UINT_MAX, "pex-clk1"), \ + _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \ + _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \ + _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \ + _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias"), \ + _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ + _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ + _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \ + _pad(TEGRA_IO_PAD_DBG, 25, UINT_MAX, "dbg"), \ + _pad(TEGRA_IO_PAD_HDMI_DP0, 28, UINT_MAX, "hdmi-dp0"), \ + _pad(TEGRA_IO_PAD_HDMI_DP1, 29, UINT_MAX, "hdmi-dp1"), \ + _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ + _pad(TEGRA_IO_PAD_SDMMC2_HV, 34, 5, "sdmmc2-hv"), \ + _pad(TEGRA_IO_PAD_SDMMC4, 36, UINT_MAX, "sdmmc4"), \ + _pad(TEGRA_IO_PAD_CAM, 38, UINT_MAX, "cam"), \ + _pad(TEGRA_IO_PAD_DSIB, 40, UINT_MAX, "dsib"), \ + _pad(TEGRA_IO_PAD_DSIC, 41, UINT_MAX, "dsic"), \ + _pad(TEGRA_IO_PAD_DSID, 42, UINT_MAX, "dsid"), \ + _pad(TEGRA_IO_PAD_CSIC, 43, UINT_MAX, "csic"), \ + _pad(TEGRA_IO_PAD_CSID, 44, UINT_MAX, "csid"), \ + _pad(TEGRA_IO_PAD_CSIE, 45, UINT_MAX, "csie"), \ + _pad(TEGRA_IO_PAD_CSIF, 46, UINT_MAX, "csif"), \ + _pad(TEGRA_IO_PAD_SPI, 47, UINT_MAX, "spi"), \ + _pad(TEGRA_IO_PAD_UFS, 49, UINT_MAX, "ufs"), \ + _pad(TEGRA_IO_PAD_DMIC_HV, 52, 2, "dmic-hv"), \ + _pad(TEGRA_IO_PAD_EDP, 53, UINT_MAX, "edp"), \ + _pad(TEGRA_IO_PAD_SDMMC1_HV, 55, 4, "sdmmc1-hv"), \ + _pad(TEGRA_IO_PAD_SDMMC3_HV, 56, 6, "sdmmc3-hv"), \ + _pad(TEGRA_IO_PAD_CONN, 60, UINT_MAX, "conn"), \ + _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 1, "audio-hv"), \ + _pad(TEGRA_IO_PAD_AO_HV, UINT_MAX, 0, "ao-hv") static const struct tegra_io_pad_soc tegra186_io_pads[] = { TEGRA186_IO_PAD_TABLE(TEGRA_IO_PAD) @@ -2874,56 +3222,69 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), .num_wake_events = ARRAY_SIZE(tegra186_wake_events), .wake_events = tegra186_wake_events, + .pmc_clks_data = NULL, + .num_pmc_clks = 0, + .has_blink_output = false, }; +#define TEGRA194_IO_PAD_TABLE(_pad) \ + /* .id .dpd .voltage .name */ \ + _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \ + _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \ + _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \ + _pad(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, UINT_MAX, "pex-clk-bias"), \ + _pad(TEGRA_IO_PAD_PEX_CLK3, 5, UINT_MAX, "pex-clk3"), \ + _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \ + _pad(TEGRA_IO_PAD_PEX_CLK1, 7, UINT_MAX, "pex-clk1"), \ + _pad(TEGRA_IO_PAD_EQOS, 8, UINT_MAX, "eqos"), \ + _pad(TEGRA_IO_PAD_PEX_CLK_2_BIAS, 9, UINT_MAX, "pex-clk-2-bias"), \ + _pad(TEGRA_IO_PAD_PEX_CLK_2, 10, UINT_MAX, "pex-clk-2"), \ + _pad(TEGRA_IO_PAD_DAP3, 11, UINT_MAX, "dap3"), \ + _pad(TEGRA_IO_PAD_DAP5, 12, UINT_MAX, "dap5"), \ + _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \ + _pad(TEGRA_IO_PAD_PWR_CTL, 15, UINT_MAX, "pwr-ctl"), \ + _pad(TEGRA_IO_PAD_SOC_GPIO53, 16, UINT_MAX, "soc-gpio53"), \ + _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ + _pad(TEGRA_IO_PAD_GP_PWM2, 18, UINT_MAX, "gp-pwm2"), \ + _pad(TEGRA_IO_PAD_GP_PWM3, 19, UINT_MAX, "gp-pwm3"), \ + _pad(TEGRA_IO_PAD_SOC_GPIO12, 20, UINT_MAX, "soc-gpio12"), \ + _pad(TEGRA_IO_PAD_SOC_GPIO13, 21, UINT_MAX, "soc-gpio13"), \ + _pad(TEGRA_IO_PAD_SOC_GPIO10, 22, UINT_MAX, "soc-gpio10"), \ + _pad(TEGRA_IO_PAD_UART4, 23, UINT_MAX, "uart4"), \ + _pad(TEGRA_IO_PAD_UART5, 24, UINT_MAX, "uart5"), \ + _pad(TEGRA_IO_PAD_DBG, 25, UINT_MAX, "dbg"), \ + _pad(TEGRA_IO_PAD_HDMI_DP3, 26, UINT_MAX, "hdmi-dp3"), \ + _pad(TEGRA_IO_PAD_HDMI_DP2, 27, UINT_MAX, "hdmi-dp2"), \ + _pad(TEGRA_IO_PAD_HDMI_DP0, 28, UINT_MAX, "hdmi-dp0"), \ + _pad(TEGRA_IO_PAD_HDMI_DP1, 29, UINT_MAX, "hdmi-dp1"), \ + _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \ + _pad(TEGRA_IO_PAD_PEX_CTL2, 33, UINT_MAX, "pex-ctl2"), \ + _pad(TEGRA_IO_PAD_PEX_L0_RST_N, 34, UINT_MAX, "pex-l0-rst"), \ + _pad(TEGRA_IO_PAD_PEX_L1_RST_N, 35, UINT_MAX, "pex-l1-rst"), \ + _pad(TEGRA_IO_PAD_SDMMC4, 36, UINT_MAX, "sdmmc4"), \ + _pad(TEGRA_IO_PAD_PEX_L5_RST_N, 37, UINT_MAX, "pex-l5-rst"), \ + _pad(TEGRA_IO_PAD_CAM, 38, UINT_MAX, "cam"), \ + _pad(TEGRA_IO_PAD_CSIC, 43, UINT_MAX, "csic"), \ + _pad(TEGRA_IO_PAD_CSID, 44, UINT_MAX, "csid"), \ + _pad(TEGRA_IO_PAD_CSIE, 45, UINT_MAX, "csie"), \ + _pad(TEGRA_IO_PAD_CSIF, 46, UINT_MAX, "csif"), \ + _pad(TEGRA_IO_PAD_SPI, 47, UINT_MAX, "spi"), \ + _pad(TEGRA_IO_PAD_UFS, 49, UINT_MAX, "ufs"), \ + _pad(TEGRA_IO_PAD_CSIG, 50, UINT_MAX, "csig"), \ + _pad(TEGRA_IO_PAD_CSIH, 51, UINT_MAX, "csih"), \ + _pad(TEGRA_IO_PAD_EDP, 53, UINT_MAX, "edp"), \ + _pad(TEGRA_IO_PAD_SDMMC1_HV, 55, 4, "sdmmc1-hv"), \ + _pad(TEGRA_IO_PAD_SDMMC3_HV, 56, 6, "sdmmc3-hv"), \ + _pad(TEGRA_IO_PAD_CONN, 60, UINT_MAX, "conn"), \ + _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 1, "audio-hv"), \ + _pad(TEGRA_IO_PAD_AO_HV, UINT_MAX, 0, "ao-hv") + static const struct tegra_io_pad_soc tegra194_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_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_EQOS, .dpd = 8, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_PEX_CLK2_BIAS, .dpd = 9, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 10, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_DAP3, .dpd = 11, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_DAP5, .dpd = 12, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_PWR_CTL, .dpd = 15, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_SOC_GPIO53, .dpd = 16, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_GP_PWM2, .dpd = 18, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_GP_PWM3, .dpd = 19, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_SOC_GPIO12, .dpd = 20, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_SOC_GPIO13, .dpd = 21, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_SOC_GPIO10, .dpd = 22, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_UART4, .dpd = 23, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_UART5, .dpd = 24, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_HDMI_DP3, .dpd = 26, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_HDMI_DP2, .dpd = 27, .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_PEX_CTL2, .dpd = 33, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_PEX_L0_RST_N, .dpd = 34, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_PEX_L1_RST_N, .dpd = 35, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_SDMMC4, .dpd = 36, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_PEX_L5_RST_N, .dpd = 37, .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_CSIG, .dpd = 50, .voltage = UINT_MAX }, - { .id = TEGRA_IO_PAD_CSIH, .dpd = 51, .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 }, + TEGRA194_IO_PAD_TABLE(TEGRA_IO_PAD) +}; + +static const struct pinctrl_pin_desc tegra194_pin_descs[] = { + TEGRA194_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) }; static const struct tegra_pmc_regs tegra194_pmc_regs = { @@ -2976,10 +3337,12 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = { .has_tsense_reset = false, .has_gpu_clamps = false, .needs_mbist_war = false, - .has_impl_33v_pwr = false, + .has_impl_33v_pwr = true, .maybe_tz_only = false, .num_io_pads = ARRAY_SIZE(tegra194_io_pads), .io_pads = tegra194_io_pads, + .num_pin_descs = ARRAY_SIZE(tegra194_pin_descs), + .pin_descs = tegra194_pin_descs, .regs = &tegra194_pmc_regs, .init = NULL, .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, @@ -2991,6 +3354,9 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = { .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), .num_wake_events = ARRAY_SIZE(tegra194_wake_events), .wake_events = tegra194_wake_events, + .pmc_clks_data = NULL, + .num_pmc_clks = 0, + .has_blink_output = false, }; static const struct of_device_id tegra_pmc_match[] = { diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index ccc6d53fe788..de0123ec8ad6 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -130,6 +130,19 @@ static int am33xx_push_sram_idle(void) return 0; } +static int am33xx_do_sram_idle(u32 wfi_flags) +{ + int ret = 0; + + if (!m3_ipc || !pm_ops) + return 0; + + if (wfi_flags & WFI_FLAG_WAKE_M3) + ret = m3_ipc->ops->prepare_low_power(m3_ipc, WKUP_M3_IDLE); + + return pm_ops->cpu_suspend(am33xx_do_wfi_sram, wfi_flags); +} + static int __init am43xx_map_gic(void) { gic_dist_base = ioremap(AM43XX_GIC_DIST_BASE, SZ_4K); @@ -260,6 +273,8 @@ static int am33xx_pm_begin(suspend_state_t state) rtc_only_idle = 0; } + pm_ops->begin_suspend(); + switch (state) { case PM_SUSPEND_MEM: ret = m3_ipc->ops->prepare_low_power(m3_ipc, WKUP_M3_DEEPSLEEP); @@ -301,6 +316,8 @@ static void am33xx_pm_end(void) } rtc_only_idle = 0; + + pm_ops->finish_suspend(); } static int am33xx_pm_valid(suspend_state_t state) @@ -503,7 +520,7 @@ static int am33xx_pm_probe(struct platform_device *pdev) suspend_wfi_flags |= WFI_FLAG_WAKE_M3; #endif /* CONFIG_SUSPEND */ - ret = pm_ops->init(); + ret = pm_ops->init(am33xx_do_sram_idle); if (ret) { dev_err(dev, "Unable to call core pm init!\n"); ret = -ENODEV; @@ -522,6 +539,8 @@ err_free_sram: static int am33xx_pm_remove(struct platform_device *pdev) { + if (pm_ops->deinit) + pm_ops->deinit(); suspend_set_ops(NULL); wkup_m3_ipc_put(m3_ipc); am33xx_pm_free_sram(); |