From 1711b1e10224dbebc885b7bf7ca2f03f51ff9f4a Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 23 Oct 2012 11:52:53 -0600 Subject: [PATCH 01/31] ARM: tegra: move timer.c to drivers/clocksource/ Move arch/arm/mach-tegra/timer.c to drivers/clocksource/tegra20_timer.c so that the code is co-located with other clocksource drivers, and to reduce the size of the mach-tegra directory. Signed-off-by: Stephen Warren --- arch/arm/Kconfig | 1 + arch/arm/mach-tegra/Makefile | 1 - arch/arm/mach-tegra/board-dt-tegra20.c | 3 ++- arch/arm/mach-tegra/board-dt-tegra30.c | 3 ++- arch/arm/mach-tegra/board.h | 1 - drivers/clocksource/Makefile | 1 + .../timer.c => drivers/clocksource/tegra20_timer.c | 7 ++----- 7 files changed, 8 insertions(+), 9 deletions(-) rename arch/arm/mach-tegra/timer.c => drivers/clocksource/tegra20_timer.c (98%) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 67874b82a4ed..eb9fc2f8acf1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -642,6 +642,7 @@ config ARCH_TEGRA select ARCH_HAS_CPUFREQ select CLKDEV_LOOKUP select CLKSRC_MMIO + select CLKSRC_OF select COMMON_CLK select GENERIC_CLOCKEVENTS select GENERIC_GPIO diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 0979e8bba78a..bd5d3120cb4b 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -2,7 +2,6 @@ obj-y += common.o obj-y += io.o obj-y += irq.o obj-y += clock.o -obj-y += timer.o obj-y += fuse.o obj-y += pmc.o obj-y += flowctrl.o diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index 3b9956aabf5a..8e35aaea5845 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -15,6 +15,7 @@ * */ +#include #include #include #include @@ -203,7 +204,7 @@ DT_MACHINE_START(TEGRA_DT, "nVidia Tegra20 (Flattened Device Tree)") .init_early = tegra20_init_early, .init_irq = tegra_dt_init_irq, .handle_irq = gic_handle_irq, - .init_time = tegra_init_timer, + .init_time = clocksource_of_init, .init_machine = tegra_dt_init, .init_late = tegra_dt_init_late, .restart = tegra_assert_system_reset, diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index 381b2f25f0b4..a9ed15dcc3ed 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -23,6 +23,7 @@ * */ +#include #include #include #include @@ -113,7 +114,7 @@ DT_MACHINE_START(TEGRA30_DT, "NVIDIA Tegra30 (Flattened Device Tree)") .init_early = tegra30_init_early, .init_irq = tegra_dt_init_irq, .handle_irq = gic_handle_irq, - .init_time = tegra_init_timer, + .init_time = clocksource_of_init, .init_machine = tegra30_dt_init, .init_late = tegra_init_late, .restart = tegra_assert_system_reset, diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h index 744cdd246f6a..da8f5a3c4240 100644 --- a/arch/arm/mach-tegra/board.h +++ b/arch/arm/mach-tegra/board.h @@ -55,5 +55,4 @@ static inline int harmony_pcie_init(void) { return 0; } void __init tegra_paz00_wifikill_init(void); -extern void tegra_init_timer(void); #endif diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index a33f79240217..b5cc50796a80 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -17,5 +17,6 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o +obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o diff --git a/arch/arm/mach-tegra/timer.c b/drivers/clocksource/tegra20_timer.c similarity index 98% rename from arch/arm/mach-tegra/timer.c rename to drivers/clocksource/tegra20_timer.c index b0036e519a15..3b2f94781df4 100644 --- a/arch/arm/mach-tegra/timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -1,6 +1,4 @@ /* - * arch/arch/mach-tegra/timer.c - * * Copyright (C) 2010 Google, Inc. * * Author: @@ -33,8 +31,6 @@ #include #include -#include "board.h" - #define RTC_SECONDS 0x08 #define RTC_SHADOW_SECONDS 0x0c #define RTC_MILLISECONDS 0x10 @@ -168,7 +164,7 @@ static const struct of_device_id rtc_match[] __initconst = { {} }; -void __init tegra_init_timer(void) +static void __init tegra20_init_timer(void) { struct device_node *np; struct clk *clk; @@ -272,6 +268,7 @@ void __init tegra_init_timer(void) #endif register_persistent_clock(NULL, tegra_read_persistent_clock); } +CLOCKSOURCE_OF_DECLARE(tegra20, "nvidia,tegra20-timer", tegra20_init_timer); #ifdef CONFIG_PM static u32 usec_config; From 37340866fb659f955489bd0742788135156a4d3c Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Mon, 17 Dec 2012 13:35:23 +0200 Subject: [PATCH 02/31] clocksource: tegra: cosmetic: Fix error message Add missing \n. Signed-off-by: Hiroshi Doyu Signed-off-by: Stephen Warren --- drivers/clocksource/tegra20_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 3b2f94781df4..5bc14299de3c 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -179,7 +179,7 @@ static void __init tegra20_init_timer(void) timer_reg_base = of_iomap(np, 0); if (!timer_reg_base) { - pr_err("Can't map timer registers"); + pr_err("Can't map timer registers\n"); BUG(); } From deeb8d194814c98be379a284e07d938c6af066f4 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Thu, 3 Jan 2013 08:27:05 +0200 Subject: [PATCH 03/31] ARM: tegra: Make variables static No need to be public. Checked with: $ touch arch/arm/mach-tegra/*[ch] && make C=1 Signed-off-by: Hiroshi Doyu Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/apbio.c | 2 +- arch/arm/mach-tegra/board-dt-tegra20.c | 10 +++++----- arch/arm/mach-tegra/board-dt-tegra30.c | 2 +- arch/arm/mach-tegra/flowctrl.c | 4 ++-- arch/arm/mach-tegra/tegra30_clocks_data.c | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c index d091675ba376..d7aa52ea6cfc 100644 --- a/arch/arm/mach-tegra/apbio.c +++ b/arch/arm/mach-tegra/apbio.c @@ -38,7 +38,7 @@ static void tegra_apb_writel_direct(u32 value, unsigned long offset); static struct dma_chan *tegra_apb_dma_chan; static struct dma_slave_config dma_sconfig; -bool tegra_apb_dma_init(void) +static bool tegra_apb_dma_init(void) { dma_cap_mask_t mask; diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index 8e35aaea5845..e1f87dd314ef 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -46,31 +46,31 @@ #include "common.h" #include "iomap.h" -struct tegra_ehci_platform_data tegra_ehci1_pdata = { +static struct tegra_ehci_platform_data tegra_ehci1_pdata = { .operating_mode = TEGRA_USB_OTG, .power_down_on_bus_suspend = 1, .vbus_gpio = -1, }; -struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = { +static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = { .reset_gpio = -1, .clk = "cdev2", }; -struct tegra_ehci_platform_data tegra_ehci2_pdata = { +static struct tegra_ehci_platform_data tegra_ehci2_pdata = { .phy_config = &tegra_ehci2_ulpi_phy_config, .operating_mode = TEGRA_USB_HOST, .power_down_on_bus_suspend = 1, .vbus_gpio = -1, }; -struct tegra_ehci_platform_data tegra_ehci3_pdata = { +static struct tegra_ehci_platform_data tegra_ehci3_pdata = { .operating_mode = TEGRA_USB_HOST, .power_down_on_bus_suspend = 1, .vbus_gpio = -1, }; -struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { +static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL), OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC2_BASE, "sdhci-tegra.1", NULL), OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC3_BASE, "sdhci-tegra.2", NULL), diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index a9ed15dcc3ed..cfe5fc02be77 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -39,7 +39,7 @@ #include "common.h" #include "iomap.h" -struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { +static struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000000, "sdhci-tegra.0", NULL), OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000200, "sdhci-tegra.1", NULL), OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000400, "sdhci-tegra.2", NULL), diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c index a2250ddae797..5393eb2cae21 100644 --- a/arch/arm/mach-tegra/flowctrl.c +++ b/arch/arm/mach-tegra/flowctrl.c @@ -26,14 +26,14 @@ #include "flowctrl.h" #include "iomap.h" -u8 flowctrl_offset_halt_cpu[] = { +static u8 flowctrl_offset_halt_cpu[] = { FLOW_CTRL_HALT_CPU0_EVENTS, FLOW_CTRL_HALT_CPU1_EVENTS, FLOW_CTRL_HALT_CPU1_EVENTS + 8, FLOW_CTRL_HALT_CPU1_EVENTS + 16, }; -u8 flowctrl_offset_cpu_csr[] = { +static u8 flowctrl_offset_cpu_csr[] = { FLOW_CTRL_CPU0_CSR, FLOW_CTRL_CPU1_CSR, FLOW_CTRL_CPU1_CSR + 8, diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c index 6942c7add3bb..741d264d5ecb 100644 --- a/arch/arm/mach-tegra/tegra30_clocks_data.c +++ b/arch/arm/mach-tegra/tegra30_clocks_data.c @@ -1183,7 +1183,7 @@ static struct clk tegra_dsib = { .num_parents = ARRAY_SIZE(mux_plld_out0_plld2_out0), }; -struct clk *tegra_list_clks[] = { +static struct clk *tegra_list_clks[] = { &tegra_apbdma, &tegra_rtc, &tegra_kbc, @@ -1289,7 +1289,7 @@ struct clk *tegra_list_clks[] = { * configuration. List those here to register them twice in the clock lookup * table under two names. */ -struct clk_duplicate tegra_clk_duplicates[] = { +static struct clk_duplicate tegra_clk_duplicates[] = { CLK_DUPLICATE("uarta", "serial8250.0", NULL), CLK_DUPLICATE("uartb", "serial8250.1", NULL), CLK_DUPLICATE("uartc", "serial8250.2", NULL), @@ -1340,7 +1340,7 @@ struct clk_duplicate tegra_clk_duplicates[] = { CLK_DUPLICATE("pll_d2_out0", "hdmi", "parent"), }; -struct clk *tegra_ptr_clks[] = { +static struct clk *tegra_ptr_clks[] = { &tegra_clk_32k, &tegra_clk_m, &tegra_clk_m_div2, From 45c9e5929624e3a169e3d4c0e6568a4e570272a2 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 2 Jan 2013 14:34:15 -0700 Subject: [PATCH 04/31] ARM: tegra: fix Kconfig warnings when !SMP Fix: warning: (ARCH_TEGRA_2x_SOC) selects ARM_ERRATA_754327 which has unmet direct dependencies (CPU_V7 && SMP) warning: (ARCH_TEGRA_2x_SOC) selects ARM_ERRATA_742230 which has unmet direct dependencies (CPU_V7 && SMP) by selecting options only if SMP. Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index b442f15fd01a..1ec7f80e2af5 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -6,9 +6,9 @@ config ARCH_TEGRA_2x_SOC bool "Enable support for Tegra20 family" select ARCH_REQUIRE_GPIOLIB select ARM_ERRATA_720789 - select ARM_ERRATA_742230 + select ARM_ERRATA_742230 if SMP select ARM_ERRATA_751472 - select ARM_ERRATA_754327 + select ARM_ERRATA_754327 if SMP select ARM_ERRATA_764369 if SMP select ARM_GIC select CPU_FREQ_TABLE if CPU_FREQ From c26cefd08990e3a393cc1592efc3f097f608015f Mon Sep 17 00:00:00 2001 From: Richard Zhao Date: Fri, 21 Dec 2012 00:09:55 +0000 Subject: [PATCH 05/31] ARM: tegra: cpufreq: move clk_get/put out of function tegra_cpu_init/exit tegra_cpu_init/exit will be called every time one cpu core is online or offline. And all cpu cores share same clocks, redundant clk_get/put wast time, so I move them out. Signed-off-by: Richard Zhao Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/cpu-tegra.c | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c index a74d3c7d2e26..85d4a23bba03 100644 --- a/arch/arm/mach-tegra/cpu-tegra.c +++ b/arch/arm/mach-tegra/cpu-tegra.c @@ -214,24 +214,6 @@ static int tegra_cpu_init(struct cpufreq_policy *policy) if (policy->cpu >= NUM_CPUS) return -EINVAL; - cpu_clk = clk_get_sys(NULL, "cpu"); - if (IS_ERR(cpu_clk)) - return PTR_ERR(cpu_clk); - - pll_x_clk = clk_get_sys(NULL, "pll_x"); - if (IS_ERR(pll_x_clk)) - return PTR_ERR(pll_x_clk); - - pll_p_clk = clk_get_sys(NULL, "pll_p"); - if (IS_ERR(pll_p_clk)) - return PTR_ERR(pll_p_clk); - - emc_clk = clk_get_sys("cpu", "emc"); - if (IS_ERR(emc_clk)) { - clk_put(cpu_clk); - return PTR_ERR(emc_clk); - } - clk_prepare_enable(emc_clk); clk_prepare_enable(cpu_clk); @@ -256,8 +238,6 @@ static int tegra_cpu_exit(struct cpufreq_policy *policy) { cpufreq_frequency_table_cpuinfo(policy, freq_table); clk_disable_unprepare(emc_clk); - clk_put(emc_clk); - clk_put(cpu_clk); return 0; } @@ -278,12 +258,32 @@ static struct cpufreq_driver tegra_cpufreq_driver = { static int __init tegra_cpufreq_init(void) { + cpu_clk = clk_get_sys(NULL, "cpu"); + if (IS_ERR(cpu_clk)) + return PTR_ERR(cpu_clk); + + pll_x_clk = clk_get_sys(NULL, "pll_x"); + if (IS_ERR(pll_x_clk)) + return PTR_ERR(pll_x_clk); + + pll_p_clk = clk_get_sys(NULL, "pll_p"); + if (IS_ERR(pll_p_clk)) + return PTR_ERR(pll_p_clk); + + emc_clk = clk_get_sys("cpu", "emc"); + if (IS_ERR(emc_clk)) { + clk_put(cpu_clk); + return PTR_ERR(emc_clk); + } + return cpufreq_register_driver(&tegra_cpufreq_driver); } static void __exit tegra_cpufreq_exit(void) { cpufreq_unregister_driver(&tegra_cpufreq_driver); + clk_put(emc_clk); + clk_put(cpu_clk); } From 130bfed72c75a36c76ecc82d73818c6fccd2a468 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Thu, 3 Jan 2013 15:31:31 +0800 Subject: [PATCH 06/31] ARM: tegra30: fix power up sequence for boot_secondary The power up sequence is different on the cold boot CPU and the CPU that resumed from the hotplug. For the cold boot CPU, it was been power gated as default. To power up the cold boot CPU, the power should be un-gated by un toggling the power gate register manually. For the CPU that resumed from the hotplug, after un-halted the CPU. The flow controller will un-gate the power of the CPU. No need to manually control, just wait the power be resumed and continue the power up sequence after the CPU power is ready. Based on the work by: Varun Wadekar Signed-off-by: Joseph Lo Acked-by: Peter De Schrijver Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/platsmp.c | 39 ++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 1b926df99c4b..40f8c37c8178 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -36,6 +37,7 @@ extern void tegra_secondary_startup(void); +static cpumask_t tegra_cpu_init_mask; static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); #define EVP_CPU_RESET_VECTOR \ @@ -50,6 +52,7 @@ static void __cpuinit tegra_secondary_init(unsigned int cpu) */ gic_secondary_init(0); + cpumask_set_cpu(cpu, &tegra_cpu_init_mask); } static int tegra20_power_up_cpu(unsigned int cpu) @@ -72,7 +75,35 @@ static int tegra30_power_up_cpu(unsigned int cpu) if (pwrgateid < 0) return pwrgateid; - /* If this is the first boot, toggle powergates directly. */ + /* + * The power up sequence of cold boot CPU and warm boot CPU + * was different. + * + * For warm boot CPU that was resumed from CPU hotplug, the + * power will be resumed automatically after un-halting the + * flow controller of the warm boot CPU. We need to wait for + * the confirmaiton that the CPU is powered then removing + * the IO clamps. + * For cold boot CPU, do not wait. After the cold boot CPU be + * booted, it will run to tegra_secondary_init() and set + * tegra_cpu_init_mask which influences what tegra30_power_up_cpu() + * next time around. + */ + if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) { + timeout = jiffies + 5*HZ; + do { + if (!tegra_powergate_is_powered(pwrgateid)) + goto remove_clamps; + udelay(10); + } while (time_before(jiffies, timeout)); + } + + /* + * The power status of the cold boot CPU is power gated as + * default. To power up the cold boot CPU, the power should + * be un-gated by un-toggling the power gate register + * manually. + */ if (!tegra_powergate_is_powered(pwrgateid)) { ret = tegra_powergate_power_on(pwrgateid); if (ret) @@ -87,6 +118,7 @@ static int tegra30_power_up_cpu(unsigned int cpu) } } +remove_clamps: /* CPU partition is powered. Enable the CPU clock. */ tegra_enable_cpu_clock(cpu); udelay(10); @@ -105,6 +137,8 @@ static int __cpuinit tegra_boot_secondary(unsigned int cpu, struct task_struct * { int status; + cpu = cpu_logical_map(cpu); + /* * Force the CPU into reset. The CPU must remain in reset when the * flow controller state is cleared (which will cause the flow @@ -165,6 +199,9 @@ static void __init tegra_smp_init_cpus(void) static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) { + /* Always mark the boot CPU (CPU0) as initialized. */ + cpumask_set_cpu(0, &tegra_cpu_init_mask); + tegra_cpu_reset_handler_init(); scu_enable(scu_base); } From 57886616ca7bff844a6427436d0c8faf74653f73 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Thu, 3 Jan 2013 14:42:59 +0800 Subject: [PATCH 07/31] ARM: tegra: update the cache maintenance order for CPU shutdown Updating the cache maintenance order before CPU shutdown when doing CPU hotplug. The old order: * clean L1 by flush_cache_all * exit SMP * CPU shutdown Adapt to: * disable L1 data cache by clear C bit * clean L1 by v7_flush_dcache_louis * exit SMP * CPU shutdown For CPU hotplug case, it's no need to do "flush_cache_all". And we should disable L1 data cache before clean L1 data cache. Then leaving the SMP coherency. Signed-off-by: Joseph Lo Acked-by: Peter De Schrijver Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/hotplug.c | 4 ++-- arch/arm/mach-tegra/sleep-tegra20.S | 3 --- arch/arm/mach-tegra/sleep-tegra30.S | 3 --- arch/arm/mach-tegra/sleep.S | 4 +++- arch/arm/mach-tegra/sleep.h | 1 + 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index dca5141a2c31..d8c683b875d1 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -28,8 +28,8 @@ void __ref tegra_cpu_die(unsigned int cpu) { cpu = cpu_logical_map(cpu); - /* Flush the L1 data cache. */ - flush_cache_all(); + /* Clean L1 data cache */ + tegra_disable_clean_inv_dcache(); /* Shut down the current CPU. */ tegra_hotplug_shutdown(); diff --git a/arch/arm/mach-tegra/sleep-tegra20.S b/arch/arm/mach-tegra/sleep-tegra20.S index 72ce709799da..ad2ca07d0578 100644 --- a/arch/arm/mach-tegra/sleep-tegra20.S +++ b/arch/arm/mach-tegra/sleep-tegra20.S @@ -33,9 +33,6 @@ * should never return */ ENTRY(tegra20_hotplug_shutdown) - /* Turn off SMP coherency */ - exit_smp r4, r5 - /* Put this CPU down */ cpu_id r0 bl tegra20_cpu_shutdown diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S index 562a8e7e413d..63a15bd9b653 100644 --- a/arch/arm/mach-tegra/sleep-tegra30.S +++ b/arch/arm/mach-tegra/sleep-tegra30.S @@ -32,9 +32,6 @@ * Should never return. */ ENTRY(tegra30_hotplug_shutdown) - /* Turn off SMP coherency */ - exit_smp r4, r5 - /* Powergate this CPU */ mov r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN bl tegra30_cpu_shutdown diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S index 26afa7cbed11..addae357da3f 100644 --- a/arch/arm/mach-tegra/sleep.S +++ b/arch/arm/mach-tegra/sleep.S @@ -34,7 +34,7 @@ #include "flowctrl.h" #include "sleep.h" -#ifdef CONFIG_PM_SLEEP +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP) /* * tegra_disable_clean_inv_dcache * @@ -60,7 +60,9 @@ ENTRY(tegra_disable_clean_inv_dcache) ldmfd sp!, {r0, r4-r5, r7, r9-r11, pc} ENDPROC(tegra_disable_clean_inv_dcache) +#endif +#ifdef CONFIG_PM_SLEEP /* * tegra_sleep_cpu_finish(unsigned long v2p) * diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h index 9821ee725420..56505c381ea8 100644 --- a/arch/arm/mach-tegra/sleep.h +++ b/arch/arm/mach-tegra/sleep.h @@ -106,6 +106,7 @@ #else void tegra_resume(void); int tegra_sleep_cpu_finish(unsigned long); +void tegra_disable_clean_inv_dcache(void); #ifdef CONFIG_HOTPLUG_CPU void tegra20_hotplug_init(void); From b811943160cf3b040341c50d23440cf6d68ae079 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Thu, 3 Jan 2013 14:43:00 +0800 Subject: [PATCH 08/31] ARM: tegra: moving the clock gating procedure to tegra_cpu_kill The tegra_cpu_die was be executed by the CPU itslf. So the clock gating procedure won't be executed after the CPU hardware shutdown code. Moving the clock gating procedure to tegra_cpu_kill that will be run by another CPU after the CPU died. Signed-off-by: Joseph Lo Acked-by: Peter De Schrijver Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/common.h | 1 + arch/arm/mach-tegra/hotplug.c | 17 +++++++++++------ arch/arm/mach-tegra/platsmp.c | 1 + 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-tegra/common.h b/arch/arm/mach-tegra/common.h index 02f71b4f1e51..32f8eb3fe344 100644 --- a/arch/arm/mach-tegra/common.h +++ b/arch/arm/mach-tegra/common.h @@ -1,4 +1,5 @@ extern struct smp_operations tegra_smp_ops; +extern int tegra_cpu_kill(unsigned int cpu); extern void tegra_cpu_die(unsigned int cpu); extern int tegra_cpu_disable(unsigned int cpu); diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index d8c683b875d1..6a27de4001ee 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -19,6 +19,17 @@ static void (*tegra_hotplug_shutdown)(void); +int tegra_cpu_kill(unsigned cpu) +{ + cpu = cpu_logical_map(cpu); + + /* Clock gate the CPU */ + tegra_wait_cpu_in_reset(cpu); + tegra_disable_cpu_clock(cpu); + + return 1; +} + /* * platform-specific code to shutdown a CPU * @@ -26,18 +37,12 @@ static void (*tegra_hotplug_shutdown)(void); */ void __ref tegra_cpu_die(unsigned int cpu) { - cpu = cpu_logical_map(cpu); - /* Clean L1 data cache */ tegra_disable_clean_inv_dcache(); /* Shut down the current CPU. */ tegra_hotplug_shutdown(); - /* Clock gate the CPU */ - tegra_wait_cpu_in_reset(cpu); - tegra_disable_cpu_clock(cpu); - /* Should never return here. */ BUG(); } diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 40f8c37c8178..5882da0f4d8a 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -212,6 +212,7 @@ struct smp_operations tegra_smp_ops __initdata = { .smp_secondary_init = tegra_secondary_init, .smp_boot_secondary = tegra_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU + .cpu_kill = tegra_cpu_kill, .cpu_die = tegra_cpu_die, .cpu_disable = tegra_cpu_disable, #endif From 8c627fa6583a4894189a47a0bf868f7848b51748 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Fri, 4 Jan 2013 17:32:21 +0800 Subject: [PATCH 09/31] ARM: tegra: clean up the CPUINIT section There are some redundant codes in the CPUINIT section that was caused by some codes not be organized well in "headsmp.S". Currently all the codes in "headsmp.S" were put into CPUINIT section. But actually it doesn't need to be loacted in CPUINIT section. There is no fuction access them in CPUINIT section and we will relocate them to IRAM. These codes also caused some unnecessary functions that access these codes been put into CPUINIT section too. This patch clean it up and put them into normal text section. Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/cpuidle-tegra30.c | 6 +++--- arch/arm/mach-tegra/headsmp.S | 2 -- arch/arm/mach-tegra/pm.c | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index 5e8cbf5b799f..82530bd9b8c2 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -121,9 +121,9 @@ static inline bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, } #endif -static int __cpuinit tegra30_idle_lp2(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) +static int tegra30_idle_lp2(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) { u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu; bool entered_lp2 = false; diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S index 4a317fae6860..23f487da7a57 100644 --- a/arch/arm/mach-tegra/headsmp.S +++ b/arch/arm/mach-tegra/headsmp.S @@ -16,8 +16,6 @@ #define RESET_DATA(x) ((TEGRA_RESET_##x)*4) .section ".text.head", "ax" - __CPUINIT - /* * Tegra specific entry point for secondary CPUs. * The secondary kernel init calls v7_flush_dcache_all before it enables diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 1b11707eaca0..498d70b33775 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -148,7 +148,7 @@ static void suspend_cpu_complex(void) save_cpu_arch_register(); } -void __cpuinit tegra_clear_cpu_in_lp2(int phy_cpu_id) +void tegra_clear_cpu_in_lp2(int phy_cpu_id) { u32 *cpu_in_lp2 = tegra_cpu_lp2_mask; @@ -160,7 +160,7 @@ void __cpuinit tegra_clear_cpu_in_lp2(int phy_cpu_id) spin_unlock(&tegra_lp2_lock); } -bool __cpuinit tegra_set_cpu_in_lp2(int phy_cpu_id) +bool tegra_set_cpu_in_lp2(int phy_cpu_id) { bool last_cpu = false; cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask; From 9e32366fe51fea464adb21c244f372d55207e13c Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Fri, 4 Jan 2013 17:32:22 +0800 Subject: [PATCH 10/31] ARM: tegra: make device can run on UP The reset handler code is used for either UP or SMP. To make Tegra device can compile for UP. It needs to be moved to another file that is not SMP only. This is because the reset handler also be needed by CPU idle "powered-down" mode. So we also need to put the reset handler init function in non-SMP only and init them always. And currently the implementation of the reset handler to know which CPU is OK to bring up was identital with "cpu_present_mask". But the "cpu_present_mask" did not initialize yet when the reset handler init function was moved to init early function. We use the "cpu_possible_mask" to replace "cpu_present_mask". Then it can work on both UP and SMP case. Signed-off-by: Joseph Lo [swarren: dropped the move of v7_invalidate_l1() from one file to another, to avoid conflicts with Pavel's cleanup of this function, adjust Makefile so each line only contains 1 file.] Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/Makefile | 3 +- arch/arm/mach-tegra/common.c | 3 + arch/arm/mach-tegra/headsmp.S | 221 +------------------------ arch/arm/mach-tegra/platsmp.c | 1 - arch/arm/mach-tegra/reset-handler.S | 239 ++++++++++++++++++++++++++++ arch/arm/mach-tegra/reset.c | 2 +- 6 files changed, 246 insertions(+), 223 deletions(-) create mode 100644 arch/arm/mach-tegra/reset-handler.S diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index bd5d3120cb4b..a839bb3d9703 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -8,6 +8,8 @@ obj-y += flowctrl.o obj-y += powergate.o obj-y += apbio.o obj-y += pm.o +obj-y += reset.o +obj-y += reset-handler.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_CPU_IDLE) += sleep.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o @@ -26,7 +28,6 @@ ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o endif obj-$(CONFIG_SMP) += platsmp.o headsmp.o -obj-$(CONFIG_SMP) += reset.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o obj-$(CONFIG_TEGRA_PCI) += pcie.o diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index d54cfc54b9fe..3efe80b2af28 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -37,6 +37,7 @@ #include "apbio.h" #include "sleep.h" #include "pm.h" +#include "reset.h" /* * Storage for debug-macro.S's state. @@ -137,6 +138,7 @@ static void __init tegra_init_cache(void) #ifdef CONFIG_ARCH_TEGRA_2x_SOC void __init tegra20_init_early(void) { + tegra_cpu_reset_handler_init(); tegra_apb_io_init(); tegra_init_fuse(); tegra2_init_clocks(); @@ -150,6 +152,7 @@ void __init tegra20_init_early(void) #ifdef CONFIG_ARCH_TEGRA_3x_SOC void __init tegra30_init_early(void) { + tegra_cpu_reset_handler_init(); tegra_apb_io_init(); tegra_init_fuse(); tegra30_init_clocks(); diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S index 23f487da7a57..b2834810b02b 100644 --- a/arch/arm/mach-tegra/headsmp.S +++ b/arch/arm/mach-tegra/headsmp.S @@ -1,21 +1,10 @@ #include #include -#include -#include -#include - -#include "flowctrl.h" -#include "iomap.h" -#include "reset.h" #include "sleep.h" -#define APB_MISC_GP_HIDREV 0x804 -#define PMC_SCRATCH41 0x140 - -#define RESET_DATA(x) ((TEGRA_RESET_##x)*4) - .section ".text.head", "ax" + /* * Tegra specific entry point for secondary CPUs. * The secondary kernel init calls v7_flush_dcache_all before it enables @@ -59,7 +48,6 @@ ENTRY(v7_invalidate_l1) mov pc, lr ENDPROC(v7_invalidate_l1) - ENTRY(tegra_secondary_startup) bl v7_invalidate_l1 /* Enable coresight */ @@ -67,210 +55,3 @@ ENTRY(tegra_secondary_startup) mcr p14, 0, r0, c7, c12, 6 b secondary_startup ENDPROC(tegra_secondary_startup) - -#ifdef CONFIG_PM_SLEEP -/* - * tegra_resume - * - * CPU boot vector when restarting the a CPU following - * an LP2 transition. Also branched to by LP0 and LP1 resume after - * re-enabling sdram. - */ -ENTRY(tegra_resume) - bl v7_invalidate_l1 - /* Enable coresight */ - mov32 r0, 0xC5ACCE55 - mcr p14, 0, r0, c7, c12, 6 - - cpu_id r0 - cmp r0, #0 @ CPU0? - bne cpu_resume @ no - -#ifdef CONFIG_ARCH_TEGRA_3x_SOC - /* Are we on Tegra20? */ - mov32 r6, TEGRA_APB_MISC_BASE - ldr r0, [r6, #APB_MISC_GP_HIDREV] - and r0, r0, #0xff00 - cmp r0, #(0x20 << 8) - beq 1f @ Yes - /* Clear the flow controller flags for this CPU. */ - mov32 r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR @ CPU0 CSR - ldr r1, [r2] - /* Clear event & intr flag */ - orr r1, r1, \ - #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG - movw r0, #0x0FFD @ enable, cluster_switch, immed, & bitmaps - bic r1, r1, r0 - str r1, [r2] -1: -#endif - -#ifdef CONFIG_HAVE_ARM_SCU - /* enable SCU */ - mov32 r0, TEGRA_ARM_PERIF_BASE - ldr r1, [r0] - orr r1, r1, #1 - str r1, [r0] -#endif - - /* L2 cache resume & re-enable */ - l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr - - b cpu_resume -ENDPROC(tegra_resume) -#endif - -#ifdef CONFIG_CACHE_L2X0 - .globl l2x0_saved_regs_addr -l2x0_saved_regs_addr: - .long 0 -#endif - - .align L1_CACHE_SHIFT -ENTRY(__tegra_cpu_reset_handler_start) - -/* - * __tegra_cpu_reset_handler: - * - * Common handler for all CPU reset events. - * - * Register usage within the reset handler: - * - * R7 = CPU present (to the OS) mask - * R8 = CPU in LP1 state mask - * R9 = CPU in LP2 state mask - * R10 = CPU number - * R11 = CPU mask - * R12 = pointer to reset handler data - * - * NOTE: This code is copied to IRAM. All code and data accesses - * must be position-independent. - */ - - .align L1_CACHE_SHIFT -ENTRY(__tegra_cpu_reset_handler) - - cpsid aif, 0x13 @ SVC mode, interrupts disabled - mrc p15, 0, r10, c0, c0, 5 @ MPIDR - and r10, r10, #0x3 @ R10 = CPU number - mov r11, #1 - mov r11, r11, lsl r10 @ R11 = CPU mask - adr r12, __tegra_cpu_reset_handler_data - -#ifdef CONFIG_SMP - /* Does the OS know about this CPU? */ - ldr r7, [r12, #RESET_DATA(MASK_PRESENT)] - tst r7, r11 @ if !present - bleq __die @ CPU not present (to OS) -#endif - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - /* Are we on Tegra20? */ - mov32 r6, TEGRA_APB_MISC_BASE - ldr r0, [r6, #APB_MISC_GP_HIDREV] - and r0, r0, #0xff00 - cmp r0, #(0x20 << 8) - bne 1f - /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */ - mov32 r6, TEGRA_PMC_BASE - mov r0, #0 - cmp r10, #0 - strne r0, [r6, #PMC_SCRATCH41] -1: -#endif - - /* Waking up from LP2? */ - ldr r9, [r12, #RESET_DATA(MASK_LP2)] - tst r9, r11 @ if in_lp2 - beq __is_not_lp2 - ldr lr, [r12, #RESET_DATA(STARTUP_LP2)] - cmp lr, #0 - bleq __die @ no LP2 startup handler - bx lr - -__is_not_lp2: - -#ifdef CONFIG_SMP - /* - * Can only be secondary boot (initial or hotplug) but CPU 0 - * cannot be here. - */ - cmp r10, #0 - bleq __die @ CPU0 cannot be here - ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)] - cmp lr, #0 - bleq __die @ no secondary startup handler - bx lr -#endif - -/* - * We don't know why the CPU reset. Just kill it. - * The LR register will contain the address we died at + 4. - */ - -__die: - sub lr, lr, #4 - mov32 r7, TEGRA_PMC_BASE - str lr, [r7, #PMC_SCRATCH41] - - mov32 r7, TEGRA_CLK_RESET_BASE - - /* Are we on Tegra20? */ - mov32 r6, TEGRA_APB_MISC_BASE - ldr r0, [r6, #APB_MISC_GP_HIDREV] - and r0, r0, #0xff00 - cmp r0, #(0x20 << 8) - bne 1f - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - mov32 r0, 0x1111 - mov r1, r0, lsl r10 - str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET -#endif -1: -#ifdef CONFIG_ARCH_TEGRA_3x_SOC - mov32 r6, TEGRA_FLOW_CTRL_BASE - - cmp r10, #0 - moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS - moveq r2, #FLOW_CTRL_CPU0_CSR - movne r1, r10, lsl #3 - addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8) - addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8) - - /* Clear CPU "event" and "interrupt" flags and power gate - it when halting but not before it is in the "WFI" state. */ - ldr r0, [r6, +r2] - orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG - orr r0, r0, #FLOW_CTRL_CSR_ENABLE - str r0, [r6, +r2] - - /* Unconditionally halt this CPU */ - mov r0, #FLOW_CTRL_WAITEVENT - str r0, [r6, +r1] - ldr r0, [r6, +r1] @ memory barrier - - dsb - isb - wfi @ CPU should be power gated here - - /* If the CPU didn't power gate above just kill it's clock. */ - - mov r0, r11, lsl #8 - str r0, [r7, #348] @ CLK_CPU_CMPLX_SET -#endif - - /* If the CPU still isn't dead, just spin here. */ - b . -ENDPROC(__tegra_cpu_reset_handler) - - .align L1_CACHE_SHIFT - .type __tegra_cpu_reset_handler_data, %object - .globl __tegra_cpu_reset_handler_data -__tegra_cpu_reset_handler_data: - .rept TEGRA_RESET_DATA_SIZE - .long 0 - .endr - .align L1_CACHE_SHIFT - -ENTRY(__tegra_cpu_reset_handler_end) diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 5882da0f4d8a..60daf9f945cb 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -202,7 +202,6 @@ static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) /* Always mark the boot CPU (CPU0) as initialized. */ cpumask_set_cpu(0, &tegra_cpu_init_mask); - tegra_cpu_reset_handler_init(); scu_enable(scu_base); } diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S new file mode 100644 index 000000000000..54382ceade4a --- /dev/null +++ b/arch/arm/mach-tegra/reset-handler.S @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include +#include + +#include "flowctrl.h" +#include "iomap.h" +#include "reset.h" +#include "sleep.h" + +#define APB_MISC_GP_HIDREV 0x804 +#define PMC_SCRATCH41 0x140 + +#define RESET_DATA(x) ((TEGRA_RESET_##x)*4) + +#ifdef CONFIG_PM_SLEEP +/* + * tegra_resume + * + * CPU boot vector when restarting the a CPU following + * an LP2 transition. Also branched to by LP0 and LP1 resume after + * re-enabling sdram. + */ +ENTRY(tegra_resume) + bl v7_invalidate_l1 + /* Enable coresight */ + mov32 r0, 0xC5ACCE55 + mcr p14, 0, r0, c7, c12, 6 + + cpu_id r0 + cmp r0, #0 @ CPU0? + bne cpu_resume @ no + +#ifdef CONFIG_ARCH_TEGRA_3x_SOC + /* Are we on Tegra20? */ + mov32 r6, TEGRA_APB_MISC_BASE + ldr r0, [r6, #APB_MISC_GP_HIDREV] + and r0, r0, #0xff00 + cmp r0, #(0x20 << 8) + beq 1f @ Yes + /* Clear the flow controller flags for this CPU. */ + mov32 r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR @ CPU0 CSR + ldr r1, [r2] + /* Clear event & intr flag */ + orr r1, r1, \ + #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG + movw r0, #0x0FFD @ enable, cluster_switch, immed, & bitmaps + bic r1, r1, r0 + str r1, [r2] +1: +#endif + +#ifdef CONFIG_HAVE_ARM_SCU + /* enable SCU */ + mov32 r0, TEGRA_ARM_PERIF_BASE + ldr r1, [r0] + orr r1, r1, #1 + str r1, [r0] +#endif + + /* L2 cache resume & re-enable */ + l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr + + b cpu_resume +ENDPROC(tegra_resume) +#endif + +#ifdef CONFIG_CACHE_L2X0 + .globl l2x0_saved_regs_addr +l2x0_saved_regs_addr: + .long 0 +#endif + + .align L1_CACHE_SHIFT +ENTRY(__tegra_cpu_reset_handler_start) + +/* + * __tegra_cpu_reset_handler: + * + * Common handler for all CPU reset events. + * + * Register usage within the reset handler: + * + * R7 = CPU present (to the OS) mask + * R8 = CPU in LP1 state mask + * R9 = CPU in LP2 state mask + * R10 = CPU number + * R11 = CPU mask + * R12 = pointer to reset handler data + * + * NOTE: This code is copied to IRAM. All code and data accesses + * must be position-independent. + */ + + .align L1_CACHE_SHIFT +ENTRY(__tegra_cpu_reset_handler) + + cpsid aif, 0x13 @ SVC mode, interrupts disabled + mrc p15, 0, r10, c0, c0, 5 @ MPIDR + and r10, r10, #0x3 @ R10 = CPU number + mov r11, #1 + mov r11, r11, lsl r10 @ R11 = CPU mask + adr r12, __tegra_cpu_reset_handler_data + +#ifdef CONFIG_SMP + /* Does the OS know about this CPU? */ + ldr r7, [r12, #RESET_DATA(MASK_PRESENT)] + tst r7, r11 @ if !present + bleq __die @ CPU not present (to OS) +#endif + +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + /* Are we on Tegra20? */ + mov32 r6, TEGRA_APB_MISC_BASE + ldr r0, [r6, #APB_MISC_GP_HIDREV] + and r0, r0, #0xff00 + cmp r0, #(0x20 << 8) + bne 1f + /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */ + mov32 r6, TEGRA_PMC_BASE + mov r0, #0 + cmp r10, #0 + strne r0, [r6, #PMC_SCRATCH41] +1: +#endif + + /* Waking up from LP2? */ + ldr r9, [r12, #RESET_DATA(MASK_LP2)] + tst r9, r11 @ if in_lp2 + beq __is_not_lp2 + ldr lr, [r12, #RESET_DATA(STARTUP_LP2)] + cmp lr, #0 + bleq __die @ no LP2 startup handler + bx lr + +__is_not_lp2: + +#ifdef CONFIG_SMP + /* + * Can only be secondary boot (initial or hotplug) but CPU 0 + * cannot be here. + */ + cmp r10, #0 + bleq __die @ CPU0 cannot be here + ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)] + cmp lr, #0 + bleq __die @ no secondary startup handler + bx lr +#endif + +/* + * We don't know why the CPU reset. Just kill it. + * The LR register will contain the address we died at + 4. + */ + +__die: + sub lr, lr, #4 + mov32 r7, TEGRA_PMC_BASE + str lr, [r7, #PMC_SCRATCH41] + + mov32 r7, TEGRA_CLK_RESET_BASE + + /* Are we on Tegra20? */ + mov32 r6, TEGRA_APB_MISC_BASE + ldr r0, [r6, #APB_MISC_GP_HIDREV] + and r0, r0, #0xff00 + cmp r0, #(0x20 << 8) + bne 1f + +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + mov32 r0, 0x1111 + mov r1, r0, lsl r10 + str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET +#endif +1: +#ifdef CONFIG_ARCH_TEGRA_3x_SOC + mov32 r6, TEGRA_FLOW_CTRL_BASE + + cmp r10, #0 + moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS + moveq r2, #FLOW_CTRL_CPU0_CSR + movne r1, r10, lsl #3 + addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8) + addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8) + + /* Clear CPU "event" and "interrupt" flags and power gate + it when halting but not before it is in the "WFI" state. */ + ldr r0, [r6, +r2] + orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG + orr r0, r0, #FLOW_CTRL_CSR_ENABLE + str r0, [r6, +r2] + + /* Unconditionally halt this CPU */ + mov r0, #FLOW_CTRL_WAITEVENT + str r0, [r6, +r1] + ldr r0, [r6, +r1] @ memory barrier + + dsb + isb + wfi @ CPU should be power gated here + + /* If the CPU didn't power gate above just kill it's clock. */ + + mov r0, r11, lsl #8 + str r0, [r7, #348] @ CLK_CPU_CMPLX_SET +#endif + + /* If the CPU still isn't dead, just spin here. */ + b . +ENDPROC(__tegra_cpu_reset_handler) + + .align L1_CACHE_SHIFT + .type __tegra_cpu_reset_handler_data, %object + .globl __tegra_cpu_reset_handler_data +__tegra_cpu_reset_handler_data: + .rept TEGRA_RESET_DATA_SIZE + .long 0 + .endr + .align L1_CACHE_SHIFT + +ENTRY(__tegra_cpu_reset_handler_end) diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c index 3fd89ecd158e..1ac434e0068f 100644 --- a/arch/arm/mach-tegra/reset.c +++ b/arch/arm/mach-tegra/reset.c @@ -75,7 +75,7 @@ void __init tegra_cpu_reset_handler_init(void) #ifdef CONFIG_SMP __tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] = - *((u32 *)cpu_present_mask); + *((u32 *)cpu_possible_mask); __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_SECONDARY] = virt_to_phys((void *)tegra_secondary_startup); #endif From 1395868c06bd41390e50e7c7fe9a4783dd620867 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Mon, 7 Jan 2013 10:56:14 +0800 Subject: [PATCH 11/31] ARM: tegra30: make the wait time of CPU power up to proportional to HZ It would rather to use the API of time_to_jiffies than a constant number of jiffies for the wait time of CPU power up. Based on the work by: Sang-Hun Lee Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/platsmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 60daf9f945cb..68670304d9bc 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -90,7 +90,7 @@ static int tegra30_power_up_cpu(unsigned int cpu) * next time around. */ if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) { - timeout = jiffies + 5*HZ; + timeout = jiffies + msecs_to_jiffies(50); do { if (!tegra_powergate_is_powered(pwrgateid)) goto remove_clamps; @@ -110,7 +110,7 @@ static int tegra30_power_up_cpu(unsigned int cpu) return ret; /* Wait for the power to come up. */ - timeout = jiffies + 10*HZ; + timeout = jiffies + msecs_to_jiffies(100); while (tegra_powergate_is_powered(pwrgateid)) { if (time_after(jiffies, timeout)) return -ETIMEDOUT; From 24e30c9417230b359bf6dfeb923e90138df7c112 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Fri, 25 Jan 2013 14:38:32 +0800 Subject: [PATCH 12/31] ARM: tegra: fix compile error when disable CPU_IDLE The "sleep.S" file has many functions that be shared by different module currently. Not just for CPU idle driver. Make it build as default now. Reported-by: Rhyland Klein Signed-off-by: Joseph Lo [swarren: add sleep.o to separate line so each line only contains 1 file] Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index a839bb3d9703..f0520961bafe 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -10,8 +10,8 @@ obj-y += apbio.o obj-y += pm.o obj-y += reset.o obj-y += reset-handler.o +obj-y += sleep.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o -obj-$(CONFIG_CPU_IDLE) += sleep.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o From c7736edf1b1734455c186deec53a0aa7f8fa87ea Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:19 +0530 Subject: [PATCH 13/31] ARM: tegra: add function to read chipid Add function to read chip id from APB MISC registers. This function will also get called from clock driver to flush write operations on apb bus. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/fuse.c | 8 +++++++- include/linux/tegra-soc.h | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 include/linux/tegra-soc.h diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index 8121742711fe..f7db0782a6b6 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "fuse.h" #include "iomap.h" @@ -105,6 +106,11 @@ static void tegra_get_process_id(void) tegra_core_process_id = (reg >> 12) & 3; } +u32 tegra_read_chipid(void) +{ + return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); +} + void tegra_init_fuse(void) { u32 id; @@ -119,7 +125,7 @@ void tegra_init_fuse(void) reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; - id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); + id = tegra_read_chipid(); tegra_chip_id = (id >> 8) & 0xff; switch (tegra_chip_id) { diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h new file mode 100644 index 000000000000..95f611d78f3a --- /dev/null +++ b/include/linux/tegra-soc.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __LINUX_TEGRA_SOC_H_ +#define __LINUX_TEGRA_SOC_H_ + +u32 tegra_read_chipid(void); + +#endif /* __LINUX_TEGRA_SOC_H_ */ From 89572c77cdffdf24f8fec50d3e38db6a18c04dbe Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:21 +0530 Subject: [PATCH 14/31] ARM: tegra: move tegra_cpu_car.h to linux/clk/tegra.h tegra_cpu_car_ops struct is going to be accessed from drivers/clk/tegra. Move the tegra_cpu_car_ops to include/linux/clk/tegra.h. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/clock.c | 2 +- arch/arm/mach-tegra/cpuidle-tegra30.c | 2 +- arch/arm/mach-tegra/hotplug.c | 2 +- arch/arm/mach-tegra/platsmp.c | 2 +- arch/arm/mach-tegra/pm.c | 2 +- arch/arm/mach-tegra/tegra20_clocks.c | 2 +- arch/arm/mach-tegra/tegra20_clocks_data.c | 2 +- arch/arm/mach-tegra/tegra30_clocks.c | 2 +- arch/arm/mach-tegra/tegra30_clocks_data.c | 2 +- .../mach-tegra/tegra_cpu_car.h => include/linux/clk/tegra.h | 6 +++--- 10 files changed, 12 insertions(+), 12 deletions(-) rename arch/arm/mach-tegra/tegra_cpu_car.h => include/linux/clk/tegra.h (96%) diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 867bf8bf5561..8c0ff061f8cf 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -26,10 +26,10 @@ #include #include #include +#include #include "board.h" #include "clock.h" -#include "tegra_cpu_car.h" /* Global data of Tegra CPU CAR ops */ struct tegra_cpu_car_ops *tegra_cpu_car_ops; diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index 82530bd9b8c2..8b50cf4ddd6f 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -32,7 +33,6 @@ #include "pm.h" #include "sleep.h" -#include "tegra_cpu_car.h" #ifdef CONFIG_PM_SLEEP static int tegra30_idle_lp2(struct cpuidle_device *dev, diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index 6a27de4001ee..a599f6e36dea 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -10,12 +10,12 @@ */ #include #include +#include #include #include #include "sleep.h" -#include "tegra_cpu_car.h" static void (*tegra_hotplug_shutdown)(void); diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 68670304d9bc..3ec7fc487857 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,6 @@ #include "fuse.h" #include "flowctrl.h" #include "reset.h" -#include "tegra_cpu_car.h" #include "common.h" #include "iomap.h" diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 498d70b33775..abfe9b93cc0c 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -36,7 +37,6 @@ #include "reset.h" #include "flowctrl.h" #include "sleep.h" -#include "tegra_cpu_car.h" #define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c index 4eb6bc81a87b..1a80ff65e5fc 100644 --- a/arch/arm/mach-tegra/tegra20_clocks.c +++ b/arch/arm/mach-tegra/tegra20_clocks.c @@ -26,12 +26,12 @@ #include #include #include +#include #include "clock.h" #include "fuse.h" #include "iomap.h" #include "tegra2_emc.h" -#include "tegra_cpu_car.h" #define RST_DEVICES 0x004 #define RST_DEVICES_SET 0x300 diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c index a23a0734e352..022cdaef7ca5 100644 --- a/arch/arm/mach-tegra/tegra20_clocks_data.c +++ b/arch/arm/mach-tegra/tegra20_clocks_data.c @@ -26,12 +26,12 @@ #include #include #include +#include #include "clock.h" #include "fuse.h" #include "tegra2_emc.h" #include "tegra20_clocks.h" -#include "tegra_cpu_car.h" /* Clock definitions */ diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c index d7147779f8ea..4330787fe5cb 100644 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ b/arch/arm/mach-tegra/tegra30_clocks.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -36,7 +37,6 @@ #include "clock.h" #include "fuse.h" #include "iomap.h" -#include "tegra_cpu_car.h" #define USE_PLL_LOCK_BITS 0 diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c index 741d264d5ecb..9bfaa490cff6 100644 --- a/arch/arm/mach-tegra/tegra30_clocks_data.c +++ b/arch/arm/mach-tegra/tegra30_clocks_data.c @@ -28,11 +28,11 @@ #include #include #include +#include #include "clock.h" #include "fuse.h" #include "tegra30_clocks.h" -#include "tegra_cpu_car.h" #define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \ _parent_names, _parents, _parent) \ diff --git a/arch/arm/mach-tegra/tegra_cpu_car.h b/include/linux/clk/tegra.h similarity index 96% rename from arch/arm/mach-tegra/tegra_cpu_car.h rename to include/linux/clk/tegra.h index 9764d31032b7..0977f2a24757 100644 --- a/arch/arm/mach-tegra/tegra_cpu_car.h +++ b/include/linux/clk/tegra.h @@ -14,8 +14,8 @@ * along with this program. If not, see . */ -#ifndef __MACH_TEGRA_CPU_CAR_H -#define __MACH_TEGRA_CPU_CAR_H +#ifndef __LINUX_CLK_TEGRA_H_ +#define __LINUX_CLK_TEGRA_H_ /* * Tegra CPU clock and reset control ops @@ -121,4 +121,4 @@ static inline void tegra_cpu_clock_resume(void) void tegra20_cpu_car_ops_init(void); void tegra30_cpu_car_ops_init(void); -#endif /* __MACH_TEGRA_CPU_CAR_H */ +#endif /* __LINUX_CLK_TEGRA_H_ */ From 270f8ce3122b12f4224f7c72806ebf05e23835a6 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 11 Jan 2013 13:16:22 +0530 Subject: [PATCH 15/31] ARM: tegra: define Tegra20 CAR binding The Tegra20 CAR (Clock And Reset) Controller controls most aspects of most clocks within Tegra20. The device tree binding models this as a single monolithic clock provider, which exports many clocks. This reduces the number of nodes needed in device tree to represent these clocks. This binding is only useful for Tegra20; the set of clocks that exists on Tegra30 is sufficiently different to merit its own binding. Signed-off-by: Stephen Warren Acked-by: Simon Glass [pgaikwad: Added mux clk ids and sorted CAR node] Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- .../bindings/clock/nvidia,tegra20-car.txt | 205 ++++++++++++++++++ arch/arm/boot/dts/tegra20.dtsi | 6 + 2 files changed, 211 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt new file mode 100644 index 000000000000..0921fac73528 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt @@ -0,0 +1,205 @@ +NVIDIA Tegra20 Clock And Reset Controller + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CAR (Clock And Reset) Controller on Tegra is the HW module responsible +for muxing and gating Tegra's clocks, and setting their rates. + +Required properties : +- compatible : Should be "nvidia,tegra20-car" +- reg : Should contain CAR registers location and length +- clocks : Should contain phandle and clock specifiers for two clocks: + the 32 KHz "32k_in", and the board-specific oscillator "osc". +- #clock-cells : Should be 1. + In clock consumers, this cell represents the clock ID exposed by the CAR. + + The first 96 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB + registers. These IDs often match those in the CAR's RST_DEVICES registers, + but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In + this case, those clocks are assigned IDs above 95 in order to highlight + this issue. Implementations that interpret these clock IDs as bit values + within the CLK_OUT_ENB or RST_DEVICES registers should be careful to + explicitly handle these special cases. + + The balance of the clocks controlled by the CAR are assigned IDs of 96 and + above. + + 0 cpu + 1 unassigned + 2 unassigned + 3 ac97 + 4 rtc + 5 tmr + 6 uart1 + 7 unassigned (register bit affects uart2 and vfir) + 8 gpio + 9 sdmmc2 + 10 unassigned (register bit affects spdif_in and spdif_out) + 11 i2s1 + 12 i2c1 + 13 ndflash + 14 sdmmc1 + 15 sdmmc4 + 16 twc + 17 pwm + 18 i2s2 + 19 epp + 20 unassigned (register bit affects vi and vi_sensor) + 21 2d + 22 usbd + 23 isp + 24 3d + 25 ide + 26 disp2 + 27 disp1 + 28 host1x + 29 vcp + 30 unassigned + 31 cache2 + + 32 mem + 33 ahbdma + 34 apbdma + 35 unassigned + 36 kbc + 37 stat_mon + 38 pmc + 39 fuse + 40 kfuse + 41 sbc1 + 42 snor + 43 spi1 + 44 sbc2 + 45 xio + 46 sbc3 + 47 dvc + 48 dsi + 49 unassigned (register bit affects tvo and cve) + 50 mipi + 51 hdmi + 52 csi + 53 tvdac + 54 i2c2 + 55 uart3 + 56 unassigned + 57 emc + 58 usb2 + 59 usb3 + 60 mpe + 61 vde + 62 bsea + 63 bsev + + 64 speedo + 65 uart4 + 66 uart5 + 67 i2c3 + 68 sbc4 + 69 sdmmc3 + 70 pcie + 71 owr + 72 afi + 73 csite + 74 unassigned + 75 avpucq + 76 la + 77 unassigned + 78 unassigned + 79 unassigned + 80 unassigned + 81 unassigned + 82 unassigned + 83 unassigned + 84 irama + 85 iramb + 86 iramc + 87 iramd + 88 cram2 + 89 audio_2x a/k/a audio_2x_sync_clk + 90 clk_d + 91 unassigned + 92 sus + 93 cdev1 + 94 cdev2 + 95 unassigned + + 96 uart2 + 97 vfir + 98 spdif_in + 99 spdif_out + 100 vi + 101 vi_sensor + 102 tvo + 103 cve + 104 osc + 105 clk_32k a/k/a clk_s + 106 clk_m + 107 sclk + 108 cclk + 109 hclk + 110 pclk + 111 blink + 112 pll_a + 113 pll_a_out0 + 114 pll_c + 115 pll_c_out1 + 116 pll_d + 117 pll_d_out0 + 118 pll_e + 119 pll_m + 120 pll_m_out1 + 121 pll_p + 122 pll_p_out1 + 123 pll_p_out2 + 124 pll_p_out3 + 125 pll_p_out4 + 126 pll_s + 127 pll_u + 128 pll_x + 129 cop a/k/a avp + 130 audio a/k/a audio_sync_clk + 131 pll_ref + 132 twd + +Example SoC include file: + +/ { + tegra_car: clock { + compatible = "nvidia,tegra20-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + }; + + usb@c5004000 { + clocks = <&tegra_car 58>; /* usb2 */ + }; +}; + +Example board file: + +/ { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + osc: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + + clk_32k: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + &tegra_car { + clocks = <&clk_32k> <&osc>; + }; +}; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index b8effa1cbda7..5b104f1d5003 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -123,6 +123,12 @@ timer@60005000 { 0 42 0x04>; }; + tegra_car: clock { + compatible = "nvidia,tegra20-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + }; + apbdma: dma { compatible = "nvidia,tegra20-apbdma"; reg = <0x6000a000 0x1200>; From 9598566721fe7524cca575975ea7e8ea2e27a71b Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:23 +0530 Subject: [PATCH 16/31] ARM: tegra: define Tegra30 CAR binding The device tree binding models Tegra30 CAR (Clock And Reset) as a single monolithic clock provider. Signed-off-by: Prashant Gaikwad [swarren: fixed typo in binding doc] Signed-off-by: Stephen Warren --- .../bindings/clock/nvidia,tegra30-car.txt | 262 ++++++++++++++++++ arch/arm/boot/dts/tegra30.dtsi | 6 + 2 files changed, 268 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt new file mode 100644 index 000000000000..f3da3be5fcad --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt @@ -0,0 +1,262 @@ +NVIDIA Tegra30 Clock And Reset Controller + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CAR (Clock And Reset) Controller on Tegra is the HW module responsible +for muxing and gating Tegra's clocks, and setting their rates. + +Required properties : +- compatible : Should be "nvidia,tegra30-car" +- reg : Should contain CAR registers location and length +- clocks : Should contain phandle and clock specifiers for two clocks: + the 32 KHz "32k_in", and the board-specific oscillator "osc". +- #clock-cells : Should be 1. + In clock consumers, this cell represents the clock ID exposed by the CAR. + + The first 130 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB + registers. These IDs often match those in the CAR's RST_DEVICES registers, + but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In + this case, those clocks are assigned IDs above 160 in order to highlight + this issue. Implementations that interpret these clock IDs as bit values + within the CLK_OUT_ENB or RST_DEVICES registers should be careful to + explicitly handle these special cases. + + The balance of the clocks controlled by the CAR are assigned IDs of 160 and + above. + + 0 cpu + 1 unassigned + 2 unassigned + 3 unassigned + 4 rtc + 5 timer + 6 uarta + 7 unassigned (register bit affects uartb and vfir) + 8 gpio + 9 sdmmc2 + 10 unassigned (register bit affects spdif_in and spdif_out) + 11 i2s1 + 12 i2c1 + 13 ndflash + 14 sdmmc1 + 15 sdmmc4 + 16 unassigned + 17 pwm + 18 i2s2 + 19 epp + 20 unassigned (register bit affects vi and vi_sensor) + 21 2d + 22 usbd + 23 isp + 24 3d + 25 unassigned + 26 disp2 + 27 disp1 + 28 host1x + 29 vcp + 30 i2s0 + 31 cop_cache + + 32 mc + 33 ahbdma + 34 apbdma + 35 unassigned + 36 kbc + 37 statmon + 38 pmc + 39 unassigned (register bit affects fuse and fuse_burn) + 40 kfuse + 41 sbc1 + 42 nor + 43 unassigned + 44 sbc2 + 45 unassigned + 46 sbc3 + 47 i2c5 + 48 dsia + 49 unassigned (register bit affects cve and tvo) + 50 mipi + 51 hdmi + 52 csi + 53 tvdac + 54 i2c2 + 55 uartc + 56 unassigned + 57 emc + 58 usb2 + 59 usb3 + 60 mpe + 61 vde + 62 bsea + 63 bsev + + 64 speedo + 65 uartd + 66 uarte + 67 i2c3 + 68 sbc4 + 69 sdmmc3 + 70 pcie + 71 owr + 72 afi + 73 csite + 74 pciex + 75 avpucq + 76 la + 77 unassigned + 78 unassigned + 79 dtv + 80 ndspeed + 81 i2cslow + 82 dsib + 83 unassigned + 84 irama + 85 iramb + 86 iramc + 87 iramd + 88 cram2 + 89 unassigned + 90 audio_2x a/k/a audio_2x_sync_clk + 91 unassigned + 92 csus + 93 cdev2 + 94 cdev1 + 95 unassigned + + 96 cpu_g + 97 cpu_lp + 98 3d2 + 99 mselect + 100 tsensor + 101 i2s3 + 102 i2s4 + 103 i2c4 + 104 sbc5 + 105 sbc6 + 106 d_audio + 107 apbif + 108 dam0 + 109 dam1 + 110 dam2 + 111 hda2codec_2x + 112 atomics + 113 audio0_2x + 114 audio1_2x + 115 audio2_2x + 116 audio3_2x + 117 audio4_2x + 118 audio5_2x + 119 actmon + 120 extern1 + 121 extern2 + 122 extern3 + 123 sata_oob + 124 sata + 125 hda + 127 se + 128 hda2hdmi + 129 sata_cold + + 160 uartb + 161 vfir + 162 spdif_in + 163 spdif_out + 164 vi + 165 vi_sensor + 166 fuse + 167 fuse_burn + 168 cve + 169 tvo + + 170 clk_32k + 171 clk_m + 172 clk_m_div2 + 173 clk_m_div4 + 174 pll_ref + 175 pll_c + 176 pll_c_out1 + 177 pll_m + 178 pll_m_out1 + 179 pll_p + 180 pll_p_out1 + 181 pll_p_out2 + 182 pll_p_out3 + 183 pll_p_out4 + 184 pll_a + 185 pll_a_out0 + 186 pll_d + 187 pll_d_out0 + 188 pll_d2 + 189 pll_d2_out0 + 190 pll_u + 191 pll_x + 192 pll_x_out0 + 193 pll_e + 194 spdif_in_sync + 195 i2s0_sync + 196 i2s1_sync + 197 i2s2_sync + 198 i2s3_sync + 199 i2s4_sync + 200 vimclk + 201 audio0 + 202 audio1 + 203 audio2 + 204 audio3 + 205 audio4 + 206 audio5 + 207 clk_out_1 (extern1) + 208 clk_out_2 (extern2) + 209 clk_out_3 (extern3) + 210 sclk + 211 blink + 212 cclk_g + 213 cclk_lp + 214 twd + 215 cml0 + 216 cml1 + 217 hclk + 218 pclk + +Example SoC include file: + +/ { + tegra_car: clock { + compatible = "nvidia,tegra30-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + }; + + usb@c5004000 { + clocks = <&tegra_car 58>; /* usb2 */ + }; +}; + +Example board file: + +/ { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + osc: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + + clk_32k: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + &tegra_car { + clocks = <&clk_32k> <&osc>; + }; +}; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 529fdb82dfdb..6765646c2248 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -125,6 +125,12 @@ timer@60005000 { 0 122 0x04>; }; + tegra_car: clock { + compatible = "nvidia,tegra30-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + }; + apbdma: dma { compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma"; reg = <0x6000a000 0x1400>; From 8f8f484bf355e546c62c47b8a8c8d19b28787798 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:20 +0530 Subject: [PATCH 17/31] clk: tegra: add Tegra specific clocks Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super. Signed-off-by: Prashant Gaikwad [swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re: storing pointers to stack variables, make a timeout loop more idiomatic, use _clk_pll_disable() not clk_disable_pll() from _program_pll() to avoid redundant lock operations, unified tegra_clk_periph() and tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock registration functions so they don't have the same name as the clock structs, return -EINVAL from clk_plle_enable when matching table rate not found, pass ops to _tegra_clk_register_pll rather than a bool.] Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/Makefile | 1 + drivers/clk/tegra/Makefile | 8 + drivers/clk/tegra/clk-audio-sync.c | 87 ++++ drivers/clk/tegra/clk-divider.c | 187 ++++++++ drivers/clk/tegra/clk-periph-gate.c | 179 ++++++++ drivers/clk/tegra/clk-periph.c | 180 ++++++++ drivers/clk/tegra/clk-pll-out.c | 123 ++++++ drivers/clk/tegra/clk-pll.c | 648 ++++++++++++++++++++++++++++ drivers/clk/tegra/clk-super.c | 154 +++++++ drivers/clk/tegra/clk.c | 69 +++ drivers/clk/tegra/clk.h | 490 +++++++++++++++++++++ 11 files changed, 2126 insertions(+) create mode 100644 drivers/clk/tegra/Makefile create mode 100644 drivers/clk/tegra/clk-audio-sync.c create mode 100644 drivers/clk/tegra/clk-divider.c create mode 100644 drivers/clk/tegra/clk-periph-gate.c create mode 100644 drivers/clk/tegra/clk-periph.c create mode 100644 drivers/clk/tegra/clk-pll-out.c create mode 100644 drivers/clk/tegra/clk-pll.c create mode 100644 drivers/clk/tegra/clk-super.c create mode 100644 drivers/clk/tegra/clk.c create mode 100644 drivers/clk/tegra/clk.h diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ee90e87e7675..f0b269a2058d 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o +obj-$(CONFIG_ARCH_TEGRA) += tegra/ # Chip specific obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile new file mode 100644 index 000000000000..68bd353a2108 --- /dev/null +++ b/drivers/clk/tegra/Makefile @@ -0,0 +1,8 @@ +obj-y += clk.o +obj-y += clk-audio-sync.o +obj-y += clk-divider.o +obj-y += clk-periph.o +obj-y += clk-periph-gate.o +obj-y += clk-pll.o +obj-y += clk-pll-out.o +obj-y += clk-super.o diff --git a/drivers/clk/tegra/clk-audio-sync.c b/drivers/clk/tegra/clk-audio-sync.c new file mode 100644 index 000000000000..c0f7843e80e6 --- /dev/null +++ b/drivers/clk/tegra/clk-audio-sync.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "clk.h" + +static unsigned long clk_sync_source_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); + + return sync->rate; +} + +static long clk_sync_source_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); + + if (rate > sync->max_rate) + return -EINVAL; + else + return rate; +} + +static int clk_sync_source_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); + + sync->rate = rate; + return 0; +} + +const struct clk_ops tegra_clk_sync_source_ops = { + .round_rate = clk_sync_source_round_rate, + .set_rate = clk_sync_source_set_rate, + .recalc_rate = clk_sync_source_recalc_rate, +}; + +struct clk *tegra_clk_register_sync_source(const char *name, + unsigned long rate, unsigned long max_rate) +{ + struct tegra_clk_sync_source *sync; + struct clk_init_data init; + struct clk *clk; + + sync = kzalloc(sizeof(*sync), GFP_KERNEL); + if (!sync) { + pr_err("%s: could not allocate sync source clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + sync->rate = rate; + sync->max_rate = max_rate; + + init.ops = &tegra_clk_sync_source_ops; + init.name = name; + init.flags = CLK_IS_ROOT; + init.parent_names = NULL; + init.num_parents = 0; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + sync->hw.init = &init; + + clk = clk_register(NULL, &sync->hw); + if (IS_ERR(clk)) + kfree(sync); + + return clk; +} diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c new file mode 100644 index 000000000000..4d75b1f37e3a --- /dev/null +++ b/drivers/clk/tegra/clk-divider.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define pll_out_override(p) (BIT((p->shift - 6))) +#define div_mask(d) ((1 << (d->width)) - 1) +#define get_mul(d) (1 << d->frac_width) +#define get_max_div(d) div_mask(d) + +#define PERIPH_CLK_UART_DIV_ENB BIT(24) + +static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate, + unsigned long parent_rate) +{ + s64 divider_ux1 = parent_rate; + u8 flags = divider->flags; + int mul; + + if (!rate) + return 0; + + mul = get_mul(divider); + + if (!(flags & TEGRA_DIVIDER_INT)) + divider_ux1 *= mul; + + if (flags & TEGRA_DIVIDER_ROUND_UP) + divider_ux1 += rate - 1; + + do_div(divider_ux1, rate); + + if (flags & TEGRA_DIVIDER_INT) + divider_ux1 *= mul; + + divider_ux1 -= mul; + + if (divider_ux1 < 0) + return 0; + + if (divider_ux1 > get_max_div(divider)) + return -EINVAL; + + return divider_ux1; +} + +static unsigned long clk_frac_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); + u32 reg; + int div, mul; + u64 rate = parent_rate; + + reg = readl_relaxed(divider->reg) >> divider->shift; + div = reg & div_mask(divider); + + mul = get_mul(divider); + div += mul; + + rate *= mul; + rate += div - 1; + do_div(rate, div); + + return rate; +} + +static long clk_frac_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); + int div, mul; + unsigned long output_rate = *prate; + + if (!rate) + return output_rate; + + div = get_div(divider, rate, output_rate); + if (div < 0) + return *prate; + + mul = get_mul(divider); + + return DIV_ROUND_UP(output_rate * mul, div + mul); +} + +static int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); + int div; + unsigned long flags = 0; + u32 val; + + div = get_div(divider, rate, parent_rate); + if (div < 0) + return div; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + + val = readl_relaxed(divider->reg); + val &= ~(div_mask(divider) << divider->shift); + val |= div << divider->shift; + + if (divider->flags & TEGRA_DIVIDER_UART) { + if (div) + val |= PERIPH_CLK_UART_DIV_ENB; + else + val &= ~PERIPH_CLK_UART_DIV_ENB; + } + + if (divider->flags & TEGRA_DIVIDER_FIXED) + val |= pll_out_override(divider); + + writel_relaxed(val, divider->reg); + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + + return 0; +} + +const struct clk_ops tegra_clk_frac_div_ops = { + .recalc_rate = clk_frac_div_recalc_rate, + .set_rate = clk_frac_div_set_rate, + .round_rate = clk_frac_div_round_rate, +}; + +struct clk *tegra_clk_register_divider(const char *name, + const char *parent_name, void __iomem *reg, + unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width, + u8 frac_width, spinlock_t *lock) +{ + struct tegra_clk_frac_div *divider; + struct clk *clk; + struct clk_init_data init; + + divider = kzalloc(sizeof(*divider), GFP_KERNEL); + if (!divider) { + pr_err("%s: could not allocate fractional divider clk\n", + __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &tegra_clk_frac_div_ops; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + divider->reg = reg; + divider->shift = shift; + divider->width = width; + divider->frac_width = frac_width; + divider->lock = lock; + divider->flags = clk_divider_flags; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + divider->hw.init = &init; + + clk = clk_register(NULL, ÷r->hw); + if (IS_ERR(clk)) + kfree(divider); + + return clk; +} diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c new file mode 100644 index 000000000000..6dd533251e7b --- /dev/null +++ b/drivers/clk/tegra/clk-periph-gate.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static DEFINE_SPINLOCK(periph_ref_lock); + +/* Macros to assist peripheral gate clock */ +#define read_enb(gate) \ + readl_relaxed(gate->clk_base + (gate->regs->enb_reg)) +#define write_enb_set(val, gate) \ + writel_relaxed(val, gate->clk_base + (gate->regs->enb_set_reg)) +#define write_enb_clr(val, gate) \ + writel_relaxed(val, gate->clk_base + (gate->regs->enb_clr_reg)) + +#define read_rst(gate) \ + readl_relaxed(gate->clk_base + (gate->regs->rst_reg)) +#define write_rst_set(val, gate) \ + writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg)) +#define write_rst_clr(val, gate) \ + writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg)) + +#define periph_clk_to_bit(periph) (1 << (gate->clk_num % 32)) + +/* Peripheral gate clock ops */ +static int clk_periph_is_enabled(struct clk_hw *hw) +{ + struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw); + int state = 1; + + if (!(read_enb(gate) & periph_clk_to_bit(gate))) + state = 0; + + if (!(gate->flags & TEGRA_PERIPH_NO_RESET)) + if (read_rst(gate) & periph_clk_to_bit(gate)) + state = 0; + + return state; +} + +static int clk_periph_enable(struct clk_hw *hw) +{ + struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw); + unsigned long flags = 0; + + spin_lock_irqsave(&periph_ref_lock, flags); + + gate->enable_refcnt[gate->clk_num]++; + if (gate->enable_refcnt[gate->clk_num] > 1) { + spin_unlock_irqrestore(&periph_ref_lock, flags); + return 0; + } + + write_enb_set(periph_clk_to_bit(gate), gate); + udelay(2); + + if (!(gate->flags & TEGRA_PERIPH_NO_RESET) && + !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) { + if (read_rst(gate) & periph_clk_to_bit(gate)) { + udelay(5); /* reset propogation delay */ + write_rst_clr(periph_clk_to_bit(gate), gate); + } + } + + spin_unlock_irqrestore(&periph_ref_lock, flags); + + return 0; +} + +static void clk_periph_disable(struct clk_hw *hw) +{ + struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw); + unsigned long flags = 0; + + spin_lock_irqsave(&periph_ref_lock, flags); + + gate->enable_refcnt[gate->clk_num]--; + if (gate->enable_refcnt[gate->clk_num] > 0) { + spin_unlock_irqrestore(&periph_ref_lock, flags); + return; + } + + /* + * If peripheral is in the APB bus then read the APB bus to + * flush the write operation in apb bus. This will avoid the + * peripheral access after disabling clock + */ + if (gate->flags & TEGRA_PERIPH_ON_APB) + tegra_read_chipid(); + + write_enb_clr(periph_clk_to_bit(gate), gate); + + spin_unlock_irqrestore(&periph_ref_lock, flags); +} + +void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert) +{ + if (gate->flags & TEGRA_PERIPH_NO_RESET) + return; + + if (assert) { + /* + * If peripheral is in the APB bus then read the APB bus to + * flush the write operation in apb bus. This will avoid the + * peripheral access after disabling clock + */ + if (gate->flags & TEGRA_PERIPH_ON_APB) + tegra_read_chipid(); + + write_rst_set(periph_clk_to_bit(gate), gate); + } else { + write_rst_clr(periph_clk_to_bit(gate), gate); + } +} + +const struct clk_ops tegra_clk_periph_gate_ops = { + .is_enabled = clk_periph_is_enabled, + .enable = clk_periph_enable, + .disable = clk_periph_disable, +}; + +struct clk *tegra_clk_register_periph_gate(const char *name, + const char *parent_name, u8 gate_flags, void __iomem *clk_base, + unsigned long flags, int clk_num, + struct tegra_clk_periph_regs *pregs, int *enable_refcnt) +{ + struct tegra_clk_periph_gate *gate; + struct clk *clk; + struct clk_init_data init; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + pr_err("%s: could not allocate periph gate clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + init.ops = &tegra_clk_periph_gate_ops; + + gate->magic = TEGRA_CLK_PERIPH_GATE_MAGIC; + gate->clk_base = clk_base; + gate->clk_num = clk_num; + gate->flags = gate_flags; + gate->enable_refcnt = enable_refcnt; + gate->regs = pregs; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + gate->hw.init = &init; + + clk = clk_register(NULL, &gate->hw); + if (IS_ERR(clk)) + kfree(gate); + + return clk; +} diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c new file mode 100644 index 000000000000..5978e81b175b --- /dev/null +++ b/drivers/clk/tegra/clk-periph.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include "clk.h" + +static u8 clk_periph_get_parent(struct clk_hw *hw) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *mux_ops = periph->mux_ops; + struct clk_hw *mux_hw = &periph->mux.hw; + + mux_hw->clk = hw->clk; + + return mux_ops->get_parent(mux_hw); +} + +static int clk_periph_set_parent(struct clk_hw *hw, u8 index) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *mux_ops = periph->mux_ops; + struct clk_hw *mux_hw = &periph->mux.hw; + + mux_hw->clk = hw->clk; + + return mux_ops->set_parent(mux_hw, index); +} + +static unsigned long clk_periph_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *div_ops = periph->div_ops; + struct clk_hw *div_hw = &periph->divider.hw; + + div_hw->clk = hw->clk; + + return div_ops->recalc_rate(div_hw, parent_rate); +} + +static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *div_ops = periph->div_ops; + struct clk_hw *div_hw = &periph->divider.hw; + + div_hw->clk = hw->clk; + + return div_ops->round_rate(div_hw, rate, prate); +} + +static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *div_ops = periph->div_ops; + struct clk_hw *div_hw = &periph->divider.hw; + + div_hw->clk = hw->clk; + + return div_ops->set_rate(div_hw, rate, parent_rate); +} + +static int clk_periph_is_enabled(struct clk_hw *hw) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *gate_ops = periph->gate_ops; + struct clk_hw *gate_hw = &periph->gate.hw; + + gate_hw->clk = hw->clk; + + return gate_ops->is_enabled(gate_hw); +} + +static int clk_periph_enable(struct clk_hw *hw) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *gate_ops = periph->gate_ops; + struct clk_hw *gate_hw = &periph->gate.hw; + + gate_hw->clk = hw->clk; + + return gate_ops->enable(gate_hw); +} + +static void clk_periph_disable(struct clk_hw *hw) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *gate_ops = periph->gate_ops; + struct clk_hw *gate_hw = &periph->gate.hw; + + gate_ops->disable(gate_hw); +} + +const struct clk_ops tegra_clk_periph_ops = { + .get_parent = clk_periph_get_parent, + .set_parent = clk_periph_set_parent, + .recalc_rate = clk_periph_recalc_rate, + .round_rate = clk_periph_round_rate, + .set_rate = clk_periph_set_rate, + .is_enabled = clk_periph_is_enabled, + .enable = clk_periph_enable, + .disable = clk_periph_disable, +}; + +const struct clk_ops tegra_clk_periph_nodiv_ops = { + .get_parent = clk_periph_get_parent, + .set_parent = clk_periph_set_parent, + .is_enabled = clk_periph_is_enabled, + .enable = clk_periph_enable, + .disable = clk_periph_disable, +}; + +static struct clk *_tegra_clk_register_periph(const char *name, + const char **parent_names, int num_parents, + struct tegra_clk_periph *periph, + void __iomem *clk_base, u32 offset, bool div) +{ + struct clk *clk; + struct clk_init_data init; + + init.name = name; + init.ops = div ? &tegra_clk_periph_ops : &tegra_clk_periph_nodiv_ops; + init.flags = div ? 0 : CLK_SET_RATE_PARENT; + init.parent_names = parent_names; + init.num_parents = num_parents; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + periph->hw.init = &init; + periph->magic = TEGRA_CLK_PERIPH_MAGIC; + periph->mux.reg = clk_base + offset; + periph->divider.reg = div ? (clk_base + offset) : NULL; + periph->gate.clk_base = clk_base; + + clk = clk_register(NULL, &periph->hw); + if (IS_ERR(clk)) + return clk; + + periph->mux.hw.clk = clk; + periph->divider.hw.clk = div ? clk : NULL; + periph->gate.hw.clk = clk; + + return clk; +} + +struct clk *tegra_clk_register_periph(const char *name, + const char **parent_names, int num_parents, + struct tegra_clk_periph *periph, void __iomem *clk_base, + u32 offset) +{ + return _tegra_clk_register_periph(name, parent_names, num_parents, + periph, clk_base, offset, true); +} + +struct clk *tegra_clk_register_periph_nodiv(const char *name, + const char **parent_names, int num_parents, + struct tegra_clk_periph *periph, void __iomem *clk_base, + u32 offset) +{ + return _tegra_clk_register_periph(name, parent_names, num_parents, + periph, clk_base, offset, false); +} diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c new file mode 100644 index 000000000000..3598987a451d --- /dev/null +++ b/drivers/clk/tegra/clk-pll-out.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define pll_out_enb(p) (BIT(p->enb_bit_idx)) +#define pll_out_rst(p) (BIT(p->rst_bit_idx)) + +static int clk_pll_out_is_enabled(struct clk_hw *hw) +{ + struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw); + u32 val = readl_relaxed(pll_out->reg); + int state; + + state = (val & pll_out_enb(pll_out)) ? 1 : 0; + if (!(val & (pll_out_rst(pll_out)))) + state = 0; + return state; +} + +static int clk_pll_out_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw); + unsigned long flags = 0; + u32 val; + + if (pll_out->lock) + spin_lock_irqsave(pll_out->lock, flags); + + val = readl_relaxed(pll_out->reg); + + val |= (pll_out_enb(pll_out) | pll_out_rst(pll_out)); + + writel_relaxed(val, pll_out->reg); + udelay(2); + + if (pll_out->lock) + spin_unlock_irqrestore(pll_out->lock, flags); + + return 0; +} + +static void clk_pll_out_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw); + unsigned long flags = 0; + u32 val; + + if (pll_out->lock) + spin_lock_irqsave(pll_out->lock, flags); + + val = readl_relaxed(pll_out->reg); + + val &= ~(pll_out_enb(pll_out) | pll_out_rst(pll_out)); + + writel_relaxed(val, pll_out->reg); + udelay(2); + + if (pll_out->lock) + spin_unlock_irqrestore(pll_out->lock, flags); +} + +const struct clk_ops tegra_clk_pll_out_ops = { + .is_enabled = clk_pll_out_is_enabled, + .enable = clk_pll_out_enable, + .disable = clk_pll_out_disable, +}; + +struct clk *tegra_clk_register_pll_out(const char *name, + const char *parent_name, void __iomem *reg, u8 enb_bit_idx, + u8 rst_bit_idx, unsigned long flags, u8 pll_out_flags, + spinlock_t *lock) +{ + struct tegra_clk_pll_out *pll_out; + struct clk *clk; + struct clk_init_data init; + + pll_out = kzalloc(sizeof(*pll_out), GFP_KERNEL); + if (!pll_out) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &tegra_clk_pll_out_ops; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + init.flags = flags; + + pll_out->reg = reg; + pll_out->enb_bit_idx = enb_bit_idx; + pll_out->rst_bit_idx = rst_bit_idx; + pll_out->flags = pll_out_flags; + pll_out->lock = lock; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + pll_out->hw.init = &init; + + clk = clk_register(NULL, &pll_out->hw); + if (IS_ERR(clk)) + kfree(pll_out); + + return clk; +} diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c new file mode 100644 index 000000000000..165f24734c1b --- /dev/null +++ b/drivers/clk/tegra/clk-pll.c @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define PLL_BASE_BYPASS BIT(31) +#define PLL_BASE_ENABLE BIT(30) +#define PLL_BASE_REF_ENABLE BIT(29) +#define PLL_BASE_OVERRIDE BIT(28) + +#define PLL_BASE_DIVP_SHIFT 20 +#define PLL_BASE_DIVP_WIDTH 3 +#define PLL_BASE_DIVN_SHIFT 8 +#define PLL_BASE_DIVN_WIDTH 10 +#define PLL_BASE_DIVM_SHIFT 0 +#define PLL_BASE_DIVM_WIDTH 5 +#define PLLU_POST_DIVP_MASK 0x1 + +#define PLL_MISC_DCCON_SHIFT 20 +#define PLL_MISC_CPCON_SHIFT 8 +#define PLL_MISC_CPCON_WIDTH 4 +#define PLL_MISC_CPCON_MASK ((1 << PLL_MISC_CPCON_WIDTH) - 1) +#define PLL_MISC_LFCON_SHIFT 4 +#define PLL_MISC_LFCON_WIDTH 4 +#define PLL_MISC_LFCON_MASK ((1 << PLL_MISC_LFCON_WIDTH) - 1) +#define PLL_MISC_VCOCON_SHIFT 0 +#define PLL_MISC_VCOCON_WIDTH 4 +#define PLL_MISC_VCOCON_MASK ((1 << PLL_MISC_VCOCON_WIDTH) - 1) + +#define OUT_OF_TABLE_CPCON 8 + +#define PMC_PLLP_WB0_OVERRIDE 0xf8 +#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE BIT(12) +#define PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE BIT(11) + +#define PLL_POST_LOCK_DELAY 50 + +#define PLLDU_LFCON_SET_DIVN 600 + +#define PLLE_BASE_DIVCML_SHIFT 24 +#define PLLE_BASE_DIVCML_WIDTH 4 +#define PLLE_BASE_DIVP_SHIFT 16 +#define PLLE_BASE_DIVP_WIDTH 7 +#define PLLE_BASE_DIVN_SHIFT 8 +#define PLLE_BASE_DIVN_WIDTH 8 +#define PLLE_BASE_DIVM_SHIFT 0 +#define PLLE_BASE_DIVM_WIDTH 8 + +#define PLLE_MISC_SETUP_BASE_SHIFT 16 +#define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT) +#define PLLE_MISC_LOCK_ENABLE BIT(9) +#define PLLE_MISC_READY BIT(15) +#define PLLE_MISC_SETUP_EX_SHIFT 2 +#define PLLE_MISC_SETUP_EX_MASK (3 << PLLE_MISC_SETUP_EX_SHIFT) +#define PLLE_MISC_SETUP_MASK (PLLE_MISC_SETUP_BASE_MASK | \ + PLLE_MISC_SETUP_EX_MASK) +#define PLLE_MISC_SETUP_VALUE (7 << PLLE_MISC_SETUP_BASE_SHIFT) + +#define PLLE_SS_CTRL 0x68 +#define PLLE_SS_DISABLE (7 << 10) + +#define PMC_SATA_PWRGT 0x1ac +#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5) +#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4) + +#define pll_readl(offset, p) readl_relaxed(p->clk_base + offset) +#define pll_readl_base(p) pll_readl(p->params->base_reg, p) +#define pll_readl_misc(p) pll_readl(p->params->misc_reg, p) + +#define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset) +#define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p) +#define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p) + +#define mask(w) ((1 << (w)) - 1) +#define divm_mask(p) mask(p->divm_width) +#define divn_mask(p) mask(p->divn_width) +#define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \ + mask(p->divp_width)) + +#define divm_max(p) (divm_mask(p)) +#define divn_max(p) (divn_mask(p)) +#define divp_max(p) (1 << (divp_mask(p))) + +static void clk_pll_enable_lock(struct tegra_clk_pll *pll) +{ + u32 val; + + if (!(pll->flags & TEGRA_PLL_USE_LOCK)) + return; + + val = pll_readl_misc(pll); + val |= BIT(pll->params->lock_enable_bit_idx); + pll_writel_misc(val, pll); +} + +static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll, + void __iomem *lock_addr, u32 lock_bit_idx) +{ + int i; + u32 val; + + if (!(pll->flags & TEGRA_PLL_USE_LOCK)) { + udelay(pll->params->lock_delay); + return 0; + } + + for (i = 0; i < pll->params->lock_delay; i++) { + val = readl_relaxed(lock_addr); + if (val & BIT(lock_bit_idx)) { + udelay(PLL_POST_LOCK_DELAY); + return 0; + } + udelay(2); /* timeout = 2 * lock time */ + } + + pr_err("%s: Timed out waiting for pll %s lock\n", __func__, + __clk_get_name(pll->hw.clk)); + + return -1; +} + +static int clk_pll_is_enabled(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + + if (pll->flags & TEGRA_PLLM) { + val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); + if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) + return val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE ? 1 : 0; + } + + val = pll_readl_base(pll); + + return val & PLL_BASE_ENABLE ? 1 : 0; +} + +static int _clk_pll_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + + clk_pll_enable_lock(pll); + + val = pll_readl_base(pll); + val &= ~PLL_BASE_BYPASS; + val |= PLL_BASE_ENABLE; + pll_writel_base(val, pll); + + if (pll->flags & TEGRA_PLLM) { + val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); + val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; + writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); + } + + clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg, + pll->params->lock_bit_idx); + + return 0; +} + +static void _clk_pll_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + + val = pll_readl_base(pll); + val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); + pll_writel_base(val, pll); + + if (pll->flags & TEGRA_PLLM) { + val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); + val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; + writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); + } +} + +static int clk_pll_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + int ret; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + ret = _clk_pll_enable(hw); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static void clk_pll_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _clk_pll_disable(hw); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); +} + +static int _get_table_rate(struct clk_hw *hw, + struct tegra_clk_pll_freq_table *cfg, + unsigned long rate, unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + struct tegra_clk_pll_freq_table *sel; + + for (sel = pll->freq_table; sel->input_rate != 0; sel++) + if (sel->input_rate == parent_rate && + sel->output_rate == rate) + break; + + if (sel->input_rate == 0) + return -EINVAL; + + BUG_ON(sel->p < 1); + + cfg->input_rate = sel->input_rate; + cfg->output_rate = sel->output_rate; + cfg->m = sel->m; + cfg->n = sel->n; + cfg->p = sel->p; + cfg->cpcon = sel->cpcon; + + return 0; +} + +static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, + unsigned long rate, unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long cfreq; + u32 p_div = 0; + + switch (parent_rate) { + case 12000000: + case 26000000: + cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000; + break; + case 13000000: + cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000; + break; + case 16800000: + case 19200000: + cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000; + break; + case 9600000: + case 28800000: + /* + * PLL_P_OUT1 rate is not listed in PLLA table + */ + cfreq = parent_rate/(parent_rate/1000000); + break; + default: + pr_err("%s Unexpected reference rate %lu\n", + __func__, parent_rate); + BUG(); + } + + /* Raise VCO to guarantee 0.5% accuracy */ + for (cfg->output_rate = rate; cfg->output_rate < 200 * cfreq; + cfg->output_rate <<= 1) + p_div++; + + cfg->p = 1 << p_div; + cfg->m = parent_rate / cfreq; + cfg->n = cfg->output_rate / cfreq; + cfg->cpcon = OUT_OF_TABLE_CPCON; + + if (cfg->m > divm_max(pll) || cfg->n > divn_max(pll) || + cfg->p > divp_max(pll) || cfg->output_rate > pll->params->vco_max) { + pr_err("%s: Failed to set %s rate %lu\n", + __func__, __clk_get_name(hw->clk), rate); + return -EINVAL; + } + + return 0; +} + +static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, + unsigned long rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + u32 divp, val, old_base; + int state; + + divp = __ffs(cfg->p); + + if (pll->flags & TEGRA_PLLU) + divp ^= 1; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + old_base = val = pll_readl_base(pll); + val &= ~((divm_mask(pll) << pll->divm_shift) | + (divn_mask(pll) << pll->divn_shift) | + (divp_mask(pll) << pll->divp_shift)); + val |= ((cfg->m << pll->divm_shift) | + (cfg->n << pll->divn_shift) | + (divp << pll->divp_shift)); + if (val == old_base) { + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + return 0; + } + + state = clk_pll_is_enabled(hw); + + if (state) { + _clk_pll_disable(hw); + val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); + } + pll_writel_base(val, pll); + + if (pll->flags & TEGRA_PLL_HAS_CPCON) { + val = pll_readl_misc(pll); + val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT); + val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT; + if (pll->flags & TEGRA_PLL_SET_LFCON) { + val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT); + if (cfg->n >= PLLDU_LFCON_SET_DIVN) + val |= 0x1 << PLL_MISC_LFCON_SHIFT; + } else if (pll->flags & TEGRA_PLL_SET_DCCON) { + val &= ~(0x1 << PLL_MISC_DCCON_SHIFT); + if (rate >= (pll->params->vco_max >> 1)) + val |= 0x1 << PLL_MISC_DCCON_SHIFT; + } + pll_writel_misc(val, pll); + } + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + if (state) + clk_pll_enable(hw); + + return 0; +} + +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + struct tegra_clk_pll_freq_table cfg; + + if (pll->flags & TEGRA_PLL_FIXED) { + if (rate != pll->fixed_rate) { + pr_err("%s: Can not change %s fixed rate %lu to %lu\n", + __func__, __clk_get_name(hw->clk), + pll->fixed_rate, rate); + return -EINVAL; + } + return 0; + } + + if (_get_table_rate(hw, &cfg, rate, parent_rate) && + _calc_rate(hw, &cfg, rate, parent_rate)) + return -EINVAL; + + return _program_pll(hw, &cfg, rate); +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + struct tegra_clk_pll_freq_table cfg; + u64 output_rate = *prate; + + if (pll->flags & TEGRA_PLL_FIXED) + return pll->fixed_rate; + + /* PLLM is used for memory; we do not change rate */ + if (pll->flags & TEGRA_PLLM) + return __clk_get_rate(hw->clk); + + if (_get_table_rate(hw, &cfg, rate, *prate) && + _calc_rate(hw, &cfg, rate, *prate)) + return -EINVAL; + + output_rate *= cfg.n; + do_div(output_rate, cfg.m * cfg.p); + + return output_rate; +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val = pll_readl_base(pll); + u32 divn = 0, divm = 0, divp = 0; + u64 rate = parent_rate; + + if (val & PLL_BASE_BYPASS) + return parent_rate; + + if ((pll->flags & TEGRA_PLL_FIXED) && !(val & PLL_BASE_OVERRIDE)) { + struct tegra_clk_pll_freq_table sel; + if (_get_table_rate(hw, &sel, pll->fixed_rate, parent_rate)) { + pr_err("Clock %s has unknown fixed frequency\n", + __clk_get_name(hw->clk)); + BUG(); + } + return pll->fixed_rate; + } + + divp = (val >> pll->divp_shift) & (divp_mask(pll)); + if (pll->flags & TEGRA_PLLU) + divp ^= 1; + + divn = (val >> pll->divn_shift) & (divn_mask(pll)); + divm = (val >> pll->divm_shift) & (divm_mask(pll)); + divm *= (1 << divp); + + rate *= divn; + do_div(rate, divm); + return rate; +} + +static int clk_plle_training(struct tegra_clk_pll *pll) +{ + u32 val; + unsigned long timeout; + + if (!pll->pmc) + return -ENOSYS; + + /* + * PLLE is already disabled, and setup cleared; + * create falling edge on PLLE IDDQ input. + */ + val = readl(pll->pmc + PMC_SATA_PWRGT); + val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; + writel(val, pll->pmc + PMC_SATA_PWRGT); + + val = readl(pll->pmc + PMC_SATA_PWRGT); + val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL; + writel(val, pll->pmc + PMC_SATA_PWRGT); + + val = readl(pll->pmc + PMC_SATA_PWRGT); + val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; + writel(val, pll->pmc + PMC_SATA_PWRGT); + + val = pll_readl_misc(pll); + + timeout = jiffies + msecs_to_jiffies(100); + while (1) { + val = pll_readl_misc(pll); + if (val & PLLE_MISC_READY) + break; + if (time_after(jiffies, timeout)) { + pr_err("%s: timeout waiting for PLLE\n", __func__); + return -EBUSY; + } + udelay(300); + } + + return 0; +} + +static int clk_plle_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk)); + struct tegra_clk_pll_freq_table sel; + u32 val; + int err; + + if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) + return -EINVAL; + + clk_pll_disable(hw); + + val = pll_readl_misc(pll); + val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK); + pll_writel_misc(val, pll); + + val = pll_readl_misc(pll); + if (!(val & PLLE_MISC_READY)) { + err = clk_plle_training(pll); + if (err) + return err; + } + + if (pll->flags & TEGRA_PLLE_CONFIGURE) { + /* configure dividers */ + val = pll_readl_base(pll); + val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll)); + val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); + val |= sel.m << pll->divm_shift; + val |= sel.n << pll->divn_shift; + val |= sel.p << pll->divp_shift; + val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; + pll_writel_base(val, pll); + } + + val = pll_readl_misc(pll); + val |= PLLE_MISC_SETUP_VALUE; + val |= PLLE_MISC_LOCK_ENABLE; + pll_writel_misc(val, pll); + + val = readl(pll->clk_base + PLLE_SS_CTRL); + val |= PLLE_SS_DISABLE; + writel(val, pll->clk_base + PLLE_SS_CTRL); + + val |= pll_readl_base(pll); + val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE); + pll_writel_base(val, pll); + + clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg, + pll->params->lock_bit_idx); + return 0; +} + +static unsigned long clk_plle_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val = pll_readl_base(pll); + u32 divn = 0, divm = 0, divp = 0; + u64 rate = parent_rate; + + divp = (val >> pll->divp_shift) & (divp_mask(pll)); + divn = (val >> pll->divn_shift) & (divn_mask(pll)); + divm = (val >> pll->divm_shift) & (divm_mask(pll)); + divm *= divp; + + rate *= divn; + do_div(rate, divm); + return rate; +} + +const struct clk_ops tegra_clk_pll_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_pll_enable, + .disable = clk_pll_disable, + .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_round_rate, + .set_rate = clk_pll_set_rate, +}; + +const struct clk_ops tegra_clk_plle_ops = { + .recalc_rate = clk_plle_recalc_rate, + .is_enabled = clk_pll_is_enabled, + .disable = clk_pll_disable, + .enable = clk_plle_enable, +}; + +static struct clk *_tegra_clk_register_pll(const char *name, + const char *parent_name, void __iomem *clk_base, + void __iomem *pmc, unsigned long flags, + unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock, + const struct clk_ops *ops) +{ + struct tegra_clk_pll *pll; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + pll->clk_base = clk_base; + pll->pmc = pmc; + + pll->freq_table = freq_table; + pll->params = pll_params; + pll->fixed_rate = fixed_rate; + pll->flags = pll_flags; + pll->lock = lock; + + pll->divp_shift = PLL_BASE_DIVP_SHIFT; + pll->divp_width = PLL_BASE_DIVP_WIDTH; + pll->divn_shift = PLL_BASE_DIVN_SHIFT; + pll->divn_width = PLL_BASE_DIVN_WIDTH; + pll->divm_shift = PLL_BASE_DIVM_SHIFT; + pll->divm_width = PLL_BASE_DIVM_WIDTH; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + +struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) +{ + return _tegra_clk_register_pll(name, parent_name, clk_base, pmc, + flags, fixed_rate, pll_params, pll_flags, freq_table, + lock, &tegra_clk_pll_ops); +} + +struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) +{ + return _tegra_clk_register_pll(name, parent_name, clk_base, pmc, + flags, fixed_rate, pll_params, pll_flags, freq_table, + lock, &tegra_clk_plle_ops); +} diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c new file mode 100644 index 000000000000..7ad48a832334 --- /dev/null +++ b/drivers/clk/tegra/clk-super.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define SUPER_STATE_IDLE 0 +#define SUPER_STATE_RUN 1 +#define SUPER_STATE_IRQ 2 +#define SUPER_STATE_FIQ 3 + +#define SUPER_STATE_SHIFT 28 +#define SUPER_STATE_MASK ((BIT(SUPER_STATE_IDLE) | BIT(SUPER_STATE_RUN) | \ + BIT(SUPER_STATE_IRQ) | BIT(SUPER_STATE_FIQ)) \ + << SUPER_STATE_SHIFT) + +#define SUPER_LP_DIV2_BYPASS (1 << 16) + +#define super_state(s) (BIT(s) << SUPER_STATE_SHIFT) +#define super_state_to_src_shift(m, s) ((m->width * s)) +#define super_state_to_src_mask(m) (((1 << m->width) - 1)) + +static u8 clk_super_get_parent(struct clk_hw *hw) +{ + struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); + u32 val, state; + u8 source, shift; + + val = readl_relaxed(mux->reg); + + state = val & SUPER_STATE_MASK; + + BUG_ON((state != super_state(SUPER_STATE_RUN)) && + (state != super_state(SUPER_STATE_IDLE))); + shift = (state == super_state(SUPER_STATE_IDLE)) ? + super_state_to_src_shift(mux, SUPER_STATE_IDLE) : + super_state_to_src_shift(mux, SUPER_STATE_RUN); + + source = (val >> shift) & super_state_to_src_mask(mux); + + /* + * If LP_DIV2_BYPASS is not set and PLLX is current parent then + * PLLX/2 is the input source to CCLKLP. + */ + if ((mux->flags & TEGRA_DIVIDER_2) && !(val & SUPER_LP_DIV2_BYPASS) && + (source == mux->pllx_index)) + source = mux->div2_index; + + return source; +} + +static int clk_super_set_parent(struct clk_hw *hw, u8 index) +{ + struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); + u32 val, state; + u8 parent_index, shift; + + val = readl_relaxed(mux->reg); + state = val & SUPER_STATE_MASK; + BUG_ON((state != super_state(SUPER_STATE_RUN)) && + (state != super_state(SUPER_STATE_IDLE))); + shift = (state == super_state(SUPER_STATE_IDLE)) ? + super_state_to_src_shift(mux, SUPER_STATE_IDLE) : + super_state_to_src_shift(mux, SUPER_STATE_RUN); + + /* + * For LP mode super-clock switch between PLLX direct + * and divided-by-2 outputs is allowed only when other + * than PLLX clock source is current parent. + */ + if ((mux->flags & TEGRA_DIVIDER_2) && ((index == mux->div2_index) || + (index == mux->pllx_index))) { + parent_index = clk_super_get_parent(hw); + if ((parent_index == mux->div2_index) || + (parent_index == mux->pllx_index)) + return -EINVAL; + + val ^= SUPER_LP_DIV2_BYPASS; + writel_relaxed(val, mux->reg); + udelay(2); + + if (index == mux->div2_index) + index = mux->pllx_index; + } + val &= ~((super_state_to_src_mask(mux)) << shift); + val |= (index & (super_state_to_src_mask(mux))) << shift; + + writel_relaxed(val, mux->reg); + udelay(2); + return 0; +} + +const struct clk_ops tegra_clk_super_ops = { + .get_parent = clk_super_get_parent, + .set_parent = clk_super_set_parent, +}; + +struct clk *tegra_clk_register_super_mux(const char *name, + const char **parent_names, u8 num_parents, + unsigned long flags, void __iomem *reg, u8 clk_super_flags, + u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock) +{ + struct tegra_clk_super_mux *super; + struct clk *clk; + struct clk_init_data init; + + super = kzalloc(sizeof(*super), GFP_KERNEL); + if (!super) { + pr_err("%s: could not allocate super clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &tegra_clk_super_ops; + init.flags = flags; + init.parent_names = parent_names; + init.num_parents = num_parents; + + super->reg = reg; + super->pllx_index = pllx_index; + super->div2_index = div2_index; + super->lock = lock; + super->width = width; + super->flags = clk_super_flags; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + super->hw.init = &init; + + clk = clk_register(NULL, &super->hw); + if (IS_ERR(clk)) + kfree(super); + + return clk; +} diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c new file mode 100644 index 000000000000..cf023a937208 --- /dev/null +++ b/drivers/clk/tegra/clk.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "clk.h" + +void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, + struct clk *clks[], int clk_max) +{ + struct clk *clk; + + for (; dup_list->clk_id < clk_max; dup_list++) { + clk = clks[dup_list->clk_id]; + dup_list->lookup.clk = clk; + clkdev_add(&dup_list->lookup); + } +} + +void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, + struct clk *clks[], int clk_max) +{ + struct clk *clk; + + for (; tbl->clk_id < clk_max; tbl++) { + clk = clks[tbl->clk_id]; + if (IS_ERR_OR_NULL(clk)) + return; + + if (tbl->parent_id < clk_max) { + struct clk *parent = clks[tbl->parent_id]; + if (clk_set_parent(clk, parent)) { + pr_err("%s: Failed to set parent %s of %s\n", + __func__, __clk_get_name(parent), + __clk_get_name(clk)); + WARN_ON(1); + } + } + + if (tbl->rate) + if (clk_set_rate(clk, tbl->rate)) { + pr_err("%s: Failed to set rate %lu of %s\n", + __func__, tbl->rate, + __clk_get_name(clk)); + WARN_ON(1); + } + + if (tbl->state) + if (clk_prepare_enable(clk)) { + pr_err("%s: Failed to enable %s\n", __func__, + __clk_get_name(clk)); + WARN_ON(1); + } + } +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h new file mode 100644 index 000000000000..5fcfa51d6b17 --- /dev/null +++ b/drivers/clk/tegra/clk.h @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TEGRA_CLK_H +#define __TEGRA_CLK_H + +#include +#include + +/** + * struct tegra_clk_sync_source - external clock source from codec + * + * @hw: handle between common and hardware-specific interfaces + * @rate: input frequency from source + * @max_rate: max rate allowed + */ +struct tegra_clk_sync_source { + struct clk_hw hw; + unsigned long rate; + unsigned long max_rate; +}; + +#define to_clk_sync_source(_hw) \ + container_of(_hw, struct tegra_clk_sync_source, hw) + +extern const struct clk_ops tegra_clk_sync_source_ops; +struct clk *tegra_clk_register_sync_source(const char *name, + unsigned long fixed_rate, unsigned long max_rate); + +/** + * struct tegra_clk_frac_div - fractional divider clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register containing divider + * @flags: hardware-specific flags + * @shift: shift to the divider bit field + * @width: width of the divider bit field + * @frac_width: width of the fractional bit field + * @lock: register lock + * + * Flags: + * TEGRA_DIVIDER_ROUND_UP - This flags indicates to round up the divider value. + * TEGRA_DIVIDER_FIXED - Fixed rate PLL dividers has addition override bit, this + * flag indicates that this divider is for fixed rate PLL. + * TEGRA_DIVIDER_INT - Some modules can not cope with the duty cycle when + * fraction bit is set. This flags indicates to calculate divider for which + * fracton bit will be zero. + * TEGRA_DIVIDER_UART - UART module divider has additional enable bit which is + * set when divider value is not 0. This flags indicates that the divider + * is for UART module. + */ +struct tegra_clk_frac_div { + struct clk_hw hw; + void __iomem *reg; + u8 flags; + u8 shift; + u8 width; + u8 frac_width; + spinlock_t *lock; +}; + +#define to_clk_frac_div(_hw) container_of(_hw, struct tegra_clk_frac_div, hw) + +#define TEGRA_DIVIDER_ROUND_UP BIT(0) +#define TEGRA_DIVIDER_FIXED BIT(1) +#define TEGRA_DIVIDER_INT BIT(2) +#define TEGRA_DIVIDER_UART BIT(3) + +extern const struct clk_ops tegra_clk_frac_div_ops; +struct clk *tegra_clk_register_divider(const char *name, + const char *parent_name, void __iomem *reg, + unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width, + u8 frac_width, spinlock_t *lock); + +/* + * Tegra PLL: + * + * In general, there are 3 requirements for each PLL + * that SW needs to be comply with. + * (1) Input frequency range (REF). + * (2) Comparison frequency range (CF). CF = REF/DIVM. + * (3) VCO frequency range (VCO). VCO = CF * DIVN. + * + * The final PLL output frequency (FO) = VCO >> DIVP. + */ + +/** + * struct tegra_clk_pll_freq_table - PLL frequecy table + * + * @input_rate: input rate from source + * @output_rate: output rate from PLL for the input rate + * @n: feedback divider + * @m: input divider + * @p: post divider + * @cpcon: charge pump current + */ +struct tegra_clk_pll_freq_table { + unsigned long input_rate; + unsigned long output_rate; + u16 n; + u16 m; + u8 p; + u8 cpcon; +}; + +/** + * struct clk_pll_params - PLL parameters + * + * @input_min: Minimum input frequency + * @input_max: Maximum input frequency + * @cf_min: Minimum comparison frequency + * @cf_max: Maximum comparison frequency + * @vco_min: Minimum VCO frequency + * @vco_max: Maximum VCO frequency + * @base_reg: PLL base reg offset + * @misc_reg: PLL misc reg offset + * @lock_reg: PLL lock reg offset + * @lock_bit_idx: Bit index for PLL lock status + * @lock_enable_bit_idx: Bit index to enable PLL lock + * @lock_delay: Delay in us if PLL lock is not used + */ +struct tegra_clk_pll_params { + unsigned long input_min; + unsigned long input_max; + unsigned long cf_min; + unsigned long cf_max; + unsigned long vco_min; + unsigned long vco_max; + + u32 base_reg; + u32 misc_reg; + u32 lock_reg; + u32 lock_bit_idx; + u32 lock_enable_bit_idx; + int lock_delay; +}; + +/** + * struct tegra_clk_pll - Tegra PLL clock + * + * @hw: handle between common and hardware-specifix interfaces + * @clk_base: address of CAR controller + * @pmc: address of PMC, required to read override bits + * @freq_table: array of frequencies supported by PLL + * @params: PLL parameters + * @flags: PLL flags + * @fixed_rate: PLL rate if it is fixed + * @lock: register lock + * @divn_shift: shift to the feedback divider bit field + * @divn_width: width of the feedback divider bit field + * @divm_shift: shift to the input divider bit field + * @divm_width: width of the input divider bit field + * @divp_shift: shift to the post divider bit field + * @divp_width: width of the post divider bit field + * + * Flags: + * TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for + * PLL locking. If not set it will use lock_delay value to wait. + * TEGRA_PLL_HAS_CPCON - This flag indicates that CPCON value needs + * to be programmed to change output frequency of the PLL. + * TEGRA_PLL_SET_LFCON - This flag indicates that LFCON value needs + * to be programmed to change output frequency of the PLL. + * TEGRA_PLL_SET_DCCON - This flag indicates that DCCON value needs + * to be programmed to change output frequency of the PLL. + * TEGRA_PLLU - PLLU has inverted post divider. This flags indicated + * that it is PLLU and invert post divider value. + * TEGRA_PLLM - PLLM has additional override settings in PMC. This + * flag indicates that it is PLLM and use override settings. + * TEGRA_PLL_FIXED - We are not supposed to change output frequency + * of some plls. + * TEGRA_PLLE_CONFIGURE - Configure PLLE when enabling. + */ +struct tegra_clk_pll { + struct clk_hw hw; + void __iomem *clk_base; + void __iomem *pmc; + u8 flags; + unsigned long fixed_rate; + spinlock_t *lock; + u8 divn_shift; + u8 divn_width; + u8 divm_shift; + u8 divm_width; + u8 divp_shift; + u8 divp_width; + struct tegra_clk_pll_freq_table *freq_table; + struct tegra_clk_pll_params *params; +}; + +#define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw) + +#define TEGRA_PLL_USE_LOCK BIT(0) +#define TEGRA_PLL_HAS_CPCON BIT(1) +#define TEGRA_PLL_SET_LFCON BIT(2) +#define TEGRA_PLL_SET_DCCON BIT(3) +#define TEGRA_PLLU BIT(4) +#define TEGRA_PLLM BIT(5) +#define TEGRA_PLL_FIXED BIT(6) +#define TEGRA_PLLE_CONFIGURE BIT(7) + +extern const struct clk_ops tegra_clk_pll_ops; +extern const struct clk_ops tegra_clk_plle_ops; +struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); +struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); + +/** + * struct tegra_clk_pll_out - PLL divider down clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register containing the PLL divider + * @enb_bit_idx: bit to enable/disable PLL divider + * @rst_bit_idx: bit to reset PLL divider + * @lock: register lock + * @flags: hardware-specific flags + */ +struct tegra_clk_pll_out { + struct clk_hw hw; + void __iomem *reg; + u8 enb_bit_idx; + u8 rst_bit_idx; + spinlock_t *lock; + u8 flags; +}; + +#define to_clk_pll_out(_hw) container_of(_hw, struct tegra_clk_pll_out, hw) + +extern const struct clk_ops tegra_clk_pll_out_ops; +struct clk *tegra_clk_register_pll_out(const char *name, + const char *parent_name, void __iomem *reg, u8 enb_bit_idx, + u8 rst_bit_idx, unsigned long flags, u8 pll_div_flags, + spinlock_t *lock); + +/** + * struct tegra_clk_periph_regs - Registers controlling peripheral clock + * + * @enb_reg: read the enable status + * @enb_set_reg: write 1 to enable clock + * @enb_clr_reg: write 1 to disable clock + * @rst_reg: read the reset status + * @rst_set_reg: write 1 to assert the reset of peripheral + * @rst_clr_reg: write 1 to deassert the reset of peripheral + */ +struct tegra_clk_periph_regs { + u32 enb_reg; + u32 enb_set_reg; + u32 enb_clr_reg; + u32 rst_reg; + u32 rst_set_reg; + u32 rst_clr_reg; +}; + +/** + * struct tegra_clk_periph_gate - peripheral gate clock + * + * @magic: magic number to validate type + * @hw: handle between common and hardware-specific interfaces + * @clk_base: address of CAR controller + * @regs: Registers to control the peripheral + * @flags: hardware-specific flags + * @clk_num: Clock number + * @enable_refcnt: array to maintain reference count of the clock + * + * Flags: + * TEGRA_PERIPH_NO_RESET - This flag indicates that reset is not allowed + * for this module. + * TEGRA_PERIPH_MANUAL_RESET - This flag indicates not to reset module + * after clock enable and driver for the module is responsible for + * doing reset. + * TEGRA_PERIPH_ON_APB - If peripheral is in the APB bus then read the + * bus to flush the write operation in apb bus. This flag indicates + * that this peripheral is in apb bus. + */ +struct tegra_clk_periph_gate { + u32 magic; + struct clk_hw hw; + void __iomem *clk_base; + u8 flags; + int clk_num; + int *enable_refcnt; + struct tegra_clk_periph_regs *regs; +}; + +#define to_clk_periph_gate(_hw) \ + container_of(_hw, struct tegra_clk_periph_gate, hw) + +#define TEGRA_CLK_PERIPH_GATE_MAGIC 0x17760309 + +#define TEGRA_PERIPH_NO_RESET BIT(0) +#define TEGRA_PERIPH_MANUAL_RESET BIT(1) +#define TEGRA_PERIPH_ON_APB BIT(2) + +void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert); +extern const struct clk_ops tegra_clk_periph_gate_ops; +struct clk *tegra_clk_register_periph_gate(const char *name, + const char *parent_name, u8 gate_flags, void __iomem *clk_base, + unsigned long flags, int clk_num, + struct tegra_clk_periph_regs *pregs, int *enable_refcnt); + +/** + * struct clk-periph - peripheral clock + * + * @magic: magic number to validate type + * @hw: handle between common and hardware-specific interfaces + * @mux: mux clock + * @divider: divider clock + * @gate: gate clock + * @mux_ops: mux clock ops + * @div_ops: divider clock ops + * @gate_ops: gate clock ops + */ +struct tegra_clk_periph { + u32 magic; + struct clk_hw hw; + struct clk_mux mux; + struct tegra_clk_frac_div divider; + struct tegra_clk_periph_gate gate; + + const struct clk_ops *mux_ops; + const struct clk_ops *div_ops; + const struct clk_ops *gate_ops; +}; + +#define to_clk_periph(_hw) container_of(_hw, struct tegra_clk_periph, hw) + +#define TEGRA_CLK_PERIPH_MAGIC 0x18221223 + +extern const struct clk_ops tegra_clk_periph_ops; +struct clk *tegra_clk_register_periph(const char *name, + const char **parent_names, int num_parents, + struct tegra_clk_periph *periph, void __iomem *clk_base, + u32 offset); +struct clk *tegra_clk_register_periph_nodiv(const char *name, + const char **parent_names, int num_parents, + struct tegra_clk_periph *periph, void __iomem *clk_base, + u32 offset); + +#define TEGRA_CLK_PERIPH(_mux_shift, _mux_width, _mux_flags, \ + _div_shift, _div_width, _div_frac_width, \ + _div_flags, _clk_num, _enb_refcnt, _regs, \ + _gate_flags) \ + { \ + .mux = { \ + .flags = _mux_flags, \ + .shift = _mux_shift, \ + .width = _mux_width, \ + }, \ + .divider = { \ + .flags = _div_flags, \ + .shift = _div_shift, \ + .width = _div_width, \ + .frac_width = _div_frac_width, \ + }, \ + .gate = { \ + .flags = _gate_flags, \ + .clk_num = _clk_num, \ + .enable_refcnt = _enb_refcnt, \ + .regs = _regs, \ + }, \ + .mux_ops = &clk_mux_ops, \ + .div_ops = &tegra_clk_frac_div_ops, \ + .gate_ops = &tegra_clk_periph_gate_ops, \ + } + +struct tegra_periph_init_data { + const char *name; + int clk_id; + const char **parent_names; + int num_parents; + struct tegra_clk_periph periph; + u32 offset; + const char *con_id; + const char *dev_id; +}; + +#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset, \ + _mux_shift, _mux_width, _mux_flags, _div_shift, \ + _div_width, _div_frac_width, _div_flags, _regs, \ + _clk_num, _enb_refcnt, _gate_flags, _clk_id) \ + { \ + .name = _name, \ + .clk_id = _clk_id, \ + .parent_names = _parent_names, \ + .num_parents = ARRAY_SIZE(_parent_names), \ + .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width, \ + _mux_flags, _div_shift, \ + _div_width, _div_frac_width, \ + _div_flags, _clk_num, \ + _enb_refcnt, _regs, \ + _gate_flags), \ + .offset = _offset, \ + .con_id = _con_id, \ + .dev_id = _dev_id, \ + } + +/** + * struct clk_super_mux - super clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register controlling multiplexer + * @width: width of the multiplexer bit field + * @flags: hardware-specific flags + * @div2_index: bit controlling divide-by-2 + * @pllx_index: PLLX index in the parent list + * @lock: register lock + * + * Flags: + * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates + * that this is LP cluster clock. + */ +struct tegra_clk_super_mux { + struct clk_hw hw; + void __iomem *reg; + u8 width; + u8 flags; + u8 div2_index; + u8 pllx_index; + spinlock_t *lock; +}; + +#define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw) + +#define TEGRA_DIVIDER_2 BIT(0) + +extern const struct clk_ops tegra_clk_super_ops; +struct clk *tegra_clk_register_super_mux(const char *name, + const char **parent_names, u8 num_parents, + unsigned long flags, void __iomem *reg, u8 clk_super_flags, + u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock); + +/** + * struct clk_init_tabel - clock initialization table + * @clk_id: clock id as mentioned in device tree bindings + * @parent_id: parent clock id as mentioned in device tree bindings + * @rate: rate to set + * @state: enable/disable + */ +struct tegra_clk_init_table { + unsigned int clk_id; + unsigned int parent_id; + unsigned long rate; + int state; +}; + +/** + * struct clk_duplicate - duplicate clocks + * @clk_id: clock id as mentioned in device tree bindings + * @lookup: duplicate lookup entry for the clock + */ +struct tegra_clk_duplicate { + int clk_id; + struct clk_lookup lookup; +}; + +#define TEGRA_CLK_DUPLICATE(_clk_id, _dev, _con) \ + { \ + .clk_id = _clk_id, \ + .lookup = { \ + .dev_id = _dev, \ + .con_id = _con, \ + }, \ + } + +void tegra_init_from_table(struct tegra_clk_init_table *tbl, + struct clk *clks[], int clk_max); + +void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, + struct clk *clks[], int clk_max); + +#endif /* TEGRA_CLK_H */ From 37c26a906527b8a6a252614ca83d21ad318c4e84 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:24 +0530 Subject: [PATCH 18/31] clk: tegra: add clock support for Tegra20 Add Tegra20 clock support based on common clock framework. Signed-off-by: Prashant Gaikwad [swarren: s/1GHz/100MHz/ in call to tegra_clk_plle() to fix PCIe, implemented KBC clock, ensure all OF lookups return valid cookies i.e. an explicit error pointer or valid pointer not NULL, adapt to renames in earlier patches, fixed some checkpatch issues.] Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/Makefile | 2 + drivers/clk/tegra/clk-tegra20.c | 1273 +++++++++++++++++++++++++++++++ drivers/clk/tegra/clk.h | 6 + 3 files changed, 1281 insertions(+) create mode 100644 drivers/clk/tegra/clk-tegra20.c diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index 68bd353a2108..00484fd4e515 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -6,3 +6,5 @@ obj-y += clk-periph-gate.o obj-y += clk-pll.o obj-y += clk-pll-out.o obj-y += clk-super.o + +obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c new file mode 100644 index 000000000000..4ae8287b0f81 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra20.c @@ -0,0 +1,1273 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define RST_DEVICES_L 0x004 +#define RST_DEVICES_H 0x008 +#define RST_DEVICES_U 0x00c +#define RST_DEVICES_SET_L 0x300 +#define RST_DEVICES_CLR_L 0x304 +#define RST_DEVICES_SET_H 0x308 +#define RST_DEVICES_CLR_H 0x30c +#define RST_DEVICES_SET_U 0x310 +#define RST_DEVICES_CLR_U 0x314 +#define RST_DEVICES_NUM 3 + +#define CLK_OUT_ENB_L 0x010 +#define CLK_OUT_ENB_H 0x014 +#define CLK_OUT_ENB_U 0x018 +#define CLK_OUT_ENB_SET_L 0x320 +#define CLK_OUT_ENB_CLR_L 0x324 +#define CLK_OUT_ENB_SET_H 0x328 +#define CLK_OUT_ENB_CLR_H 0x32c +#define CLK_OUT_ENB_SET_U 0x330 +#define CLK_OUT_ENB_CLR_U 0x334 +#define CLK_OUT_ENB_NUM 3 + +#define OSC_CTRL 0x50 +#define OSC_CTRL_OSC_FREQ_MASK (3<<30) +#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30) +#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30) +#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30) +#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30) +#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK) + +#define OSC_CTRL_PLL_REF_DIV_MASK (3<<28) +#define OSC_CTRL_PLL_REF_DIV_1 (0<<28) +#define OSC_CTRL_PLL_REF_DIV_2 (1<<28) +#define OSC_CTRL_PLL_REF_DIV_4 (2<<28) + +#define OSC_FREQ_DET 0x58 +#define OSC_FREQ_DET_TRIG (1<<31) + +#define OSC_FREQ_DET_STATUS 0x5c +#define OSC_FREQ_DET_BUSY (1<<31) +#define OSC_FREQ_DET_CNT_MASK 0xFFFF + +#define PLLS_BASE 0xf0 +#define PLLS_MISC 0xf4 +#define PLLC_BASE 0x80 +#define PLLC_MISC 0x8c +#define PLLM_BASE 0x90 +#define PLLM_MISC 0x9c +#define PLLP_BASE 0xa0 +#define PLLP_MISC 0xac +#define PLLA_BASE 0xb0 +#define PLLA_MISC 0xbc +#define PLLU_BASE 0xc0 +#define PLLU_MISC 0xcc +#define PLLD_BASE 0xd0 +#define PLLD_MISC 0xdc +#define PLLX_BASE 0xe0 +#define PLLX_MISC 0xe4 +#define PLLE_BASE 0xe8 +#define PLLE_MISC 0xec + +#define PLL_BASE_LOCK 27 +#define PLLE_MISC_LOCK 11 + +#define PLL_MISC_LOCK_ENABLE 18 +#define PLLDU_MISC_LOCK_ENABLE 22 +#define PLLE_MISC_LOCK_ENABLE 9 + +#define PLLC_OUT 0x84 +#define PLLM_OUT 0x94 +#define PLLP_OUTA 0xa4 +#define PLLP_OUTB 0xa8 +#define PLLA_OUT 0xb4 + +#define CCLK_BURST_POLICY 0x20 +#define SUPER_CCLK_DIVIDER 0x24 +#define SCLK_BURST_POLICY 0x28 +#define SUPER_SCLK_DIVIDER 0x2c +#define CLK_SYSTEM_RATE 0x30 + +#define CLK_SOURCE_I2S1 0x100 +#define CLK_SOURCE_I2S2 0x104 +#define CLK_SOURCE_SPDIF_OUT 0x108 +#define CLK_SOURCE_SPDIF_IN 0x10c +#define CLK_SOURCE_PWM 0x110 +#define CLK_SOURCE_SPI 0x114 +#define CLK_SOURCE_SBC1 0x134 +#define CLK_SOURCE_SBC2 0x118 +#define CLK_SOURCE_SBC3 0x11c +#define CLK_SOURCE_SBC4 0x1b4 +#define CLK_SOURCE_XIO 0x120 +#define CLK_SOURCE_TWC 0x12c +#define CLK_SOURCE_IDE 0x144 +#define CLK_SOURCE_NDFLASH 0x160 +#define CLK_SOURCE_VFIR 0x168 +#define CLK_SOURCE_SDMMC1 0x150 +#define CLK_SOURCE_SDMMC2 0x154 +#define CLK_SOURCE_SDMMC3 0x1bc +#define CLK_SOURCE_SDMMC4 0x164 +#define CLK_SOURCE_CVE 0x140 +#define CLK_SOURCE_TVO 0x188 +#define CLK_SOURCE_TVDAC 0x194 +#define CLK_SOURCE_HDMI 0x18c +#define CLK_SOURCE_DISP1 0x138 +#define CLK_SOURCE_DISP2 0x13c +#define CLK_SOURCE_CSITE 0x1d4 +#define CLK_SOURCE_LA 0x1f8 +#define CLK_SOURCE_OWR 0x1cc +#define CLK_SOURCE_NOR 0x1d0 +#define CLK_SOURCE_MIPI 0x174 +#define CLK_SOURCE_I2C1 0x124 +#define CLK_SOURCE_I2C2 0x198 +#define CLK_SOURCE_I2C3 0x1b8 +#define CLK_SOURCE_DVC 0x128 +#define CLK_SOURCE_UARTA 0x178 +#define CLK_SOURCE_UARTB 0x17c +#define CLK_SOURCE_UARTC 0x1a0 +#define CLK_SOURCE_UARTD 0x1c0 +#define CLK_SOURCE_UARTE 0x1c4 +#define CLK_SOURCE_3D 0x158 +#define CLK_SOURCE_2D 0x15c +#define CLK_SOURCE_MPE 0x170 +#define CLK_SOURCE_EPP 0x16c +#define CLK_SOURCE_HOST1X 0x180 +#define CLK_SOURCE_VDE 0x1c8 +#define CLK_SOURCE_VI 0x148 +#define CLK_SOURCE_VI_SENSOR 0x1a8 +#define CLK_SOURCE_EMC 0x19c + +#define AUDIO_SYNC_CLK 0x38 + +#define PMC_CTRL 0x0 +#define PMC_CTRL_BLINK_ENB 7 +#define PMC_DPD_PADS_ORIDE 0x1c +#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 +#define PMC_BLINK_TIMER 0x40 + +/* Tegra CPU clock and reset control regs */ +#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c +#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 +#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344 + +#define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) +#define CPU_RESET(cpu) (0x1111ul << (cpu)) + +static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; + +static void __iomem *clk_base; +static void __iomem *pmc_base; + +static DEFINE_SPINLOCK(pll_div_lock); + +#define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, \ + _regs, _clk_num, periph_clk_enb_refcnt, \ + _gate_flags, _clk_id) + +#define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id) + +#define TEGRA_INIT_DATA_DIV16(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id) + +#define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \ + _mux_shift, _mux_width, _clk_num, _regs, \ + _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + _mux_shift, _mux_width, 0, 0, 0, 0, 0, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id) + +/* IDs assigned here must be in sync with DT bindings definition + * for Tegra20 clocks . + */ +enum tegra20_clk { + cpu, ac97 = 3, rtc, timer, uarta, gpio = 8, sdmmc2, i2s1 = 11, i2c1, + ndflash, sdmmc1, sdmmc4, twc, pwm, i2s2, epp, gr2d = 21, usbd, isp, + gr3d, ide, disp2, disp1, host1x, vcp, cache2 = 31, mem, ahbdma, apbdma, + kbc = 36, stat_mon, pmc, fuse, kfuse, sbc1, nor, spi, sbc2, xio, sbc3, + dvc, dsi, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2, + usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3, + pex, owr, afi, csite, pcie_xclk, avpucq = 75, la, irama = 84, iramb, + iramc, iramd, cram2, audio_2x, clk_d, csus = 92, cdev1, cdev2, + uartb = 96, vfir, spdif_in, spdif_out, vi, vi_sensor, tvo, cve, + osc, clk_32k, clk_m, sclk, cclk, hclk, pclk, blink, pll_a, pll_a_out0, + pll_c, pll_c_out1, pll_d, pll_d_out0, pll_e, pll_m, pll_m_out1, + pll_p, pll_p_out1, pll_p_out2, pll_p_out3, pll_p_out4, pll_u, + pll_x, audio, pll_ref, twd, clk_max, +}; + +static struct clk *clks[clk_max]; +static struct clk_onecell_data clk_data; + +static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { + { 12000000, 600000000, 600, 12, 1, 8 }, + { 13000000, 600000000, 600, 13, 1, 8 }, + { 19200000, 600000000, 500, 16, 1, 6 }, + { 26000000, 600000000, 600, 26, 1, 8 }, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_m_freq_table[] = { + { 12000000, 666000000, 666, 12, 1, 8}, + { 13000000, 666000000, 666, 13, 1, 8}, + { 19200000, 666000000, 555, 16, 1, 8}, + { 26000000, 666000000, 666, 26, 1, 8}, + { 12000000, 600000000, 600, 12, 1, 8}, + { 13000000, 600000000, 600, 13, 1, 8}, + { 19200000, 600000000, 375, 12, 1, 6}, + { 26000000, 600000000, 600, 26, 1, 8}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { + { 12000000, 216000000, 432, 12, 2, 8}, + { 13000000, 216000000, 432, 13, 2, 8}, + { 19200000, 216000000, 90, 4, 2, 1}, + { 26000000, 216000000, 432, 26, 2, 8}, + { 12000000, 432000000, 432, 12, 1, 8}, + { 13000000, 432000000, 432, 13, 1, 8}, + { 19200000, 432000000, 90, 4, 1, 1}, + { 26000000, 432000000, 432, 26, 1, 8}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { + { 28800000, 56448000, 49, 25, 1, 1}, + { 28800000, 73728000, 64, 25, 1, 1}, + { 28800000, 24000000, 5, 6, 1, 1}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { + { 12000000, 216000000, 216, 12, 1, 4}, + { 13000000, 216000000, 216, 13, 1, 4}, + { 19200000, 216000000, 135, 12, 1, 3}, + { 26000000, 216000000, 216, 26, 1, 4}, + + { 12000000, 594000000, 594, 12, 1, 8}, + { 13000000, 594000000, 594, 13, 1, 8}, + { 19200000, 594000000, 495, 16, 1, 8}, + { 26000000, 594000000, 594, 26, 1, 8}, + + { 12000000, 1000000000, 1000, 12, 1, 12}, + { 13000000, 1000000000, 1000, 13, 1, 12}, + { 19200000, 1000000000, 625, 12, 1, 8}, + { 26000000, 1000000000, 1000, 26, 1, 12}, + + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { + { 12000000, 480000000, 960, 12, 2, 0}, + { 13000000, 480000000, 960, 13, 2, 0}, + { 19200000, 480000000, 200, 4, 2, 0}, + { 26000000, 480000000, 960, 26, 2, 0}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { + /* 1 GHz */ + { 12000000, 1000000000, 1000, 12, 1, 12}, + { 13000000, 1000000000, 1000, 13, 1, 12}, + { 19200000, 1000000000, 625, 12, 1, 8}, + { 26000000, 1000000000, 1000, 26, 1, 12}, + + /* 912 MHz */ + { 12000000, 912000000, 912, 12, 1, 12}, + { 13000000, 912000000, 912, 13, 1, 12}, + { 19200000, 912000000, 760, 16, 1, 8}, + { 26000000, 912000000, 912, 26, 1, 12}, + + /* 816 MHz */ + { 12000000, 816000000, 816, 12, 1, 12}, + { 13000000, 816000000, 816, 13, 1, 12}, + { 19200000, 816000000, 680, 16, 1, 8}, + { 26000000, 816000000, 816, 26, 1, 12}, + + /* 760 MHz */ + { 12000000, 760000000, 760, 12, 1, 12}, + { 13000000, 760000000, 760, 13, 1, 12}, + { 19200000, 760000000, 950, 24, 1, 8}, + { 26000000, 760000000, 760, 26, 1, 12}, + + /* 750 MHz */ + { 12000000, 750000000, 750, 12, 1, 12}, + { 13000000, 750000000, 750, 13, 1, 12}, + { 19200000, 750000000, 625, 16, 1, 8}, + { 26000000, 750000000, 750, 26, 1, 12}, + + /* 608 MHz */ + { 12000000, 608000000, 608, 12, 1, 12}, + { 13000000, 608000000, 608, 13, 1, 12}, + { 19200000, 608000000, 380, 12, 1, 8}, + { 26000000, 608000000, 608, 26, 1, 12}, + + /* 456 MHz */ + { 12000000, 456000000, 456, 12, 1, 12}, + { 13000000, 456000000, 456, 13, 1, 12}, + { 19200000, 456000000, 380, 16, 1, 8}, + { 26000000, 456000000, 456, 26, 1, 12}, + + /* 312 MHz */ + { 12000000, 312000000, 312, 12, 1, 12}, + { 13000000, 312000000, 312, 13, 1, 12}, + { 19200000, 312000000, 260, 16, 1, 8}, + { 26000000, 312000000, 312, 26, 1, 12}, + + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { + { 12000000, 100000000, 200, 24, 1, 0 }, + { 0, 0, 0, 0, 0, 0 }, +}; + +/* PLL parameters */ +static struct tegra_clk_pll_params pll_c_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1400000000, + .base_reg = PLLC_BASE, + .misc_reg = PLLC_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_m_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1200000000, + .base_reg = PLLM_BASE, + .misc_reg = PLLM_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_p_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1400000000, + .base_reg = PLLP_BASE, + .misc_reg = PLLP_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_a_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1400000000, + .base_reg = PLLA_BASE, + .misc_reg = PLLA_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_d_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 40000000, + .vco_max = 1000000000, + .base_reg = PLLD_BASE, + .misc_reg = PLLD_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct tegra_clk_pll_params pll_u_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 48000000, + .vco_max = 960000000, + .base_reg = PLLU_BASE, + .misc_reg = PLLU_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct tegra_clk_pll_params pll_x_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1200000000, + .base_reg = PLLX_BASE, + .misc_reg = PLLX_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_e_params = { + .input_min = 12000000, + .input_max = 12000000, + .cf_min = 0, + .cf_max = 0, + .vco_min = 0, + .vco_max = 0, + .base_reg = PLLE_BASE, + .misc_reg = PLLE_MISC, + .lock_bit_idx = PLLE_MISC_LOCK, + .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, + .lock_delay = 0, +}; + +/* Peripheral clock registers */ +static struct tegra_clk_periph_regs periph_l_regs = { + .enb_reg = CLK_OUT_ENB_L, + .enb_set_reg = CLK_OUT_ENB_SET_L, + .enb_clr_reg = CLK_OUT_ENB_CLR_L, + .rst_reg = RST_DEVICES_L, + .rst_set_reg = RST_DEVICES_SET_L, + .rst_clr_reg = RST_DEVICES_CLR_L, +}; + +static struct tegra_clk_periph_regs periph_h_regs = { + .enb_reg = CLK_OUT_ENB_H, + .enb_set_reg = CLK_OUT_ENB_SET_H, + .enb_clr_reg = CLK_OUT_ENB_CLR_H, + .rst_reg = RST_DEVICES_H, + .rst_set_reg = RST_DEVICES_SET_H, + .rst_clr_reg = RST_DEVICES_CLR_H, +}; + +static struct tegra_clk_periph_regs periph_u_regs = { + .enb_reg = CLK_OUT_ENB_U, + .enb_set_reg = CLK_OUT_ENB_SET_U, + .enb_clr_reg = CLK_OUT_ENB_CLR_U, + .rst_reg = RST_DEVICES_U, + .rst_set_reg = RST_DEVICES_SET_U, + .rst_clr_reg = RST_DEVICES_CLR_U, +}; + +static unsigned long tegra20_clk_measure_input_freq(void) +{ + u32 osc_ctrl = readl_relaxed(clk_base + OSC_CTRL); + u32 auto_clk_control = osc_ctrl & OSC_CTRL_OSC_FREQ_MASK; + u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK; + unsigned long input_freq; + + switch (auto_clk_control) { + case OSC_CTRL_OSC_FREQ_12MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 12000000; + break; + case OSC_CTRL_OSC_FREQ_13MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 13000000; + break; + case OSC_CTRL_OSC_FREQ_19_2MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 19200000; + break; + case OSC_CTRL_OSC_FREQ_26MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 26000000; + break; + default: + pr_err("Unexpected clock autodetect value %d", + auto_clk_control); + BUG(); + return 0; + } + + return input_freq; +} + +static unsigned int tegra20_get_pll_ref_div(void) +{ + u32 pll_ref_div = readl_relaxed(clk_base + OSC_CTRL) & + OSC_CTRL_PLL_REF_DIV_MASK; + + switch (pll_ref_div) { + case OSC_CTRL_PLL_REF_DIV_1: + return 1; + case OSC_CTRL_PLL_REF_DIV_2: + return 2; + case OSC_CTRL_PLL_REF_DIV_4: + return 4; + default: + pr_err("Invalied pll ref divider %d\n", pll_ref_div); + BUG(); + } + return 0; +} + +static void tegra20_pll_init(void) +{ + struct clk *clk; + + /* PLLC */ + clk = tegra_clk_register_pll("pll_c", "pll_ref", clk_base, NULL, 0, + 0, &pll_c_params, TEGRA_PLL_HAS_CPCON, + pll_c_freq_table, NULL); + clk_register_clkdev(clk, "pll_c", NULL); + clks[pll_c] = clk; + + /* PLLC_OUT1 */ + clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", + clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", + clk_base + PLLC_OUT, 1, 0, CLK_SET_RATE_PARENT, + 0, NULL); + clk_register_clkdev(clk, "pll_c_out1", NULL); + clks[pll_c_out1] = clk; + + /* PLLP */ + clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, NULL, 0, + 216000000, &pll_p_params, TEGRA_PLL_FIXED | + TEGRA_PLL_HAS_CPCON, pll_p_freq_table, NULL); + clk_register_clkdev(clk, "pll_p", NULL); + clks[pll_p] = clk; + + /* PLLP_OUT1 */ + clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p", + clk_base + PLLP_OUTA, 0, + TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div", + clk_base + PLLP_OUTA, 1, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out1", NULL); + clks[pll_p_out1] = clk; + + /* PLLP_OUT2 */ + clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p", + clk_base + PLLP_OUTA, 0, + TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, + 24, 8, 1, &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div", + clk_base + PLLP_OUTA, 17, 16, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out2", NULL); + clks[pll_p_out2] = clk; + + /* PLLP_OUT3 */ + clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p", + clk_base + PLLP_OUTB, 0, + TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div", + clk_base + PLLP_OUTB, 1, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out3", NULL); + clks[pll_p_out3] = clk; + + /* PLLP_OUT4 */ + clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p", + clk_base + PLLP_OUTB, 0, + TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, + 24, 8, 1, &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div", + clk_base + PLLP_OUTB, 17, 16, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out4", NULL); + clks[pll_p_out4] = clk; + + /* PLLM */ + clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, NULL, + CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, + &pll_m_params, TEGRA_PLL_HAS_CPCON, + pll_m_freq_table, NULL); + clk_register_clkdev(clk, "pll_m", NULL); + clks[pll_m] = clk; + + /* PLLM_OUT1 */ + clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m", + clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", + clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_m_out1", NULL); + clks[pll_m_out1] = clk; + + /* PLLX */ + clk = tegra_clk_register_pll("pll_x", "pll_ref", clk_base, NULL, 0, + 0, &pll_x_params, TEGRA_PLL_HAS_CPCON, + pll_x_freq_table, NULL); + clk_register_clkdev(clk, "pll_x", NULL); + clks[pll_x] = clk; + + /* PLLU */ + clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, NULL, 0, + 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON, + pll_u_freq_table, NULL); + clk_register_clkdev(clk, "pll_u", NULL); + clks[pll_u] = clk; + + /* PLLD */ + clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, NULL, 0, + 0, &pll_d_params, TEGRA_PLL_HAS_CPCON, + pll_d_freq_table, NULL); + clk_register_clkdev(clk, "pll_d", NULL); + clks[pll_d] = clk; + + /* PLLD_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_d_out0", NULL); + clks[pll_d_out0] = clk; + + /* PLLA */ + clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, NULL, 0, + 0, &pll_a_params, TEGRA_PLL_HAS_CPCON, + pll_a_freq_table, NULL); + clk_register_clkdev(clk, "pll_a", NULL); + clks[pll_a] = clk; + + /* PLLA_OUT0 */ + clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a", + clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div", + clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_a_out0", NULL); + clks[pll_a_out0] = clk; + + /* PLLE */ + clk = tegra_clk_register_plle("pll_e", "pll_ref", clk_base, NULL, + 0, 100000000, &pll_e_params, + 0, pll_e_freq_table, NULL); + clk_register_clkdev(clk, "pll_e", NULL); + clks[pll_e] = clk; +} + +static const char *cclk_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", + "pll_p_cclk", "pll_p_out4_cclk", + "pll_p_out3_cclk", "clk_d", "pll_x" }; +static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", + "pll_p_out3", "pll_p_out2", "clk_d", + "clk_32k", "pll_m_out1" }; + +static void tegra20_super_clk_init(void) +{ + struct clk *clk; + + /* + * DIV_U71 dividers for CCLK, these dividers are used only + * if parent clock is fixed rate. + */ + + /* + * Clock input to cclk divided from pll_p using + * U71 divider of cclk. + */ + clk = tegra_clk_register_divider("pll_p_cclk", "pll_p", + clk_base + SUPER_CCLK_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_cclk", NULL); + + /* + * Clock input to cclk divided from pll_p_out3 using + * U71 divider of cclk. + */ + clk = tegra_clk_register_divider("pll_p_out3_cclk", "pll_p_out3", + clk_base + SUPER_CCLK_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_out3_cclk", NULL); + + /* + * Clock input to cclk divided from pll_p_out4 using + * U71 divider of cclk. + */ + clk = tegra_clk_register_divider("pll_p_out4_cclk", "pll_p_out4", + clk_base + SUPER_CCLK_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_out4_cclk", NULL); + + /* CCLK */ + clk = tegra_clk_register_super_mux("cclk", cclk_parents, + ARRAY_SIZE(cclk_parents), CLK_SET_RATE_PARENT, + clk_base + CCLK_BURST_POLICY, 0, 4, 0, 0, NULL); + clk_register_clkdev(clk, "cclk", NULL); + clks[cclk] = clk; + + /* SCLK */ + clk = tegra_clk_register_super_mux("sclk", sclk_parents, + ARRAY_SIZE(sclk_parents), CLK_SET_RATE_PARENT, + clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); + clk_register_clkdev(clk, "sclk", NULL); + clks[sclk] = clk; + + /* HCLK */ + clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, + clk_base + CLK_SYSTEM_RATE, 4, 2, 0, NULL); + clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT, + clk_base + CLK_SYSTEM_RATE, 7, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "hclk", NULL); + clks[hclk] = clk; + + /* PCLK */ + clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, + clk_base + CLK_SYSTEM_RATE, 0, 2, 0, NULL); + clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT, + clk_base + CLK_SYSTEM_RATE, 3, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "pclk", NULL); + clks[pclk] = clk; + + /* twd */ + clk = clk_register_fixed_factor(NULL, "twd", "cclk", 0, 1, 4); + clk_register_clkdev(clk, "twd", NULL); + clks[twd] = clk; +} + +static const char *audio_parents[] = {"spdif_in", "i2s1", "i2s2", "unused", + "pll_a_out0", "unused", "unused", + "unused"}; + +static void __init tegra20_audio_clk_init(void) +{ + struct clk *clk; + + /* audio */ + clk = clk_register_mux(NULL, "audio_mux", audio_parents, + ARRAY_SIZE(audio_parents), 0, + clk_base + AUDIO_SYNC_CLK, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "audio", "audio_mux", 0, + clk_base + AUDIO_SYNC_CLK, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio", NULL); + clks[audio] = clk; + + /* audio_2x */ + clk = clk_register_fixed_factor(NULL, "audio_doubler", "audio", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_periph_gate("audio_2x", "audio_doubler", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 89, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio_2x", NULL); + clks[audio_2x] = clk; + +} + +static const char *i2s1_parents[] = {"pll_a_out0", "audio_2x", "pll_p", + "clk_m"}; +static const char *i2s2_parents[] = {"pll_a_out0", "audio_2x", "pll_p", + "clk_m"}; +static const char *spdif_out_parents[] = {"pll_a_out0", "audio_2x", "pll_p", + "clk_m"}; +static const char *spdif_in_parents[] = {"pll_p", "pll_c", "pll_m"}; +static const char *pwm_parents[] = {"pll_p", "pll_c", "audio", "clk_m", + "clk_32k"}; +static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c", "pll_m", "clk_m"}; +static const char *mux_pllmcpa[] = {"pll_m", "pll_c", "pll_c", "pll_a"}; +static const char *mux_pllpdc_clkm[] = {"pll_p", "pll_d_out0", "pll_c", + "clk_m"}; +static const char *mux_pllmcp_clkm[] = {"pll_m", "pll_c", "pll_p", "clk_m"}; + +static struct tegra_periph_init_data tegra_periph_clk_list[] = { + TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra20-i2s.0", i2s1_parents, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1), + TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra20-i2s.1", i2s2_parents, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2), + TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra20-spdif", spdif_out_parents, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out), + TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra20-spdif", spdif_in_parents, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in), + TEGRA_INIT_DATA_MUX("sbc1", NULL, "spi_tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1), + TEGRA_INIT_DATA_MUX("sbc2", NULL, "spi_tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2), + TEGRA_INIT_DATA_MUX("sbc3", NULL, "spi_tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3), + TEGRA_INIT_DATA_MUX("sbc4", NULL, "spi_tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4), + TEGRA_INIT_DATA_MUX("spi", NULL, "spi", mux_pllpcm_clkm, CLK_SOURCE_SPI, 43, &periph_h_regs, TEGRA_PERIPH_ON_APB, spi), + TEGRA_INIT_DATA_MUX("xio", NULL, "xio", mux_pllpcm_clkm, CLK_SOURCE_XIO, 45, &periph_h_regs, 0, xio), + TEGRA_INIT_DATA_MUX("twc", NULL, "twc", mux_pllpcm_clkm, CLK_SOURCE_TWC, 16, &periph_l_regs, TEGRA_PERIPH_ON_APB, twc), + TEGRA_INIT_DATA_MUX("ide", NULL, "ide", mux_pllpcm_clkm, CLK_SOURCE_XIO, 25, &periph_l_regs, 0, ide), + TEGRA_INIT_DATA_MUX("ndflash", NULL, "tegra_nand", mux_pllpcm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_l_regs, 0, ndflash), + TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllpcm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir), + TEGRA_INIT_DATA_MUX("csite", NULL, "csite", mux_pllpcm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, 0, csite), + TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllpcm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, 0, la), + TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllpcm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr), + TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllpcm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi), + TEGRA_INIT_DATA_MUX("vde", NULL, "vde", mux_pllpcm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde), + TEGRA_INIT_DATA_MUX("vi", "vi", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi), + TEGRA_INIT_DATA_MUX("epp", NULL, "epp", mux_pllmcpa, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp), + TEGRA_INIT_DATA_MUX("mpe", NULL, "mpe", mux_pllmcpa, CLK_SOURCE_MPE, 60, &periph_h_regs, 0, mpe), + TEGRA_INIT_DATA_MUX("host1x", NULL, "host1x", mux_pllmcpa, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x), + TEGRA_INIT_DATA_MUX("3d", NULL, "3d", mux_pllmcpa, CLK_SOURCE_3D, 24, &periph_l_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d), + TEGRA_INIT_DATA_MUX("2d", NULL, "2d", mux_pllmcpa, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr2d), + TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllpcm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor), + TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1), + TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2), + TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3), + TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4), + TEGRA_INIT_DATA_MUX("cve", NULL, "cve", mux_pllpdc_clkm, CLK_SOURCE_CVE, 49, &periph_h_regs, 0, cve), + TEGRA_INIT_DATA_MUX("tvo", NULL, "tvo", mux_pllpdc_clkm, CLK_SOURCE_TVO, 49, &periph_h_regs, 0, tvo), + TEGRA_INIT_DATA_MUX("tvdac", NULL, "tvdac", mux_pllpdc_clkm, CLK_SOURCE_TVDAC, 53, &periph_h_regs, 0, tvdac), + TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor), + TEGRA_INIT_DATA_DIV16("i2c1", "div-clk", "tegra-i2c.0", mux_pllpcm_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2c1), + TEGRA_INIT_DATA_DIV16("i2c2", "div-clk", "tegra-i2c.1", mux_pllpcm_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c2), + TEGRA_INIT_DATA_DIV16("i2c3", "div-clk", "tegra-i2c.2", mux_pllpcm_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2c3), + TEGRA_INIT_DATA_DIV16("dvc", "div-clk", "tegra-i2c.3", mux_pllpcm_clkm, CLK_SOURCE_DVC, 47, &periph_h_regs, TEGRA_PERIPH_ON_APB, dvc), + TEGRA_INIT_DATA_MUX("hdmi", NULL, "hdmi", mux_pllpdc_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi), + TEGRA_INIT_DATA("pwm", NULL, "tegra-pwm", pwm_parents, CLK_SOURCE_PWM, 28, 3, 0, 0, 8, 1, 0, &periph_l_regs, 17, periph_clk_enb_refcnt, TEGRA_PERIPH_ON_APB, pwm), +}; + +static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = { + TEGRA_INIT_DATA_NODIV("uarta", NULL, "tegra_uart.0", mux_pllpcm_clkm, CLK_SOURCE_UARTA, 30, 2, 6, &periph_l_regs, TEGRA_PERIPH_ON_APB, uarta), + TEGRA_INIT_DATA_NODIV("uartb", NULL, "tegra_uart.1", mux_pllpcm_clkm, CLK_SOURCE_UARTB, 30, 2, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, uartb), + TEGRA_INIT_DATA_NODIV("uartc", NULL, "tegra_uart.2", mux_pllpcm_clkm, CLK_SOURCE_UARTC, 30, 2, 55, &periph_h_regs, TEGRA_PERIPH_ON_APB, uartc), + TEGRA_INIT_DATA_NODIV("uartd", NULL, "tegra_uart.3", mux_pllpcm_clkm, CLK_SOURCE_UARTD, 30, 2, 65, &periph_u_regs, TEGRA_PERIPH_ON_APB, uartd), + TEGRA_INIT_DATA_NODIV("uarte", NULL, "tegra_uart.4", mux_pllpcm_clkm, CLK_SOURCE_UARTE, 30, 2, 66, &periph_u_regs, TEGRA_PERIPH_ON_APB, uarte), + TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllpdc_clkm, CLK_SOURCE_DISP1, 30, 2, 27, &periph_l_regs, 0, disp1), + TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllpdc_clkm, CLK_SOURCE_DISP2, 30, 2, 26, &periph_l_regs, 0, disp2), +}; + +static void __init tegra20_periph_clk_init(void) +{ + struct tegra_periph_init_data *data; + struct clk *clk; + int i; + + /* apbdma */ + clk = tegra_clk_register_periph_gate("apbdma", "pclk", 0, clk_base, + 0, 34, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-apbdma"); + clks[apbdma] = clk; + + /* rtc */ + clk = tegra_clk_register_periph_gate("rtc", "clk_32k", + TEGRA_PERIPH_NO_RESET, + clk_base, 0, 4, &periph_l_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "rtc-tegra"); + clks[rtc] = clk; + + /* timer */ + clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base, + 0, 5, &periph_l_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "timer"); + clks[timer] = clk; + + /* kbc */ + clk = tegra_clk_register_periph_gate("kbc", "clk_32k", + TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, + clk_base, 0, 36, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-kbc"); + clks[kbc] = clk; + + /* csus */ + clk = tegra_clk_register_periph_gate("csus", "clk_m", + TEGRA_PERIPH_NO_RESET, + clk_base, 0, 92, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "csus", "tengra_camera"); + clks[csus] = clk; + + /* vcp */ + clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, + clk_base, 0, 29, &periph_l_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "vcp", "tegra-avp"); + clks[vcp] = clk; + + /* bsea */ + clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0, + clk_base, 0, 62, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "bsea", "tegra-avp"); + clks[bsea] = clk; + + /* bsev */ + clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0, + clk_base, 0, 63, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "bsev", "tegra-aes"); + clks[bsev] = clk; + + /* emc */ + clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, + ARRAY_SIZE(mux_pllmcp_clkm), 0, + clk_base + CLK_SOURCE_EMC, + 30, 2, 0, NULL); + clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, + 57, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "emc", NULL); + clks[emc] = clk; + + /* usbd */ + clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, 0, + 22, &periph_l_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "fsl-tegra-udc"); + clks[usbd] = clk; + + /* usb2 */ + clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base, 0, + 58, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-ehci.1"); + clks[usb2] = clk; + + /* usb3 */ + clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base, 0, + 59, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-ehci.2"); + clks[usb3] = clk; + + /* dsi */ + clk = tegra_clk_register_periph_gate("dsi", "pll_d", 0, clk_base, 0, + 48, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "dsi"); + clks[dsi] = clk; + + /* csi */ + clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base, + 0, 52, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "csi", "tegra_camera"); + clks[csi] = clk; + + /* isp */ + clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0, 23, + &periph_l_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "isp", "tegra_camera"); + clks[isp] = clk; + + /* pex */ + clk = tegra_clk_register_periph_gate("pex", "clk_m", 0, clk_base, 0, 70, + &periph_u_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "pex", NULL); + clks[pex] = clk; + + /* afi */ + clk = tegra_clk_register_periph_gate("afi", "clk_m", 0, clk_base, 0, 72, + &periph_u_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "afi", NULL); + clks[afi] = clk; + + /* pcie_xclk */ + clk = tegra_clk_register_periph_gate("pcie_xclk", "clk_m", 0, clk_base, + 0, 74, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "pcie_xclk", NULL); + clks[pcie_xclk] = clk; + + /* cdev1 */ + clk = clk_register_fixed_rate(NULL, "cdev1_fixed", NULL, CLK_IS_ROOT, + 26000000); + clk = tegra_clk_register_periph_gate("cdev1", "cdev1_fixed", 0, + clk_base, 0, 94, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "cdev1", NULL); + clks[cdev1] = clk; + + /* cdev2 */ + clk = clk_register_fixed_rate(NULL, "cdev2_fixed", NULL, CLK_IS_ROOT, + 26000000); + clk = tegra_clk_register_periph_gate("cdev2", "cdev2_fixed", 0, + clk_base, 0, 93, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "cdev2", NULL); + clks[cdev2] = clk; + + for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { + data = &tegra_periph_clk_list[i]; + clk = tegra_clk_register_periph(data->name, data->parent_names, + data->num_parents, &data->periph, + clk_base, data->offset); + clk_register_clkdev(clk, data->con_id, data->dev_id); + clks[data->clk_id] = clk; + } + + for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) { + data = &tegra_periph_nodiv_clk_list[i]; + clk = tegra_clk_register_periph_nodiv(data->name, + data->parent_names, + data->num_parents, &data->periph, + clk_base, data->offset); + clk_register_clkdev(clk, data->con_id, data->dev_id); + clks[data->clk_id] = clk; + } +} + + +static void __init tegra20_fixed_clk_init(void) +{ + struct clk *clk; + + /* clk_32k */ + clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT, + 32768); + clk_register_clkdev(clk, "clk_32k", NULL); + clks[clk_32k] = clk; +} + +static void __init tegra20_pmc_clk_init(void) +{ + struct clk *clk; + + /* blink */ + writel_relaxed(0, pmc_base + PMC_BLINK_TIMER); + clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, + pmc_base + PMC_DPD_PADS_ORIDE, + PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); + clk = clk_register_gate(NULL, "blink", "blink_override", 0, + pmc_base + PMC_CTRL, + PMC_CTRL_BLINK_ENB, 0, NULL); + clk_register_clkdev(clk, "blink", NULL); + clks[blink] = clk; +} + +static void __init tegra20_osc_clk_init(void) +{ + struct clk *clk; + unsigned long input_freq; + unsigned int pll_ref_div; + + input_freq = tegra20_clk_measure_input_freq(); + + /* clk_m */ + clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT | + CLK_IGNORE_UNUSED, input_freq); + clk_register_clkdev(clk, "clk_m", NULL); + clks[clk_m] = clk; + + /* pll_ref */ + pll_ref_div = tegra20_get_pll_ref_div(); + clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m", + CLK_SET_RATE_PARENT, 1, pll_ref_div); + clk_register_clkdev(clk, "pll_ref", NULL); + clks[pll_ref] = clk; +} + +/* Tegra20 CPU clock and reset control functions */ +static void tegra20_wait_cpu_in_reset(u32 cpu) +{ + unsigned int reg; + + do { + reg = readl(clk_base + + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); + cpu_relax(); + } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ + + return; +} + +static void tegra20_put_cpu_in_reset(u32 cpu) +{ + writel(CPU_RESET(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); + dmb(); +} + +static void tegra20_cpu_out_of_reset(u32 cpu) +{ + writel(CPU_RESET(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); + wmb(); +} + +static void tegra20_enable_cpu_clock(u32 cpu) +{ + unsigned int reg; + + reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); + writel(reg & ~CPU_CLOCK(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); + barrier(); + reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); +} + +static void tegra20_disable_cpu_clock(u32 cpu) +{ + unsigned int reg; + + reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); + writel(reg | CPU_CLOCK(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); +} + +static struct tegra_cpu_car_ops tegra20_cpu_car_ops = { + .wait_for_reset = tegra20_wait_cpu_in_reset, + .put_in_reset = tegra20_put_cpu_in_reset, + .out_of_reset = tegra20_cpu_out_of_reset, + .enable_clock = tegra20_enable_cpu_clock, + .disable_clock = tegra20_disable_cpu_clock, +}; + +static __initdata struct tegra_clk_init_table init_table[] = { + {pll_p, clk_max, 216000000, 1}, + {pll_p_out1, clk_max, 28800000, 1}, + {pll_p_out2, clk_max, 48000000, 1}, + {pll_p_out3, clk_max, 72000000, 1}, + {pll_p_out4, clk_max, 24000000, 1}, + {pll_c, clk_max, 600000000, 1}, + {pll_c_out1, clk_max, 120000000, 1}, + {sclk, pll_c_out1, 0, 1}, + {hclk, clk_max, 0, 1}, + {pclk, clk_max, 60000000, 1}, + {csite, clk_max, 0, 1}, + {emc, clk_max, 0, 1}, + {cclk, clk_max, 0, 1}, + {uarta, pll_p, 0, 1}, + {uartd, pll_p, 0, 1}, + {usbd, clk_max, 12000000, 0}, + {usb2, clk_max, 12000000, 0}, + {usb3, clk_max, 12000000, 0}, + {pll_a, clk_max, 56448000, 1}, + {pll_a_out0, clk_max, 11289600, 1}, + {cdev1, clk_max, 0, 1}, + {blink, clk_max, 32768, 1}, + {i2s1, pll_a_out0, 11289600, 0}, + {i2s2, pll_a_out0, 11289600, 0}, + {sdmmc1, pll_p, 48000000, 0}, + {sdmmc3, pll_p, 48000000, 0}, + {sdmmc4, pll_p, 48000000, 0}, + {spi, pll_p, 20000000, 0}, + {sbc1, pll_p, 100000000, 0}, + {sbc2, pll_p, 100000000, 0}, + {sbc3, pll_p, 100000000, 0}, + {sbc4, pll_p, 100000000, 0}, + {host1x, pll_c, 150000000, 0}, + {disp1, pll_p, 600000000, 0}, + {disp2, pll_p, 600000000, 0}, + {clk_max, clk_max, 0, 0}, /* This MUST be the last entry */ +}; + +/* + * Some clocks may be used by different drivers depending on the board + * configuration. List those here to register them twice in the clock lookup + * table under two names. + */ +static struct tegra_clk_duplicate tegra_clk_duplicates[] = { + TEGRA_CLK_DUPLICATE(uarta, "serial8250.0", NULL), + TEGRA_CLK_DUPLICATE(uartb, "serial8250.1", NULL), + TEGRA_CLK_DUPLICATE(uartc, "serial8250.2", NULL), + TEGRA_CLK_DUPLICATE(uartd, "serial8250.3", NULL), + TEGRA_CLK_DUPLICATE(uarte, "serial8250.4", NULL), + TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL), + TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), + TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), + TEGRA_CLK_DUPLICATE(pll_p, "tegradc.0", "parent"), + TEGRA_CLK_DUPLICATE(pll_p, "tegradc.1", "parent"), + TEGRA_CLK_DUPLICATE(pll_d_out0, "hdmi", "parent"), + TEGRA_CLK_DUPLICATE(gr2d, "tegra_grhost", "gr2d"), + TEGRA_CLK_DUPLICATE(gr3d, "tegra_grhost", "gr3d"), + TEGRA_CLK_DUPLICATE(epp, "tegra_grhost", "epp"), + TEGRA_CLK_DUPLICATE(mpe, "tegra_grhost", "mpe"), + TEGRA_CLK_DUPLICATE(vde, "tegra-aes", "vde"), + TEGRA_CLK_DUPLICATE(cclk, NULL, "cpu"), + TEGRA_CLK_DUPLICATE(twd, "smp_twd", NULL), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.0", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.1", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.2", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.3", "fast-clk"), + TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* Must be the last entry */ +}; + +static const struct of_device_id pmc_match[] __initconst = { + { .compatible = "nvidia,tegra20-pmc" }, + {}, +}; + +void __init tegra20_clock_init(struct device_node *np) +{ + int i; + struct device_node *node; + + clk_base = of_iomap(np, 0); + if (!clk_base) { + pr_err("Can't map CAR registers\n"); + BUG(); + } + + node = of_find_matching_node(NULL, pmc_match); + if (!node) { + pr_err("Failed to find pmc node\n"); + BUG(); + } + + pmc_base = of_iomap(node, 0); + if (!pmc_base) { + pr_err("Can't map pmc registers\n"); + BUG(); + } + + tegra20_osc_clk_init(); + tegra20_pmc_clk_init(); + tegra20_fixed_clk_init(); + tegra20_pll_init(); + tegra20_super_clk_init(); + tegra20_periph_clk_init(); + tegra20_audio_clk_init(); + + + for (i = 0; i < ARRAY_SIZE(clks); i++) { + if (IS_ERR(clks[i])) { + pr_err("Tegra20 clk %d: register failed with %ld\n", + i, PTR_ERR(clks[i])); + BUG(); + } + if (!clks[i]) + clks[i] = ERR_PTR(-EINVAL); + } + + tegra_init_dup_clks(tegra_clk_duplicates, clks, clk_max); + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + tegra_init_from_table(init_table, clks, clk_max); + + tegra_cpu_car_ops = &tegra20_cpu_car_ops; +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 5fcfa51d6b17..82835f24533c 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -487,4 +487,10 @@ void tegra_init_from_table(struct tegra_clk_init_table *tbl, void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, struct clk *clks[], int clk_max); +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +void tegra20_clock_init(struct device_node *np); +#else +static inline void tegra20_clock_init(struct device_node *np) {} +#endif /* CONFIG_ARCH_TEGRA_2x_SOC */ + #endif /* TEGRA_CLK_H */ From b08e8c0ecc42afa3a2e1019851af741980dd5a6b Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:25 +0530 Subject: [PATCH 19/31] clk: tegra: add clock support for Tegra30 Add Tegra30 clock support based on common clock framework. Signed-off-by: Prashant Gaikwad [swarren: ensure all OF lookups return valid cookies i.e. an explicit error pointer or valid pointer not NULL, adapt to renames in earlier patches, fixed some checkpatch issues.] Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/Makefile | 1 + drivers/clk/tegra/clk-tegra30.c | 2057 +++++++++++++++++++++++++++++++ drivers/clk/tegra/clk.h | 6 + 3 files changed, 2064 insertions(+) create mode 100644 drivers/clk/tegra/clk-tegra30.c diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index 00484fd4e515..2b41b0f4f731 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -8,3 +8,4 @@ obj-y += clk-pll-out.o obj-y += clk-super.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o +obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c new file mode 100644 index 000000000000..1c2765db1199 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra30.c @@ -0,0 +1,2057 @@ +/* + * Copyright (c) 2012, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" + +#define RST_DEVICES_L 0x004 +#define RST_DEVICES_H 0x008 +#define RST_DEVICES_U 0x00c +#define RST_DEVICES_V 0x358 +#define RST_DEVICES_W 0x35c +#define RST_DEVICES_SET_L 0x300 +#define RST_DEVICES_CLR_L 0x304 +#define RST_DEVICES_SET_H 0x308 +#define RST_DEVICES_CLR_H 0x30c +#define RST_DEVICES_SET_U 0x310 +#define RST_DEVICES_CLR_U 0x314 +#define RST_DEVICES_SET_V 0x430 +#define RST_DEVICES_CLR_V 0x434 +#define RST_DEVICES_SET_W 0x438 +#define RST_DEVICES_CLR_W 0x43c +#define RST_DEVICES_NUM 5 + +#define CLK_OUT_ENB_L 0x010 +#define CLK_OUT_ENB_H 0x014 +#define CLK_OUT_ENB_U 0x018 +#define CLK_OUT_ENB_V 0x360 +#define CLK_OUT_ENB_W 0x364 +#define CLK_OUT_ENB_SET_L 0x320 +#define CLK_OUT_ENB_CLR_L 0x324 +#define CLK_OUT_ENB_SET_H 0x328 +#define CLK_OUT_ENB_CLR_H 0x32c +#define CLK_OUT_ENB_SET_U 0x330 +#define CLK_OUT_ENB_CLR_U 0x334 +#define CLK_OUT_ENB_SET_V 0x440 +#define CLK_OUT_ENB_CLR_V 0x444 +#define CLK_OUT_ENB_SET_W 0x448 +#define CLK_OUT_ENB_CLR_W 0x44c +#define CLK_OUT_ENB_NUM 5 + +#define OSC_CTRL 0x50 +#define OSC_CTRL_OSC_FREQ_MASK (0xF<<28) +#define OSC_CTRL_OSC_FREQ_13MHZ (0X0<<28) +#define OSC_CTRL_OSC_FREQ_19_2MHZ (0X4<<28) +#define OSC_CTRL_OSC_FREQ_12MHZ (0X8<<28) +#define OSC_CTRL_OSC_FREQ_26MHZ (0XC<<28) +#define OSC_CTRL_OSC_FREQ_16_8MHZ (0X1<<28) +#define OSC_CTRL_OSC_FREQ_38_4MHZ (0X5<<28) +#define OSC_CTRL_OSC_FREQ_48MHZ (0X9<<28) +#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK) + +#define OSC_CTRL_PLL_REF_DIV_MASK (3<<26) +#define OSC_CTRL_PLL_REF_DIV_1 (0<<26) +#define OSC_CTRL_PLL_REF_DIV_2 (1<<26) +#define OSC_CTRL_PLL_REF_DIV_4 (2<<26) + +#define OSC_FREQ_DET 0x58 +#define OSC_FREQ_DET_TRIG BIT(31) + +#define OSC_FREQ_DET_STATUS 0x5c +#define OSC_FREQ_DET_BUSY BIT(31) +#define OSC_FREQ_DET_CNT_MASK 0xffff + +#define CCLKG_BURST_POLICY 0x368 +#define SUPER_CCLKG_DIVIDER 0x36c +#define CCLKLP_BURST_POLICY 0x370 +#define SUPER_CCLKLP_DIVIDER 0x374 +#define SCLK_BURST_POLICY 0x028 +#define SUPER_SCLK_DIVIDER 0x02c + +#define SYSTEM_CLK_RATE 0x030 + +#define PLLC_BASE 0x80 +#define PLLC_MISC 0x8c +#define PLLM_BASE 0x90 +#define PLLM_MISC 0x9c +#define PLLP_BASE 0xa0 +#define PLLP_MISC 0xac +#define PLLX_BASE 0xe0 +#define PLLX_MISC 0xe4 +#define PLLD_BASE 0xd0 +#define PLLD_MISC 0xdc +#define PLLD2_BASE 0x4b8 +#define PLLD2_MISC 0x4bc +#define PLLE_BASE 0xe8 +#define PLLE_MISC 0xec +#define PLLA_BASE 0xb0 +#define PLLA_MISC 0xbc +#define PLLU_BASE 0xc0 +#define PLLU_MISC 0xcc + +#define PLL_MISC_LOCK_ENABLE 18 +#define PLLDU_MISC_LOCK_ENABLE 22 +#define PLLE_MISC_LOCK_ENABLE 9 + +#define PLL_BASE_LOCK 27 +#define PLLE_MISC_LOCK 11 + +#define PLLE_AUX 0x48c +#define PLLC_OUT 0x84 +#define PLLM_OUT 0x94 +#define PLLP_OUTA 0xa4 +#define PLLP_OUTB 0xa8 +#define PLLA_OUT 0xb4 + +#define AUDIO_SYNC_CLK_I2S0 0x4a0 +#define AUDIO_SYNC_CLK_I2S1 0x4a4 +#define AUDIO_SYNC_CLK_I2S2 0x4a8 +#define AUDIO_SYNC_CLK_I2S3 0x4ac +#define AUDIO_SYNC_CLK_I2S4 0x4b0 +#define AUDIO_SYNC_CLK_SPDIF 0x4b4 + +#define PMC_CLK_OUT_CNTRL 0x1a8 + +#define CLK_SOURCE_I2S0 0x1d8 +#define CLK_SOURCE_I2S1 0x100 +#define CLK_SOURCE_I2S2 0x104 +#define CLK_SOURCE_I2S3 0x3bc +#define CLK_SOURCE_I2S4 0x3c0 +#define CLK_SOURCE_SPDIF_OUT 0x108 +#define CLK_SOURCE_SPDIF_IN 0x10c +#define CLK_SOURCE_PWM 0x110 +#define CLK_SOURCE_D_AUDIO 0x3d0 +#define CLK_SOURCE_DAM0 0x3d8 +#define CLK_SOURCE_DAM1 0x3dc +#define CLK_SOURCE_DAM2 0x3e0 +#define CLK_SOURCE_HDA 0x428 +#define CLK_SOURCE_HDA2CODEC_2X 0x3e4 +#define CLK_SOURCE_SBC1 0x134 +#define CLK_SOURCE_SBC2 0x118 +#define CLK_SOURCE_SBC3 0x11c +#define CLK_SOURCE_SBC4 0x1b4 +#define CLK_SOURCE_SBC5 0x3c8 +#define CLK_SOURCE_SBC6 0x3cc +#define CLK_SOURCE_SATA_OOB 0x420 +#define CLK_SOURCE_SATA 0x424 +#define CLK_SOURCE_NDFLASH 0x160 +#define CLK_SOURCE_NDSPEED 0x3f8 +#define CLK_SOURCE_VFIR 0x168 +#define CLK_SOURCE_SDMMC1 0x150 +#define CLK_SOURCE_SDMMC2 0x154 +#define CLK_SOURCE_SDMMC3 0x1bc +#define CLK_SOURCE_SDMMC4 0x164 +#define CLK_SOURCE_VDE 0x1c8 +#define CLK_SOURCE_CSITE 0x1d4 +#define CLK_SOURCE_LA 0x1f8 +#define CLK_SOURCE_OWR 0x1cc +#define CLK_SOURCE_NOR 0x1d0 +#define CLK_SOURCE_MIPI 0x174 +#define CLK_SOURCE_I2C1 0x124 +#define CLK_SOURCE_I2C2 0x198 +#define CLK_SOURCE_I2C3 0x1b8 +#define CLK_SOURCE_I2C4 0x3c4 +#define CLK_SOURCE_I2C5 0x128 +#define CLK_SOURCE_UARTA 0x178 +#define CLK_SOURCE_UARTB 0x17c +#define CLK_SOURCE_UARTC 0x1a0 +#define CLK_SOURCE_UARTD 0x1c0 +#define CLK_SOURCE_UARTE 0x1c4 +#define CLK_SOURCE_VI 0x148 +#define CLK_SOURCE_VI_SENSOR 0x1a8 +#define CLK_SOURCE_3D 0x158 +#define CLK_SOURCE_3D2 0x3b0 +#define CLK_SOURCE_2D 0x15c +#define CLK_SOURCE_EPP 0x16c +#define CLK_SOURCE_MPE 0x170 +#define CLK_SOURCE_HOST1X 0x180 +#define CLK_SOURCE_CVE 0x140 +#define CLK_SOURCE_TVO 0x188 +#define CLK_SOURCE_DTV 0x1dc +#define CLK_SOURCE_HDMI 0x18c +#define CLK_SOURCE_TVDAC 0x194 +#define CLK_SOURCE_DISP1 0x138 +#define CLK_SOURCE_DISP2 0x13c +#define CLK_SOURCE_DSIB 0xd0 +#define CLK_SOURCE_TSENSOR 0x3b8 +#define CLK_SOURCE_ACTMON 0x3e8 +#define CLK_SOURCE_EXTERN1 0x3ec +#define CLK_SOURCE_EXTERN2 0x3f0 +#define CLK_SOURCE_EXTERN3 0x3f4 +#define CLK_SOURCE_I2CSLOW 0x3fc +#define CLK_SOURCE_SE 0x42c +#define CLK_SOURCE_MSELECT 0x3b4 +#define CLK_SOURCE_EMC 0x19c + +#define AUDIO_SYNC_DOUBLER 0x49c + +#define PMC_CTRL 0 +#define PMC_CTRL_BLINK_ENB 7 + +#define PMC_DPD_PADS_ORIDE 0x1c +#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 +#define PMC_BLINK_TIMER 0x40 + +#define UTMIP_PLL_CFG2 0x488 +#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6) +#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4) + +#define UTMIP_PLL_CFG1 0x484 +#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6) +#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) +#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14) +#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12) +#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16) + +/* Tegra CPU clock and reset control regs */ +#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c +#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 +#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344 +#define TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR 0x34c +#define TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470 + +#define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) +#define CPU_RESET(cpu) (0x1111ul << (cpu)) + +#define CLK_RESET_CCLK_BURST 0x20 +#define CLK_RESET_CCLK_DIVIDER 0x24 +#define CLK_RESET_PLLX_BASE 0xe0 +#define CLK_RESET_PLLX_MISC 0xe4 + +#define CLK_RESET_SOURCE_CSITE 0x1d4 + +#define CLK_RESET_CCLK_BURST_POLICY_SHIFT 28 +#define CLK_RESET_CCLK_RUN_POLICY_SHIFT 4 +#define CLK_RESET_CCLK_IDLE_POLICY_SHIFT 0 +#define CLK_RESET_CCLK_IDLE_POLICY 1 +#define CLK_RESET_CCLK_RUN_POLICY 2 +#define CLK_RESET_CCLK_BURST_POLICY_PLLX 8 + +#ifdef CONFIG_PM_SLEEP +static struct cpu_clk_suspend_context { + u32 pllx_misc; + u32 pllx_base; + + u32 cpu_burst; + u32 clk_csite_src; + u32 cclk_divider; +} tegra30_cpu_clk_sctx; +#endif + +static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; + +static void __iomem *clk_base; +static void __iomem *pmc_base; +static unsigned long input_freq; + +static DEFINE_SPINLOCK(clk_doubler_lock); +static DEFINE_SPINLOCK(clk_out_lock); +static DEFINE_SPINLOCK(pll_div_lock); +static DEFINE_SPINLOCK(cml_lock); +static DEFINE_SPINLOCK(pll_d_lock); + +#define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 8, 1, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, _gate_flags, _clk_id) + +#define TEGRA_INIT_DATA_DIV16(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP, \ + _regs, _clk_num, periph_clk_enb_refcnt, \ + _gate_flags, _clk_id) + +#define TEGRA_INIT_DATA_MUX8(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 29, 3, 0, 0, 8, 1, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, _gate_flags, _clk_id) + +#define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id) + +#define TEGRA_INIT_DATA_UART(_name, _con_id, _dev_id, _parents, _offset,\ + _clk_num, _regs, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 16, 1, TEGRA_DIVIDER_UART, _regs, \ + _clk_num, periph_clk_enb_refcnt, 0, _clk_id) + +#define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \ + _mux_shift, _mux_width, _clk_num, _regs, \ + _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + _mux_shift, _mux_width, 0, 0, 0, 0, 0, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id) + +/* + * IDs assigned here must be in sync with DT bindings definition + * for Tegra30 clocks. + */ +enum tegra30_clk { + cpu, rtc = 4, timer, uarta, gpio = 8, sdmmc2, i2s1 = 11, i2c1, ndflash, + sdmmc1, sdmmc4, pwm = 17, i2s2, epp, gr2d = 21, usbd, isp, gr3d, + disp2 = 26, disp1, host1x, vcp, i2s0, cop_cache, mc, ahbdma, apbdma, + kbc = 36, statmon, pmc, kfuse = 40, sbc1, nor, sbc2 = 44, sbc3 = 46, + i2c5, dsia, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2, + usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3, + pcie, owr, afi, csite, pciex, avpucq, la, dtv = 79, ndspeed, i2c_slow, + dsib, irama = 84, iramb, iramc, iramd, cram2, audio_2x = 90, csus = 92, + cdev1, cdev2, cpu_g = 96, cpu_lp, gr3d2, mselect, tsensor, i2s3, i2s4, + i2c4, sbc5, sbc6, d_audio, apbif, dam0, dam1, dam2, hda2codec_2x, + atomics, audio0_2x, audio1_2x, audio2_2x, audio3_2x, audio4_2x, + spdif_2x, actmon, extern1, extern2, extern3, sata_oob, sata, hda, se, + hda2hdmi, sata_cold, uartb = 160, vfir, spdif_out, spdif_in, vi, + vi_sensor, fuse, fuse_burn, cve, tvo, clk_32k, clk_m, clk_m_div2, + clk_m_div4, pll_ref, pll_c, pll_c_out1, pll_m, pll_m_out1, pll_p, + pll_p_out1, pll_p_out2, pll_p_out3, pll_p_out4, pll_a, pll_a_out0, + pll_d, pll_d_out0, pll_d2, pll_d2_out0, pll_u, pll_x, pll_x_out0, pll_e, + spdif_in_sync, i2s0_sync, i2s1_sync, i2s2_sync, i2s3_sync, i2s4_sync, + vimclk_sync, audio0, audio1, audio2, audio3, audio4, spdif, clk_out_1, + clk_out_2, clk_out_3, sclk, blink, cclk_g, cclk_lp, twd, cml0, cml1, + i2cslow, hclk, pclk, clk_out_1_mux = 300, clk_max +}; + +static struct clk *clks[clk_max]; +static struct clk_onecell_data clk_data; + +/* + * Structure defining the fields for USB UTMI clocks Parameters. + */ +struct utmi_clk_param { + /* Oscillator Frequency in KHz */ + u32 osc_frequency; + /* UTMIP PLL Enable Delay Count */ + u8 enable_delay_count; + /* UTMIP PLL Stable count */ + u8 stable_count; + /* UTMIP PLL Active delay count */ + u8 active_delay_count; + /* UTMIP PLL Xtal frequency count */ + u8 xtal_freq_count; +}; + +static const struct utmi_clk_param utmi_parameters[] = { +/* OSC_FREQUENCY, ENABLE_DLY, STABLE_CNT, ACTIVE_DLY, XTAL_FREQ_CNT */ + {13000000, 0x02, 0x33, 0x05, 0x7F}, + {19200000, 0x03, 0x4B, 0x06, 0xBB}, + {12000000, 0x02, 0x2F, 0x04, 0x76}, + {26000000, 0x04, 0x66, 0x09, 0xFE}, + {16800000, 0x03, 0x41, 0x0A, 0xA4}, +}; + +static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { + { 12000000, 1040000000, 520, 6, 1, 8}, + { 13000000, 1040000000, 480, 6, 1, 8}, + { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */ + { 19200000, 1040000000, 325, 6, 1, 6}, + { 26000000, 1040000000, 520, 13, 1, 8}, + + { 12000000, 832000000, 416, 6, 1, 8}, + { 13000000, 832000000, 832, 13, 1, 8}, + { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */ + { 19200000, 832000000, 260, 6, 1, 8}, + { 26000000, 832000000, 416, 13, 1, 8}, + + { 12000000, 624000000, 624, 12, 1, 8}, + { 13000000, 624000000, 624, 13, 1, 8}, + { 16800000, 600000000, 520, 14, 1, 8}, + { 19200000, 624000000, 520, 16, 1, 8}, + { 26000000, 624000000, 624, 26, 1, 8}, + + { 12000000, 600000000, 600, 12, 1, 8}, + { 13000000, 600000000, 600, 13, 1, 8}, + { 16800000, 600000000, 500, 14, 1, 8}, + { 19200000, 600000000, 375, 12, 1, 6}, + { 26000000, 600000000, 600, 26, 1, 8}, + + { 12000000, 520000000, 520, 12, 1, 8}, + { 13000000, 520000000, 520, 13, 1, 8}, + { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */ + { 19200000, 520000000, 325, 12, 1, 6}, + { 26000000, 520000000, 520, 26, 1, 8}, + + { 12000000, 416000000, 416, 12, 1, 8}, + { 13000000, 416000000, 416, 13, 1, 8}, + { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */ + { 19200000, 416000000, 260, 12, 1, 6}, + { 26000000, 416000000, 416, 26, 1, 8}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_m_freq_table[] = { + { 12000000, 666000000, 666, 12, 1, 8}, + { 13000000, 666000000, 666, 13, 1, 8}, + { 16800000, 666000000, 555, 14, 1, 8}, + { 19200000, 666000000, 555, 16, 1, 8}, + { 26000000, 666000000, 666, 26, 1, 8}, + { 12000000, 600000000, 600, 12, 1, 8}, + { 13000000, 600000000, 600, 13, 1, 8}, + { 16800000, 600000000, 500, 14, 1, 8}, + { 19200000, 600000000, 375, 12, 1, 6}, + { 26000000, 600000000, 600, 26, 1, 8}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { + { 12000000, 216000000, 432, 12, 2, 8}, + { 13000000, 216000000, 432, 13, 2, 8}, + { 16800000, 216000000, 360, 14, 2, 8}, + { 19200000, 216000000, 360, 16, 2, 8}, + { 26000000, 216000000, 432, 26, 2, 8}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { + { 9600000, 564480000, 294, 5, 1, 4}, + { 9600000, 552960000, 288, 5, 1, 4}, + { 9600000, 24000000, 5, 2, 1, 1}, + + { 28800000, 56448000, 49, 25, 1, 1}, + { 28800000, 73728000, 64, 25, 1, 1}, + { 28800000, 24000000, 5, 6, 1, 1}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { + { 12000000, 216000000, 216, 12, 1, 4}, + { 13000000, 216000000, 216, 13, 1, 4}, + { 16800000, 216000000, 180, 14, 1, 4}, + { 19200000, 216000000, 180, 16, 1, 4}, + { 26000000, 216000000, 216, 26, 1, 4}, + + { 12000000, 594000000, 594, 12, 1, 8}, + { 13000000, 594000000, 594, 13, 1, 8}, + { 16800000, 594000000, 495, 14, 1, 8}, + { 19200000, 594000000, 495, 16, 1, 8}, + { 26000000, 594000000, 594, 26, 1, 8}, + + { 12000000, 1000000000, 1000, 12, 1, 12}, + { 13000000, 1000000000, 1000, 13, 1, 12}, + { 19200000, 1000000000, 625, 12, 1, 8}, + { 26000000, 1000000000, 1000, 26, 1, 12}, + + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { + { 12000000, 480000000, 960, 12, 2, 12}, + { 13000000, 480000000, 960, 13, 2, 12}, + { 16800000, 480000000, 400, 7, 2, 5}, + { 19200000, 480000000, 200, 4, 2, 3}, + { 26000000, 480000000, 960, 26, 2, 12}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { + /* 1.7 GHz */ + { 12000000, 1700000000, 850, 6, 1, 8}, + { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */ + { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */ + { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */ + { 26000000, 1700000000, 850, 13, 1, 8}, + + /* 1.6 GHz */ + { 12000000, 1600000000, 800, 6, 1, 8}, + { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */ + { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */ + { 19200000, 1600000000, 500, 6, 1, 8}, + { 26000000, 1600000000, 800, 13, 1, 8}, + + /* 1.5 GHz */ + { 12000000, 1500000000, 750, 6, 1, 8}, + { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */ + { 16800000, 1500000000, 625, 7, 1, 8}, + { 19200000, 1500000000, 625, 8, 1, 8}, + { 26000000, 1500000000, 750, 13, 1, 8}, + + /* 1.4 GHz */ + { 12000000, 1400000000, 700, 6, 1, 8}, + { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */ + { 16800000, 1400000000, 1000, 12, 1, 8}, + { 19200000, 1400000000, 875, 12, 1, 8}, + { 26000000, 1400000000, 700, 13, 1, 8}, + + /* 1.3 GHz */ + { 12000000, 1300000000, 975, 9, 1, 8}, + { 13000000, 1300000000, 1000, 10, 1, 8}, + { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */ + { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */ + { 26000000, 1300000000, 650, 13, 1, 8}, + + /* 1.2 GHz */ + { 12000000, 1200000000, 1000, 10, 1, 8}, + { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */ + { 16800000, 1200000000, 1000, 14, 1, 8}, + { 19200000, 1200000000, 1000, 16, 1, 8}, + { 26000000, 1200000000, 600, 13, 1, 8}, + + /* 1.1 GHz */ + { 12000000, 1100000000, 825, 9, 1, 8}, + { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */ + { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */ + { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */ + { 26000000, 1100000000, 550, 13, 1, 8}, + + /* 1 GHz */ + { 12000000, 1000000000, 1000, 12, 1, 8}, + { 13000000, 1000000000, 1000, 13, 1, 8}, + { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */ + { 19200000, 1000000000, 625, 12, 1, 8}, + { 26000000, 1000000000, 1000, 26, 1, 8}, + + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { + /* PLLE special case: use cpcon field to store cml divider value */ + { 12000000, 100000000, 150, 1, 18, 11}, + { 216000000, 100000000, 200, 18, 24, 13}, + { 0, 0, 0, 0, 0, 0 }, +}; + +/* PLL parameters */ +static struct tegra_clk_pll_params pll_c_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1400000000, + .base_reg = PLLC_BASE, + .misc_reg = PLLC_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_m_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1200000000, + .base_reg = PLLM_BASE, + .misc_reg = PLLM_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_p_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1400000000, + .base_reg = PLLP_BASE, + .misc_reg = PLLP_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_a_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1400000000, + .base_reg = PLLA_BASE, + .misc_reg = PLLA_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_d_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 40000000, + .vco_max = 1000000000, + .base_reg = PLLD_BASE, + .misc_reg = PLLD_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct tegra_clk_pll_params pll_d2_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 40000000, + .vco_max = 1000000000, + .base_reg = PLLD2_BASE, + .misc_reg = PLLD2_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct tegra_clk_pll_params pll_u_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 48000000, + .vco_max = 960000000, + .base_reg = PLLU_BASE, + .misc_reg = PLLU_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct tegra_clk_pll_params pll_x_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1700000000, + .base_reg = PLLX_BASE, + .misc_reg = PLLX_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_e_params = { + .input_min = 12000000, + .input_max = 216000000, + .cf_min = 12000000, + .cf_max = 12000000, + .vco_min = 1200000000, + .vco_max = 2400000000U, + .base_reg = PLLE_BASE, + .misc_reg = PLLE_MISC, + .lock_bit_idx = PLLE_MISC_LOCK, + .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +/* Peripheral clock registers */ +static struct tegra_clk_periph_regs periph_l_regs = { + .enb_reg = CLK_OUT_ENB_L, + .enb_set_reg = CLK_OUT_ENB_SET_L, + .enb_clr_reg = CLK_OUT_ENB_CLR_L, + .rst_reg = RST_DEVICES_L, + .rst_set_reg = RST_DEVICES_SET_L, + .rst_clr_reg = RST_DEVICES_CLR_L, +}; + +static struct tegra_clk_periph_regs periph_h_regs = { + .enb_reg = CLK_OUT_ENB_H, + .enb_set_reg = CLK_OUT_ENB_SET_H, + .enb_clr_reg = CLK_OUT_ENB_CLR_H, + .rst_reg = RST_DEVICES_H, + .rst_set_reg = RST_DEVICES_SET_H, + .rst_clr_reg = RST_DEVICES_CLR_H, +}; + +static struct tegra_clk_periph_regs periph_u_regs = { + .enb_reg = CLK_OUT_ENB_U, + .enb_set_reg = CLK_OUT_ENB_SET_U, + .enb_clr_reg = CLK_OUT_ENB_CLR_U, + .rst_reg = RST_DEVICES_U, + .rst_set_reg = RST_DEVICES_SET_U, + .rst_clr_reg = RST_DEVICES_CLR_U, +}; + +static struct tegra_clk_periph_regs periph_v_regs = { + .enb_reg = CLK_OUT_ENB_V, + .enb_set_reg = CLK_OUT_ENB_SET_V, + .enb_clr_reg = CLK_OUT_ENB_CLR_V, + .rst_reg = RST_DEVICES_V, + .rst_set_reg = RST_DEVICES_SET_V, + .rst_clr_reg = RST_DEVICES_CLR_V, +}; + +static struct tegra_clk_periph_regs periph_w_regs = { + .enb_reg = CLK_OUT_ENB_W, + .enb_set_reg = CLK_OUT_ENB_SET_W, + .enb_clr_reg = CLK_OUT_ENB_CLR_W, + .rst_reg = RST_DEVICES_W, + .rst_set_reg = RST_DEVICES_SET_W, + .rst_clr_reg = RST_DEVICES_CLR_W, +}; + +static void tegra30_clk_measure_input_freq(void) +{ + u32 osc_ctrl = readl_relaxed(clk_base + OSC_CTRL); + u32 auto_clk_control = osc_ctrl & OSC_CTRL_OSC_FREQ_MASK; + u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK; + + switch (auto_clk_control) { + case OSC_CTRL_OSC_FREQ_12MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 12000000; + break; + case OSC_CTRL_OSC_FREQ_13MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 13000000; + break; + case OSC_CTRL_OSC_FREQ_19_2MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 19200000; + break; + case OSC_CTRL_OSC_FREQ_26MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 26000000; + break; + case OSC_CTRL_OSC_FREQ_16_8MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 16800000; + break; + case OSC_CTRL_OSC_FREQ_38_4MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_2); + input_freq = 38400000; + break; + case OSC_CTRL_OSC_FREQ_48MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4); + input_freq = 48000000; + break; + default: + pr_err("Unexpected auto clock control value %d", + auto_clk_control); + BUG(); + return; + } +} + +static unsigned int tegra30_get_pll_ref_div(void) +{ + u32 pll_ref_div = readl_relaxed(clk_base + OSC_CTRL) & + OSC_CTRL_PLL_REF_DIV_MASK; + + switch (pll_ref_div) { + case OSC_CTRL_PLL_REF_DIV_1: + return 1; + case OSC_CTRL_PLL_REF_DIV_2: + return 2; + case OSC_CTRL_PLL_REF_DIV_4: + return 4; + default: + pr_err("Invalid pll ref divider %d", pll_ref_div); + BUG(); + } + return 0; +} + +static void tegra30_utmi_param_configure(void) +{ + u32 reg; + int i; + + for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) { + if (input_freq == utmi_parameters[i].osc_frequency) + break; + } + + if (i >= ARRAY_SIZE(utmi_parameters)) { + pr_err("%s: Unexpected input rate %lu\n", __func__, input_freq); + return; + } + + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2); + + /* Program UTMIP PLL stable and active counts */ + reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0); + reg |= UTMIP_PLL_CFG2_STABLE_COUNT( + utmi_parameters[i].stable_count); + + reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0); + + reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT( + utmi_parameters[i].active_delay_count); + + /* Remove power downs from UTMIP PLL control bits */ + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN; + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN; + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN; + + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2); + + /* Program UTMIP PLL delay and oscillator frequency counts */ + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1); + reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0); + + reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT( + utmi_parameters[i].enable_delay_count); + + reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0); + reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT( + utmi_parameters[i].xtal_freq_count); + + /* Remove power downs from UTMIP PLL control bits */ + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN; + + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1); +} + +static const char *pll_e_parents[] = {"pll_ref", "pll_p"}; + +static void __init tegra30_pll_init(void) +{ + struct clk *clk; + + /* PLLC */ + clk = tegra_clk_register_pll("pll_c", "pll_ref", clk_base, pmc_base, 0, + 0, &pll_c_params, + TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK, + pll_c_freq_table, NULL); + clk_register_clkdev(clk, "pll_c", NULL); + clks[pll_c] = clk; + + /* PLLC_OUT1 */ + clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", + clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", + clk_base + PLLC_OUT, 1, 0, CLK_SET_RATE_PARENT, + 0, NULL); + clk_register_clkdev(clk, "pll_c_out1", NULL); + clks[pll_c_out1] = clk; + + /* PLLP */ + clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, pmc_base, 0, + 408000000, &pll_p_params, + TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_USE_LOCK, pll_p_freq_table, NULL); + clk_register_clkdev(clk, "pll_p", NULL); + clks[pll_p] = clk; + + /* PLLP_OUT1 */ + clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p", + clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | + TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, + &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div", + clk_base + PLLP_OUTA, 1, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out1", NULL); + clks[pll_p_out1] = clk; + + /* PLLP_OUT2 */ + clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p", + clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | + TEGRA_DIVIDER_ROUND_UP, 24, 8, 1, + &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div", + clk_base + PLLP_OUTA, 17, 16, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out2", NULL); + clks[pll_p_out2] = clk; + + /* PLLP_OUT3 */ + clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p", + clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED | + TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, + &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div", + clk_base + PLLP_OUTB, 1, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out3", NULL); + clks[pll_p_out3] = clk; + + /* PLLP_OUT4 */ + clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p", + clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED | + TEGRA_DIVIDER_ROUND_UP, 24, 8, 1, + &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div", + clk_base + PLLP_OUTB, 17, 16, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out4", NULL); + clks[pll_p_out4] = clk; + + /* PLLM */ + clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, pmc_base, + CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, + &pll_m_params, TEGRA_PLLM | TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK, + pll_m_freq_table, NULL); + clk_register_clkdev(clk, "pll_m", NULL); + clks[pll_m] = clk; + + /* PLLM_OUT1 */ + clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m", + clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", + clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_m_out1", NULL); + clks[pll_m_out1] = clk; + + /* PLLX */ + clk = tegra_clk_register_pll("pll_x", "pll_ref", clk_base, pmc_base, 0, + 0, &pll_x_params, TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK, + pll_x_freq_table, NULL); + clk_register_clkdev(clk, "pll_x", NULL); + clks[pll_x] = clk; + + /* PLLX_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_x_out0", NULL); + clks[pll_x_out0] = clk; + + /* PLLU */ + clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc_base, 0, + 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK, + pll_u_freq_table, + NULL); + clk_register_clkdev(clk, "pll_u", NULL); + clks[pll_u] = clk; + + tegra30_utmi_param_configure(); + + /* PLLD */ + clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc_base, 0, + 0, &pll_d_params, TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK, + pll_d_freq_table, &pll_d_lock); + clk_register_clkdev(clk, "pll_d", NULL); + clks[pll_d] = clk; + + /* PLLD_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_d_out0", NULL); + clks[pll_d_out0] = clk; + + /* PLLD2 */ + clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc_base, 0, + 0, &pll_d2_params, TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK, + pll_d_freq_table, NULL); + clk_register_clkdev(clk, "pll_d2", NULL); + clks[pll_d2] = clk; + + /* PLLD2_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_d2_out0", NULL); + clks[pll_d2_out0] = clk; + + /* PLLA */ + clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, pmc_base, + 0, 0, &pll_a_params, TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_USE_LOCK, pll_a_freq_table, NULL); + clk_register_clkdev(clk, "pll_a", NULL); + clks[pll_a] = clk; + + /* PLLA_OUT0 */ + clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a", + clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div", + clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_a_out0", NULL); + clks[pll_a_out0] = clk; + + /* PLLE */ + clk = clk_register_mux(NULL, "pll_e_mux", pll_e_parents, + ARRAY_SIZE(pll_e_parents), 0, + clk_base + PLLE_AUX, 2, 1, 0, NULL); + clk = tegra_clk_register_plle("pll_e", "pll_e_mux", clk_base, pmc_base, + CLK_GET_RATE_NOCACHE, 100000000, &pll_e_params, + TEGRA_PLLE_CONFIGURE, pll_e_freq_table, NULL); + clk_register_clkdev(clk, "pll_e", NULL); + clks[pll_e] = clk; +} + +static const char *mux_audio_sync_clk[] = { "spdif_in_sync", "i2s0_sync", + "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync",}; +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2", + "clk_m_div4", "extern1", }; +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2", + "clk_m_div4", "extern2", }; +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2", + "clk_m_div4", "extern3", }; + +static void __init tegra30_audio_clk_init(void) +{ + struct clk *clk; + + /* spdif_in_sync */ + clk = tegra_clk_register_sync_source("spdif_in_sync", 24000000, + 24000000); + clk_register_clkdev(clk, "spdif_in_sync", NULL); + clks[spdif_in_sync] = clk; + + /* i2s0_sync */ + clk = tegra_clk_register_sync_source("i2s0_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s0_sync", NULL); + clks[i2s0_sync] = clk; + + /* i2s1_sync */ + clk = tegra_clk_register_sync_source("i2s1_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s1_sync", NULL); + clks[i2s1_sync] = clk; + + /* i2s2_sync */ + clk = tegra_clk_register_sync_source("i2s2_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s2_sync", NULL); + clks[i2s2_sync] = clk; + + /* i2s3_sync */ + clk = tegra_clk_register_sync_source("i2s3_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s3_sync", NULL); + clks[i2s3_sync] = clk; + + /* i2s4_sync */ + clk = tegra_clk_register_sync_source("i2s4_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s4_sync", NULL); + clks[i2s4_sync] = clk; + + /* vimclk_sync */ + clk = tegra_clk_register_sync_source("vimclk_sync", 24000000, 24000000); + clk_register_clkdev(clk, "vimclk_sync", NULL); + clks[vimclk_sync] = clk; + + /* audio0 */ + clk = clk_register_mux(NULL, "audio0_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S0, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "audio0", "audio0_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S0, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio0", NULL); + clks[audio0] = clk; + + /* audio1 */ + clk = clk_register_mux(NULL, "audio1_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S1, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "audio1", "audio1_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S1, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio1", NULL); + clks[audio1] = clk; + + /* audio2 */ + clk = clk_register_mux(NULL, "audio2_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S2, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "audio2", "audio2_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S2, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio2", NULL); + clks[audio2] = clk; + + /* audio3 */ + clk = clk_register_mux(NULL, "audio3_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S3, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "audio3", "audio3_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S3, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio3", NULL); + clks[audio3] = clk; + + /* audio4 */ + clk = clk_register_mux(NULL, "audio4_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S4, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "audio4", "audio4_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S4, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio4", NULL); + clks[audio4] = clk; + + /* spdif */ + clk = clk_register_mux(NULL, "spdif_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_SPDIF, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "spdif", "spdif_mux", 0, + clk_base + AUDIO_SYNC_CLK_SPDIF, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "spdif", NULL); + clks[spdif] = clk; + + /* audio0_2x */ + clk = clk_register_fixed_factor(NULL, "audio0_doubler", "audio0", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio0_div", "audio0_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 24, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio0_2x", "audio0_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 113, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio0_2x", NULL); + clks[audio0_2x] = clk; + + /* audio1_2x */ + clk = clk_register_fixed_factor(NULL, "audio1_doubler", "audio1", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio1_div", "audio1_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 25, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio1_2x", "audio1_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 114, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio1_2x", NULL); + clks[audio1_2x] = clk; + + /* audio2_2x */ + clk = clk_register_fixed_factor(NULL, "audio2_doubler", "audio2", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio2_div", "audio2_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 26, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio2_2x", "audio2_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 115, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio2_2x", NULL); + clks[audio2_2x] = clk; + + /* audio3_2x */ + clk = clk_register_fixed_factor(NULL, "audio3_doubler", "audio3", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio3_div", "audio3_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 27, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio3_2x", "audio3_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 116, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio3_2x", NULL); + clks[audio3_2x] = clk; + + /* audio4_2x */ + clk = clk_register_fixed_factor(NULL, "audio4_doubler", "audio4", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio4_div", "audio4_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 28, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio4_2x", "audio4_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 117, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio4_2x", NULL); + clks[audio4_2x] = clk; + + /* spdif_2x */ + clk = clk_register_fixed_factor(NULL, "spdif_doubler", "spdif", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("spdif_div", "spdif_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 29, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("spdif_2x", "spdif_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 118, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "spdif_2x", NULL); + clks[spdif_2x] = clk; +} + +static void __init tegra30_pmc_clk_init(void) +{ + struct clk *clk; + + /* clk_out_1 */ + clk = clk_register_mux(NULL, "clk_out_1_mux", clk_out1_parents, + ARRAY_SIZE(clk_out1_parents), 0, + pmc_base + PMC_CLK_OUT_CNTRL, 6, 3, 0, + &clk_out_lock); + clks[clk_out_1_mux] = clk; + clk = clk_register_gate(NULL, "clk_out_1", "clk_out_1_mux", 0, + pmc_base + PMC_CLK_OUT_CNTRL, 2, 0, + &clk_out_lock); + clk_register_clkdev(clk, "extern1", "clk_out_1"); + clks[clk_out_1] = clk; + + /* clk_out_2 */ + clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents, + ARRAY_SIZE(clk_out1_parents), 0, + pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0, + &clk_out_lock); + clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0, + pmc_base + PMC_CLK_OUT_CNTRL, 10, 0, + &clk_out_lock); + clk_register_clkdev(clk, "extern2", "clk_out_2"); + clks[clk_out_2] = clk; + + /* clk_out_3 */ + clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents, + ARRAY_SIZE(clk_out1_parents), 0, + pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0, + &clk_out_lock); + clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0, + pmc_base + PMC_CLK_OUT_CNTRL, 18, 0, + &clk_out_lock); + clk_register_clkdev(clk, "extern3", "clk_out_3"); + clks[clk_out_3] = clk; + + /* blink */ + writel_relaxed(0, pmc_base + PMC_BLINK_TIMER); + clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, + pmc_base + PMC_DPD_PADS_ORIDE, + PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); + clk = clk_register_gate(NULL, "blink", "blink_override", 0, + pmc_base + PMC_CTRL, + PMC_CTRL_BLINK_ENB, 0, NULL); + clk_register_clkdev(clk, "blink", NULL); + clks[blink] = clk; + +} + +const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", + "pll_p_cclkg", "pll_p_out4_cclkg", + "pll_p_out3_cclkg", "unused", "pll_x" }; +const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", + "pll_p_cclklp", "pll_p_out4_cclklp", + "pll_p_out3_cclklp", "unused", "pll_x", + "pll_x_out0" }; +const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", + "pll_p_out3", "pll_p_out2", "unused", + "clk_32k", "pll_m_out1" }; + +static void __init tegra30_super_clk_init(void) +{ + struct clk *clk; + + /* + * Clock input to cclk_g divided from pll_p using + * U71 divider of cclk_g. + */ + clk = tegra_clk_register_divider("pll_p_cclkg", "pll_p", + clk_base + SUPER_CCLKG_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_cclkg", NULL); + + /* + * Clock input to cclk_g divided from pll_p_out3 using + * U71 divider of cclk_g. + */ + clk = tegra_clk_register_divider("pll_p_out3_cclkg", "pll_p_out3", + clk_base + SUPER_CCLKG_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_out3_cclkg", NULL); + + /* + * Clock input to cclk_g divided from pll_p_out4 using + * U71 divider of cclk_g. + */ + clk = tegra_clk_register_divider("pll_p_out4_cclkg", "pll_p_out4", + clk_base + SUPER_CCLKG_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_out4_cclkg", NULL); + + /* CCLKG */ + clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents, + ARRAY_SIZE(cclk_g_parents), + CLK_SET_RATE_PARENT, + clk_base + CCLKG_BURST_POLICY, + 0, 4, 0, 0, NULL); + clk_register_clkdev(clk, "cclk_g", NULL); + clks[cclk_g] = clk; + + /* + * Clock input to cclk_lp divided from pll_p using + * U71 divider of cclk_lp. + */ + clk = tegra_clk_register_divider("pll_p_cclklp", "pll_p", + clk_base + SUPER_CCLKLP_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_cclklp", NULL); + + /* + * Clock input to cclk_lp divided from pll_p_out3 using + * U71 divider of cclk_lp. + */ + clk = tegra_clk_register_divider("pll_p_out3_cclklp", "pll_p_out3", + clk_base + SUPER_CCLKG_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_out3_cclklp", NULL); + + /* + * Clock input to cclk_lp divided from pll_p_out4 using + * U71 divider of cclk_lp. + */ + clk = tegra_clk_register_divider("pll_p_out4_cclklp", "pll_p_out4", + clk_base + SUPER_CCLKLP_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_out4_cclklp", NULL); + + /* CCLKLP */ + clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents, + ARRAY_SIZE(cclk_lp_parents), + CLK_SET_RATE_PARENT, + clk_base + CCLKLP_BURST_POLICY, + TEGRA_DIVIDER_2, 4, 8, 9, + NULL); + clk_register_clkdev(clk, "cclk_lp", NULL); + clks[cclk_lp] = clk; + + /* SCLK */ + clk = tegra_clk_register_super_mux("sclk", sclk_parents, + ARRAY_SIZE(sclk_parents), + CLK_SET_RATE_PARENT, + clk_base + SCLK_BURST_POLICY, + 0, 4, 0, 0, NULL); + clk_register_clkdev(clk, "sclk", NULL); + clks[sclk] = clk; + + /* HCLK */ + clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, + clk_base + SYSTEM_CLK_RATE, 4, 2, 0, NULL); + clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT, + clk_base + SYSTEM_CLK_RATE, 7, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "hclk", NULL); + clks[hclk] = clk; + + /* PCLK */ + clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, + clk_base + SYSTEM_CLK_RATE, 0, 2, 0, NULL); + clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT, + clk_base + SYSTEM_CLK_RATE, 3, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "pclk", NULL); + clks[pclk] = clk; + + /* twd */ + clk = clk_register_fixed_factor(NULL, "twd", "cclk_g", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "twd", NULL); + clks[twd] = clk; +} + +static const char *mux_pllacp_clkm[] = { "pll_a_out0", "unused", "pll_p", + "clk_m" }; +static const char *mux_pllpcm_clkm[] = { "pll_p", "pll_c", "pll_m", "clk_m" }; +static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m" }; +static const char *i2s0_parents[] = { "pll_a_out0", "audio0_2x", "pll_p", + "clk_m" }; +static const char *i2s1_parents[] = { "pll_a_out0", "audio1_2x", "pll_p", + "clk_m" }; +static const char *i2s2_parents[] = { "pll_a_out0", "audio2_2x", "pll_p", + "clk_m" }; +static const char *i2s3_parents[] = { "pll_a_out0", "audio3_2x", "pll_p", + "clk_m" }; +static const char *i2s4_parents[] = { "pll_a_out0", "audio4_2x", "pll_p", + "clk_m" }; +static const char *spdif_out_parents[] = { "pll_a_out0", "spdif_2x", "pll_p", + "clk_m" }; +static const char *spdif_in_parents[] = { "pll_p", "pll_c", "pll_m" }; +static const char *mux_pllpc_clk32k_clkm[] = { "pll_p", "pll_c", "clk_32k", + "clk_m" }; +static const char *mux_pllpc_clkm_clk32k[] = { "pll_p", "pll_c", "clk_m", + "clk_32k" }; +static const char *mux_pllmcpa[] = { "pll_m", "pll_c", "pll_p", "pll_a_out0" }; +static const char *mux_pllpdc_clkm[] = { "pll_p", "pll_d_out0", "pll_c", + "clk_m" }; +static const char *mux_pllp_clkm[] = { "pll_p", "unused", "unused", "clk_m" }; +static const char *mux_pllpmdacd2_clkm[] = { "pll_p", "pll_m", "pll_d_out0", + "pll_a_out0", "pll_c", + "pll_d2_out0", "clk_m" }; +static const char *mux_plla_clk32k_pllp_clkm_plle[] = { "pll_a_out0", + "clk_32k", "pll_p", + "clk_m", "pll_e" }; +static const char *mux_plld_out0_plld2_out0[] = { "pll_d_out0", + "pll_d2_out0" }; + +static struct tegra_periph_init_data tegra_periph_clk_list[] = { + TEGRA_INIT_DATA_MUX("i2s0", NULL, "tegra30-i2s.0", i2s0_parents, CLK_SOURCE_I2S0, 30, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s0), + TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra30-i2s.1", i2s1_parents, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1), + TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra30-i2s.2", i2s2_parents, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2), + TEGRA_INIT_DATA_MUX("i2s3", NULL, "tegra30-i2s.3", i2s3_parents, CLK_SOURCE_I2S3, 101, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s3), + TEGRA_INIT_DATA_MUX("i2s4", NULL, "tegra30-i2s.4", i2s4_parents, CLK_SOURCE_I2S4, 102, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s4), + TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra30-spdif", spdif_out_parents, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out), + TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra30-spdif", spdif_in_parents, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in), + TEGRA_INIT_DATA_MUX("d_audio", "d_audio", "tegra30-ahub", mux_pllacp_clkm, CLK_SOURCE_D_AUDIO, 106, &periph_v_regs, 0, d_audio), + TEGRA_INIT_DATA_MUX("dam0", NULL, "tegra30-dam.0", mux_pllacp_clkm, CLK_SOURCE_DAM0, 108, &periph_v_regs, 0, dam0), + TEGRA_INIT_DATA_MUX("dam1", NULL, "tegra30-dam.1", mux_pllacp_clkm, CLK_SOURCE_DAM1, 109, &periph_v_regs, 0, dam1), + TEGRA_INIT_DATA_MUX("dam2", NULL, "tegra30-dam.2", mux_pllacp_clkm, CLK_SOURCE_DAM2, 110, &periph_v_regs, 0, dam2), + TEGRA_INIT_DATA_MUX("hda", "hda", "tegra30-hda", mux_pllpcm_clkm, CLK_SOURCE_HDA, 125, &periph_v_regs, 0, hda), + TEGRA_INIT_DATA_MUX("hda2codec_2x", "hda2codec", "tegra30-hda", mux_pllpcm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, &periph_v_regs, 0, hda2codec_2x), + TEGRA_INIT_DATA_MUX("sbc1", NULL, "spi_tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1), + TEGRA_INIT_DATA_MUX("sbc2", NULL, "spi_tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2), + TEGRA_INIT_DATA_MUX("sbc3", NULL, "spi_tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3), + TEGRA_INIT_DATA_MUX("sbc4", NULL, "spi_tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4), + TEGRA_INIT_DATA_MUX("sbc5", NULL, "spi_tegra.4", mux_pllpcm_clkm, CLK_SOURCE_SBC5, 104, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc5), + TEGRA_INIT_DATA_MUX("sbc6", NULL, "spi_tegra.5", mux_pllpcm_clkm, CLK_SOURCE_SBC6, 105, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc6), + TEGRA_INIT_DATA_MUX("sata_oob", NULL, "tegra_sata_oob", mux_pllpcm_clkm, CLK_SOURCE_SATA_OOB, 123, &periph_v_regs, TEGRA_PERIPH_ON_APB, sata_oob), + TEGRA_INIT_DATA_MUX("sata", NULL, "tegra_sata", mux_pllpcm_clkm, CLK_SOURCE_SATA, 124, &periph_v_regs, TEGRA_PERIPH_ON_APB, sata), + TEGRA_INIT_DATA_MUX("ndflash", NULL, "tegra_nand", mux_pllpcm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_l_regs, TEGRA_PERIPH_ON_APB, ndflash), + TEGRA_INIT_DATA_MUX("ndspeed", NULL, "tegra_nand_speed", mux_pllpcm_clkm, CLK_SOURCE_NDSPEED, 80, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed), + TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllpcm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir), + TEGRA_INIT_DATA_MUX("csite", NULL, "csite", mux_pllpcm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, TEGRA_PERIPH_ON_APB, csite), + TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllpcm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, TEGRA_PERIPH_ON_APB, la), + TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllpcm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr), + TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllpcm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi), + TEGRA_INIT_DATA_MUX("tsensor", NULL, "tegra-tsensor", mux_pllpc_clkm_clk32k, CLK_SOURCE_TSENSOR, 100, &periph_v_regs, TEGRA_PERIPH_ON_APB, tsensor), + TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllpc_clk32k_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow), + TEGRA_INIT_DATA_INT("vde", NULL, "vde", mux_pllpcm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde), + TEGRA_INIT_DATA_INT("vi", "vi", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi), + TEGRA_INIT_DATA_INT("epp", NULL, "epp", mux_pllmcpa, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp), + TEGRA_INIT_DATA_INT("mpe", NULL, "mpe", mux_pllmcpa, CLK_SOURCE_MPE, 60, &periph_h_regs, 0, mpe), + TEGRA_INIT_DATA_INT("host1x", NULL, "host1x", mux_pllmcpa, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x), + TEGRA_INIT_DATA_INT("3d", NULL, "3d", mux_pllmcpa, CLK_SOURCE_3D, 24, &periph_l_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d), + TEGRA_INIT_DATA_INT("3d2", NULL, "3d2", mux_pllmcpa, CLK_SOURCE_3D2, 98, &periph_v_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d2), + TEGRA_INIT_DATA_INT("2d", NULL, "2d", mux_pllmcpa, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr2d), + TEGRA_INIT_DATA_INT("se", NULL, "se", mux_pllpcm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, 0, se), + TEGRA_INIT_DATA_MUX("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect), + TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllpcm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor), + TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1), + TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2), + TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3), + TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4), + TEGRA_INIT_DATA_MUX("cve", NULL, "cve", mux_pllpdc_clkm, CLK_SOURCE_CVE, 49, &periph_h_regs, 0, cve), + TEGRA_INIT_DATA_MUX("tvo", NULL, "tvo", mux_pllpdc_clkm, CLK_SOURCE_TVO, 49, &periph_h_regs, 0, tvo), + TEGRA_INIT_DATA_MUX("tvdac", NULL, "tvdac", mux_pllpdc_clkm, CLK_SOURCE_TVDAC, 53, &periph_h_regs, 0, tvdac), + TEGRA_INIT_DATA_MUX("actmon", NULL, "actmon", mux_pllpc_clk32k_clkm, CLK_SOURCE_ACTMON, 119, &periph_v_regs, 0, actmon), + TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor), + TEGRA_INIT_DATA_DIV16("i2c1", "div-clk", "tegra-i2c.0", mux_pllp_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2c1), + TEGRA_INIT_DATA_DIV16("i2c2", "div-clk", "tegra-i2c.1", mux_pllp_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c2), + TEGRA_INIT_DATA_DIV16("i2c3", "div-clk", "tegra-i2c.2", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2c3), + TEGRA_INIT_DATA_DIV16("i2c4", "div-clk", "tegra-i2c.3", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2c4), + TEGRA_INIT_DATA_DIV16("i2c5", "div-clk", "tegra-i2c.4", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c5), + TEGRA_INIT_DATA_UART("uarta", NULL, "tegra_uart.0", mux_pllpcm_clkm, CLK_SOURCE_UARTA, 6, &periph_l_regs, uarta), + TEGRA_INIT_DATA_UART("uartb", NULL, "tegra_uart.1", mux_pllpcm_clkm, CLK_SOURCE_UARTB, 7, &periph_l_regs, uartb), + TEGRA_INIT_DATA_UART("uartc", NULL, "tegra_uart.2", mux_pllpcm_clkm, CLK_SOURCE_UARTC, 55, &periph_h_regs, uartc), + TEGRA_INIT_DATA_UART("uartd", NULL, "tegra_uart.3", mux_pllpcm_clkm, CLK_SOURCE_UARTD, 65, &periph_u_regs, uartd), + TEGRA_INIT_DATA_UART("uarte", NULL, "tegra_uart.4", mux_pllpcm_clkm, CLK_SOURCE_UARTE, 66, &periph_u_regs, uarte), + TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllpmdacd2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi), + TEGRA_INIT_DATA_MUX8("extern1", NULL, "extern1", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, &periph_v_regs, 0, extern1), + TEGRA_INIT_DATA_MUX8("extern2", NULL, "extern2", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, &periph_v_regs, 0, extern2), + TEGRA_INIT_DATA_MUX8("extern3", NULL, "extern3", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, &periph_v_regs, 0, extern3), + TEGRA_INIT_DATA("pwm", NULL, "pwm", mux_pllpc_clk32k_clkm, CLK_SOURCE_PWM, 28, 2, 0, 0, 8, 1, 0, &periph_l_regs, 17, periph_clk_enb_refcnt, 0, pwm), +}; + +static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = { + TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllpmdacd2_clkm, CLK_SOURCE_DISP1, 29, 3, 27, &periph_l_regs, 0, disp1), + TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllpmdacd2_clkm, CLK_SOURCE_DISP2, 29, 3, 26, &periph_l_regs, 0, disp2), + TEGRA_INIT_DATA_NODIV("dsib", NULL, "tegradc.1", mux_plld_out0_plld2_out0, CLK_SOURCE_DSIB, 25, 1, 82, &periph_u_regs, 0, dsib), +}; + +static void __init tegra30_periph_clk_init(void) +{ + struct tegra_periph_init_data *data; + struct clk *clk; + int i; + + /* apbdma */ + clk = tegra_clk_register_periph_gate("apbdma", "clk_m", 0, clk_base, 0, 34, + &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-apbdma"); + clks[apbdma] = clk; + + /* rtc */ + clk = tegra_clk_register_periph_gate("rtc", "clk_32k", + TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, + clk_base, 0, 4, &periph_l_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "rtc-tegra"); + clks[rtc] = clk; + + /* timer */ + clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base, 0, + 5, &periph_l_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "timer"); + clks[timer] = clk; + + /* kbc */ + clk = tegra_clk_register_periph_gate("kbc", "clk_32k", + TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, + clk_base, 0, 36, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-kbc"); + clks[kbc] = clk; + + /* csus */ + clk = tegra_clk_register_periph_gate("csus", "clk_m", + TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, + clk_base, 0, 92, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "csus", "tengra_camera"); + clks[csus] = clk; + + /* vcp */ + clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, clk_base, 0, 29, + &periph_l_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "vcp", "tegra-avp"); + clks[vcp] = clk; + + /* bsea */ + clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0, clk_base, 0, + 62, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "bsea", "tegra-avp"); + clks[bsea] = clk; + + /* bsev */ + clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0, clk_base, 0, + 63, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "bsev", "tegra-aes"); + clks[bsev] = clk; + + /* usbd */ + clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, 0, + 22, &periph_l_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "fsl-tegra-udc"); + clks[usbd] = clk; + + /* usb2 */ + clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base, 0, + 58, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-ehci.1"); + clks[usb2] = clk; + + /* usb3 */ + clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base, 0, + 59, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-ehci.2"); + clks[usb3] = clk; + + /* dsia */ + clk = tegra_clk_register_periph_gate("dsia", "pll_d_out0", 0, clk_base, + 0, 48, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "dsia", "tegradc.0"); + clks[dsia] = clk; + + /* csi */ + clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base, + 0, 52, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "csi", "tegra_camera"); + clks[csi] = clk; + + /* isp */ + clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0, 23, + &periph_l_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "isp", "tegra_camera"); + clks[isp] = clk; + + /* pcie */ + clk = tegra_clk_register_periph_gate("pcie", "clk_m", 0, clk_base, 0, + 70, &periph_u_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "pcie", "tegra-pcie"); + clks[pcie] = clk; + + /* afi */ + clk = tegra_clk_register_periph_gate("afi", "clk_m", 0, clk_base, 0, 72, + &periph_u_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "afi", "tegra-pcie"); + clks[afi] = clk; + + /* kfuse */ + clk = tegra_clk_register_periph_gate("kfuse", "clk_m", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 40, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "kfuse-tegra"); + clks[kfuse] = clk; + + /* fuse */ + clk = tegra_clk_register_periph_gate("fuse", "clk_m", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 39, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "fuse", "fuse-tegra"); + clks[fuse] = clk; + + /* fuse_burn */ + clk = tegra_clk_register_periph_gate("fuse_burn", "clk_m", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 39, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "fuse_burn", "fuse-tegra"); + clks[fuse_burn] = clk; + + /* apbif */ + clk = tegra_clk_register_periph_gate("apbif", "clk_m", 0, + clk_base, 0, 107, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "apbif", "tegra30-ahub"); + clks[apbif] = clk; + + /* hda2hdmi */ + clk = tegra_clk_register_periph_gate("hda2hdmi", "clk_m", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 128, &periph_w_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "hda2hdmi", "tegra30-hda"); + clks[hda2hdmi] = clk; + + /* sata_cold */ + clk = tegra_clk_register_periph_gate("sata_cold", "clk_m", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 129, &periph_w_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra_sata_cold"); + clks[sata_cold] = clk; + + /* dtv */ + clk = tegra_clk_register_periph_gate("dtv", "clk_m", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 79, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "dtv"); + clks[dtv] = clk; + + /* emc */ + clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, + ARRAY_SIZE(mux_pllmcp_clkm), 0, + clk_base + CLK_SOURCE_EMC, + 30, 2, 0, NULL); + clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, + 57, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "emc", NULL); + clks[emc] = clk; + + /* i2c1-fast */ + clk = clk_register_fixed_factor(NULL, "i2c1-fast", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "fast-clk", "tegra-i2c.0"); + + /* i2c2-fast */ + clk = clk_register_fixed_factor(NULL, "i2c2-fast", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "fast-clk", "tegra-i2c.1"); + + /* i2c3-fast */ + clk = clk_register_fixed_factor(NULL, "i2c3-fast", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "fast-clk", "tegra-i2c.2"); + + /* i2c4-fast */ + clk = clk_register_fixed_factor(NULL, "i2c4-fast", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "fast-clk", "tegra-i2c.3"); + + /* i2c5-fast */ + clk = clk_register_fixed_factor(NULL, "i2c5-fast", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "fast-clk", "tegra-i2c.5"); + + /* dsi1-fixed */ + clk = clk_register_fixed_factor(NULL, "dsi1-fixed", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "dsi-fixed", "tegradc.0"); + + /* dsi2-fixed */ + clk = clk_register_fixed_factor(NULL, "dsi2-fixed", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "dsi-fixed", "tegradc.1"); + + for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { + data = &tegra_periph_clk_list[i]; + clk = tegra_clk_register_periph(data->name, data->parent_names, + data->num_parents, &data->periph, + clk_base, data->offset); + clk_register_clkdev(clk, data->con_id, data->dev_id); + clks[data->clk_id] = clk; + } + + for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) { + data = &tegra_periph_nodiv_clk_list[i]; + clk = tegra_clk_register_periph_nodiv(data->name, + data->parent_names, + data->num_parents, &data->periph, + clk_base, data->offset); + clk_register_clkdev(clk, data->con_id, data->dev_id); + clks[data->clk_id] = clk; + } +} + +static void __init tegra30_fixed_clk_init(void) +{ + struct clk *clk; + + /* clk_32k */ + clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT, + 32768); + clk_register_clkdev(clk, "clk_32k", NULL); + clks[clk_32k] = clk; + + /* clk_m_div2 */ + clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "clk_m_div2", NULL); + clks[clk_m_div2] = clk; + + /* clk_m_div4 */ + clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m", + CLK_SET_RATE_PARENT, 1, 4); + clk_register_clkdev(clk, "clk_m_div4", NULL); + clks[clk_m_div4] = clk; + + /* cml0 */ + clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX, + 0, 0, &cml_lock); + clk_register_clkdev(clk, "cml0", NULL); + clks[cml0] = clk; + + /* cml1 */ + clk = clk_register_gate(NULL, "cml1", "pll_e", 0, clk_base + PLLE_AUX, + 1, 0, &cml_lock); + clk_register_clkdev(clk, "cml1", NULL); + clks[cml1] = clk; + + /* pciex */ + clk = clk_register_fixed_rate(NULL, "pciex", "pll_e", 0, 100000000); + clk_register_clkdev(clk, "pciex", NULL); + clks[pciex] = clk; +} + +static void __init tegra30_osc_clk_init(void) +{ + struct clk *clk; + unsigned int pll_ref_div; + + tegra30_clk_measure_input_freq(); + + /* clk_m */ + clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT, + input_freq); + clk_register_clkdev(clk, "clk_m", NULL); + clks[clk_m] = clk; + + /* pll_ref */ + pll_ref_div = tegra30_get_pll_ref_div(); + clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m", + CLK_SET_RATE_PARENT, 1, pll_ref_div); + clk_register_clkdev(clk, "pll_ref", NULL); + clks[pll_ref] = clk; +} + +/* Tegra30 CPU clock and reset control functions */ +static void tegra30_wait_cpu_in_reset(u32 cpu) +{ + unsigned int reg; + + do { + reg = readl(clk_base + + TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); + cpu_relax(); + } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ + + return; +} + +static void tegra30_put_cpu_in_reset(u32 cpu) +{ + writel(CPU_RESET(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); + dmb(); +} + +static void tegra30_cpu_out_of_reset(u32 cpu) +{ + writel(CPU_RESET(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); + wmb(); +} + + +static void tegra30_enable_cpu_clock(u32 cpu) +{ + unsigned int reg; + + writel(CPU_CLOCK(cpu), + clk_base + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); + reg = readl(clk_base + + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); +} + +static void tegra30_disable_cpu_clock(u32 cpu) +{ + + unsigned int reg; + + reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); + writel(reg | CPU_CLOCK(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); +} + +#ifdef CONFIG_PM_SLEEP +static bool tegra30_cpu_rail_off_ready(void) +{ + unsigned int cpu_rst_status; + int cpu_pwr_status; + + cpu_rst_status = readl(clk_base + + TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); + cpu_pwr_status = tegra_powergate_is_powered(TEGRA_POWERGATE_CPU1) || + tegra_powergate_is_powered(TEGRA_POWERGATE_CPU2) || + tegra_powergate_is_powered(TEGRA_POWERGATE_CPU3); + + if (((cpu_rst_status & 0xE) != 0xE) || cpu_pwr_status) + return false; + + return true; +} + +static void tegra30_cpu_clock_suspend(void) +{ + /* switch coresite to clk_m, save off original source */ + tegra30_cpu_clk_sctx.clk_csite_src = + readl(clk_base + CLK_RESET_SOURCE_CSITE); + writel(3<<30, clk_base + CLK_RESET_SOURCE_CSITE); + + tegra30_cpu_clk_sctx.cpu_burst = + readl(clk_base + CLK_RESET_CCLK_BURST); + tegra30_cpu_clk_sctx.pllx_base = + readl(clk_base + CLK_RESET_PLLX_BASE); + tegra30_cpu_clk_sctx.pllx_misc = + readl(clk_base + CLK_RESET_PLLX_MISC); + tegra30_cpu_clk_sctx.cclk_divider = + readl(clk_base + CLK_RESET_CCLK_DIVIDER); +} + +static void tegra30_cpu_clock_resume(void) +{ + unsigned int reg, policy; + + /* Is CPU complex already running on PLLX? */ + reg = readl(clk_base + CLK_RESET_CCLK_BURST); + policy = (reg >> CLK_RESET_CCLK_BURST_POLICY_SHIFT) & 0xF; + + if (policy == CLK_RESET_CCLK_IDLE_POLICY) + reg = (reg >> CLK_RESET_CCLK_IDLE_POLICY_SHIFT) & 0xF; + else if (policy == CLK_RESET_CCLK_RUN_POLICY) + reg = (reg >> CLK_RESET_CCLK_RUN_POLICY_SHIFT) & 0xF; + else + BUG(); + + if (reg != CLK_RESET_CCLK_BURST_POLICY_PLLX) { + /* restore PLLX settings if CPU is on different PLL */ + writel(tegra30_cpu_clk_sctx.pllx_misc, + clk_base + CLK_RESET_PLLX_MISC); + writel(tegra30_cpu_clk_sctx.pllx_base, + clk_base + CLK_RESET_PLLX_BASE); + + /* wait for PLL stabilization if PLLX was enabled */ + if (tegra30_cpu_clk_sctx.pllx_base & (1 << 30)) + udelay(300); + } + + /* + * Restore original burst policy setting for calls resulting from CPU + * LP2 in idle or system suspend. + */ + writel(tegra30_cpu_clk_sctx.cclk_divider, + clk_base + CLK_RESET_CCLK_DIVIDER); + writel(tegra30_cpu_clk_sctx.cpu_burst, + clk_base + CLK_RESET_CCLK_BURST); + + writel(tegra30_cpu_clk_sctx.clk_csite_src, + clk_base + CLK_RESET_SOURCE_CSITE); +} +#endif + +static struct tegra_cpu_car_ops tegra30_cpu_car_ops = { + .wait_for_reset = tegra30_wait_cpu_in_reset, + .put_in_reset = tegra30_put_cpu_in_reset, + .out_of_reset = tegra30_cpu_out_of_reset, + .enable_clock = tegra30_enable_cpu_clock, + .disable_clock = tegra30_disable_cpu_clock, +#ifdef CONFIG_PM_SLEEP + .rail_off_ready = tegra30_cpu_rail_off_ready, + .suspend = tegra30_cpu_clock_suspend, + .resume = tegra30_cpu_clock_resume, +#endif +}; + +static __initdata struct tegra_clk_init_table init_table[] = { + {uarta, pll_p, 408000000, 1}, + {pll_a, clk_max, 564480000, 1}, + {pll_a_out0, clk_max, 11289600, 1}, + {extern1, pll_a_out0, 0, 1}, + {clk_out_1_mux, extern1, 0, 0}, + {clk_out_1, clk_max, 0, 1}, + {blink, clk_max, 0, 1}, + {i2s0, pll_a_out0, 11289600, 0}, + {i2s1, pll_a_out0, 11289600, 0}, + {i2s2, pll_a_out0, 11289600, 0}, + {i2s3, pll_a_out0, 11289600, 0}, + {i2s4, pll_a_out0, 11289600, 0}, + {sdmmc1, pll_p, 48000000, 0}, + {sdmmc2, pll_p, 48000000, 0}, + {sdmmc3, pll_p, 48000000, 0}, + {pll_m, clk_max, 0, 1}, + {pclk, clk_max, 0, 1}, + {csite, clk_max, 0, 1}, + {emc, clk_max, 0, 1}, + {mselect, clk_max, 0, 1}, + {sbc1, pll_p, 100000000, 0}, + {sbc2, pll_p, 100000000, 0}, + {sbc3, pll_p, 100000000, 0}, + {sbc4, pll_p, 100000000, 0}, + {sbc5, pll_p, 100000000, 0}, + {sbc6, pll_p, 100000000, 0}, + {host1x, pll_c, 150000000, 0}, + {disp1, pll_p, 600000000, 0}, + {disp2, pll_p, 600000000, 0}, + {twd, clk_max, 0, 1}, + {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */ +}; + +/* + * Some clocks may be used by different drivers depending on the board + * configuration. List those here to register them twice in the clock lookup + * table under two names. + */ +static struct tegra_clk_duplicate tegra_clk_duplicates[] = { + TEGRA_CLK_DUPLICATE(uarta, "serial8250.0", NULL), + TEGRA_CLK_DUPLICATE(uartb, "serial8250.1", NULL), + TEGRA_CLK_DUPLICATE(uartc, "serial8250.2", NULL), + TEGRA_CLK_DUPLICATE(uartd, "serial8250.3", NULL), + TEGRA_CLK_DUPLICATE(uarte, "serial8250.4", NULL), + TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL), + TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), + TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), + TEGRA_CLK_DUPLICATE(pll_p, "tegradc.0", "parent"), + TEGRA_CLK_DUPLICATE(pll_p, "tegradc.1", "parent"), + TEGRA_CLK_DUPLICATE(pll_d2_out0, "hdmi", "parent"), + TEGRA_CLK_DUPLICATE(dsib, "tegradc.0", "dsib"), + TEGRA_CLK_DUPLICATE(dsia, "tegradc.1", "dsia"), + TEGRA_CLK_DUPLICATE(bsev, "tegra-avp", "bsev"), + TEGRA_CLK_DUPLICATE(bsev, "nvavp", "bsev"), + TEGRA_CLK_DUPLICATE(vde, "tegra-aes", "vde"), + TEGRA_CLK_DUPLICATE(bsea, "tegra-aes", "bsea"), + TEGRA_CLK_DUPLICATE(bsea, "nvavp", "bsea"), + TEGRA_CLK_DUPLICATE(cml1, "tegra_sata_cml", NULL), + TEGRA_CLK_DUPLICATE(cml0, "tegra_pcie", "cml"), + TEGRA_CLK_DUPLICATE(pciex, "tegra_pcie", "pciex"), + TEGRA_CLK_DUPLICATE(i2c1, "tegra-i2c-slave.0", NULL), + TEGRA_CLK_DUPLICATE(i2c2, "tegra-i2c-slave.1", NULL), + TEGRA_CLK_DUPLICATE(i2c3, "tegra-i2c-slave.2", NULL), + TEGRA_CLK_DUPLICATE(i2c4, "tegra-i2c-slave.3", NULL), + TEGRA_CLK_DUPLICATE(i2c5, "tegra-i2c-slave.4", NULL), + TEGRA_CLK_DUPLICATE(sbc1, "spi_slave_tegra.0", NULL), + TEGRA_CLK_DUPLICATE(sbc2, "spi_slave_tegra.1", NULL), + TEGRA_CLK_DUPLICATE(sbc3, "spi_slave_tegra.2", NULL), + TEGRA_CLK_DUPLICATE(sbc4, "spi_slave_tegra.3", NULL), + TEGRA_CLK_DUPLICATE(sbc5, "spi_slave_tegra.4", NULL), + TEGRA_CLK_DUPLICATE(sbc6, "spi_slave_tegra.5", NULL), + TEGRA_CLK_DUPLICATE(twd, "smp_twd", NULL), + TEGRA_CLK_DUPLICATE(vcp, "nvavp", "vcp"), + TEGRA_CLK_DUPLICATE(i2s0, NULL, "i2s0"), + TEGRA_CLK_DUPLICATE(i2s1, NULL, "i2s1"), + TEGRA_CLK_DUPLICATE(i2s2, NULL, "i2s2"), + TEGRA_CLK_DUPLICATE(i2s3, NULL, "i2s3"), + TEGRA_CLK_DUPLICATE(i2s4, NULL, "i2s4"), + TEGRA_CLK_DUPLICATE(dam0, NULL, "dam0"), + TEGRA_CLK_DUPLICATE(dam1, NULL, "dam1"), + TEGRA_CLK_DUPLICATE(dam2, NULL, "dam2"), + TEGRA_CLK_DUPLICATE(spdif_in, NULL, "spdif_in"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.0", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.1", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.2", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.3", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.4", "fast-clk"), + TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* MUST be the last entry */ +}; + +static const struct of_device_id pmc_match[] __initconst = { + { .compatible = "nvidia,tegra30-pmc" }, + {}, +}; + +void __init tegra30_clock_init(struct device_node *np) +{ + struct device_node *node; + int i; + + clk_base = of_iomap(np, 0); + if (!clk_base) { + pr_err("ioremap tegra30 CAR failed\n"); + return; + } + + node = of_find_matching_node(NULL, pmc_match); + if (!node) { + pr_err("Failed to find pmc node\n"); + BUG(); + } + + pmc_base = of_iomap(node, 0); + if (!pmc_base) { + pr_err("Can't map pmc registers\n"); + BUG(); + } + + tegra30_osc_clk_init(); + tegra30_fixed_clk_init(); + tegra30_pll_init(); + tegra30_super_clk_init(); + tegra30_periph_clk_init(); + tegra30_audio_clk_init(); + tegra30_pmc_clk_init(); + + for (i = 0; i < ARRAY_SIZE(clks); i++) { + if (IS_ERR(clks[i])) { + pr_err("Tegra30 clk %d: register failed with %ld\n", + i, PTR_ERR(clks[i])); + BUG(); + } + if (!clks[i]) + clks[i] = ERR_PTR(-EINVAL); + } + + tegra_init_dup_clks(tegra_clk_duplicates, clks, clk_max); + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + tegra_init_from_table(init_table, clks, clk_max); + + tegra_cpu_car_ops = &tegra30_cpu_car_ops; +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 82835f24533c..0744731c6229 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -493,4 +493,10 @@ void tegra20_clock_init(struct device_node *np); static inline void tegra20_clock_init(struct device_node *np) {} #endif /* CONFIG_ARCH_TEGRA_2x_SOC */ +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +void tegra30_clock_init(struct device_node *np); +#else +static inline void tegra30_clock_init(struct device_node *np) {} +#endif /* CONFIG_ARCH_TEGRA_3x_SOC */ + #endif /* TEGRA_CLK_H */ From 61fd290d213e25d5a119b8ca25644001ed9f8f2d Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:26 +0530 Subject: [PATCH 20/31] ARM: tegra: migrate to new clock code Migrate Tegra clock support to drivers/clk/tegra, this involves moving: 1. definition of tegra_cpu_car_ops to clk.c 2. definition of reset functions to clk-peripheral.c 3. change parent of cpu clock. 4. Remove legacy clock initialization. 5. Initialize clocks using DT. 6. Remove all instance of mach/clk.h Signed-off-by: Prashant Gaikwad [swarren: use to_clk_periph_gate().] Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/board-dt-tegra20.c | 30 ------------------ arch/arm/mach-tegra/board-dt-tegra30.c | 31 ------------------ arch/arm/mach-tegra/clock.c | 19 ----------- arch/arm/mach-tegra/common.c | 44 ++------------------------ arch/arm/mach-tegra/cpu-tegra.c | 2 +- arch/arm/mach-tegra/include/mach/clk.h | 3 -- arch/arm/mach-tegra/pcie.c | 2 +- arch/arm/mach-tegra/powergate.c | 2 +- drivers/clk/tegra/clk-periph.c | 38 ++++++++++++++++++++++ drivers/clk/tegra/clk.c | 16 ++++++++++ drivers/dma/tegra20-apb-dma.c | 2 +- drivers/gpu/drm/tegra/dc.c | 3 +- drivers/gpu/drm/tegra/drm.c | 1 - drivers/gpu/drm/tegra/hdmi.c | 3 +- drivers/i2c/busses/i2c-tegra.c | 3 +- drivers/input/keyboard/tegra-kbc.c | 2 +- drivers/spi/spi-tegra20-sflash.c | 2 +- drivers/spi/spi-tegra20-slink.c | 2 +- drivers/staging/nvec/nvec.c | 3 +- include/linux/clk/tegra.h | 5 +++ sound/soc/tegra/tegra30_ahub.c | 2 +- 21 files changed, 73 insertions(+), 142 deletions(-) diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index e1f87dd314ef..0c11b8af3af3 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -42,7 +42,6 @@ #include #include "board.h" -#include "clock.h" #include "common.h" #include "iomap.h" @@ -104,37 +103,8 @@ static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { {} }; -static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = { - /* name parent rate enabled */ - { "uarta", "pll_p", 216000000, true }, - { "uartd", "pll_p", 216000000, true }, - { "usbd", "clk_m", 12000000, false }, - { "usb2", "clk_m", 12000000, false }, - { "usb3", "clk_m", 12000000, false }, - { "pll_a", "pll_p_out1", 56448000, true }, - { "pll_a_out0", "pll_a", 11289600, true }, - { "cdev1", NULL, 0, true }, - { "blink", "clk_32k", 32768, true }, - { "i2s1", "pll_a_out0", 11289600, false}, - { "i2s2", "pll_a_out0", 11289600, false}, - { "sdmmc1", "pll_p", 48000000, false}, - { "sdmmc3", "pll_p", 48000000, false}, - { "sdmmc4", "pll_p", 48000000, false}, - { "spi", "pll_p", 20000000, false }, - { "sbc1", "pll_p", 100000000, false }, - { "sbc2", "pll_p", 100000000, false }, - { "sbc3", "pll_p", 100000000, false }, - { "sbc4", "pll_p", 100000000, false }, - { "host1x", "pll_c", 150000000, false }, - { "disp1", "pll_p", 600000000, false }, - { "disp2", "pll_p", 600000000, false }, - { NULL, NULL, 0, 0}, -}; - static void __init tegra_dt_init(void) { - tegra_clk_init_from_table(tegra_dt_clk_init_table); - /* * Finished with the static registrations now; fill in the missing * devices diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index cfe5fc02be77..92f6014d22a1 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -35,7 +35,6 @@ #include #include "board.h" -#include "clock.h" #include "common.h" #include "iomap.h" @@ -67,38 +66,8 @@ static struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { {} }; -static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = { - /* name parent rate enabled */ - { "uarta", "pll_p", 408000000, true }, - { "pll_a", "pll_p_out1", 564480000, true }, - { "pll_a_out0", "pll_a", 11289600, true }, - { "extern1", "pll_a_out0", 0, true }, - { "clk_out_1", "extern1", 0, true }, - { "blink", "clk_32k", 32768, true }, - { "i2s0", "pll_a_out0", 11289600, false}, - { "i2s1", "pll_a_out0", 11289600, false}, - { "i2s2", "pll_a_out0", 11289600, false}, - { "i2s3", "pll_a_out0", 11289600, false}, - { "i2s4", "pll_a_out0", 11289600, false}, - { "sdmmc1", "pll_p", 48000000, false}, - { "sdmmc3", "pll_p", 48000000, false}, - { "sdmmc4", "pll_p", 48000000, false}, - { "sbc1", "pll_p", 100000000, false}, - { "sbc2", "pll_p", 100000000, false}, - { "sbc3", "pll_p", 100000000, false}, - { "sbc4", "pll_p", 100000000, false}, - { "sbc5", "pll_p", 100000000, false}, - { "sbc6", "pll_p", 100000000, false}, - { "host1x", "pll_c", 150000000, false}, - { "disp1", "pll_p", 600000000, false}, - { "disp2", "pll_p", 600000000, false}, - { NULL, NULL, 0, 0}, -}; - static void __init tegra30_dt_init(void) { - tegra_clk_init_from_table(tegra_dt_clk_init_table); - of_platform_populate(NULL, of_default_bus_match_table, tegra30_auxdata_lookup, NULL); } diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 8c0ff061f8cf..baa0c5b008f1 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -31,9 +31,6 @@ #include "board.h" #include "clock.h" -/* Global data of Tegra CPU CAR ops */ -struct tegra_cpu_car_ops *tegra_cpu_car_ops; - /* * Locking: * @@ -131,22 +128,6 @@ void tegra_clk_init_from_table(struct tegra_clk_init_table *table) tegra_clk_init_one_from_table(table); } -void tegra_periph_reset_deassert(struct clk *c) -{ - struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c)); - BUG_ON(!clk->reset); - clk->reset(__clk_get_hw(c), false); -} -EXPORT_SYMBOL(tegra_periph_reset_deassert); - -void tegra_periph_reset_assert(struct clk *c) -{ - struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c)); - BUG_ON(!clk->reset); - clk->reset(__clk_get_hw(c), true); -} -EXPORT_SYMBOL(tegra_periph_reset_assert); - /* Several extended clock configuration bits (e.g., clock routing, clock * phase control) are included in PLL and peripheral clock source * registers. */ diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 3efe80b2af28..87dd69ccdf8e 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,6 @@ #include #include "board.h" -#include "clock.h" #include "common.h" #include "fuse.h" #include "iomap.h" @@ -65,6 +65,7 @@ static const struct of_device_id tegra_dt_irq_match[] __initconst = { void __init tegra_dt_init_irq(void) { + tegra_clocks_init(); tegra_init_irq(); of_irq_init(tegra_dt_irq_match); } @@ -80,43 +81,6 @@ void tegra_assert_system_reset(char mode, const char *cmd) writel_relaxed(reg, reset); } -#ifdef CONFIG_ARCH_TEGRA_2x_SOC -static __initdata struct tegra_clk_init_table tegra20_clk_init_table[] = { - /* name parent rate enabled */ - { "clk_m", NULL, 0, true }, - { "pll_p", "clk_m", 216000000, true }, - { "pll_p_out1", "pll_p", 28800000, true }, - { "pll_p_out2", "pll_p", 48000000, true }, - { "pll_p_out3", "pll_p", 72000000, true }, - { "pll_p_out4", "pll_p", 24000000, true }, - { "pll_c", "clk_m", 600000000, true }, - { "pll_c_out1", "pll_c", 120000000, true }, - { "sclk", "pll_c_out1", 120000000, true }, - { "hclk", "sclk", 120000000, true }, - { "pclk", "hclk", 60000000, true }, - { "csite", NULL, 0, true }, - { "emc", NULL, 0, true }, - { "cpu", NULL, 0, true }, - { NULL, NULL, 0, 0}, -}; -#endif - -#ifdef CONFIG_ARCH_TEGRA_3x_SOC -static __initdata struct tegra_clk_init_table tegra30_clk_init_table[] = { - /* name parent rate enabled */ - { "clk_m", NULL, 0, true }, - { "pll_p", "pll_ref", 408000000, true }, - { "pll_p_out1", "pll_p", 9600000, true }, - { "pll_p_out4", "pll_p", 102000000, true }, - { "sclk", "pll_p_out4", 102000000, true }, - { "hclk", "sclk", 102000000, true }, - { "pclk", "hclk", 51000000, true }, - { "csite", NULL, 0, true }, - { NULL, NULL, 0, 0}, -}; -#endif - - static void __init tegra_init_cache(void) { #ifdef CONFIG_CACHE_L2X0 @@ -141,8 +105,6 @@ void __init tegra20_init_early(void) tegra_cpu_reset_handler_init(); tegra_apb_io_init(); tegra_init_fuse(); - tegra2_init_clocks(); - tegra_clk_init_from_table(tegra20_clk_init_table); tegra_init_cache(); tegra_pmc_init(); tegra_powergate_init(); @@ -155,8 +117,6 @@ void __init tegra30_init_early(void) tegra_cpu_reset_handler_init(); tegra_apb_io_init(); tegra_init_fuse(); - tegra30_init_clocks(); - tegra_clk_init_from_table(tegra30_clk_init_table); tegra_init_cache(); tegra_pmc_init(); tegra_powergate_init(); diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c index 85d4a23bba03..ebffed67e2f5 100644 --- a/arch/arm/mach-tegra/cpu-tegra.c +++ b/arch/arm/mach-tegra/cpu-tegra.c @@ -266,7 +266,7 @@ static int __init tegra_cpufreq_init(void) if (IS_ERR(pll_x_clk)) return PTR_ERR(pll_x_clk); - pll_p_clk = clk_get_sys(NULL, "pll_p"); + pll_p_clk = clk_get_sys(NULL, "pll_p_cclk"); if (IS_ERR(pll_p_clk)) return PTR_ERR(pll_p_clk); diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h index 95f3a547c770..85bbf10a7d0d 100644 --- a/arch/arm/mach-tegra/include/mach/clk.h +++ b/arch/arm/mach-tegra/include/mach/clk.h @@ -31,9 +31,6 @@ enum tegra_clk_ex_param { TEGRA_CLK_PLLD_MIPI_MUX_SEL, }; -void tegra_periph_reset_deassert(struct clk *c); -void tegra_periph_reset_assert(struct clk *c); - #ifndef CONFIG_COMMON_CLK unsigned long clk_get_rate_all_locked(struct clk *c); #endif diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c index bffcd643d7a3..b60165f1ca02 100644 --- a/arch/arm/mach-tegra/pcie.c +++ b/arch/arm/mach-tegra/pcie.c @@ -33,11 +33,11 @@ #include #include #include +#include #include #include -#include #include #include "board.h" diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index 2cc1185d902e..c6bc8f85759c 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -26,8 +26,8 @@ #include #include #include +#include -#include #include #include "fuse.h" diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index 5978e81b175b..788486e6331a 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -110,6 +110,44 @@ static void clk_periph_disable(struct clk_hw *hw) gate_ops->disable(gate_hw); } +void tegra_periph_reset_deassert(struct clk *c) +{ + struct clk_hw *hw = __clk_get_hw(c); + struct tegra_clk_periph *periph = to_clk_periph(hw); + struct tegra_clk_periph_gate *gate; + + if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) { + gate = to_clk_periph_gate(hw); + if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) { + WARN_ON(1); + return; + } + } else { + gate = &periph->gate; + } + + tegra_periph_reset(gate, 0); +} + +void tegra_periph_reset_assert(struct clk *c) +{ + struct clk_hw *hw = __clk_get_hw(c); + struct tegra_clk_periph *periph = to_clk_periph(hw); + struct tegra_clk_periph_gate *gate; + + if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) { + gate = to_clk_periph_gate(hw); + if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) { + WARN_ON(1); + return; + } + } else { + gate = &periph->gate; + } + + tegra_periph_reset(gate, 1); +} + const struct clk_ops tegra_clk_periph_ops = { .get_parent = clk_periph_get_parent, .set_parent = clk_periph_set_parent, diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index cf023a937208..a603b9af0ad3 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -16,9 +16,14 @@ #include #include +#include +#include #include "clk.h" +/* Global data of Tegra CPU CAR ops */ +struct tegra_cpu_car_ops *tegra_cpu_car_ops; + void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, struct clk *clks[], int clk_max) { @@ -67,3 +72,14 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, } } } + +static const struct of_device_id tegra_dt_clk_match[] = { + { .compatible = "nvidia,tegra20-car", .data = tegra20_clock_init }, + { .compatible = "nvidia,tegra30-car", .data = tegra30_clock_init }, + { } +}; + +void __init tegra_clocks_init(void) +{ + of_clk_init(tegra_dt_clk_match); +} diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index c39e61bc8172..afc9b89e20f4 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -31,8 +31,8 @@ #include #include #include +#include -#include #include "dmaengine.h" #define TEGRA_APBDMA_GENERAL 0x0 diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 656b2e3334a6..56813f967c8f 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -12,8 +12,7 @@ #include #include #include - -#include +#include #include "drm.h" #include "dc.h" diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 3a503c9e4686..d980dc75788c 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -11,7 +11,6 @@ #include #include -#include #include #include diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index e060c7e6434d..92ad276cc5e0 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -14,8 +14,7 @@ #include #include #include - -#include +#include #include "hdmi.h" #include "drm.h" diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 7b38877ffec1..c7aca35e38fd 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -29,11 +29,10 @@ #include #include #include +#include #include -#include - #define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000)) #define BYTES_PER_FIFO_WORD 4 diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index c76f96872d31..54ac1dc7d477 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #define KBC_MAX_DEBOUNCE_CNT 0x3ffu diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 448a8cc71df3..02feaa51a0fa 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #define SPI_COMMAND 0x000 #define SPI_GO BIT(30) diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 651167f2e0af..fa208a5cc612 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #define SLINK_COMMAND 0x000 #define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0) diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 2830946860d1..d51615b19797 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -37,8 +37,7 @@ #include #include #include - -#include +#include #include "nvec.h" diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index 0977f2a24757..a7e5a3999099 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -17,6 +17,8 @@ #ifndef __LINUX_CLK_TEGRA_H_ #define __LINUX_CLK_TEGRA_H_ +#include + /* * Tegra CPU clock and reset control ops * @@ -120,5 +122,8 @@ static inline void tegra_cpu_clock_resume(void) void tegra20_cpu_car_ops_init(void); void tegra30_cpu_car_ops_init(void); +void tegra_periph_reset_deassert(struct clk *c); +void tegra_periph_reset_assert(struct clk *c); +void tegra_clocks_init(void); #endif /* __LINUX_CLK_TEGRA_H_ */ diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index f354dc390a0b..bb31c4123a7b 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include "tegra30_ahub.h" From 52dec4c9eacc339dbf1b2ab549248df1cc6eb030 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:27 +0530 Subject: [PATCH 21/31] ARM: tegra: remove legacy clock code Remove all legacy clock code from mach-tegra. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/Makefile | 5 - arch/arm/mach-tegra/clock.c | 147 -- arch/arm/mach-tegra/clock.h | 153 -- arch/arm/mach-tegra/include/mach/clk.h | 41 - arch/arm/mach-tegra/tegra20_clocks.c | 1623 ------------- arch/arm/mach-tegra/tegra20_clocks.h | 42 - arch/arm/mach-tegra/tegra20_clocks_data.c | 1143 ---------- arch/arm/mach-tegra/tegra30_clocks.c | 2506 --------------------- arch/arm/mach-tegra/tegra30_clocks.h | 54 - arch/arm/mach-tegra/tegra30_clocks_data.c | 1425 ------------ include/linux/clk/tegra.h | 2 - 11 files changed, 7141 deletions(-) delete mode 100644 arch/arm/mach-tegra/clock.c delete mode 100644 arch/arm/mach-tegra/clock.h delete mode 100644 arch/arm/mach-tegra/include/mach/clk.h delete mode 100644 arch/arm/mach-tegra/tegra20_clocks.c delete mode 100644 arch/arm/mach-tegra/tegra20_clocks.h delete mode 100644 arch/arm/mach-tegra/tegra20_clocks_data.c delete mode 100644 arch/arm/mach-tegra/tegra30_clocks.c delete mode 100644 arch/arm/mach-tegra/tegra30_clocks.h delete mode 100644 arch/arm/mach-tegra/tegra30_clocks_data.c diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index f0520961bafe..6018a05e808c 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -1,7 +1,6 @@ obj-y += common.o obj-y += io.o obj-y += irq.o -obj-y += clock.o obj-y += fuse.o obj-y += pmc.o obj-y += flowctrl.o @@ -12,16 +11,12 @@ obj-y += reset.o obj-y += reset-handler.o obj-y += sleep.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o -obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o -obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o endif -obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o -obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o ifeq ($(CONFIG_CPU_IDLE),y) diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c deleted file mode 100644 index baa0c5b008f1..000000000000 --- a/arch/arm/mach-tegra/clock.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * - * Copyright (C) 2010 Google, Inc. - * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved. - * - * Author: - * Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "board.h" -#include "clock.h" - -/* - * Locking: - * - * An additional mutex, clock_list_lock, is used to protect the list of all - * clocks. - * - */ -static DEFINE_MUTEX(clock_list_lock); -static LIST_HEAD(clocks); - -void tegra_clk_add(struct clk *clk) -{ - struct clk_tegra *c = to_clk_tegra(__clk_get_hw(clk)); - - mutex_lock(&clock_list_lock); - list_add(&c->node, &clocks); - mutex_unlock(&clock_list_lock); -} - -struct clk *tegra_get_clock_by_name(const char *name) -{ - struct clk_tegra *c; - struct clk *ret = NULL; - mutex_lock(&clock_list_lock); - list_for_each_entry(c, &clocks, node) { - if (strcmp(__clk_get_name(c->hw.clk), name) == 0) { - ret = c->hw.clk; - break; - } - } - mutex_unlock(&clock_list_lock); - return ret; -} - -static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table) -{ - struct clk *c; - struct clk *p; - struct clk *parent; - - int ret = 0; - - c = tegra_get_clock_by_name(table->name); - - if (!c) { - pr_warn("Unable to initialize clock %s\n", - table->name); - return -ENODEV; - } - - parent = clk_get_parent(c); - - if (table->parent) { - p = tegra_get_clock_by_name(table->parent); - if (!p) { - pr_warn("Unable to find parent %s of clock %s\n", - table->parent, table->name); - return -ENODEV; - } - - if (parent != p) { - ret = clk_set_parent(c, p); - if (ret) { - pr_warn("Unable to set parent %s of clock %s: %d\n", - table->parent, table->name, ret); - return -EINVAL; - } - } - } - - if (table->rate && table->rate != clk_get_rate(c)) { - ret = clk_set_rate(c, table->rate); - if (ret) { - pr_warn("Unable to set clock %s to rate %lu: %d\n", - table->name, table->rate, ret); - return -EINVAL; - } - } - - if (table->enabled) { - ret = clk_prepare_enable(c); - if (ret) { - pr_warn("Unable to enable clock %s: %d\n", - table->name, ret); - return -EINVAL; - } - } - - return 0; -} - -void tegra_clk_init_from_table(struct tegra_clk_init_table *table) -{ - for (; table->name; table++) - tegra_clk_init_one_from_table(table); -} - -/* Several extended clock configuration bits (e.g., clock routing, clock - * phase control) are included in PLL and peripheral clock source - * registers. */ -int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) -{ - int ret = 0; - struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c)); - - if (!clk->clk_cfg_ex) { - ret = -ENOSYS; - goto out; - } - ret = clk->clk_cfg_ex(__clk_get_hw(c), p, setting); - -out: - return ret; -} diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h deleted file mode 100644 index 2aa37f5c44c0..000000000000 --- a/arch/arm/mach-tegra/clock.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * arch/arm/mach-tegra/include/mach/clock.h - * - * Copyright (C) 2010 Google, Inc. - * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved. - * - * Author: - * Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that 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. - * - */ - -#ifndef __MACH_TEGRA_CLOCK_H -#define __MACH_TEGRA_CLOCK_H - -#include -#include -#include - -#include - -#define DIV_BUS (1 << 0) -#define DIV_U71 (1 << 1) -#define DIV_U71_FIXED (1 << 2) -#define DIV_2 (1 << 3) -#define DIV_U16 (1 << 4) -#define PLL_FIXED (1 << 5) -#define PLL_HAS_CPCON (1 << 6) -#define MUX (1 << 7) -#define PLLD (1 << 8) -#define PERIPH_NO_RESET (1 << 9) -#define PERIPH_NO_ENB (1 << 10) -#define PERIPH_EMC_ENB (1 << 11) -#define PERIPH_MANUAL_RESET (1 << 12) -#define PLL_ALT_MISC_REG (1 << 13) -#define PLLU (1 << 14) -#define PLLX (1 << 15) -#define MUX_PWM (1 << 16) -#define MUX8 (1 << 17) -#define DIV_U71_UART (1 << 18) -#define MUX_CLK_OUT (1 << 19) -#define PLLM (1 << 20) -#define DIV_U71_INT (1 << 21) -#define DIV_U71_IDLE (1 << 22) -#define ENABLE_ON_INIT (1 << 28) -#define PERIPH_ON_APB (1 << 29) - -struct clk_tegra; -#define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw) - -struct clk_mux_sel { - struct clk *input; - u32 value; -}; - -struct clk_pll_freq_table { - unsigned long input_rate; - unsigned long output_rate; - u16 n; - u16 m; - u8 p; - u8 cpcon; -}; - -enum clk_state { - UNINITIALIZED = 0, - ON, - OFF, -}; - -struct clk_tegra { - /* node for master clocks list */ - struct list_head node; /* node for list of all clocks */ - struct clk_lookup lookup; - struct clk_hw hw; - - bool set; - unsigned long fixed_rate; - unsigned long max_rate; - unsigned long min_rate; - u32 flags; - const char *name; - - enum clk_state state; - u32 div; - u32 mul; - - u32 reg; - u32 reg_shift; - - struct list_head shared_bus_list; - - union { - struct { - unsigned int clk_num; - } periph; - struct { - unsigned long input_min; - unsigned long input_max; - unsigned long cf_min; - unsigned long cf_max; - unsigned long vco_min; - unsigned long vco_max; - const struct clk_pll_freq_table *freq_table; - int lock_delay; - unsigned long fixed_rate; - } pll; - struct { - u32 sel; - u32 reg_mask; - } mux; - struct { - struct clk *main; - struct clk *backup; - } cpu; - struct { - struct list_head node; - bool enabled; - unsigned long rate; - } shared_bus_user; - } u; - - void (*reset)(struct clk_hw *, bool); - int (*clk_cfg_ex)(struct clk_hw *, enum tegra_clk_ex_param, u32); -}; - -struct clk_duplicate { - const char *name; - struct clk_lookup lookup; -}; - -struct tegra_clk_init_table { - const char *name; - const char *parent; - unsigned long rate; - bool enabled; -}; - -void tegra_clk_add(struct clk *c); -void tegra2_init_clocks(void); -void tegra30_init_clocks(void); -struct clk *tegra_get_clock_by_name(const char *name); -void tegra_clk_init_from_table(struct tegra_clk_init_table *table); - -#endif diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h deleted file mode 100644 index 85bbf10a7d0d..000000000000 --- a/arch/arm/mach-tegra/include/mach/clk.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * arch/arm/mach-tegra/include/mach/clk.h - * - * Copyright (C) 2010 Google, Inc. - * - * Author: - * Erik Gilling - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that 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. - * - */ - -#ifndef __MACH_CLK_H -#define __MACH_CLK_H - -struct clk; - -enum tegra_clk_ex_param { - TEGRA_CLK_VI_INP_SEL, - TEGRA_CLK_DTV_INVERT, - TEGRA_CLK_NAND_PAD_DIV2_ENB, - TEGRA_CLK_PLLD_CSI_OUT_ENB, - TEGRA_CLK_PLLD_DSI_OUT_ENB, - TEGRA_CLK_PLLD_MIPI_MUX_SEL, -}; - -#ifndef CONFIG_COMMON_CLK -unsigned long clk_get_rate_all_locked(struct clk *c); -#endif - -void tegra2_sdmmc_tap_delay(struct clk *c, int delay); -int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting); - -#endif diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c deleted file mode 100644 index 1a80ff65e5fc..000000000000 --- a/arch/arm/mach-tegra/tegra20_clocks.c +++ /dev/null @@ -1,1623 +0,0 @@ -/* - * arch/arm/mach-tegra/tegra20_clocks.c - * - * Copyright (C) 2010 Google, Inc. - * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved. - * - * Author: - * Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clock.h" -#include "fuse.h" -#include "iomap.h" -#include "tegra2_emc.h" - -#define RST_DEVICES 0x004 -#define RST_DEVICES_SET 0x300 -#define RST_DEVICES_CLR 0x304 -#define RST_DEVICES_NUM 3 - -#define CLK_OUT_ENB 0x010 -#define CLK_OUT_ENB_SET 0x320 -#define CLK_OUT_ENB_CLR 0x324 -#define CLK_OUT_ENB_NUM 3 - -#define CLK_MASK_ARM 0x44 -#define MISC_CLK_ENB 0x48 - -#define OSC_CTRL 0x50 -#define OSC_CTRL_OSC_FREQ_MASK (3<<30) -#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30) -#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30) -#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30) -#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30) -#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK) - -#define OSC_FREQ_DET 0x58 -#define OSC_FREQ_DET_TRIG (1<<31) - -#define OSC_FREQ_DET_STATUS 0x5C -#define OSC_FREQ_DET_BUSY (1<<31) -#define OSC_FREQ_DET_CNT_MASK 0xFFFF - -#define PERIPH_CLK_SOURCE_I2S1 0x100 -#define PERIPH_CLK_SOURCE_EMC 0x19c -#define PERIPH_CLK_SOURCE_OSC 0x1fc -#define PERIPH_CLK_SOURCE_NUM \ - ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4) - -#define PERIPH_CLK_SOURCE_MASK (3<<30) -#define PERIPH_CLK_SOURCE_SHIFT 30 -#define PERIPH_CLK_SOURCE_PWM_MASK (7<<28) -#define PERIPH_CLK_SOURCE_PWM_SHIFT 28 -#define PERIPH_CLK_SOURCE_ENABLE (1<<28) -#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF -#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF -#define PERIPH_CLK_SOURCE_DIV_SHIFT 0 - -#define SDMMC_CLK_INT_FB_SEL (1 << 23) -#define SDMMC_CLK_INT_FB_DLY_SHIFT 16 -#define SDMMC_CLK_INT_FB_DLY_MASK (0xF << SDMMC_CLK_INT_FB_DLY_SHIFT) - -#define PLL_BASE 0x0 -#define PLL_BASE_BYPASS (1<<31) -#define PLL_BASE_ENABLE (1<<30) -#define PLL_BASE_REF_ENABLE (1<<29) -#define PLL_BASE_OVERRIDE (1<<28) -#define PLL_BASE_DIVP_MASK (0x7<<20) -#define PLL_BASE_DIVP_SHIFT 20 -#define PLL_BASE_DIVN_MASK (0x3FF<<8) -#define PLL_BASE_DIVN_SHIFT 8 -#define PLL_BASE_DIVM_MASK (0x1F) -#define PLL_BASE_DIVM_SHIFT 0 - -#define PLL_OUT_RATIO_MASK (0xFF<<8) -#define PLL_OUT_RATIO_SHIFT 8 -#define PLL_OUT_OVERRIDE (1<<2) -#define PLL_OUT_CLKEN (1<<1) -#define PLL_OUT_RESET_DISABLE (1<<0) - -#define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc) - -#define PLL_MISC_DCCON_SHIFT 20 -#define PLL_MISC_CPCON_SHIFT 8 -#define PLL_MISC_CPCON_MASK (0xF<u.periph.clk_num / 32) * 4) -#define PERIPH_CLK_TO_ENB_SET_REG(c) ((c->u.periph.clk_num / 32) * 8) -#define PERIPH_CLK_TO_ENB_BIT(c) (1 << (c->u.periph.clk_num % 32)) - -#define SUPER_CLK_MUX 0x00 -#define SUPER_STATE_SHIFT 28 -#define SUPER_STATE_MASK (0xF << SUPER_STATE_SHIFT) -#define SUPER_STATE_STANDBY (0x0 << SUPER_STATE_SHIFT) -#define SUPER_STATE_IDLE (0x1 << SUPER_STATE_SHIFT) -#define SUPER_STATE_RUN (0x2 << SUPER_STATE_SHIFT) -#define SUPER_STATE_IRQ (0x3 << SUPER_STATE_SHIFT) -#define SUPER_STATE_FIQ (0x4 << SUPER_STATE_SHIFT) -#define SUPER_SOURCE_MASK 0xF -#define SUPER_FIQ_SOURCE_SHIFT 12 -#define SUPER_IRQ_SOURCE_SHIFT 8 -#define SUPER_RUN_SOURCE_SHIFT 4 -#define SUPER_IDLE_SOURCE_SHIFT 0 - -#define SUPER_CLK_DIVIDER 0x04 - -#define BUS_CLK_DISABLE (1<<3) -#define BUS_CLK_DIV_MASK 0x3 - -#define PMC_CTRL 0x0 - #define PMC_CTRL_BLINK_ENB (1 << 7) - -#define PMC_DPD_PADS_ORIDE 0x1c - #define PMC_DPD_PADS_ORIDE_BLINK_ENB (1 << 20) - -#define PMC_BLINK_TIMER_DATA_ON_SHIFT 0 -#define PMC_BLINK_TIMER_DATA_ON_MASK 0x7fff -#define PMC_BLINK_TIMER_ENB (1 << 15) -#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16 -#define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff - -/* Tegra CPU clock and reset control regs */ -#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c -#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 -#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344 - -#define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) -#define CPU_RESET(cpu) (0x1111ul << (cpu)) - -static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE); -static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - -/* - * Some clocks share a register with other clocks. Any clock op that - * non-atomically modifies a register used by another clock must lock - * clock_register_lock first. - */ -static DEFINE_SPINLOCK(clock_register_lock); - -/* - * Some peripheral clocks share an enable bit, so refcount the enable bits - * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U - */ -static int tegra_periph_clk_enable_refcount[3 * 32]; - -#define clk_writel(value, reg) \ - __raw_writel(value, reg_clk_base + (reg)) -#define clk_readl(reg) \ - __raw_readl(reg_clk_base + (reg)) -#define pmc_writel(value, reg) \ - __raw_writel(value, reg_pmc_base + (reg)) -#define pmc_readl(reg) \ - __raw_readl(reg_pmc_base + (reg)) - -static unsigned long clk_measure_input_freq(void) -{ - u32 clock_autodetect; - clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET); - do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY); - clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS); - if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) { - return 12000000; - } else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) { - return 13000000; - } else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) { - return 19200000; - } else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) { - return 26000000; - } else { - pr_err("%s: Unexpected clock autodetect value %d", - __func__, clock_autodetect); - BUG(); - return 0; - } -} - -static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate) -{ - s64 divider_u71 = parent_rate * 2; - divider_u71 += rate - 1; - do_div(divider_u71, rate); - - if (divider_u71 - 2 < 0) - return 0; - - if (divider_u71 - 2 > 255) - return -EINVAL; - - return divider_u71 - 2; -} - -static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate) -{ - s64 divider_u16; - - divider_u16 = parent_rate; - divider_u16 += rate - 1; - do_div(divider_u16, rate); - - if (divider_u16 - 1 < 0) - return 0; - - if (divider_u16 - 1 > 0xFFFF) - return -EINVAL; - - return divider_u16 - 1; -} - -static unsigned long tegra_clk_fixed_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - return to_clk_tegra(hw)->fixed_rate; -} - -struct clk_ops tegra_clk_32k_ops = { - .recalc_rate = tegra_clk_fixed_recalc_rate, -}; - -/* clk_m functions */ -static unsigned long tegra20_clk_m_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - if (!to_clk_tegra(hw)->fixed_rate) - to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq(); - return to_clk_tegra(hw)->fixed_rate; -} - -static void tegra20_clk_m_init(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 osc_ctrl = clk_readl(OSC_CTRL); - u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK; - - switch (c->fixed_rate) { - case 12000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ; - break; - case 13000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ; - break; - case 19200000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ; - break; - case 26000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ; - break; - default: - BUG(); - } - clk_writel(auto_clock_control, OSC_CTRL); -} - -struct clk_ops tegra_clk_m_ops = { - .init = tegra20_clk_m_init, - .recalc_rate = tegra20_clk_m_recalc_rate, -}; - -/* super clock functions */ -/* "super clocks" on tegra have two-stage muxes and a clock skipping - * super divider. We will ignore the clock skipping divider, since we - * can't lower the voltage when using the clock skip, but we can if we - * lower the PLL frequency. - */ -static int tegra20_super_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg + SUPER_CLK_MUX); - BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && - ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); - c->state = ON; - return c->state; -} - -static int tegra20_super_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - clk_writel(0, c->reg + SUPER_CLK_DIVIDER); - return 0; -} - -static void tegra20_super_clk_disable(struct clk_hw *hw) -{ - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - /* oops - don't disable the CPU clock! */ - BUG(); -} - -static u8 tegra20_super_clk_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - int val = clk_readl(c->reg + SUPER_CLK_MUX); - int source; - int shift; - - BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && - ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); - shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ? - SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT; - source = (val >> shift) & SUPER_SOURCE_MASK; - return source; -} - -static int tegra20_super_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg + SUPER_CLK_MUX); - int shift; - - BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && - ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); - shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ? - SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT; - val &= ~(SUPER_SOURCE_MASK << shift); - val |= index << shift; - - clk_writel(val, c->reg); - - return 0; -} - -/* FIX ME: Need to switch parents to change the source PLL rate */ -static unsigned long tegra20_super_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - return prate; -} - -static long tegra20_super_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - return *prate; -} - -static int tegra20_super_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - return 0; -} - -struct clk_ops tegra_super_ops = { - .is_enabled = tegra20_super_clk_is_enabled, - .enable = tegra20_super_clk_enable, - .disable = tegra20_super_clk_disable, - .set_parent = tegra20_super_clk_set_parent, - .get_parent = tegra20_super_clk_get_parent, - .set_rate = tegra20_super_clk_set_rate, - .round_rate = tegra20_super_clk_round_rate, - .recalc_rate = tegra20_super_clk_recalc_rate, -}; - -static unsigned long tegra20_twd_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -struct clk_ops tegra_twd_ops = { - .recalc_rate = tegra20_twd_clk_recalc_rate, -}; - -static u8 tegra20_cop_clk_get_parent(struct clk_hw *hw) -{ - return 0; -} - -struct clk_ops tegra_cop_ops = { - .get_parent = tegra20_cop_clk_get_parent, -}; - -/* virtual cop clock functions. Used to acquire the fake 'cop' clock to - * reset the COP block (i.e. AVP) */ -void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert) -{ - unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR; - - pr_debug("%s %s\n", __func__, assert ? "assert" : "deassert"); - clk_writel(1 << 1, reg); -} - -/* bus clock functions */ -static int tegra20_bus_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - - c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON; - return c->state; -} - -static int tegra20_bus_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - u32 val; - - spin_lock_irqsave(&clock_register_lock, flags); - - val = clk_readl(c->reg); - val &= ~(BUS_CLK_DISABLE << c->reg_shift); - clk_writel(val, c->reg); - - spin_unlock_irqrestore(&clock_register_lock, flags); - - return 0; -} - -static void tegra20_bus_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - u32 val; - - spin_lock_irqsave(&clock_register_lock, flags); - - val = clk_readl(c->reg); - val |= BUS_CLK_DISABLE << c->reg_shift; - clk_writel(val, c->reg); - - spin_unlock_irqrestore(&clock_register_lock, flags); -} - -static unsigned long tegra20_bus_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - u64 rate = prate; - - c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1; - c->mul = 1; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - return rate; -} - -static int tegra20_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - int ret = -EINVAL; - unsigned long flags; - u32 val; - int i; - - spin_lock_irqsave(&clock_register_lock, flags); - - val = clk_readl(c->reg); - for (i = 1; i <= 4; i++) { - if (rate == parent_rate / i) { - val &= ~(BUS_CLK_DIV_MASK << c->reg_shift); - val |= (i - 1) << c->reg_shift; - clk_writel(val, c->reg); - c->div = i; - c->mul = 1; - ret = 0; - break; - } - } - - spin_unlock_irqrestore(&clock_register_lock, flags); - - return ret; -} - -static long tegra20_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - unsigned long parent_rate = *prate; - s64 divider; - - if (rate >= parent_rate) - return rate; - - divider = parent_rate; - divider += rate - 1; - do_div(divider, rate); - - if (divider < 0) - return divider; - - if (divider > 4) - divider = 4; - do_div(parent_rate, divider); - - return parent_rate; -} - -struct clk_ops tegra_bus_ops = { - .is_enabled = tegra20_bus_clk_is_enabled, - .enable = tegra20_bus_clk_enable, - .disable = tegra20_bus_clk_disable, - .set_rate = tegra20_bus_clk_set_rate, - .round_rate = tegra20_bus_clk_round_rate, - .recalc_rate = tegra20_bus_clk_recalc_rate, -}; - -/* Blink output functions */ -static int tegra20_blink_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = pmc_readl(PMC_CTRL); - c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF; - return c->state; -} - -static unsigned long tegra20_blink_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = prate; - u32 val; - - c->mul = 1; - val = pmc_readl(c->reg); - - if (val & PMC_BLINK_TIMER_ENB) { - unsigned int on_off; - - on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) & - PMC_BLINK_TIMER_DATA_ON_MASK; - val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT; - val &= PMC_BLINK_TIMER_DATA_OFF_MASK; - on_off += val; - /* each tick in the blink timer is 4 32KHz clocks */ - c->div = on_off * 4; - } else { - c->div = 1; - } - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - return rate; -} - -static int tegra20_blink_clk_enable(struct clk_hw *hw) -{ - u32 val; - - val = pmc_readl(PMC_DPD_PADS_ORIDE); - pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE); - - val = pmc_readl(PMC_CTRL); - pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL); - - return 0; -} - -static void tegra20_blink_clk_disable(struct clk_hw *hw) -{ - u32 val; - - val = pmc_readl(PMC_CTRL); - pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL); - - val = pmc_readl(PMC_DPD_PADS_ORIDE); - pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE); -} - -static int tegra20_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (rate >= parent_rate) { - c->div = 1; - pmc_writel(0, c->reg); - } else { - unsigned int on_off; - u32 val; - - on_off = DIV_ROUND_UP(parent_rate / 8, rate); - c->div = on_off * 8; - - val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) << - PMC_BLINK_TIMER_DATA_ON_SHIFT; - on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK; - on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT; - val |= on_off; - val |= PMC_BLINK_TIMER_ENB; - pmc_writel(val, c->reg); - } - - return 0; -} - -static long tegra20_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - int div; - int mul; - long round_rate = *prate; - - mul = 1; - - if (rate >= *prate) { - div = 1; - } else { - div = DIV_ROUND_UP(*prate / 8, rate); - div *= 8; - } - - round_rate *= mul; - round_rate += div - 1; - do_div(round_rate, div); - - return round_rate; -} - -struct clk_ops tegra_blink_clk_ops = { - .is_enabled = tegra20_blink_clk_is_enabled, - .enable = tegra20_blink_clk_enable, - .disable = tegra20_blink_clk_disable, - .set_rate = tegra20_blink_clk_set_rate, - .round_rate = tegra20_blink_clk_round_rate, - .recalc_rate = tegra20_blink_clk_recalc_rate, -}; - -/* PLL Functions */ -static int tegra20_pll_clk_wait_for_lock(struct clk_tegra *c) -{ - udelay(c->u.pll.lock_delay); - return 0; -} - -static int tegra20_pll_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg + PLL_BASE); - - c->state = (val & PLL_BASE_ENABLE) ? ON : OFF; - return c->state; -} - -static unsigned long tegra20_pll_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg + PLL_BASE); - u64 rate = prate; - - if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) { - const struct clk_pll_freq_table *sel; - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == prate && - sel->output_rate == c->u.pll.fixed_rate) { - c->mul = sel->n; - c->div = sel->m * sel->p; - break; - } - } - pr_err("Clock %s has unknown fixed frequency\n", - __clk_get_name(hw->clk)); - BUG(); - } else if (val & PLL_BASE_BYPASS) { - c->mul = 1; - c->div = 1; - } else { - c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT; - c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT; - if (c->flags & PLLU) - c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2; - else - c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1; - } - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - return rate; -} - -static int tegra20_pll_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - val = clk_readl(c->reg + PLL_BASE); - val &= ~PLL_BASE_BYPASS; - val |= PLL_BASE_ENABLE; - clk_writel(val, c->reg + PLL_BASE); - - tegra20_pll_clk_wait_for_lock(c); - - return 0; -} - -static void tegra20_pll_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - val = clk_readl(c->reg); - val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); - clk_writel(val, c->reg); -} - -static int tegra20_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long input_rate = parent_rate; - const struct clk_pll_freq_table *sel; - u32 val; - - pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate); - - if (c->flags & PLL_FIXED) { - int ret = 0; - if (rate != c->u.pll.fixed_rate) { - pr_err("%s: Can not change %s fixed rate %lu to %lu\n", - __func__, __clk_get_name(hw->clk), - c->u.pll.fixed_rate, rate); - ret = -EINVAL; - } - return ret; - } - - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == input_rate && sel->output_rate == rate) { - c->mul = sel->n; - c->div = sel->m * sel->p; - - val = clk_readl(c->reg + PLL_BASE); - if (c->flags & PLL_FIXED) - val |= PLL_BASE_OVERRIDE; - val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK | - PLL_BASE_DIVM_MASK); - val |= (sel->m << PLL_BASE_DIVM_SHIFT) | - (sel->n << PLL_BASE_DIVN_SHIFT); - BUG_ON(sel->p < 1 || sel->p > 2); - if (c->flags & PLLU) { - if (sel->p == 1) - val |= PLLU_BASE_POST_DIV; - } else { - if (sel->p == 2) - val |= 1 << PLL_BASE_DIVP_SHIFT; - } - clk_writel(val, c->reg + PLL_BASE); - - if (c->flags & PLL_HAS_CPCON) { - val = clk_readl(c->reg + PLL_MISC(c)); - val &= ~PLL_MISC_CPCON_MASK; - val |= sel->cpcon << PLL_MISC_CPCON_SHIFT; - clk_writel(val, c->reg + PLL_MISC(c)); - } - - if (c->state == ON) - tegra20_pll_clk_enable(hw); - return 0; - } - } - return -EINVAL; -} - -static long tegra20_pll_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - const struct clk_pll_freq_table *sel; - unsigned long input_rate = *prate; - u64 output_rate = *prate; - int mul; - int div; - - if (c->flags & PLL_FIXED) - return c->u.pll.fixed_rate; - - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) - if (sel->input_rate == input_rate && sel->output_rate == rate) { - mul = sel->n; - div = sel->m * sel->p; - break; - } - - if (sel->input_rate == 0) - return -EINVAL; - - output_rate *= mul; - output_rate += div - 1; /* round up */ - do_div(output_rate, div); - - return output_rate; -} - -struct clk_ops tegra_pll_ops = { - .is_enabled = tegra20_pll_clk_is_enabled, - .enable = tegra20_pll_clk_enable, - .disable = tegra20_pll_clk_disable, - .set_rate = tegra20_pll_clk_set_rate, - .recalc_rate = tegra20_pll_clk_recalc_rate, - .round_rate = tegra20_pll_clk_round_rate, -}; - -static void tegra20_pllx_clk_init(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (tegra_sku_id == 7) - c->max_rate = 750000000; -} - -struct clk_ops tegra_pllx_ops = { - .init = tegra20_pllx_clk_init, - .is_enabled = tegra20_pll_clk_is_enabled, - .enable = tegra20_pll_clk_enable, - .disable = tegra20_pll_clk_disable, - .set_rate = tegra20_pll_clk_set_rate, - .recalc_rate = tegra20_pll_clk_recalc_rate, - .round_rate = tegra20_pll_clk_round_rate, -}; - -static int tegra20_plle_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - mdelay(1); - - val = clk_readl(c->reg + PLL_BASE); - if (!(val & PLLE_MISC_READY)) - return -EBUSY; - - val = clk_readl(c->reg + PLL_BASE); - val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS; - clk_writel(val, c->reg + PLL_BASE); - - return 0; -} - -struct clk_ops tegra_plle_ops = { - .is_enabled = tegra20_pll_clk_is_enabled, - .enable = tegra20_plle_clk_enable, - .set_rate = tegra20_pll_clk_set_rate, - .recalc_rate = tegra20_pll_clk_recalc_rate, - .round_rate = tegra20_pll_clk_round_rate, -}; - -/* Clock divider ops */ -static int tegra20_pll_div_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - - val >>= c->reg_shift; - c->state = (val & PLL_OUT_CLKEN) ? ON : OFF; - if (!(val & PLL_OUT_RESET_DISABLE)) - c->state = OFF; - return c->state; -} - -static unsigned long tegra20_pll_div_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = prate; - u32 val = clk_readl(c->reg); - u32 divu71; - - val >>= c->reg_shift; - - if (c->flags & DIV_U71) { - divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT; - c->div = (divu71 + 2); - c->mul = 2; - } else if (c->flags & DIV_2) { - c->div = 2; - c->mul = 1; - } else { - c->div = 1; - c->mul = 1; - } - - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - - return rate; -} - -static int tegra20_pll_div_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - u32 new_val; - u32 val; - - pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); - - if (c->flags & DIV_U71) { - spin_lock_irqsave(&clock_register_lock, flags); - val = clk_readl(c->reg); - new_val = val >> c->reg_shift; - new_val &= 0xFFFF; - - new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE; - - val &= ~(0xFFFF << c->reg_shift); - val |= new_val << c->reg_shift; - clk_writel(val, c->reg); - spin_unlock_irqrestore(&clock_register_lock, flags); - return 0; - } else if (c->flags & DIV_2) { - BUG_ON(!(c->flags & PLLD)); - spin_lock_irqsave(&clock_register_lock, flags); - val = clk_readl(c->reg); - val &= ~PLLD_MISC_DIV_RST; - clk_writel(val, c->reg); - spin_unlock_irqrestore(&clock_register_lock, flags); - return 0; - } - return -EINVAL; -} - -static void tegra20_pll_div_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - u32 new_val; - u32 val; - - pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); - - if (c->flags & DIV_U71) { - spin_lock_irqsave(&clock_register_lock, flags); - val = clk_readl(c->reg); - new_val = val >> c->reg_shift; - new_val &= 0xFFFF; - - new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE); - - val &= ~(0xFFFF << c->reg_shift); - val |= new_val << c->reg_shift; - clk_writel(val, c->reg); - spin_unlock_irqrestore(&clock_register_lock, flags); - } else if (c->flags & DIV_2) { - BUG_ON(!(c->flags & PLLD)); - spin_lock_irqsave(&clock_register_lock, flags); - val = clk_readl(c->reg); - val |= PLLD_MISC_DIV_RST; - clk_writel(val, c->reg); - spin_unlock_irqrestore(&clock_register_lock, flags); - } -} - -static int tegra20_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - int divider_u71; - u32 new_val; - u32 val; - - pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate); - - if (c->flags & DIV_U71) { - divider_u71 = clk_div71_get_divider(parent_rate, rate); - if (divider_u71 >= 0) { - spin_lock_irqsave(&clock_register_lock, flags); - val = clk_readl(c->reg); - new_val = val >> c->reg_shift; - new_val &= 0xFFFF; - if (c->flags & DIV_U71_FIXED) - new_val |= PLL_OUT_OVERRIDE; - new_val &= ~PLL_OUT_RATIO_MASK; - new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT; - - val &= ~(0xFFFF << c->reg_shift); - val |= new_val << c->reg_shift; - clk_writel(val, c->reg); - c->div = divider_u71 + 2; - c->mul = 2; - spin_unlock_irqrestore(&clock_register_lock, flags); - return 0; - } - } else if (c->flags & DIV_2) { - if (parent_rate == rate * 2) - return 0; - } - return -EINVAL; -} - -static long tegra20_pll_div_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long parent_rate = *prate; - int divider; - - pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate); - - if (c->flags & DIV_U71) { - divider = clk_div71_get_divider(parent_rate, rate); - if (divider < 0) - return divider; - return DIV_ROUND_UP(parent_rate * 2, divider + 2); - } else if (c->flags & DIV_2) { - return DIV_ROUND_UP(parent_rate, 2); - } - return -EINVAL; -} - -struct clk_ops tegra_pll_div_ops = { - .is_enabled = tegra20_pll_div_clk_is_enabled, - .enable = tegra20_pll_div_clk_enable, - .disable = tegra20_pll_div_clk_disable, - .set_rate = tegra20_pll_div_clk_set_rate, - .round_rate = tegra20_pll_div_clk_round_rate, - .recalc_rate = tegra20_pll_div_clk_recalc_rate, -}; - -/* Periph clk ops */ - -static int tegra20_periph_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - c->state = ON; - - if (!c->u.periph.clk_num) - goto out; - - if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) & - PERIPH_CLK_TO_ENB_BIT(c))) - c->state = OFF; - - if (!(c->flags & PERIPH_NO_RESET)) - if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) & - PERIPH_CLK_TO_ENB_BIT(c)) - c->state = OFF; - -out: - return c->state; -} - -static int tegra20_periph_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - u32 val; - - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - if (!c->u.periph.clk_num) - return 0; - - tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++; - if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1) - return 0; - - spin_lock_irqsave(&clock_register_lock, flags); - - clk_writel(PERIPH_CLK_TO_ENB_BIT(c), - CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c)); - if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET)) - clk_writel(PERIPH_CLK_TO_ENB_BIT(c), - RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG(c)); - if (c->flags & PERIPH_EMC_ENB) { - /* The EMC peripheral clock has 2 extra enable bits */ - /* FIXME: Do they need to be disabled? */ - val = clk_readl(c->reg); - val |= 0x3 << 24; - clk_writel(val, c->reg); - } - - spin_unlock_irqrestore(&clock_register_lock, flags); - - return 0; -} - -static void tegra20_periph_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - if (!c->u.periph.clk_num) - return; - - tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--; - - if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0) - return; - - spin_lock_irqsave(&clock_register_lock, flags); - - clk_writel(PERIPH_CLK_TO_ENB_BIT(c), - CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c)); - - spin_unlock_irqrestore(&clock_register_lock, flags); -} - -void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR; - - pr_debug("%s %s on clock %s\n", __func__, - assert ? "assert" : "deassert", __clk_get_name(hw->clk)); - - BUG_ON(!c->u.periph.clk_num); - - if (!(c->flags & PERIPH_NO_RESET)) - clk_writel(PERIPH_CLK_TO_ENB_BIT(c), - base + PERIPH_CLK_TO_ENB_SET_REG(c)); -} - -static int tegra20_periph_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - u32 mask; - u32 shift; - - pr_debug("%s: %s %d\n", __func__, __clk_get_name(hw->clk), index); - - if (c->flags & MUX_PWM) { - shift = PERIPH_CLK_SOURCE_PWM_SHIFT; - mask = PERIPH_CLK_SOURCE_PWM_MASK; - } else { - shift = PERIPH_CLK_SOURCE_SHIFT; - mask = PERIPH_CLK_SOURCE_MASK; - } - - val = clk_readl(c->reg); - val &= ~mask; - val |= (index) << shift; - - clk_writel(val, c->reg); - - return 0; -} - -static u8 tegra20_periph_clk_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - u32 mask; - u32 shift; - - if (c->flags & MUX_PWM) { - shift = PERIPH_CLK_SOURCE_PWM_SHIFT; - mask = PERIPH_CLK_SOURCE_PWM_MASK; - } else { - shift = PERIPH_CLK_SOURCE_SHIFT; - mask = PERIPH_CLK_SOURCE_MASK; - } - - if (c->flags & MUX) - return (val & mask) >> shift; - else - return 0; -} - -static unsigned long tegra20_periph_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long rate = prate; - u32 val = clk_readl(c->reg); - - if (c->flags & DIV_U71) { - u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK; - c->div = divu71 + 2; - c->mul = 2; - } else if (c->flags & DIV_U16) { - u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK; - c->div = divu16 + 1; - c->mul = 1; - } else { - c->div = 1; - c->mul = 1; - return rate; - } - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -static int tegra20_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - int divider; - - val = clk_readl(c->reg); - - if (c->flags & DIV_U71) { - divider = clk_div71_get_divider(parent_rate, rate); - - if (divider >= 0) { - val = clk_readl(c->reg); - val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK; - val |= divider; - clk_writel(val, c->reg); - c->div = divider + 2; - c->mul = 2; - return 0; - } - } else if (c->flags & DIV_U16) { - divider = clk_div16_get_divider(parent_rate, rate); - if (divider >= 0) { - val = clk_readl(c->reg); - val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK; - val |= divider; - clk_writel(val, c->reg); - c->div = divider + 1; - c->mul = 1; - return 0; - } - } else if (parent_rate <= rate) { - c->div = 1; - c->mul = 1; - return 0; - } - - return -EINVAL; -} - -static long tegra20_periph_clk_round_rate(struct clk_hw *hw, - unsigned long rate, unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); - int divider; - - pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate); - - if (prate) - parent_rate = *prate; - - if (c->flags & DIV_U71) { - divider = clk_div71_get_divider(parent_rate, rate); - if (divider < 0) - return divider; - - return DIV_ROUND_UP(parent_rate * 2, divider + 2); - } else if (c->flags & DIV_U16) { - divider = clk_div16_get_divider(parent_rate, rate); - if (divider < 0) - return divider; - return DIV_ROUND_UP(parent_rate, divider + 1); - } - return -EINVAL; -} - -struct clk_ops tegra_periph_clk_ops = { - .is_enabled = tegra20_periph_clk_is_enabled, - .enable = tegra20_periph_clk_enable, - .disable = tegra20_periph_clk_disable, - .set_parent = tegra20_periph_clk_set_parent, - .get_parent = tegra20_periph_clk_get_parent, - .set_rate = tegra20_periph_clk_set_rate, - .round_rate = tegra20_periph_clk_round_rate, - .recalc_rate = tegra20_periph_clk_recalc_rate, -}; - -/* External memory controller clock ops */ -static void tegra20_emc_clk_init(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - c->max_rate = __clk_get_rate(hw->clk); -} - -static long tegra20_emc_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - long emc_rate; - long clk_rate; - - /* - * The slowest entry in the EMC clock table that is at least as - * fast as rate. - */ - emc_rate = tegra_emc_round_rate(rate); - if (emc_rate < 0) - return c->max_rate; - - /* - * The fastest rate the PLL will generate that is at most the - * requested rate. - */ - clk_rate = tegra20_periph_clk_round_rate(hw, emc_rate, NULL); - - /* - * If this fails, and emc_rate > clk_rate, it's because the maximum - * rate in the EMC tables is larger than the maximum rate of the EMC - * clock. The EMC clock's max rate is the rate it was running when the - * kernel booted. Such a mismatch is probably due to using the wrong - * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25. - */ - WARN_ONCE(emc_rate != clk_rate, - "emc_rate %ld != clk_rate %ld", - emc_rate, clk_rate); - - return emc_rate; -} - -static int tegra20_emc_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - int ret; - - /* - * The Tegra2 memory controller has an interlock with the clock - * block that allows memory shadowed registers to be updated, - * and then transfer them to the main registers at the same - * time as the clock update without glitches. - */ - ret = tegra_emc_set_rate(rate); - if (ret < 0) - return ret; - - ret = tegra20_periph_clk_set_rate(hw, rate, parent_rate); - udelay(1); - - return ret; -} - -struct clk_ops tegra_emc_clk_ops = { - .init = tegra20_emc_clk_init, - .is_enabled = tegra20_periph_clk_is_enabled, - .enable = tegra20_periph_clk_enable, - .disable = tegra20_periph_clk_disable, - .set_parent = tegra20_periph_clk_set_parent, - .get_parent = tegra20_periph_clk_get_parent, - .set_rate = tegra20_emc_clk_set_rate, - .round_rate = tegra20_emc_clk_round_rate, - .recalc_rate = tegra20_periph_clk_recalc_rate, -}; - -/* Clock doubler ops */ -static int tegra20_clk_double_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - c->state = ON; - - if (!c->u.periph.clk_num) - goto out; - - if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) & - PERIPH_CLK_TO_ENB_BIT(c))) - c->state = OFF; - -out: - return c->state; -}; - -static unsigned long tegra20_clk_double_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = prate; - - c->mul = 2; - c->div = 1; - - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - - return rate; -} - -static long tegra20_clk_double_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - unsigned long output_rate = *prate; - - do_div(output_rate, 2); - return output_rate; -} - -static int tegra20_clk_double_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - if (rate != 2 * parent_rate) - return -EINVAL; - return 0; -} - -struct clk_ops tegra_clk_double_ops = { - .is_enabled = tegra20_clk_double_is_enabled, - .enable = tegra20_periph_clk_enable, - .disable = tegra20_periph_clk_disable, - .set_rate = tegra20_clk_double_set_rate, - .recalc_rate = tegra20_clk_double_recalc_rate, - .round_rate = tegra20_clk_double_round_rate, -}; - -/* Audio sync clock ops */ -static int tegra20_audio_sync_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - - c->state = (val & (1<<4)) ? OFF : ON; - return c->state; -} - -static int tegra20_audio_sync_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - clk_writel(0, c->reg); - return 0; -} - -static void tegra20_audio_sync_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - clk_writel(1, c->reg); -} - -static u8 tegra20_audio_sync_clk_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - int source; - - source = val & 0xf; - return source; -} - -static int tegra20_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg); - val &= ~0xf; - val |= index; - - clk_writel(val, c->reg); - - return 0; -} - -struct clk_ops tegra_audio_sync_clk_ops = { - .is_enabled = tegra20_audio_sync_clk_is_enabled, - .enable = tegra20_audio_sync_clk_enable, - .disable = tegra20_audio_sync_clk_disable, - .set_parent = tegra20_audio_sync_clk_set_parent, - .get_parent = tegra20_audio_sync_clk_get_parent, -}; - -/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */ - -static int tegra20_cdev_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - /* We could un-tristate the cdev1 or cdev2 pingroup here; this is - * currently done in the pinmux code. */ - c->state = ON; - - BUG_ON(!c->u.periph.clk_num); - - if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) & - PERIPH_CLK_TO_ENB_BIT(c))) - c->state = OFF; - return c->state; -} - -static int tegra20_cdev_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - BUG_ON(!c->u.periph.clk_num); - - clk_writel(PERIPH_CLK_TO_ENB_BIT(c), - CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c)); - return 0; -} - -static void tegra20_cdev_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - BUG_ON(!c->u.periph.clk_num); - - clk_writel(PERIPH_CLK_TO_ENB_BIT(c), - CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c)); -} - -static unsigned long tegra20_cdev_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - return to_clk_tegra(hw)->fixed_rate; -} - -struct clk_ops tegra_cdev_clk_ops = { - .is_enabled = tegra20_cdev_clk_is_enabled, - .enable = tegra20_cdev_clk_enable, - .disable = tegra20_cdev_clk_disable, - .recalc_rate = tegra20_cdev_recalc_rate, -}; - -/* Tegra20 CPU clock and reset control functions */ -static void tegra20_wait_cpu_in_reset(u32 cpu) -{ - unsigned int reg; - - do { - reg = readl(reg_clk_base + - TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); - cpu_relax(); - } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ - - return; -} - -static void tegra20_put_cpu_in_reset(u32 cpu) -{ - writel(CPU_RESET(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); - dmb(); -} - -static void tegra20_cpu_out_of_reset(u32 cpu) -{ - writel(CPU_RESET(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); - wmb(); -} - -static void tegra20_enable_cpu_clock(u32 cpu) -{ - unsigned int reg; - - reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); - writel(reg & ~CPU_CLOCK(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); - barrier(); - reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); -} - -static void tegra20_disable_cpu_clock(u32 cpu) -{ - unsigned int reg; - - reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); - writel(reg | CPU_CLOCK(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); -} - -static struct tegra_cpu_car_ops tegra20_cpu_car_ops = { - .wait_for_reset = tegra20_wait_cpu_in_reset, - .put_in_reset = tegra20_put_cpu_in_reset, - .out_of_reset = tegra20_cpu_out_of_reset, - .enable_clock = tegra20_enable_cpu_clock, - .disable_clock = tegra20_disable_cpu_clock, -}; - -void __init tegra20_cpu_car_ops_init(void) -{ - tegra_cpu_car_ops = &tegra20_cpu_car_ops; -} diff --git a/arch/arm/mach-tegra/tegra20_clocks.h b/arch/arm/mach-tegra/tegra20_clocks.h deleted file mode 100644 index 8bfd31bcc490..000000000000 --- a/arch/arm/mach-tegra/tegra20_clocks.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2012, 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __MACH_TEGRA20_CLOCK_H -#define __MACH_TEGRA20_CLOCK_H - -extern struct clk_ops tegra_clk_32k_ops; -extern struct clk_ops tegra_pll_ops; -extern struct clk_ops tegra_clk_m_ops; -extern struct clk_ops tegra_pll_div_ops; -extern struct clk_ops tegra_pllx_ops; -extern struct clk_ops tegra_plle_ops; -extern struct clk_ops tegra_clk_double_ops; -extern struct clk_ops tegra_cdev_clk_ops; -extern struct clk_ops tegra_audio_sync_clk_ops; -extern struct clk_ops tegra_super_ops; -extern struct clk_ops tegra_cpu_ops; -extern struct clk_ops tegra_twd_ops; -extern struct clk_ops tegra_cop_ops; -extern struct clk_ops tegra_bus_ops; -extern struct clk_ops tegra_blink_clk_ops; -extern struct clk_ops tegra_emc_clk_ops; -extern struct clk_ops tegra_periph_clk_ops; -extern struct clk_ops tegra_clk_shared_bus_ops; - -void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert); -void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert); - -#endif diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c deleted file mode 100644 index 022cdaef7ca5..000000000000 --- a/arch/arm/mach-tegra/tegra20_clocks_data.c +++ /dev/null @@ -1,1143 +0,0 @@ -/* - * arch/arm/mach-tegra/tegra2_clocks.c - * - * Copyright (C) 2010 Google, Inc. - * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved. - * - * Author: - * Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clock.h" -#include "fuse.h" -#include "tegra2_emc.h" -#include "tegra20_clocks.h" - -/* Clock definitions */ - -#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \ - _parent_names, _parents, _parent) \ - static struct clk tegra_##_name = { \ - .hw = &tegra_##_name##_hw.hw, \ - .name = #_name, \ - .rate = _rate, \ - .ops = _ops, \ - .flags = _flags, \ - .parent_names = _parent_names, \ - .parents = _parents, \ - .num_parents = ARRAY_SIZE(_parent_names), \ - .parent = _parent, \ - }; - -static struct clk tegra_clk_32k; -static struct clk_tegra tegra_clk_32k_hw = { - .hw = { - .clk = &tegra_clk_32k, - }, - .fixed_rate = 32768, -}; - -static struct clk tegra_clk_32k = { - .name = "clk_32k", - .rate = 32768, - .ops = &tegra_clk_32k_ops, - .hw = &tegra_clk_32k_hw.hw, - .flags = CLK_IS_ROOT, -}; - -static struct clk tegra_clk_m; -static struct clk_tegra tegra_clk_m_hw = { - .hw = { - .clk = &tegra_clk_m, - }, - .flags = ENABLE_ON_INIT, - .reg = 0x1fc, - .reg_shift = 28, - .max_rate = 26000000, - .fixed_rate = 0, -}; - -static struct clk tegra_clk_m = { - .name = "clk_m", - .ops = &tegra_clk_m_ops, - .hw = &tegra_clk_m_hw.hw, - .flags = CLK_IS_ROOT, -}; - -#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min, \ - _input_max, _cf_min, _cf_max, _vco_min, \ - _vco_max, _freq_table, _lock_delay, _ops, \ - _fixed_rate, _parent) \ - static const char *tegra_##_name##_parent_names[] = { \ - #_parent, \ - }; \ - static struct clk *tegra_##_name##_parents[] = { \ - &tegra_##_parent, \ - }; \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .flags = _flags, \ - .reg = _reg, \ - .max_rate = _max_rate, \ - .u.pll = { \ - .input_min = _input_min, \ - .input_max = _input_max, \ - .cf_min = _cf_min, \ - .cf_max = _cf_max, \ - .vco_min = _vco_min, \ - .vco_max = _vco_max, \ - .freq_table = _freq_table, \ - .lock_delay = _lock_delay, \ - .fixed_rate = _fixed_rate, \ - }, \ - }; \ - static struct clk tegra_##_name = { \ - .name = #_name, \ - .ops = &_ops, \ - .hw = &tegra_##_name##_hw.hw, \ - .parent = &tegra_##_parent, \ - .parent_names = tegra_##_name##_parent_names, \ - .parents = tegra_##_name##_parents, \ - .num_parents = 1, \ - }; - -#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift, \ - _max_rate, _ops, _parent, _clk_flags) \ - static const char *tegra_##_name##_parent_names[] = { \ - #_parent, \ - }; \ - static struct clk *tegra_##_name##_parents[] = { \ - &tegra_##_parent, \ - }; \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .flags = _flags, \ - .reg = _reg, \ - .max_rate = _max_rate, \ - .reg_shift = _reg_shift, \ - }; \ - static struct clk tegra_##_name = { \ - .name = #_name, \ - .ops = &tegra_pll_div_ops, \ - .hw = &tegra_##_name##_hw.hw, \ - .parent = &tegra_##_parent, \ - .parent_names = tegra_##_name##_parent_names, \ - .parents = tegra_##_name##_parents, \ - .num_parents = 1, \ - .flags = _clk_flags, \ - }; - - -static struct clk_pll_freq_table tegra_pll_s_freq_table[] = { - {32768, 12000000, 366, 1, 1, 0}, - {32768, 13000000, 397, 1, 1, 0}, - {32768, 19200000, 586, 1, 1, 0}, - {32768, 26000000, 793, 1, 1, 0}, - {0, 0, 0, 0, 0, 0}, -}; - -DEFINE_PLL(pll_s, PLL_ALT_MISC_REG, 0xf0, 26000000, 32768, 32768, 0, - 0, 12000000, 26000000, tegra_pll_s_freq_table, 300, - tegra_pll_ops, 0, clk_32k); - -static struct clk_pll_freq_table tegra_pll_c_freq_table[] = { - { 12000000, 600000000, 600, 12, 1, 8 }, - { 13000000, 600000000, 600, 13, 1, 8 }, - { 19200000, 600000000, 500, 16, 1, 6 }, - { 26000000, 600000000, 600, 26, 1, 8 }, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 600000000, 2000000, 31000000, 1000000, - 6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300, - tegra_pll_ops, 0, clk_m); - -DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 600000000, - tegra_pll_div_ops, pll_c, 0); - -static struct clk_pll_freq_table tegra_pll_m_freq_table[] = { - { 12000000, 666000000, 666, 12, 1, 8}, - { 13000000, 666000000, 666, 13, 1, 8}, - { 19200000, 666000000, 555, 16, 1, 8}, - { 26000000, 666000000, 666, 26, 1, 8}, - { 12000000, 600000000, 600, 12, 1, 8}, - { 13000000, 600000000, 600, 13, 1, 8}, - { 19200000, 600000000, 375, 12, 1, 6}, - { 26000000, 600000000, 600, 26, 1, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_m, PLL_HAS_CPCON, 0x90, 800000000, 2000000, 31000000, 1000000, - 6000000, 20000000, 1200000000, tegra_pll_m_freq_table, 300, - tegra_pll_ops, 0, clk_m); - -DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000, - tegra_pll_div_ops, pll_m, 0); - -static struct clk_pll_freq_table tegra_pll_p_freq_table[] = { - { 12000000, 216000000, 432, 12, 2, 8}, - { 13000000, 216000000, 432, 13, 2, 8}, - { 19200000, 216000000, 90, 4, 2, 1}, - { 26000000, 216000000, 432, 26, 2, 8}, - { 12000000, 432000000, 432, 12, 1, 8}, - { 13000000, 432000000, 432, 13, 1, 8}, - { 19200000, 432000000, 90, 4, 1, 1}, - { 26000000, 432000000, 432, 26, 1, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - - -DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000, - 2000000, 31000000, 1000000, 6000000, 20000000, 1400000000, - tegra_pll_p_freq_table, 300, tegra_pll_ops, 216000000, clk_m); - -DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 0, - 432000000, tegra_pll_div_ops, pll_p, 0); -DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 16, - 432000000, tegra_pll_div_ops, pll_p, 0); -DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 0, - 432000000, tegra_pll_div_ops, pll_p, 0); -DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 16, - 432000000, tegra_pll_div_ops, pll_p, 0); - -static struct clk_pll_freq_table tegra_pll_a_freq_table[] = { - { 28800000, 56448000, 49, 25, 1, 1}, - { 28800000, 73728000, 64, 25, 1, 1}, - { 28800000, 24000000, 5, 6, 1, 1}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 73728000, 2000000, 31000000, 1000000, - 6000000, 20000000, 1400000000, tegra_pll_a_freq_table, 300, - tegra_pll_ops, 0, pll_p_out1); - -DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 73728000, - tegra_pll_div_ops, pll_a, 0); - -static struct clk_pll_freq_table tegra_pll_d_freq_table[] = { - { 12000000, 216000000, 216, 12, 1, 4}, - { 13000000, 216000000, 216, 13, 1, 4}, - { 19200000, 216000000, 135, 12, 1, 3}, - { 26000000, 216000000, 216, 26, 1, 4}, - - { 12000000, 297000000, 99, 4, 1, 4 }, - { 12000000, 339000000, 113, 4, 1, 4 }, - - { 12000000, 594000000, 594, 12, 1, 8}, - { 13000000, 594000000, 594, 13, 1, 8}, - { 19200000, 594000000, 495, 16, 1, 8}, - { 26000000, 594000000, 594, 26, 1, 8}, - - { 12000000, 616000000, 616, 12, 1, 8}, - - { 12000000, 1000000000, 1000, 12, 1, 12}, - { 13000000, 1000000000, 1000, 13, 1, 12}, - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 12}, - - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000, - 1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table, - 1000, tegra_pll_ops, 0, clk_m); - -DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000, - tegra_pll_div_ops, pll_d, CLK_SET_RATE_PARENT); - -static struct clk_pll_freq_table tegra_pll_u_freq_table[] = { - { 12000000, 480000000, 960, 12, 2, 0}, - { 13000000, 480000000, 960, 13, 2, 0}, - { 19200000, 480000000, 200, 4, 2, 0}, - { 26000000, 480000000, 960, 26, 2, 0}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_u, PLLU, 0xc0, 480000000, 2000000, 40000000, 1000000, 6000000, - 48000000, 960000000, tegra_pll_u_freq_table, 1000, - tegra_pll_ops, 0, clk_m); - -static struct clk_pll_freq_table tegra_pll_x_freq_table[] = { - /* 1 GHz */ - { 12000000, 1000000000, 1000, 12, 1, 12}, - { 13000000, 1000000000, 1000, 13, 1, 12}, - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 12}, - - /* 912 MHz */ - { 12000000, 912000000, 912, 12, 1, 12}, - { 13000000, 912000000, 912, 13, 1, 12}, - { 19200000, 912000000, 760, 16, 1, 8}, - { 26000000, 912000000, 912, 26, 1, 12}, - - /* 816 MHz */ - { 12000000, 816000000, 816, 12, 1, 12}, - { 13000000, 816000000, 816, 13, 1, 12}, - { 19200000, 816000000, 680, 16, 1, 8}, - { 26000000, 816000000, 816, 26, 1, 12}, - - /* 760 MHz */ - { 12000000, 760000000, 760, 12, 1, 12}, - { 13000000, 760000000, 760, 13, 1, 12}, - { 19200000, 760000000, 950, 24, 1, 8}, - { 26000000, 760000000, 760, 26, 1, 12}, - - /* 750 MHz */ - { 12000000, 750000000, 750, 12, 1, 12}, - { 13000000, 750000000, 750, 13, 1, 12}, - { 19200000, 750000000, 625, 16, 1, 8}, - { 26000000, 750000000, 750, 26, 1, 12}, - - /* 608 MHz */ - { 12000000, 608000000, 608, 12, 1, 12}, - { 13000000, 608000000, 608, 13, 1, 12}, - { 19200000, 608000000, 380, 12, 1, 8}, - { 26000000, 608000000, 608, 26, 1, 12}, - - /* 456 MHz */ - { 12000000, 456000000, 456, 12, 1, 12}, - { 13000000, 456000000, 456, 13, 1, 12}, - { 19200000, 456000000, 380, 16, 1, 8}, - { 26000000, 456000000, 456, 26, 1, 12}, - - /* 312 MHz */ - { 12000000, 312000000, 312, 12, 1, 12}, - { 13000000, 312000000, 312, 13, 1, 12}, - { 19200000, 312000000, 260, 16, 1, 8}, - { 26000000, 312000000, 312, 26, 1, 12}, - - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG, 0xe0, 1000000000, 2000000, - 31000000, 1000000, 6000000, 20000000, 1200000000, - tegra_pll_x_freq_table, 300, tegra_pllx_ops, 0, clk_m); - -static struct clk_pll_freq_table tegra_pll_e_freq_table[] = { - { 12000000, 100000000, 200, 24, 1, 0 }, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 12000000, 12000000, 0, 0, - 0, 0, tegra_pll_e_freq_table, 0, tegra_plle_ops, 0, clk_m); - -static const char *tegra_common_parent_names[] = { - "clk_m", -}; - -static struct clk *tegra_common_parents[] = { - &tegra_clk_m, -}; - -static struct clk tegra_clk_d; -static struct clk_tegra tegra_clk_d_hw = { - .hw = { - .clk = &tegra_clk_d, - }, - .flags = PERIPH_NO_RESET, - .reg = 0x34, - .reg_shift = 12, - .max_rate = 52000000, - .u.periph = { - .clk_num = 90, - }, -}; - -static struct clk tegra_clk_d = { - .name = "clk_d", - .hw = &tegra_clk_d_hw.hw, - .ops = &tegra_clk_double_ops, - .parent = &tegra_clk_m, - .parent_names = tegra_common_parent_names, - .parents = tegra_common_parents, - .num_parents = ARRAY_SIZE(tegra_common_parent_names), -}; - -static struct clk tegra_cdev1; -static struct clk_tegra tegra_cdev1_hw = { - .hw = { - .clk = &tegra_cdev1, - }, - .fixed_rate = 26000000, - .u.periph = { - .clk_num = 94, - }, -}; -static struct clk tegra_cdev1 = { - .name = "cdev1", - .hw = &tegra_cdev1_hw.hw, - .ops = &tegra_cdev_clk_ops, - .flags = CLK_IS_ROOT, -}; - -/* dap_mclk2, belongs to the cdev2 pingroup. */ -static struct clk tegra_cdev2; -static struct clk_tegra tegra_cdev2_hw = { - .hw = { - .clk = &tegra_cdev2, - }, - .fixed_rate = 26000000, - .u.periph = { - .clk_num = 93, - }, -}; -static struct clk tegra_cdev2 = { - .name = "cdev2", - .hw = &tegra_cdev2_hw.hw, - .ops = &tegra_cdev_clk_ops, - .flags = CLK_IS_ROOT, -}; - -/* initialized before peripheral clocks */ -static struct clk_mux_sel mux_audio_sync_clk[8+1]; -static const struct audio_sources { - const char *name; - int value; -} mux_audio_sync_clk_sources[] = { - { .name = "spdif_in", .value = 0 }, - { .name = "i2s1", .value = 1 }, - { .name = "i2s2", .value = 2 }, - { .name = "pll_a_out0", .value = 4 }, -#if 0 /* FIXME: not implemented */ - { .name = "ac97", .value = 3 }, - { .name = "ext_audio_clk2", .value = 5 }, - { .name = "ext_audio_clk1", .value = 6 }, - { .name = "ext_vimclk", .value = 7 }, -#endif - { NULL, 0 } -}; - -static const char *audio_parent_names[] = { - "spdif_in", - "i2s1", - "i2s2", - "dummy", - "pll_a_out0", - "dummy", - "dummy", - "dummy", -}; - -static struct clk *audio_parents[] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, -}; - -static struct clk tegra_audio; -static struct clk_tegra tegra_audio_hw = { - .hw = { - .clk = &tegra_audio, - }, - .reg = 0x38, - .max_rate = 73728000, -}; -DEFINE_CLK_TEGRA(audio, 0, &tegra_audio_sync_clk_ops, 0, audio_parent_names, - audio_parents, NULL); - -static const char *audio_2x_parent_names[] = { - "audio", -}; - -static struct clk *audio_2x_parents[] = { - &tegra_audio, -}; - -static struct clk tegra_audio_2x; -static struct clk_tegra tegra_audio_2x_hw = { - .hw = { - .clk = &tegra_audio_2x, - }, - .flags = PERIPH_NO_RESET, - .max_rate = 48000000, - .reg = 0x34, - .reg_shift = 8, - .u.periph = { - .clk_num = 89, - }, -}; -DEFINE_CLK_TEGRA(audio_2x, 0, &tegra_clk_double_ops, 0, audio_2x_parent_names, - audio_2x_parents, &tegra_audio); - -static struct clk_lookup tegra_audio_clk_lookups[] = { - { .con_id = "audio", .clk = &tegra_audio }, - { .con_id = "audio_2x", .clk = &tegra_audio_2x } -}; - -/* This is called after peripheral clocks are initialized, as the - * audio_sync clock depends on some of the peripheral clocks. - */ - -static void init_audio_sync_clock_mux(void) -{ - int i; - struct clk_mux_sel *sel = mux_audio_sync_clk; - const struct audio_sources *src = mux_audio_sync_clk_sources; - struct clk_lookup *lookup; - - for (i = 0; src->name; i++, sel++, src++) { - sel->input = tegra_get_clock_by_name(src->name); - if (!sel->input) - pr_err("%s: could not find clk %s\n", __func__, - src->name); - audio_parents[src->value] = sel->input; - sel->value = src->value; - } - - lookup = tegra_audio_clk_lookups; - for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) { - struct clk *c = lookup->clk; - struct clk_tegra *clk = to_clk_tegra(c->hw); - __clk_init(NULL, c); - INIT_LIST_HEAD(&clk->shared_bus_list); - clk->lookup.con_id = lookup->con_id; - clk->lookup.clk = c; - clkdev_add(&clk->lookup); - tegra_clk_add(c); - } -} - -static const char *mux_cclk[] = { - "clk_m", - "pll_c", - "clk_32k", - "pll_m", - "pll_p", - "pll_p_out4", - "pll_p_out3", - "clk_d", - "pll_x", -}; - - -static struct clk *mux_cclk_p[] = { - &tegra_clk_m, - &tegra_pll_c, - &tegra_clk_32k, - &tegra_pll_m, - &tegra_pll_p, - &tegra_pll_p_out4, - &tegra_pll_p_out3, - &tegra_clk_d, - &tegra_pll_x, -}; - -static const char *mux_sclk[] = { - "clk_m", - "pll_c_out1", - "pll_p_out4", - "pllp_p_out3", - "pll_p_out2", - "clk_d", - "clk_32k", - "pll_m_out1", -}; - -static struct clk *mux_sclk_p[] = { - &tegra_clk_m, - &tegra_pll_c_out1, - &tegra_pll_p_out4, - &tegra_pll_p_out3, - &tegra_pll_p_out2, - &tegra_clk_d, - &tegra_clk_32k, - &tegra_pll_m_out1, -}; - -static struct clk tegra_cclk; -static struct clk_tegra tegra_cclk_hw = { - .hw = { - .clk = &tegra_cclk, - }, - .reg = 0x20, - .max_rate = 1000000000, -}; -DEFINE_CLK_TEGRA(cclk, 0, &tegra_super_ops, 0, mux_cclk, - mux_cclk_p, NULL); - -static const char *mux_twd[] = { - "cclk", -}; - -static struct clk *mux_twd_p[] = { - &tegra_cclk, -}; - -static struct clk tegra_clk_twd; -static struct clk_tegra tegra_clk_twd_hw = { - .hw = { - .clk = &tegra_clk_twd, - }, - .max_rate = 1000000000, - .mul = 1, - .div = 4, -}; - -static struct clk tegra_clk_twd = { - .name = "twd", - .ops = &tegra_twd_ops, - .hw = &tegra_clk_twd_hw.hw, - .parent = &tegra_cclk, - .parent_names = mux_twd, - .parents = mux_twd_p, - .num_parents = ARRAY_SIZE(mux_twd), -}; - -static struct clk tegra_sclk; -static struct clk_tegra tegra_sclk_hw = { - .hw = { - .clk = &tegra_sclk, - }, - .reg = 0x28, - .max_rate = 240000000, - .min_rate = 120000000, -}; -DEFINE_CLK_TEGRA(sclk, 0, &tegra_super_ops, 0, mux_sclk, - mux_sclk_p, NULL); - -static const char *tegra_cop_parent_names[] = { - "tegra_sclk", -}; - -static struct clk *tegra_cop_parents[] = { - &tegra_sclk, -}; - -static struct clk tegra_cop; -static struct clk_tegra tegra_cop_hw = { - .hw = { - .clk = &tegra_cop, - }, - .max_rate = 240000000, - .reset = &tegra2_cop_clk_reset, -}; -DEFINE_CLK_TEGRA(cop, 0, &tegra_cop_ops, CLK_SET_RATE_PARENT, - tegra_cop_parent_names, tegra_cop_parents, &tegra_sclk); - -static const char *tegra_hclk_parent_names[] = { - "tegra_sclk", -}; - -static struct clk *tegra_hclk_parents[] = { - &tegra_sclk, -}; - -static struct clk tegra_hclk; -static struct clk_tegra tegra_hclk_hw = { - .hw = { - .clk = &tegra_hclk, - }, - .flags = DIV_BUS, - .reg = 0x30, - .reg_shift = 4, - .max_rate = 240000000, -}; -DEFINE_CLK_TEGRA(hclk, 0, &tegra_bus_ops, 0, tegra_hclk_parent_names, - tegra_hclk_parents, &tegra_sclk); - -static const char *tegra_pclk_parent_names[] = { - "tegra_hclk", -}; - -static struct clk *tegra_pclk_parents[] = { - &tegra_hclk, -}; - -static struct clk tegra_pclk; -static struct clk_tegra tegra_pclk_hw = { - .hw = { - .clk = &tegra_pclk, - }, - .flags = DIV_BUS, - .reg = 0x30, - .reg_shift = 0, - .max_rate = 120000000, -}; -DEFINE_CLK_TEGRA(pclk, 0, &tegra_bus_ops, 0, tegra_pclk_parent_names, - tegra_pclk_parents, &tegra_hclk); - -static const char *tegra_blink_parent_names[] = { - "clk_32k", -}; - -static struct clk *tegra_blink_parents[] = { - &tegra_clk_32k, -}; - -static struct clk tegra_blink; -static struct clk_tegra tegra_blink_hw = { - .hw = { - .clk = &tegra_blink, - }, - .reg = 0x40, - .max_rate = 32768, -}; -DEFINE_CLK_TEGRA(blink, 0, &tegra_blink_clk_ops, 0, tegra_blink_parent_names, - tegra_blink_parents, &tegra_clk_32k); - -static const char *mux_pllm_pllc_pllp_plla[] = { - "pll_m", - "pll_c", - "pll_p", - "pll_a_out0", -}; - -static struct clk *mux_pllm_pllc_pllp_plla_p[] = { - &tegra_pll_m, - &tegra_pll_c, - &tegra_pll_p, - &tegra_pll_a_out0, -}; - -static const char *mux_pllm_pllc_pllp_clkm[] = { - "pll_m", - "pll_c", - "pll_p", - "clk_m", -}; - -static struct clk *mux_pllm_pllc_pllp_clkm_p[] = { - &tegra_pll_m, - &tegra_pll_c, - &tegra_pll_p, - &tegra_clk_m, -}; - -static const char *mux_pllp_pllc_pllm_clkm[] = { - "pll_p", - "pll_c", - "pll_m", - "clk_m", -}; - -static struct clk *mux_pllp_pllc_pllm_clkm_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_pll_m, - &tegra_clk_m, -}; - -static const char *mux_pllaout0_audio2x_pllp_clkm[] = { - "pll_a_out0", - "audio_2x", - "pll_p", - "clk_m", -}; - -static struct clk *mux_pllaout0_audio2x_pllp_clkm_p[] = { - &tegra_pll_a_out0, - &tegra_audio_2x, - &tegra_pll_p, - &tegra_clk_m, -}; - -static const char *mux_pllp_plld_pllc_clkm[] = { - "pllp", - "pll_d_out0", - "pll_c", - "clk_m", -}; - -static struct clk *mux_pllp_plld_pllc_clkm_p[] = { - &tegra_pll_p, - &tegra_pll_d_out0, - &tegra_pll_c, - &tegra_clk_m, -}; - -static const char *mux_pllp_pllc_audio_clkm_clk32[] = { - "pll_p", - "pll_c", - "audio", - "clk_m", - "clk_32k", -}; - -static struct clk *mux_pllp_pllc_audio_clkm_clk32_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_audio, - &tegra_clk_m, - &tegra_clk_32k, -}; - -static const char *mux_pllp_pllc_pllm[] = { - "pll_p", - "pll_c", - "pll_m" -}; - -static struct clk *mux_pllp_pllc_pllm_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_pll_m, -}; - -static const char *mux_clk_m[] = { - "clk_m", -}; - -static struct clk *mux_clk_m_p[] = { - &tegra_clk_m, -}; - -static const char *mux_pllp_out3[] = { - "pll_p_out3", -}; - -static struct clk *mux_pllp_out3_p[] = { - &tegra_pll_p_out3, -}; - -static const char *mux_plld[] = { - "pll_d", -}; - -static struct clk *mux_plld_p[] = { - &tegra_pll_d, -}; - -static const char *mux_clk_32k[] = { - "clk_32k", -}; - -static struct clk *mux_clk_32k_p[] = { - &tegra_clk_32k, -}; - -static const char *mux_pclk[] = { - "pclk", -}; - -static struct clk *mux_pclk_p[] = { - &tegra_pclk, -}; - -static struct clk tegra_emc; -static struct clk_tegra tegra_emc_hw = { - .hw = { - .clk = &tegra_emc, - }, - .reg = 0x19c, - .max_rate = 800000000, - .flags = MUX | DIV_U71 | PERIPH_EMC_ENB, - .reset = &tegra2_periph_clk_reset, - .u.periph = { - .clk_num = 57, - }, -}; -DEFINE_CLK_TEGRA(emc, 0, &tegra_emc_clk_ops, 0, mux_pllm_pllc_pllp_clkm, - mux_pllm_pllc_pllp_clkm_p, NULL); - -#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, \ - _max, _inputs, _flags) \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .lookup = { \ - .dev_id = _dev, \ - .con_id = _con, \ - }, \ - .reg = _reg, \ - .flags = _flags, \ - .max_rate = _max, \ - .u.periph = { \ - .clk_num = _clk_num, \ - }, \ - .reset = tegra2_periph_clk_reset, \ - }; \ - static struct clk tegra_##_name = { \ - .name = #_name, \ - .ops = &tegra_periph_clk_ops, \ - .hw = &tegra_##_name##_hw.hw, \ - .parent_names = _inputs, \ - .parents = _inputs##_p, \ - .num_parents = ARRAY_SIZE(_inputs), \ - }; - -PERIPH_CLK(apbdma, "tegra-apbdma", NULL, 34, 0, 108000000, mux_pclk, 0); -PERIPH_CLK(rtc, "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET); -PERIPH_CLK(timer, "timer", NULL, 5, 0, 26000000, mux_clk_m, 0); -PERIPH_CLK(i2s1, "tegra20-i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(i2s2, "tegra20-i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(spdif_out, "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(spdif_in, "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71); -PERIPH_CLK(pwm, "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71 | MUX_PWM); -PERIPH_CLK(spi, "spi", NULL, 43, 0x114, 40000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(xio, "xio", NULL, 45, 0x120, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(twc, "twc", NULL, 16, 0x12c, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sbc1, "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sbc2, "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sbc3, "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sbc4, "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(ide, "ide", NULL, 25, 0x144, 100000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(ndflash, "tegra_nand", NULL, 13, 0x160, 164000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(vfir, "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sdmmc1, "sdhci-tegra.0", NULL, 14, 0x150, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(sdmmc2, "sdhci-tegra.1", NULL, 9, 0x154, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(sdmmc3, "sdhci-tegra.2", NULL, 69, 0x1bc, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(sdmmc4, "sdhci-tegra.3", NULL, 15, 0x164, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(vcp, "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(bsea, "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(bsev, "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(vde, "tegra-avp", "vde", 61, 0x1c8, 250000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage and process_id */ -PERIPH_CLK(csite, "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* max rate ??? */ -/* FIXME: what is la? */ -PERIPH_CLK(la, "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(owr, "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(nor, "nor", NULL, 42, 0x1d0, 92000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(mipi, "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(i2c1, "tegra-i2c.0", "div-clk", 12, 0x124, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); -PERIPH_CLK(i2c2, "tegra-i2c.1", "div-clk", 54, 0x198, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); -PERIPH_CLK(i2c3, "tegra-i2c.2", "div-clk", 67, 0x1b8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); -PERIPH_CLK(dvc, "tegra-i2c.3", "div-clk", 47, 0x128, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); -PERIPH_CLK(uarta, "tegra-uart.0", NULL, 6, 0x178, 600000000, mux_pllp_pllc_pllm_clkm, MUX); -PERIPH_CLK(uartb, "tegra-uart.1", NULL, 7, 0x17c, 600000000, mux_pllp_pllc_pllm_clkm, MUX); -PERIPH_CLK(uartc, "tegra-uart.2", NULL, 55, 0x1a0, 600000000, mux_pllp_pllc_pllm_clkm, MUX); -PERIPH_CLK(uartd, "tegra-uart.3", NULL, 65, 0x1c0, 600000000, mux_pllp_pllc_pllm_clkm, MUX); -PERIPH_CLK(uarte, "tegra-uart.4", NULL, 66, 0x1c4, 600000000, mux_pllp_pllc_pllm_clkm, MUX); -PERIPH_CLK(3d, "3d", NULL, 24, 0x158, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET); /* scales with voltage and process_id */ -PERIPH_CLK(2d, "2d", NULL, 21, 0x15c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */ -PERIPH_CLK(vi, "tegra_camera", "vi", 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */ -PERIPH_CLK(vi_sensor, "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET); /* scales with voltage and process_id */ -PERIPH_CLK(epp, "epp", NULL, 19, 0x16c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */ -PERIPH_CLK(mpe, "mpe", NULL, 60, 0x170, 250000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */ -PERIPH_CLK(host1x, "host1x", NULL, 28, 0x180, 166000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */ -PERIPH_CLK(cve, "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(tvo, "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(hdmi, "hdmi", NULL, 51, 0x18c, 600000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(tvdac, "tvdac", NULL, 53, 0x194, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(disp1, "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_plld_pllc_clkm, MUX); /* scales with voltage and process_id */ -PERIPH_CLK(disp2, "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_plld_pllc_clkm, MUX); /* scales with voltage and process_id */ -PERIPH_CLK(usbd, "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0); /* requires min voltage */ -PERIPH_CLK(usb2, "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0); /* requires min voltage */ -PERIPH_CLK(usb3, "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0); /* requires min voltage */ -PERIPH_CLK(dsi, "dsi", NULL, 48, 0, 500000000, mux_plld, 0); /* scales with voltage */ -PERIPH_CLK(csi, "tegra_camera", "csi", 52, 0, 72000000, mux_pllp_out3, 0); -PERIPH_CLK(isp, "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0); /* same frequency as VI */ -PERIPH_CLK(csus, "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET); -PERIPH_CLK(pex, NULL, "pex", 70, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET); -PERIPH_CLK(afi, NULL, "afi", 72, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET); -PERIPH_CLK(pcie_xclk, NULL, "pcie_xclk", 74, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET); - -static struct clk *tegra_list_clks[] = { - &tegra_apbdma, - &tegra_rtc, - &tegra_timer, - &tegra_i2s1, - &tegra_i2s2, - &tegra_spdif_out, - &tegra_spdif_in, - &tegra_pwm, - &tegra_spi, - &tegra_xio, - &tegra_twc, - &tegra_sbc1, - &tegra_sbc2, - &tegra_sbc3, - &tegra_sbc4, - &tegra_ide, - &tegra_ndflash, - &tegra_vfir, - &tegra_sdmmc1, - &tegra_sdmmc2, - &tegra_sdmmc3, - &tegra_sdmmc4, - &tegra_vcp, - &tegra_bsea, - &tegra_bsev, - &tegra_vde, - &tegra_csite, - &tegra_la, - &tegra_owr, - &tegra_nor, - &tegra_mipi, - &tegra_i2c1, - &tegra_i2c2, - &tegra_i2c3, - &tegra_dvc, - &tegra_uarta, - &tegra_uartb, - &tegra_uartc, - &tegra_uartd, - &tegra_uarte, - &tegra_3d, - &tegra_2d, - &tegra_vi, - &tegra_vi_sensor, - &tegra_epp, - &tegra_mpe, - &tegra_host1x, - &tegra_cve, - &tegra_tvo, - &tegra_hdmi, - &tegra_tvdac, - &tegra_disp1, - &tegra_disp2, - &tegra_usbd, - &tegra_usb2, - &tegra_usb3, - &tegra_dsi, - &tegra_csi, - &tegra_isp, - &tegra_csus, - &tegra_pex, - &tegra_afi, - &tegra_pcie_xclk, -}; - -#define CLK_DUPLICATE(_name, _dev, _con) \ - { \ - .name = _name, \ - .lookup = { \ - .dev_id = _dev, \ - .con_id = _con, \ - }, \ - } - -/* Some clocks may be used by different drivers depending on the board - * configuration. List those here to register them twice in the clock lookup - * table under two names. - */ -static struct clk_duplicate tegra_clk_duplicates[] = { - CLK_DUPLICATE("uarta", "serial8250.0", NULL), - CLK_DUPLICATE("uartb", "serial8250.1", NULL), - CLK_DUPLICATE("uartc", "serial8250.2", NULL), - CLK_DUPLICATE("uartd", "serial8250.3", NULL), - CLK_DUPLICATE("uarte", "serial8250.4", NULL), - CLK_DUPLICATE("usbd", "utmip-pad", NULL), - CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL), - CLK_DUPLICATE("usbd", "tegra-otg", NULL), - CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"), - CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"), - CLK_DUPLICATE("epp", "tegra_grhost", "epp"), - CLK_DUPLICATE("mpe", "tegra_grhost", "mpe"), - CLK_DUPLICATE("cop", "tegra-avp", "cop"), - CLK_DUPLICATE("vde", "tegra-aes", "vde"), - CLK_DUPLICATE("cclk", NULL, "cpu"), - CLK_DUPLICATE("twd", "smp_twd", NULL), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.0", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"), - CLK_DUPLICATE("pll_p", "tegradc.0", "parent"), - CLK_DUPLICATE("pll_p", "tegradc.1", "parent"), - CLK_DUPLICATE("pll_d_out0", "hdmi", "parent"), -}; - -#define CLK(dev, con, ck) \ - { \ - .dev_id = dev, \ - .con_id = con, \ - .clk = ck, \ - } - -static struct clk *tegra_ptr_clks[] = { - &tegra_clk_32k, - &tegra_pll_s, - &tegra_clk_m, - &tegra_pll_m, - &tegra_pll_m_out1, - &tegra_pll_c, - &tegra_pll_c_out1, - &tegra_pll_p, - &tegra_pll_p_out1, - &tegra_pll_p_out2, - &tegra_pll_p_out3, - &tegra_pll_p_out4, - &tegra_pll_a, - &tegra_pll_a_out0, - &tegra_pll_d, - &tegra_pll_d_out0, - &tegra_pll_u, - &tegra_pll_x, - &tegra_pll_e, - &tegra_cclk, - &tegra_clk_twd, - &tegra_sclk, - &tegra_hclk, - &tegra_pclk, - &tegra_clk_d, - &tegra_cdev1, - &tegra_cdev2, - &tegra_blink, - &tegra_cop, - &tegra_emc, -}; - -static void tegra2_init_one_clock(struct clk *c) -{ - struct clk_tegra *clk = to_clk_tegra(c->hw); - int ret; - - ret = __clk_init(NULL, c); - if (ret) - pr_err("clk init failed %s\n", __clk_get_name(c)); - - INIT_LIST_HEAD(&clk->shared_bus_list); - if (!clk->lookup.dev_id && !clk->lookup.con_id) - clk->lookup.con_id = c->name; - clk->lookup.clk = c; - clkdev_add(&clk->lookup); - tegra_clk_add(c); -} - -void __init tegra2_init_clocks(void) -{ - int i; - struct clk *c; - - for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++) - tegra2_init_one_clock(tegra_ptr_clks[i]); - - for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++) - tegra2_init_one_clock(tegra_list_clks[i]); - - for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) { - c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name); - if (!c) { - pr_err("%s: Unknown duplicate clock %s\n", __func__, - tegra_clk_duplicates[i].name); - continue; - } - - tegra_clk_duplicates[i].lookup.clk = c; - clkdev_add(&tegra_clk_duplicates[i].lookup); - } - - init_audio_sync_clock_mux(); - tegra20_cpu_car_ops_init(); -} diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c deleted file mode 100644 index 4330787fe5cb..000000000000 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ /dev/null @@ -1,2506 +0,0 @@ -/* - * arch/arm/mach-tegra/tegra30_clocks.c - * - * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "clock.h" -#include "fuse.h" -#include "iomap.h" - -#define USE_PLL_LOCK_BITS 0 - -#define RST_DEVICES_L 0x004 -#define RST_DEVICES_H 0x008 -#define RST_DEVICES_U 0x00C -#define RST_DEVICES_V 0x358 -#define RST_DEVICES_W 0x35C -#define RST_DEVICES_SET_L 0x300 -#define RST_DEVICES_CLR_L 0x304 -#define RST_DEVICES_SET_V 0x430 -#define RST_DEVICES_CLR_V 0x434 -#define RST_DEVICES_NUM 5 - -#define CLK_OUT_ENB_L 0x010 -#define CLK_OUT_ENB_H 0x014 -#define CLK_OUT_ENB_U 0x018 -#define CLK_OUT_ENB_V 0x360 -#define CLK_OUT_ENB_W 0x364 -#define CLK_OUT_ENB_SET_L 0x320 -#define CLK_OUT_ENB_CLR_L 0x324 -#define CLK_OUT_ENB_SET_V 0x440 -#define CLK_OUT_ENB_CLR_V 0x444 -#define CLK_OUT_ENB_NUM 5 - -#define RST_DEVICES_V_SWR_CPULP_RST_DIS (0x1 << 1) -#define CLK_OUT_ENB_V_CLK_ENB_CPULP_EN (0x1 << 1) - -#define PERIPH_CLK_TO_BIT(c) (1 << (c->u.periph.clk_num % 32)) -#define PERIPH_CLK_TO_RST_REG(c) \ - periph_clk_to_reg((c), RST_DEVICES_L, RST_DEVICES_V, 4) -#define PERIPH_CLK_TO_RST_SET_REG(c) \ - periph_clk_to_reg((c), RST_DEVICES_SET_L, RST_DEVICES_SET_V, 8) -#define PERIPH_CLK_TO_RST_CLR_REG(c) \ - periph_clk_to_reg((c), RST_DEVICES_CLR_L, RST_DEVICES_CLR_V, 8) - -#define PERIPH_CLK_TO_ENB_REG(c) \ - periph_clk_to_reg((c), CLK_OUT_ENB_L, CLK_OUT_ENB_V, 4) -#define PERIPH_CLK_TO_ENB_SET_REG(c) \ - periph_clk_to_reg((c), CLK_OUT_ENB_SET_L, CLK_OUT_ENB_SET_V, 8) -#define PERIPH_CLK_TO_ENB_CLR_REG(c) \ - periph_clk_to_reg((c), CLK_OUT_ENB_CLR_L, CLK_OUT_ENB_CLR_V, 8) - -#define CLK_MASK_ARM 0x44 -#define MISC_CLK_ENB 0x48 - -#define OSC_CTRL 0x50 -#define OSC_CTRL_OSC_FREQ_MASK (0xF<<28) -#define OSC_CTRL_OSC_FREQ_13MHZ (0x0<<28) -#define OSC_CTRL_OSC_FREQ_19_2MHZ (0x4<<28) -#define OSC_CTRL_OSC_FREQ_12MHZ (0x8<<28) -#define OSC_CTRL_OSC_FREQ_26MHZ (0xC<<28) -#define OSC_CTRL_OSC_FREQ_16_8MHZ (0x1<<28) -#define OSC_CTRL_OSC_FREQ_38_4MHZ (0x5<<28) -#define OSC_CTRL_OSC_FREQ_48MHZ (0x9<<28) -#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK) - -#define OSC_CTRL_PLL_REF_DIV_MASK (3<<26) -#define OSC_CTRL_PLL_REF_DIV_1 (0<<26) -#define OSC_CTRL_PLL_REF_DIV_2 (1<<26) -#define OSC_CTRL_PLL_REF_DIV_4 (2<<26) - -#define OSC_FREQ_DET 0x58 -#define OSC_FREQ_DET_TRIG (1<<31) - -#define OSC_FREQ_DET_STATUS 0x5C -#define OSC_FREQ_DET_BUSY (1<<31) -#define OSC_FREQ_DET_CNT_MASK 0xFFFF - -#define PERIPH_CLK_SOURCE_I2S1 0x100 -#define PERIPH_CLK_SOURCE_EMC 0x19c -#define PERIPH_CLK_SOURCE_OSC 0x1fc -#define PERIPH_CLK_SOURCE_NUM1 \ - ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4) - -#define PERIPH_CLK_SOURCE_G3D2 0x3b0 -#define PERIPH_CLK_SOURCE_SE 0x42c -#define PERIPH_CLK_SOURCE_NUM2 \ - ((PERIPH_CLK_SOURCE_SE - PERIPH_CLK_SOURCE_G3D2) / 4 + 1) - -#define AUDIO_DLY_CLK 0x49c -#define AUDIO_SYNC_CLK_SPDIF 0x4b4 -#define PERIPH_CLK_SOURCE_NUM3 \ - ((AUDIO_SYNC_CLK_SPDIF - AUDIO_DLY_CLK) / 4 + 1) - -#define PERIPH_CLK_SOURCE_NUM (PERIPH_CLK_SOURCE_NUM1 + \ - PERIPH_CLK_SOURCE_NUM2 + \ - PERIPH_CLK_SOURCE_NUM3) - -#define CPU_SOFTRST_CTRL 0x380 - -#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF -#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF -#define PERIPH_CLK_SOURCE_DIV_SHIFT 0 -#define PERIPH_CLK_SOURCE_DIVIDLE_SHIFT 8 -#define PERIPH_CLK_SOURCE_DIVIDLE_VAL 50 -#define PERIPH_CLK_UART_DIV_ENB (1<<24) -#define PERIPH_CLK_VI_SEL_EX_SHIFT 24 -#define PERIPH_CLK_VI_SEL_EX_MASK (0x3<reg_shift - 24) * 4) - -#define PLL_BASE 0x0 -#define PLL_BASE_BYPASS (1<<31) -#define PLL_BASE_ENABLE (1<<30) -#define PLL_BASE_REF_ENABLE (1<<29) -#define PLL_BASE_OVERRIDE (1<<28) -#define PLL_BASE_LOCK (1<<27) -#define PLL_BASE_DIVP_MASK (0x7<<20) -#define PLL_BASE_DIVP_SHIFT 20 -#define PLL_BASE_DIVN_MASK (0x3FF<<8) -#define PLL_BASE_DIVN_SHIFT 8 -#define PLL_BASE_DIVM_MASK (0x1F) -#define PLL_BASE_DIVM_SHIFT 0 - -#define PLL_OUT_RATIO_MASK (0xFF<<8) -#define PLL_OUT_RATIO_SHIFT 8 -#define PLL_OUT_OVERRIDE (1<<2) -#define PLL_OUT_CLKEN (1<<1) -#define PLL_OUT_RESET_DISABLE (1<<0) - -#define PLL_MISC(c) \ - (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc) -#define PLL_MISC_LOCK_ENABLE(c) \ - (((c)->flags & (PLLU | PLLD)) ? (1<<22) : (1<<18)) - -#define PLL_MISC_DCCON_SHIFT 20 -#define PLL_MISC_CPCON_SHIFT 8 -#define PLL_MISC_CPCON_MASK (0xF<hw.clk; - - return clk_set_rate(clk, - (__clk_get_rate(__clk_get_parent(clk)) + n - 1) / n); -} - -static inline u32 periph_clk_to_reg( - struct clk_tegra *c, u32 reg_L, u32 reg_V, int offs) -{ - u32 reg = c->u.periph.clk_num / 32; - BUG_ON(reg >= RST_DEVICES_NUM); - if (reg < 3) - reg = reg_L + (reg * offs); - else - reg = reg_V + ((reg - 3) * offs); - return reg; -} - -static unsigned long clk_measure_input_freq(void) -{ - u32 clock_autodetect; - clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET); - do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY); - clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS); - if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) { - return 12000000; - } else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) { - return 13000000; - } else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) { - return 19200000; - } else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) { - return 26000000; - } else if (clock_autodetect >= 1025 - 3 && clock_autodetect <= 1025 + 3) { - return 16800000; - } else if (clock_autodetect >= 2344 - 3 && clock_autodetect <= 2344 + 3) { - return 38400000; - } else if (clock_autodetect >= 2928 - 3 && clock_autodetect <= 2928 + 3) { - return 48000000; - } else { - pr_err("%s: Unexpected clock autodetect value %d", __func__, - clock_autodetect); - BUG(); - return 0; - } -} - -static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate, - u32 flags, u32 round_mode) -{ - s64 divider_u71 = parent_rate; - if (!rate) - return -EINVAL; - - if (!(flags & DIV_U71_INT)) - divider_u71 *= 2; - if (round_mode == ROUND_DIVIDER_UP) - divider_u71 += rate - 1; - do_div(divider_u71, rate); - if (flags & DIV_U71_INT) - divider_u71 *= 2; - - if (divider_u71 - 2 < 0) - return 0; - - if (divider_u71 - 2 > 255) - return -EINVAL; - - return divider_u71 - 2; -} - -static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate) -{ - s64 divider_u16; - - divider_u16 = parent_rate; - if (!rate) - return -EINVAL; - divider_u16 += rate - 1; - do_div(divider_u16, rate); - - if (divider_u16 - 1 < 0) - return 0; - - if (divider_u16 - 1 > 0xFFFF) - return -EINVAL; - - return divider_u16 - 1; -} - -static unsigned long tegra30_clk_fixed_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - return to_clk_tegra(hw)->fixed_rate; -} - -struct clk_ops tegra30_clk_32k_ops = { - .recalc_rate = tegra30_clk_fixed_recalc_rate, -}; - -/* clk_m functions */ -static unsigned long tegra30_clk_m_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - if (!to_clk_tegra(hw)->fixed_rate) - to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq(); - return to_clk_tegra(hw)->fixed_rate; -} - -static void tegra30_clk_m_init(struct clk_hw *hw) -{ - u32 osc_ctrl = clk_readl(OSC_CTRL); - u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK; - u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK; - - switch (to_clk_tegra(hw)->fixed_rate) { - case 12000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - break; - case 13000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - break; - case 19200000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - break; - case 26000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - break; - case 16800000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_16_8MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - break; - case 38400000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_38_4MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_2); - break; - case 48000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_48MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4); - break; - default: - pr_err("%s: Unexpected clock rate %ld", __func__, - to_clk_tegra(hw)->fixed_rate); - BUG(); - } - clk_writel(auto_clock_control, OSC_CTRL); -} - -struct clk_ops tegra30_clk_m_ops = { - .init = tegra30_clk_m_init, - .recalc_rate = tegra30_clk_m_recalc_rate, -}; - -static unsigned long tegra30_clk_m_div_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -struct clk_ops tegra_clk_m_div_ops = { - .recalc_rate = tegra30_clk_m_div_recalc_rate, -}; - -/* PLL reference divider functions */ -static unsigned long tegra30_pll_ref_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long rate = parent_rate; - u32 pll_ref_div = clk_readl(OSC_CTRL) & OSC_CTRL_PLL_REF_DIV_MASK; - - switch (pll_ref_div) { - case OSC_CTRL_PLL_REF_DIV_1: - c->div = 1; - break; - case OSC_CTRL_PLL_REF_DIV_2: - c->div = 2; - break; - case OSC_CTRL_PLL_REF_DIV_4: - c->div = 4; - break; - default: - pr_err("%s: Invalid pll ref divider %d", __func__, pll_ref_div); - BUG(); - } - c->mul = 1; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -struct clk_ops tegra_pll_ref_ops = { - .recalc_rate = tegra30_pll_ref_recalc_rate, -}; - -/* super clock functions */ -/* "super clocks" on tegra30 have two-stage muxes, fractional 7.1 divider and - * clock skipping super divider. We will ignore the clock skipping divider, - * since we can't lower the voltage when using the clock skip, but we can if - * we lower the PLL frequency. We will use 7.1 divider for CPU super-clock - * only when its parent is a fixed rate PLL, since we can't change PLL rate - * in this case. - */ -static void tegra30_super_clk_init(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - struct clk_tegra *p = - to_clk_tegra(__clk_get_hw(__clk_get_parent(hw->clk))); - - c->state = ON; - if (c->flags & DIV_U71) { - /* Init safe 7.1 divider value (does not affect PLLX path) */ - clk_writel(SUPER_CLOCK_DIV_U71_MIN << SUPER_CLOCK_DIV_U71_SHIFT, - c->reg + SUPER_CLK_DIVIDER); - c->mul = 2; - c->div = 2; - if (!(p->flags & PLLX)) - c->div += SUPER_CLOCK_DIV_U71_MIN; - } else - clk_writel(0, c->reg + SUPER_CLK_DIVIDER); -} - -static u8 tegra30_super_clk_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - int source; - int shift; - - val = clk_readl(c->reg + SUPER_CLK_MUX); - BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && - ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); - shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ? - SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT; - source = (val >> shift) & SUPER_SOURCE_MASK; - if (c->flags & DIV_2) - source |= val & SUPER_LP_DIV2_BYPASS; - - return source; -} - -static int tegra30_super_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - struct clk_tegra *p = - to_clk_tegra(__clk_get_hw(clk_get_parent(hw->clk))); - u32 val; - int shift; - - val = clk_readl(c->reg + SUPER_CLK_MUX); - BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && - ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); - shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ? - SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT; - - /* For LP mode super-clock switch between PLLX direct - and divided-by-2 outputs is allowed only when other - than PLLX clock source is current parent */ - if ((c->flags & DIV_2) && (p->flags & PLLX) && - ((index ^ val) & SUPER_LP_DIV2_BYPASS)) { - if (p->flags & PLLX) - return -EINVAL; - val ^= SUPER_LP_DIV2_BYPASS; - clk_writel_delay(val, c->reg); - } - val &= ~(SUPER_SOURCE_MASK << shift); - val |= (index & SUPER_SOURCE_MASK) << shift; - - /* 7.1 divider for CPU super-clock does not affect - PLLX path */ - if (c->flags & DIV_U71) { - u32 div = 0; - if (!(p->flags & PLLX)) { - div = clk_readl(c->reg + - SUPER_CLK_DIVIDER); - div &= SUPER_CLOCK_DIV_U71_MASK; - div >>= SUPER_CLOCK_DIV_U71_SHIFT; - } - c->div = div + 2; - c->mul = 2; - } - clk_writel_delay(val, c->reg); - - return 0; -} - -/* - * Do not use super clocks "skippers", since dividing using a clock skipper - * does not allow the voltage to be scaled down. Instead adjust the rate of - * the parent clock. This requires that the parent of a super clock have no - * other children, otherwise the rate will change underneath the other - * children. Special case: if fixed rate PLL is CPU super clock parent the - * rate of this PLL can't be changed, and it has many other children. In - * this case use 7.1 fractional divider to adjust the super clock rate. - */ -static int tegra30_super_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - struct clk *parent = __clk_get_parent(hw->clk); - struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent)); - - if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) { - int div = clk_div71_get_divider(parent_rate, - rate, c->flags, ROUND_DIVIDER_DOWN); - div = max(div, SUPER_CLOCK_DIV_U71_MIN); - - clk_writel(div << SUPER_CLOCK_DIV_U71_SHIFT, - c->reg + SUPER_CLK_DIVIDER); - c->div = div + 2; - c->mul = 2; - return 0; - } - return 0; -} - -static unsigned long tegra30_super_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -static long tegra30_super_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - struct clk *parent = __clk_get_parent(hw->clk); - struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent)); - int mul = 2; - int div; - - if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) { - div = clk_div71_get_divider(*prate, - rate, c->flags, ROUND_DIVIDER_DOWN); - div = max(div, SUPER_CLOCK_DIV_U71_MIN) + 2; - rate = *prate * mul; - rate += div - 1; /* round up */ - do_div(rate, c->div); - - return rate; - } - return *prate; -} - -struct clk_ops tegra30_super_ops = { - .init = tegra30_super_clk_init, - .set_parent = tegra30_super_clk_set_parent, - .get_parent = tegra30_super_clk_get_parent, - .recalc_rate = tegra30_super_clk_recalc_rate, - .round_rate = tegra30_super_clk_round_rate, - .set_rate = tegra30_super_clk_set_rate, -}; - -static unsigned long tegra30_twd_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -struct clk_ops tegra30_twd_ops = { - .recalc_rate = tegra30_twd_clk_recalc_rate, -}; - -/* bus clock functions */ -static int tegra30_bus_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - - c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON; - return c->state; -} - -static int tegra30_bus_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg); - val &= ~(BUS_CLK_DISABLE << c->reg_shift); - clk_writel(val, c->reg); - - return 0; -} - -static void tegra30_bus_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg); - val |= BUS_CLK_DISABLE << c->reg_shift; - clk_writel(val, c->reg); -} - -static unsigned long tegra30_bus_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - u64 rate = prate; - - c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1; - c->mul = 1; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - return rate; -} - -static int tegra30_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - int ret = -EINVAL; - u32 val; - int i; - - val = clk_readl(c->reg); - for (i = 1; i <= 4; i++) { - if (rate == parent_rate / i) { - val &= ~(BUS_CLK_DIV_MASK << c->reg_shift); - val |= (i - 1) << c->reg_shift; - clk_writel(val, c->reg); - c->div = i; - c->mul = 1; - ret = 0; - break; - } - } - - return ret; -} - -static long tegra30_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - unsigned long parent_rate = *prate; - s64 divider; - - if (rate >= parent_rate) - return parent_rate; - - divider = parent_rate; - divider += rate - 1; - do_div(divider, rate); - - if (divider < 0) - return divider; - - if (divider > 4) - divider = 4; - do_div(parent_rate, divider); - - return parent_rate; -} - -struct clk_ops tegra30_bus_ops = { - .is_enabled = tegra30_bus_clk_is_enabled, - .enable = tegra30_bus_clk_enable, - .disable = tegra30_bus_clk_disable, - .set_rate = tegra30_bus_clk_set_rate, - .round_rate = tegra30_bus_clk_round_rate, - .recalc_rate = tegra30_bus_clk_recalc_rate, -}; - -/* Blink output functions */ -static int tegra30_blink_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = pmc_readl(PMC_CTRL); - c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF; - return c->state; -} - -static int tegra30_blink_clk_enable(struct clk_hw *hw) -{ - u32 val; - - val = pmc_readl(PMC_DPD_PADS_ORIDE); - pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE); - - val = pmc_readl(PMC_CTRL); - pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL); - - return 0; -} - -static void tegra30_blink_clk_disable(struct clk_hw *hw) -{ - u32 val; - - val = pmc_readl(PMC_CTRL); - pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL); - - val = pmc_readl(PMC_DPD_PADS_ORIDE); - pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE); -} - -static int tegra30_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (rate >= parent_rate) { - c->div = 1; - pmc_writel(0, c->reg); - } else { - unsigned int on_off; - u32 val; - - on_off = DIV_ROUND_UP(parent_rate / 8, rate); - c->div = on_off * 8; - - val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) << - PMC_BLINK_TIMER_DATA_ON_SHIFT; - on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK; - on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT; - val |= on_off; - val |= PMC_BLINK_TIMER_ENB; - pmc_writel(val, c->reg); - } - - return 0; -} - -static unsigned long tegra30_blink_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - u32 val; - u32 mul; - u32 div; - u32 on_off; - - mul = 1; - val = pmc_readl(c->reg); - - if (val & PMC_BLINK_TIMER_ENB) { - on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) & - PMC_BLINK_TIMER_DATA_ON_MASK; - val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT; - val &= PMC_BLINK_TIMER_DATA_OFF_MASK; - on_off += val; - /* each tick in the blink timer is 4 32KHz clocks */ - div = on_off * 4; - } else { - div = 1; - } - - if (mul != 0 && div != 0) { - rate *= mul; - rate += div - 1; /* round up */ - do_div(rate, div); - } - return rate; -} - -static long tegra30_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - int div; - int mul; - long round_rate = *prate; - - mul = 1; - - if (rate >= *prate) { - div = 1; - } else { - div = DIV_ROUND_UP(*prate / 8, rate); - div *= 8; - } - - round_rate *= mul; - round_rate += div - 1; - do_div(round_rate, div); - - return round_rate; -} - -struct clk_ops tegra30_blink_clk_ops = { - .is_enabled = tegra30_blink_clk_is_enabled, - .enable = tegra30_blink_clk_enable, - .disable = tegra30_blink_clk_disable, - .recalc_rate = tegra30_blink_clk_recalc_rate, - .round_rate = tegra30_blink_clk_round_rate, - .set_rate = tegra30_blink_clk_set_rate, -}; - -static void tegra30_utmi_param_configure(struct clk_hw *hw) -{ - unsigned long main_rate = - __clk_get_rate(__clk_get_parent(__clk_get_parent(hw->clk))); - u32 reg; - int i; - - for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) { - if (main_rate == utmi_parameters[i].osc_frequency) - break; - } - - if (i >= ARRAY_SIZE(utmi_parameters)) { - pr_err("%s: Unexpected main rate %lu\n", __func__, main_rate); - return; - } - - reg = clk_readl(UTMIP_PLL_CFG2); - - /* Program UTMIP PLL stable and active counts */ - /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */ - reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0); - reg |= UTMIP_PLL_CFG2_STABLE_COUNT( - utmi_parameters[i].stable_count); - - reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0); - - reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT( - utmi_parameters[i].active_delay_count); - - /* Remove power downs from UTMIP PLL control bits */ - reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN; - reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN; - reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN; - - clk_writel(reg, UTMIP_PLL_CFG2); - - /* Program UTMIP PLL delay and oscillator frequency counts */ - reg = clk_readl(UTMIP_PLL_CFG1); - reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0); - - reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT( - utmi_parameters[i].enable_delay_count); - - reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0); - reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT( - utmi_parameters[i].xtal_freq_count); - - /* Remove power downs from UTMIP PLL control bits */ - reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; - reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN; - reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN; - - clk_writel(reg, UTMIP_PLL_CFG1); -} - -/* PLL Functions */ -static int tegra30_pll_clk_wait_for_lock(struct clk_tegra *c, u32 lock_reg, - u32 lock_bit) -{ - int ret = 0; - -#if USE_PLL_LOCK_BITS - int i; - for (i = 0; i < c->u.pll.lock_delay; i++) { - if (clk_readl(lock_reg) & lock_bit) { - udelay(PLL_POST_LOCK_DELAY); - return 0; - } - udelay(2); /* timeout = 2 * lock time */ - } - pr_err("Timed out waiting for lock bit on pll %s", - __clk_get_name(hw->clk)); - ret = -1; -#else - udelay(c->u.pll.lock_delay); -#endif - return ret; -} - -static int tegra30_pll_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg + PLL_BASE); - - c->state = (val & PLL_BASE_ENABLE) ? ON : OFF; - return c->state; -} - -static void tegra30_pll_clk_init(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (c->flags & PLLU) - tegra30_utmi_param_configure(hw); -} - -static int tegra30_pll_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - -#if USE_PLL_LOCK_BITS - val = clk_readl(c->reg + PLL_MISC(c)); - val |= PLL_MISC_LOCK_ENABLE(c); - clk_writel(val, c->reg + PLL_MISC(c)); -#endif - val = clk_readl(c->reg + PLL_BASE); - val &= ~PLL_BASE_BYPASS; - val |= PLL_BASE_ENABLE; - clk_writel(val, c->reg + PLL_BASE); - - if (c->flags & PLLM) { - val = pmc_readl(PMC_PLLP_WB0_OVERRIDE); - val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; - pmc_writel(val, PMC_PLLP_WB0_OVERRIDE); - } - - tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_BASE, PLL_BASE_LOCK); - - return 0; -} - -static void tegra30_pll_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - val = clk_readl(c->reg); - val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); - clk_writel(val, c->reg); - - if (c->flags & PLLM) { - val = pmc_readl(PMC_PLLP_WB0_OVERRIDE); - val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; - pmc_writel(val, PMC_PLLP_WB0_OVERRIDE); - } -} - -static int tegra30_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val, p_div, old_base; - unsigned long input_rate; - const struct clk_pll_freq_table *sel; - struct clk_pll_freq_table cfg; - - if (c->flags & PLL_FIXED) { - int ret = 0; - if (rate != c->u.pll.fixed_rate) { - pr_err("%s: Can not change %s fixed rate %lu to %lu\n", - __func__, __clk_get_name(hw->clk), - c->u.pll.fixed_rate, rate); - ret = -EINVAL; - } - return ret; - } - - if (c->flags & PLLM) { - if (rate != __clk_get_rate(hw->clk)) { - pr_err("%s: Can not change memory %s rate in flight\n", - __func__, __clk_get_name(hw->clk)); - return -EINVAL; - } - } - - p_div = 0; - input_rate = parent_rate; - - /* Check if the target rate is tabulated */ - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == input_rate && sel->output_rate == rate) { - if (c->flags & PLLU) { - BUG_ON(sel->p < 1 || sel->p > 2); - if (sel->p == 1) - p_div = PLLU_BASE_POST_DIV; - } else { - BUG_ON(sel->p < 1); - for (val = sel->p; val > 1; val >>= 1) - p_div++; - p_div <<= PLL_BASE_DIVP_SHIFT; - } - break; - } - } - - /* Configure out-of-table rate */ - if (sel->input_rate == 0) { - unsigned long cfreq; - BUG_ON(c->flags & PLLU); - sel = &cfg; - - switch (input_rate) { - case 12000000: - case 26000000: - cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000; - break; - case 13000000: - cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000; - break; - case 16800000: - case 19200000: - cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000; - break; - default: - pr_err("%s: Unexpected reference rate %lu\n", - __func__, input_rate); - BUG(); - } - - /* Raise VCO to guarantee 0.5% accuracy */ - for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq; - cfg.output_rate <<= 1) - p_div++; - - cfg.p = 0x1 << p_div; - cfg.m = input_rate / cfreq; - cfg.n = cfg.output_rate / cfreq; - cfg.cpcon = OUT_OF_TABLE_CPCON; - - if ((cfg.m > (PLL_BASE_DIVM_MASK >> PLL_BASE_DIVM_SHIFT)) || - (cfg.n > (PLL_BASE_DIVN_MASK >> PLL_BASE_DIVN_SHIFT)) || - (p_div > (PLL_BASE_DIVP_MASK >> PLL_BASE_DIVP_SHIFT)) || - (cfg.output_rate > c->u.pll.vco_max)) { - pr_err("%s: Failed to set %s out-of-table rate %lu\n", - __func__, __clk_get_name(hw->clk), rate); - return -EINVAL; - } - p_div <<= PLL_BASE_DIVP_SHIFT; - } - - c->mul = sel->n; - c->div = sel->m * sel->p; - - old_base = val = clk_readl(c->reg + PLL_BASE); - val &= ~(PLL_BASE_DIVM_MASK | PLL_BASE_DIVN_MASK | - ((c->flags & PLLU) ? PLLU_BASE_POST_DIV : PLL_BASE_DIVP_MASK)); - val |= (sel->m << PLL_BASE_DIVM_SHIFT) | - (sel->n << PLL_BASE_DIVN_SHIFT) | p_div; - if (val == old_base) - return 0; - - if (c->state == ON) { - tegra30_pll_clk_disable(hw); - val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); - } - clk_writel(val, c->reg + PLL_BASE); - - if (c->flags & PLL_HAS_CPCON) { - val = clk_readl(c->reg + PLL_MISC(c)); - val &= ~PLL_MISC_CPCON_MASK; - val |= sel->cpcon << PLL_MISC_CPCON_SHIFT; - if (c->flags & (PLLU | PLLD)) { - val &= ~PLL_MISC_LFCON_MASK; - if (sel->n >= PLLDU_LFCON_SET_DIVN) - val |= 0x1 << PLL_MISC_LFCON_SHIFT; - } else if (c->flags & (PLLX | PLLM)) { - val &= ~(0x1 << PLL_MISC_DCCON_SHIFT); - if (rate >= (c->u.pll.vco_max >> 1)) - val |= 0x1 << PLL_MISC_DCCON_SHIFT; - } - clk_writel(val, c->reg + PLL_MISC(c)); - } - - if (c->state == ON) - tegra30_pll_clk_enable(hw); - - c->u.pll.fixed_rate = rate; - - return 0; -} - -static long tegra30_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long input_rate = *prate; - u64 output_rate = *prate; - const struct clk_pll_freq_table *sel; - struct clk_pll_freq_table cfg; - int mul; - int div; - u32 p_div; - u32 val; - - if (c->flags & PLL_FIXED) - return c->u.pll.fixed_rate; - - if (c->flags & PLLM) - return __clk_get_rate(hw->clk); - - p_div = 0; - /* Check if the target rate is tabulated */ - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == input_rate && sel->output_rate == rate) { - if (c->flags & PLLU) { - BUG_ON(sel->p < 1 || sel->p > 2); - if (sel->p == 1) - p_div = PLLU_BASE_POST_DIV; - } else { - BUG_ON(sel->p < 1); - for (val = sel->p; val > 1; val >>= 1) - p_div++; - p_div <<= PLL_BASE_DIVP_SHIFT; - } - break; - } - } - - if (sel->input_rate == 0) { - unsigned long cfreq; - BUG_ON(c->flags & PLLU); - sel = &cfg; - - switch (input_rate) { - case 12000000: - case 26000000: - cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000; - break; - case 13000000: - cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000; - break; - case 16800000: - case 19200000: - cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000; - break; - default: - pr_err("%s: Unexpected reference rate %lu\n", - __func__, input_rate); - BUG(); - } - - /* Raise VCO to guarantee 0.5% accuracy */ - for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq; - cfg.output_rate <<= 1) - p_div++; - - cfg.p = 0x1 << p_div; - cfg.m = input_rate / cfreq; - cfg.n = cfg.output_rate / cfreq; - } - - mul = sel->n; - div = sel->m * sel->p; - - output_rate *= mul; - output_rate += div - 1; /* round up */ - do_div(output_rate, div); - - return output_rate; -} - -static unsigned long tegra30_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - u32 val = clk_readl(c->reg + PLL_BASE); - - if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) { - const struct clk_pll_freq_table *sel; - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == parent_rate && - sel->output_rate == c->u.pll.fixed_rate) { - c->mul = sel->n; - c->div = sel->m * sel->p; - break; - } - } - pr_err("Clock %s has unknown fixed frequency\n", - __clk_get_name(hw->clk)); - BUG(); - } else if (val & PLL_BASE_BYPASS) { - c->mul = 1; - c->div = 1; - } else { - c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT; - c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT; - if (c->flags & PLLU) - c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2; - else - c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >> - PLL_BASE_DIVP_SHIFT)); - } - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -struct clk_ops tegra30_pll_ops = { - .is_enabled = tegra30_pll_clk_is_enabled, - .init = tegra30_pll_clk_init, - .enable = tegra30_pll_clk_enable, - .disable = tegra30_pll_clk_disable, - .recalc_rate = tegra30_pll_recalc_rate, - .round_rate = tegra30_pll_round_rate, - .set_rate = tegra30_pll_clk_set_rate, -}; - -int tegra30_plld_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val, mask, reg; - - switch (p) { - case TEGRA_CLK_PLLD_CSI_OUT_ENB: - mask = PLLD_BASE_CSI_CLKENABLE; - reg = c->reg + PLL_BASE; - break; - case TEGRA_CLK_PLLD_DSI_OUT_ENB: - mask = PLLD_MISC_DSI_CLKENABLE; - reg = c->reg + PLL_MISC(c); - break; - case TEGRA_CLK_PLLD_MIPI_MUX_SEL: - if (!(c->flags & PLL_ALT_MISC_REG)) { - mask = PLLD_BASE_DSIB_MUX_MASK; - reg = c->reg + PLL_BASE; - break; - } - /* fall through - error since PLLD2 does not have MUX_SEL control */ - default: - return -EINVAL; - } - - val = clk_readl(reg); - if (setting) - val |= mask; - else - val &= ~mask; - clk_writel(val, reg); - return 0; -} - -static int tegra30_plle_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg + PLL_BASE); - c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF; - return c->state; -} - -static void tegra30_plle_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg + PLL_BASE); - val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE); - clk_writel(val, c->reg + PLL_BASE); -} - -static void tegra30_plle_training(struct clk_tegra *c) -{ - u32 val; - - /* PLLE is already disabled, and setup cleared; - * create falling edge on PLLE IDDQ input */ - val = pmc_readl(PMC_SATA_PWRGT); - val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; - pmc_writel(val, PMC_SATA_PWRGT); - - val = pmc_readl(PMC_SATA_PWRGT); - val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL; - pmc_writel(val, PMC_SATA_PWRGT); - - val = pmc_readl(PMC_SATA_PWRGT); - val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; - pmc_writel(val, PMC_SATA_PWRGT); - - do { - val = clk_readl(c->reg + PLL_MISC(c)); - } while (!(val & PLLE_MISC_READY)); -} - -static int tegra30_plle_configure(struct clk_hw *hw, bool force_training) -{ - struct clk_tegra *c = to_clk_tegra(hw); - struct clk *parent = __clk_get_parent(hw->clk); - const struct clk_pll_freq_table *sel; - u32 val; - - unsigned long rate = c->u.pll.fixed_rate; - unsigned long input_rate = __clk_get_rate(parent); - - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == input_rate && sel->output_rate == rate) - break; - } - - if (sel->input_rate == 0) - return -ENOSYS; - - /* disable PLLE, clear setup fiels */ - tegra30_plle_clk_disable(hw); - - val = clk_readl(c->reg + PLL_MISC(c)); - val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK); - clk_writel(val, c->reg + PLL_MISC(c)); - - /* training */ - val = clk_readl(c->reg + PLL_MISC(c)); - if (force_training || (!(val & PLLE_MISC_READY))) - tegra30_plle_training(c); - - /* configure dividers, setup, disable SS */ - val = clk_readl(c->reg + PLL_BASE); - val &= ~PLLE_BASE_DIV_MASK; - val |= PLLE_BASE_DIV(sel->m, sel->n, sel->p, sel->cpcon); - clk_writel(val, c->reg + PLL_BASE); - c->mul = sel->n; - c->div = sel->m * sel->p; - - val = clk_readl(c->reg + PLL_MISC(c)); - val |= PLLE_MISC_SETUP_VALUE; - val |= PLLE_MISC_LOCK_ENABLE; - clk_writel(val, c->reg + PLL_MISC(c)); - - val = clk_readl(PLLE_SS_CTRL); - val |= PLLE_SS_DISABLE; - clk_writel(val, PLLE_SS_CTRL); - - /* enable and lock PLLE*/ - val = clk_readl(c->reg + PLL_BASE); - val |= (PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE); - clk_writel(val, c->reg + PLL_BASE); - - tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_MISC(c), PLLE_MISC_LOCK); - - return 0; -} - -static int tegra30_plle_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - return tegra30_plle_configure(hw, !c->set); -} - -static unsigned long tegra30_plle_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long rate = parent_rate; - u32 val; - - val = clk_readl(c->reg + PLL_BASE); - c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT; - c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT; - c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - return rate; -} - -struct clk_ops tegra30_plle_ops = { - .is_enabled = tegra30_plle_clk_is_enabled, - .enable = tegra30_plle_clk_enable, - .disable = tegra30_plle_clk_disable, - .recalc_rate = tegra30_plle_clk_recalc_rate, -}; - -/* Clock divider ops */ -static int tegra30_pll_div_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (c->flags & DIV_U71) { - u32 val = clk_readl(c->reg); - val >>= c->reg_shift; - c->state = (val & PLL_OUT_CLKEN) ? ON : OFF; - if (!(val & PLL_OUT_RESET_DISABLE)) - c->state = OFF; - } else { - c->state = ON; - } - return c->state; -} - -static int tegra30_pll_div_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - u32 new_val; - - pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); - if (c->flags & DIV_U71) { - val = clk_readl(c->reg); - new_val = val >> c->reg_shift; - new_val &= 0xFFFF; - - new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE; - - val &= ~(0xFFFF << c->reg_shift); - val |= new_val << c->reg_shift; - clk_writel_delay(val, c->reg); - return 0; - } else if (c->flags & DIV_2) { - return 0; - } - return -EINVAL; -} - -static void tegra30_pll_div_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - u32 new_val; - - pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); - if (c->flags & DIV_U71) { - val = clk_readl(c->reg); - new_val = val >> c->reg_shift; - new_val &= 0xFFFF; - - new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE); - - val &= ~(0xFFFF << c->reg_shift); - val |= new_val << c->reg_shift; - clk_writel_delay(val, c->reg); - } -} - -static int tegra30_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - u32 new_val; - int divider_u71; - - if (c->flags & DIV_U71) { - divider_u71 = clk_div71_get_divider( - parent_rate, rate, c->flags, ROUND_DIVIDER_UP); - if (divider_u71 >= 0) { - val = clk_readl(c->reg); - new_val = val >> c->reg_shift; - new_val &= 0xFFFF; - if (c->flags & DIV_U71_FIXED) - new_val |= PLL_OUT_OVERRIDE; - new_val &= ~PLL_OUT_RATIO_MASK; - new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT; - - val &= ~(0xFFFF << c->reg_shift); - val |= new_val << c->reg_shift; - clk_writel_delay(val, c->reg); - c->div = divider_u71 + 2; - c->mul = 2; - c->fixed_rate = rate; - return 0; - } - } else if (c->flags & DIV_2) { - c->fixed_rate = rate; - return 0; - } - - return -EINVAL; -} - -static unsigned long tegra30_pll_div_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - - if (c->flags & DIV_U71) { - u32 divu71; - u32 val = clk_readl(c->reg); - val >>= c->reg_shift; - - divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT; - c->div = (divu71 + 2); - c->mul = 2; - } else if (c->flags & DIV_2) { - if (c->flags & (PLLD | PLLX)) { - c->div = 2; - c->mul = 1; - } else - BUG(); - } else { - c->div = 1; - c->mul = 1; - } - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -static long tegra30_pll_div_clk_round_rate(struct clk_hw *hw, - unsigned long rate, unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); - int divider; - - if (prate) - parent_rate = *prate; - - if (c->flags & DIV_U71) { - divider = clk_div71_get_divider( - parent_rate, rate, c->flags, ROUND_DIVIDER_UP); - if (divider < 0) - return divider; - return DIV_ROUND_UP(parent_rate * 2, divider + 2); - } else if (c->flags & DIV_2) { - *prate = rate * 2; - return rate; - } - - return -EINVAL; -} - -struct clk_ops tegra30_pll_div_ops = { - .is_enabled = tegra30_pll_div_clk_is_enabled, - .enable = tegra30_pll_div_clk_enable, - .disable = tegra30_pll_div_clk_disable, - .set_rate = tegra30_pll_div_clk_set_rate, - .recalc_rate = tegra30_pll_div_clk_recalc_rate, - .round_rate = tegra30_pll_div_clk_round_rate, -}; - -/* Periph clk ops */ -static inline u32 periph_clk_source_mask(struct clk_tegra *c) -{ - if (c->flags & MUX8) - return 7 << 29; - else if (c->flags & MUX_PWM) - return 3 << 28; - else if (c->flags & MUX_CLK_OUT) - return 3 << (c->u.periph.clk_num + 4); - else if (c->flags & PLLD) - return PLLD_BASE_DSIB_MUX_MASK; - else - return 3 << 30; -} - -static inline u32 periph_clk_source_shift(struct clk_tegra *c) -{ - if (c->flags & MUX8) - return 29; - else if (c->flags & MUX_PWM) - return 28; - else if (c->flags & MUX_CLK_OUT) - return c->u.periph.clk_num + 4; - else if (c->flags & PLLD) - return PLLD_BASE_DSIB_MUX_SHIFT; - else - return 30; -} - -static int tegra30_periph_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - c->state = ON; - if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c))) - c->state = OFF; - if (!(c->flags & PERIPH_NO_RESET)) - if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c)) - c->state = OFF; - return c->state; -} - -static int tegra30_periph_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++; - if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1) - return 0; - - clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_SET_REG(c)); - if (!(c->flags & PERIPH_NO_RESET) && - !(c->flags & PERIPH_MANUAL_RESET)) { - if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & - PERIPH_CLK_TO_BIT(c)) { - udelay(5); /* reset propagation delay */ - clk_writel(PERIPH_CLK_TO_BIT(c), - PERIPH_CLK_TO_RST_CLR_REG(c)); - } - } - return 0; -} - -static void tegra30_periph_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long val; - - tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--; - - if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0) - return; - - /* If peripheral is in the APB bus then read the APB bus to - * flush the write operation in apb bus. This will avoid the - * peripheral access after disabling clock*/ - if (c->flags & PERIPH_ON_APB) - val = chipid_readl(); - - clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c)); -} - -void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long val; - - if (!(c->flags & PERIPH_NO_RESET)) { - if (assert) { - /* If peripheral is in the APB bus then read the APB - * bus to flush the write operation in apb bus. This - * will avoid the peripheral access after disabling - * clock */ - if (c->flags & PERIPH_ON_APB) - val = chipid_readl(); - - clk_writel(PERIPH_CLK_TO_BIT(c), - PERIPH_CLK_TO_RST_SET_REG(c)); - } else - clk_writel(PERIPH_CLK_TO_BIT(c), - PERIPH_CLK_TO_RST_CLR_REG(c)); - } -} - -static int tegra30_periph_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - if (!(c->flags & MUX)) - return (index == 0) ? 0 : (-EINVAL); - - val = clk_readl(c->reg); - val &= ~periph_clk_source_mask(c); - val |= (index << periph_clk_source_shift(c)); - clk_writel_delay(val, c->reg); - return 0; -} - -static u8 tegra30_periph_clk_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - int source = (val & periph_clk_source_mask(c)) >> - periph_clk_source_shift(c); - - if (!(c->flags & MUX)) - return 0; - - return source; -} - -static int tegra30_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - int divider; - - if (c->flags & DIV_U71) { - divider = clk_div71_get_divider( - parent_rate, rate, c->flags, ROUND_DIVIDER_UP); - if (divider >= 0) { - val = clk_readl(c->reg); - val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK; - val |= divider; - if (c->flags & DIV_U71_UART) { - if (divider) - val |= PERIPH_CLK_UART_DIV_ENB; - else - val &= ~PERIPH_CLK_UART_DIV_ENB; - } - clk_writel_delay(val, c->reg); - c->div = divider + 2; - c->mul = 2; - return 0; - } - } else if (c->flags & DIV_U16) { - divider = clk_div16_get_divider(parent_rate, rate); - if (divider >= 0) { - val = clk_readl(c->reg); - val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK; - val |= divider; - clk_writel_delay(val, c->reg); - c->div = divider + 1; - c->mul = 1; - return 0; - } - } else if (parent_rate <= rate) { - c->div = 1; - c->mul = 1; - return 0; - } - return -EINVAL; -} - -static long tegra30_periph_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); - int divider; - - if (prate) - parent_rate = *prate; - - if (c->flags & DIV_U71) { - divider = clk_div71_get_divider( - parent_rate, rate, c->flags, ROUND_DIVIDER_UP); - if (divider < 0) - return divider; - - return DIV_ROUND_UP(parent_rate * 2, divider + 2); - } else if (c->flags & DIV_U16) { - divider = clk_div16_get_divider(parent_rate, rate); - if (divider < 0) - return divider; - return DIV_ROUND_UP(parent_rate, divider + 1); - } - return -EINVAL; -} - -static unsigned long tegra30_periph_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - u32 val = clk_readl(c->reg); - - if (c->flags & DIV_U71) { - u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK; - if ((c->flags & DIV_U71_UART) && - (!(val & PERIPH_CLK_UART_DIV_ENB))) { - divu71 = 0; - } - if (c->flags & DIV_U71_IDLE) { - val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK << - PERIPH_CLK_SOURCE_DIVIDLE_SHIFT); - val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL << - PERIPH_CLK_SOURCE_DIVIDLE_SHIFT); - clk_writel(val, c->reg); - } - c->div = divu71 + 2; - c->mul = 2; - } else if (c->flags & DIV_U16) { - u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK; - c->div = divu16 + 1; - c->mul = 1; - } else { - c->div = 1; - c->mul = 1; - } - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - return rate; -} - -struct clk_ops tegra30_periph_clk_ops = { - .is_enabled = tegra30_periph_clk_is_enabled, - .enable = tegra30_periph_clk_enable, - .disable = tegra30_periph_clk_disable, - .set_parent = tegra30_periph_clk_set_parent, - .get_parent = tegra30_periph_clk_get_parent, - .set_rate = tegra30_periph_clk_set_rate, - .round_rate = tegra30_periph_clk_round_rate, - .recalc_rate = tegra30_periph_clk_recalc_rate, -}; - -static int tegra30_dsib_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk *d = clk_get_sys(NULL, "pll_d"); - /* The DSIB parent selection bit is in PLLD base register */ - tegra_clk_cfg_ex( - d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, index); - - return 0; -} - -struct clk_ops tegra30_dsib_clk_ops = { - .is_enabled = tegra30_periph_clk_is_enabled, - .enable = &tegra30_periph_clk_enable, - .disable = &tegra30_periph_clk_disable, - .set_parent = &tegra30_dsib_clk_set_parent, - .get_parent = &tegra30_periph_clk_get_parent, - .set_rate = &tegra30_periph_clk_set_rate, - .round_rate = &tegra30_periph_clk_round_rate, - .recalc_rate = &tegra30_periph_clk_recalc_rate, -}; - -/* Periph extended clock configuration ops */ -int tegra30_vi_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (p == TEGRA_CLK_VI_INP_SEL) { - u32 val = clk_readl(c->reg); - val &= ~PERIPH_CLK_VI_SEL_EX_MASK; - val |= (setting << PERIPH_CLK_VI_SEL_EX_SHIFT) & - PERIPH_CLK_VI_SEL_EX_MASK; - clk_writel(val, c->reg); - return 0; - } - return -EINVAL; -} - -int tegra30_nand_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (p == TEGRA_CLK_NAND_PAD_DIV2_ENB) { - u32 val = clk_readl(c->reg); - if (setting) - val |= PERIPH_CLK_NAND_DIV_EX_ENB; - else - val &= ~PERIPH_CLK_NAND_DIV_EX_ENB; - clk_writel(val, c->reg); - return 0; - } - return -EINVAL; -} - -int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (p == TEGRA_CLK_DTV_INVERT) { - u32 val = clk_readl(c->reg); - if (setting) - val |= PERIPH_CLK_DTV_POLARITY_INV; - else - val &= ~PERIPH_CLK_DTV_POLARITY_INV; - clk_writel(val, c->reg); - return 0; - } - return -EINVAL; -} - -/* Output clock ops */ - -static DEFINE_SPINLOCK(clk_out_lock); - -static int tegra30_clk_out_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = pmc_readl(c->reg); - - c->state = (val & (0x1 << c->u.periph.clk_num)) ? ON : OFF; - c->mul = 1; - c->div = 1; - return c->state; -} - -static int tegra30_clk_out_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - unsigned long flags; - - spin_lock_irqsave(&clk_out_lock, flags); - val = pmc_readl(c->reg); - val |= (0x1 << c->u.periph.clk_num); - pmc_writel(val, c->reg); - spin_unlock_irqrestore(&clk_out_lock, flags); - - return 0; -} - -static void tegra30_clk_out_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - unsigned long flags; - - spin_lock_irqsave(&clk_out_lock, flags); - val = pmc_readl(c->reg); - val &= ~(0x1 << c->u.periph.clk_num); - pmc_writel(val, c->reg); - spin_unlock_irqrestore(&clk_out_lock, flags); -} - -static int tegra30_clk_out_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - unsigned long flags; - - spin_lock_irqsave(&clk_out_lock, flags); - val = pmc_readl(c->reg); - val &= ~periph_clk_source_mask(c); - val |= (index << periph_clk_source_shift(c)); - pmc_writel(val, c->reg); - spin_unlock_irqrestore(&clk_out_lock, flags); - - return 0; -} - -static u8 tegra30_clk_out_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = pmc_readl(c->reg); - int source; - - source = (val & periph_clk_source_mask(c)) >> - periph_clk_source_shift(c); - return source; -} - -struct clk_ops tegra_clk_out_ops = { - .is_enabled = tegra30_clk_out_is_enabled, - .enable = tegra30_clk_out_enable, - .disable = tegra30_clk_out_disable, - .set_parent = tegra30_clk_out_set_parent, - .get_parent = tegra30_clk_out_get_parent, - .recalc_rate = tegra30_clk_fixed_recalc_rate, -}; - -/* Clock doubler ops */ -static int tegra30_clk_double_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - c->state = ON; - if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c))) - c->state = OFF; - return c->state; -}; - -static int tegra30_clk_double_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - if (rate == parent_rate) { - val = clk_readl(c->reg) | (0x1 << c->reg_shift); - clk_writel(val, c->reg); - c->mul = 1; - c->div = 1; - return 0; - } else if (rate == 2 * parent_rate) { - val = clk_readl(c->reg) & (~(0x1 << c->reg_shift)); - clk_writel(val, c->reg); - c->mul = 2; - c->div = 1; - return 0; - } - return -EINVAL; -} - -static unsigned long tegra30_clk_double_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - - u32 val = clk_readl(c->reg); - c->mul = val & (0x1 << c->reg_shift) ? 1 : 2; - c->div = 1; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -static long tegra30_clk_double_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - unsigned long output_rate = *prate; - - do_div(output_rate, 2); - return output_rate; -} - -struct clk_ops tegra30_clk_double_ops = { - .is_enabled = tegra30_clk_double_is_enabled, - .enable = tegra30_periph_clk_enable, - .disable = tegra30_periph_clk_disable, - .recalc_rate = tegra30_clk_double_recalc_rate, - .round_rate = tegra30_clk_double_round_rate, - .set_rate = tegra30_clk_double_set_rate, -}; - -/* Audio sync clock ops */ -struct clk_ops tegra_sync_source_ops = { - .recalc_rate = tegra30_clk_fixed_recalc_rate, -}; - -static int tegra30_audio_sync_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - c->state = (val & AUDIO_SYNC_DISABLE_BIT) ? OFF : ON; - return c->state; -} - -static int tegra30_audio_sync_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - clk_writel((val & (~AUDIO_SYNC_DISABLE_BIT)), c->reg); - return 0; -} - -static void tegra30_audio_sync_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - clk_writel((val | AUDIO_SYNC_DISABLE_BIT), c->reg); -} - -static int tegra30_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg); - val &= ~AUDIO_SYNC_SOURCE_MASK; - val |= index; - - clk_writel(val, c->reg); - return 0; -} - -static u8 tegra30_audio_sync_clk_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - int source; - - source = val & AUDIO_SYNC_SOURCE_MASK; - return source; -} - -struct clk_ops tegra30_audio_sync_clk_ops = { - .is_enabled = tegra30_audio_sync_clk_is_enabled, - .enable = tegra30_audio_sync_clk_enable, - .disable = tegra30_audio_sync_clk_disable, - .set_parent = tegra30_audio_sync_clk_set_parent, - .get_parent = tegra30_audio_sync_clk_get_parent, - .recalc_rate = tegra30_clk_fixed_recalc_rate, -}; - -/* cml0 (pcie), and cml1 (sata) clock ops */ -static int tegra30_cml_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF; - return c->state; -} - -static int tegra30_cml_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - u32 val = clk_readl(c->reg); - val |= (0x1 << c->u.periph.clk_num); - clk_writel(val, c->reg); - - return 0; -} - -static void tegra30_cml_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - u32 val = clk_readl(c->reg); - val &= ~(0x1 << c->u.periph.clk_num); - clk_writel(val, c->reg); -} - -struct clk_ops tegra_cml_clk_ops = { - .is_enabled = tegra30_cml_clk_is_enabled, - .enable = tegra30_cml_clk_enable, - .disable = tegra30_cml_clk_disable, - .recalc_rate = tegra30_clk_fixed_recalc_rate, -}; - -struct clk_ops tegra_pciex_clk_ops = { - .recalc_rate = tegra30_clk_fixed_recalc_rate, -}; - -/* Tegra30 CPU clock and reset control functions */ -static void tegra30_wait_cpu_in_reset(u32 cpu) -{ - unsigned int reg; - - do { - reg = readl(reg_clk_base + - TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); - cpu_relax(); - } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ - - return; -} - -static void tegra30_put_cpu_in_reset(u32 cpu) -{ - writel(CPU_RESET(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); - dmb(); -} - -static void tegra30_cpu_out_of_reset(u32 cpu) -{ - writel(CPU_RESET(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); - wmb(); -} - -static void tegra30_enable_cpu_clock(u32 cpu) -{ - unsigned int reg; - - writel(CPU_CLOCK(cpu), - reg_clk_base + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); - reg = readl(reg_clk_base + - TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); -} - -static void tegra30_disable_cpu_clock(u32 cpu) -{ - - unsigned int reg; - - reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); - writel(reg | CPU_CLOCK(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); -} - -#ifdef CONFIG_PM_SLEEP -static bool tegra30_cpu_rail_off_ready(void) -{ - unsigned int cpu_rst_status; - int cpu_pwr_status; - - cpu_rst_status = readl(reg_clk_base + - TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); - cpu_pwr_status = tegra_powergate_is_powered(TEGRA_POWERGATE_CPU1) || - tegra_powergate_is_powered(TEGRA_POWERGATE_CPU2) || - tegra_powergate_is_powered(TEGRA_POWERGATE_CPU3); - - if (((cpu_rst_status & 0xE) != 0xE) || cpu_pwr_status) - return false; - - return true; -} - -static void tegra30_cpu_clock_suspend(void) -{ - /* switch coresite to clk_m, save off original source */ - tegra30_cpu_clk_sctx.clk_csite_src = - readl(reg_clk_base + CLK_RESET_SOURCE_CSITE); - writel(3<<30, reg_clk_base + CLK_RESET_SOURCE_CSITE); - - tegra30_cpu_clk_sctx.cpu_burst = - readl(reg_clk_base + CLK_RESET_CCLK_BURST); - tegra30_cpu_clk_sctx.pllx_base = - readl(reg_clk_base + CLK_RESET_PLLX_BASE); - tegra30_cpu_clk_sctx.pllx_misc = - readl(reg_clk_base + CLK_RESET_PLLX_MISC); - tegra30_cpu_clk_sctx.cclk_divider = - readl(reg_clk_base + CLK_RESET_CCLK_DIVIDER); -} - -static void tegra30_cpu_clock_resume(void) -{ - unsigned int reg, policy; - - /* Is CPU complex already running on PLLX? */ - reg = readl(reg_clk_base + CLK_RESET_CCLK_BURST); - policy = (reg >> CLK_RESET_CCLK_BURST_POLICY_SHIFT) & 0xF; - - if (policy == CLK_RESET_CCLK_IDLE_POLICY) - reg = (reg >> CLK_RESET_CCLK_IDLE_POLICY_SHIFT) & 0xF; - else if (policy == CLK_RESET_CCLK_RUN_POLICY) - reg = (reg >> CLK_RESET_CCLK_RUN_POLICY_SHIFT) & 0xF; - else - BUG(); - - if (reg != CLK_RESET_CCLK_BURST_POLICY_PLLX) { - /* restore PLLX settings if CPU is on different PLL */ - writel(tegra30_cpu_clk_sctx.pllx_misc, - reg_clk_base + CLK_RESET_PLLX_MISC); - writel(tegra30_cpu_clk_sctx.pllx_base, - reg_clk_base + CLK_RESET_PLLX_BASE); - - /* wait for PLL stabilization if PLLX was enabled */ - if (tegra30_cpu_clk_sctx.pllx_base & (1 << 30)) - udelay(300); - } - - /* - * Restore original burst policy setting for calls resulting from CPU - * LP2 in idle or system suspend. - */ - writel(tegra30_cpu_clk_sctx.cclk_divider, - reg_clk_base + CLK_RESET_CCLK_DIVIDER); - writel(tegra30_cpu_clk_sctx.cpu_burst, - reg_clk_base + CLK_RESET_CCLK_BURST); - - writel(tegra30_cpu_clk_sctx.clk_csite_src, - reg_clk_base + CLK_RESET_SOURCE_CSITE); -} -#endif - -static struct tegra_cpu_car_ops tegra30_cpu_car_ops = { - .wait_for_reset = tegra30_wait_cpu_in_reset, - .put_in_reset = tegra30_put_cpu_in_reset, - .out_of_reset = tegra30_cpu_out_of_reset, - .enable_clock = tegra30_enable_cpu_clock, - .disable_clock = tegra30_disable_cpu_clock, -#ifdef CONFIG_PM_SLEEP - .rail_off_ready = tegra30_cpu_rail_off_ready, - .suspend = tegra30_cpu_clock_suspend, - .resume = tegra30_cpu_clock_resume, -#endif -}; - -void __init tegra30_cpu_car_ops_init(void) -{ - tegra_cpu_car_ops = &tegra30_cpu_car_ops; -} diff --git a/arch/arm/mach-tegra/tegra30_clocks.h b/arch/arm/mach-tegra/tegra30_clocks.h deleted file mode 100644 index 7a34adb2f72d..000000000000 --- a/arch/arm/mach-tegra/tegra30_clocks.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2012, 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __MACH_TEGRA30_CLOCK_H -#define __MACH_TEGRA30_CLOCK_H - -extern struct clk_ops tegra30_clk_32k_ops; -extern struct clk_ops tegra30_clk_m_ops; -extern struct clk_ops tegra_clk_m_div_ops; -extern struct clk_ops tegra_pll_ref_ops; -extern struct clk_ops tegra30_pll_ops; -extern struct clk_ops tegra30_pll_div_ops; -extern struct clk_ops tegra_plld_ops; -extern struct clk_ops tegra30_plle_ops; -extern struct clk_ops tegra_cml_clk_ops; -extern struct clk_ops tegra_pciex_clk_ops; -extern struct clk_ops tegra_sync_source_ops; -extern struct clk_ops tegra30_audio_sync_clk_ops; -extern struct clk_ops tegra30_clk_double_ops; -extern struct clk_ops tegra_clk_out_ops; -extern struct clk_ops tegra30_super_ops; -extern struct clk_ops tegra30_blink_clk_ops; -extern struct clk_ops tegra30_twd_ops; -extern struct clk_ops tegra30_bus_ops; -extern struct clk_ops tegra30_periph_clk_ops; -extern struct clk_ops tegra30_dsib_clk_ops; -extern struct clk_ops tegra_nand_clk_ops; -extern struct clk_ops tegra_vi_clk_ops; -extern struct clk_ops tegra_dtv_clk_ops; -extern struct clk_ops tegra_clk_shared_bus_ops; - -int tegra30_plld_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting); -void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert); -int tegra30_vi_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting); -int tegra30_nand_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting); -int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting); -#endif diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c deleted file mode 100644 index 9bfaa490cff6..000000000000 --- a/arch/arm/mach-tegra/tegra30_clocks_data.c +++ /dev/null @@ -1,1425 +0,0 @@ -/* - * arch/arm/mach-tegra/tegra30_clocks.c - * - * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clock.h" -#include "fuse.h" -#include "tegra30_clocks.h" - -#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \ - _parent_names, _parents, _parent) \ - static struct clk tegra_##_name = { \ - .hw = &tegra_##_name##_hw.hw, \ - .name = #_name, \ - .rate = _rate, \ - .ops = _ops, \ - .flags = _flags, \ - .parent_names = _parent_names, \ - .parents = _parents, \ - .num_parents = ARRAY_SIZE(_parent_names), \ - .parent = _parent, \ - }; - -static struct clk tegra_clk_32k; -static struct clk_tegra tegra_clk_32k_hw = { - .hw = { - .clk = &tegra_clk_32k, - }, - .fixed_rate = 32768, -}; -static struct clk tegra_clk_32k = { - .name = "clk_32k", - .hw = &tegra_clk_32k_hw.hw, - .ops = &tegra30_clk_32k_ops, - .flags = CLK_IS_ROOT, -}; - -static struct clk tegra_clk_m; -static struct clk_tegra tegra_clk_m_hw = { - .hw = { - .clk = &tegra_clk_m, - }, - .flags = ENABLE_ON_INIT, - .reg = 0x1fc, - .reg_shift = 28, - .max_rate = 48000000, -}; -static struct clk tegra_clk_m = { - .name = "clk_m", - .hw = &tegra_clk_m_hw.hw, - .ops = &tegra30_clk_m_ops, - .flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED, -}; - -static const char *clk_m_div_parent_names[] = { - "clk_m", -}; - -static struct clk *clk_m_div_parents[] = { - &tegra_clk_m, -}; - -static struct clk tegra_clk_m_div2; -static struct clk_tegra tegra_clk_m_div2_hw = { - .hw = { - .clk = &tegra_clk_m_div2, - }, - .mul = 1, - .div = 2, - .max_rate = 24000000, -}; -DEFINE_CLK_TEGRA(clk_m_div2, 0, &tegra_clk_m_div_ops, 0, - clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m); - -static struct clk tegra_clk_m_div4; -static struct clk_tegra tegra_clk_m_div4_hw = { - .hw = { - .clk = &tegra_clk_m_div4, - }, - .mul = 1, - .div = 4, - .max_rate = 12000000, -}; -DEFINE_CLK_TEGRA(clk_m_div4, 0, &tegra_clk_m_div_ops, 0, - clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m); - -static struct clk tegra_pll_ref; -static struct clk_tegra tegra_pll_ref_hw = { - .hw = { - .clk = &tegra_pll_ref, - }, - .flags = ENABLE_ON_INIT, - .max_rate = 26000000, -}; -DEFINE_CLK_TEGRA(pll_ref, 0, &tegra_pll_ref_ops, 0, clk_m_div_parent_names, - clk_m_div_parents, &tegra_clk_m); - -#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min, \ - _input_max, _cf_min, _cf_max, _vco_min, \ - _vco_max, _freq_table, _lock_delay, _ops, \ - _fixed_rate, _clk_cfg_ex, _parent) \ - static struct clk tegra_##_name; \ - static const char *_name##_parent_names[] = { \ - #_parent, \ - }; \ - static struct clk *_name##_parents[] = { \ - &tegra_##_parent, \ - }; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .flags = _flags, \ - .reg = _reg, \ - .max_rate = _max_rate, \ - .u.pll = { \ - .input_min = _input_min, \ - .input_max = _input_max, \ - .cf_min = _cf_min, \ - .cf_max = _cf_max, \ - .vco_min = _vco_min, \ - .vco_max = _vco_max, \ - .freq_table = _freq_table, \ - .lock_delay = _lock_delay, \ - .fixed_rate = _fixed_rate, \ - }, \ - .clk_cfg_ex = _clk_cfg_ex, \ - }; \ - DEFINE_CLK_TEGRA(_name, 0, &_ops, CLK_IGNORE_UNUSED, \ - _name##_parent_names, _name##_parents, \ - &tegra_##_parent); - -#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift, \ - _max_rate, _ops, _parent, _clk_flags) \ - static const char *_name##_parent_names[] = { \ - #_parent, \ - }; \ - static struct clk *_name##_parents[] = { \ - &tegra_##_parent, \ - }; \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .flags = _flags, \ - .reg = _reg, \ - .max_rate = _max_rate, \ - .reg_shift = _reg_shift, \ - }; \ - DEFINE_CLK_TEGRA(_name, 0, &tegra30_pll_div_ops, \ - _clk_flags, _name##_parent_names, \ - _name##_parents, &tegra_##_parent); - -static struct clk_pll_freq_table tegra_pll_c_freq_table[] = { - { 12000000, 1040000000, 520, 6, 1, 8}, - { 13000000, 1040000000, 480, 6, 1, 8}, - { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */ - { 19200000, 1040000000, 325, 6, 1, 6}, - { 26000000, 1040000000, 520, 13, 1, 8}, - - { 12000000, 832000000, 416, 6, 1, 8}, - { 13000000, 832000000, 832, 13, 1, 8}, - { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */ - { 19200000, 832000000, 260, 6, 1, 8}, - { 26000000, 832000000, 416, 13, 1, 8}, - - { 12000000, 624000000, 624, 12, 1, 8}, - { 13000000, 624000000, 624, 13, 1, 8}, - { 16800000, 600000000, 520, 14, 1, 8}, - { 19200000, 624000000, 520, 16, 1, 8}, - { 26000000, 624000000, 624, 26, 1, 8}, - - { 12000000, 600000000, 600, 12, 1, 8}, - { 13000000, 600000000, 600, 13, 1, 8}, - { 16800000, 600000000, 500, 14, 1, 8}, - { 19200000, 600000000, 375, 12, 1, 6}, - { 26000000, 600000000, 600, 26, 1, 8}, - - { 12000000, 520000000, 520, 12, 1, 8}, - { 13000000, 520000000, 520, 13, 1, 8}, - { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */ - { 19200000, 520000000, 325, 12, 1, 6}, - { 26000000, 520000000, 520, 26, 1, 8}, - - { 12000000, 416000000, 416, 12, 1, 8}, - { 13000000, 416000000, 416, 13, 1, 8}, - { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */ - { 19200000, 416000000, 260, 12, 1, 6}, - { 26000000, 416000000, 416, 26, 1, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 1400000000, 2000000, 31000000, 1000000, - 6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300, - tegra30_pll_ops, 0, NULL, pll_ref); - -DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 700000000, - tegra30_pll_div_ops, pll_c, CLK_IGNORE_UNUSED); - -static struct clk_pll_freq_table tegra_pll_m_freq_table[] = { - { 12000000, 666000000, 666, 12, 1, 8}, - { 13000000, 666000000, 666, 13, 1, 8}, - { 16800000, 666000000, 555, 14, 1, 8}, - { 19200000, 666000000, 555, 16, 1, 8}, - { 26000000, 666000000, 666, 26, 1, 8}, - { 12000000, 600000000, 600, 12, 1, 8}, - { 13000000, 600000000, 600, 13, 1, 8}, - { 16800000, 600000000, 500, 14, 1, 8}, - { 19200000, 600000000, 375, 12, 1, 6}, - { 26000000, 600000000, 600, 26, 1, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_m, PLL_HAS_CPCON | PLLM, 0x90, 800000000, 2000000, 31000000, - 1000000, 6000000, 20000000, 1200000000, tegra_pll_m_freq_table, - 300, tegra30_pll_ops, 0, NULL, pll_ref); - -DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000, - tegra30_pll_div_ops, pll_m, CLK_IGNORE_UNUSED); - -static struct clk_pll_freq_table tegra_pll_p_freq_table[] = { - { 12000000, 216000000, 432, 12, 2, 8}, - { 13000000, 216000000, 432, 13, 2, 8}, - { 16800000, 216000000, 360, 14, 2, 8}, - { 19200000, 216000000, 360, 16, 2, 8}, - { 26000000, 216000000, 432, 26, 2, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000, - 2000000, 31000000, 1000000, 6000000, 20000000, 1400000000, - tegra_pll_p_freq_table, 300, tegra30_pll_ops, 408000000, NULL, - pll_ref); - -DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, - 0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED); -DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, - 16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED); -DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, - 0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED); -DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, - 16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED); - -static struct clk_pll_freq_table tegra_pll_a_freq_table[] = { - { 9600000, 564480000, 294, 5, 1, 4}, - { 9600000, 552960000, 288, 5, 1, 4}, - { 9600000, 24000000, 5, 2, 1, 1}, - - { 28800000, 56448000, 49, 25, 1, 1}, - { 28800000, 73728000, 64, 25, 1, 1}, - { 28800000, 24000000, 5, 6, 1, 1}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 700000000, 2000000, 31000000, 1000000, - 6000000, 20000000, 1400000000, tegra_pll_a_freq_table, - 300, tegra30_pll_ops, 0, NULL, pll_p_out1); - -DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 100000000, tegra30_pll_div_ops, - pll_a, CLK_IGNORE_UNUSED); - -static struct clk_pll_freq_table tegra_pll_d_freq_table[] = { - { 12000000, 216000000, 216, 12, 1, 4}, - { 13000000, 216000000, 216, 13, 1, 4}, - { 16800000, 216000000, 180, 14, 1, 4}, - { 19200000, 216000000, 180, 16, 1, 4}, - { 26000000, 216000000, 216, 26, 1, 4}, - - { 12000000, 594000000, 594, 12, 1, 8}, - { 13000000, 594000000, 594, 13, 1, 8}, - { 16800000, 594000000, 495, 14, 1, 8}, - { 19200000, 594000000, 495, 16, 1, 8}, - { 26000000, 594000000, 594, 26, 1, 8}, - - { 12000000, 1000000000, 1000, 12, 1, 12}, - { 13000000, 1000000000, 1000, 13, 1, 12}, - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 12}, - - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000, - 1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table, - 1000, tegra30_pll_ops, 0, tegra30_plld_clk_cfg_ex, pll_ref); - -DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops, - pll_d, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED); - -DEFINE_PLL(pll_d2, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD, 0x4b8, 1000000000, - 2000000, 40000000, 1000000, 6000000, 40000000, 1000000000, - tegra_pll_d_freq_table, 1000, tegra30_pll_ops, 0, NULL, - pll_ref); - -DEFINE_PLL_OUT(pll_d2_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops, - pll_d2, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED); - -static struct clk_pll_freq_table tegra_pll_u_freq_table[] = { - { 12000000, 480000000, 960, 12, 2, 12}, - { 13000000, 480000000, 960, 13, 2, 12}, - { 16800000, 480000000, 400, 7, 2, 5}, - { 19200000, 480000000, 200, 4, 2, 3}, - { 26000000, 480000000, 960, 26, 2, 12}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_u, PLL_HAS_CPCON | PLLU, 0xc0, 480000000, 2000000, 40000000, - 1000000, 6000000, 48000000, 960000000, tegra_pll_u_freq_table, - 1000, tegra30_pll_ops, 0, NULL, pll_ref); - -static struct clk_pll_freq_table tegra_pll_x_freq_table[] = { - /* 1.7 GHz */ - { 12000000, 1700000000, 850, 6, 1, 8}, - { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */ - { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */ - { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */ - { 26000000, 1700000000, 850, 13, 1, 8}, - - /* 1.6 GHz */ - { 12000000, 1600000000, 800, 6, 1, 8}, - { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */ - { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */ - { 19200000, 1600000000, 500, 6, 1, 8}, - { 26000000, 1600000000, 800, 13, 1, 8}, - - /* 1.5 GHz */ - { 12000000, 1500000000, 750, 6, 1, 8}, - { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */ - { 16800000, 1500000000, 625, 7, 1, 8}, - { 19200000, 1500000000, 625, 8, 1, 8}, - { 26000000, 1500000000, 750, 13, 1, 8}, - - /* 1.4 GHz */ - { 12000000, 1400000000, 700, 6, 1, 8}, - { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */ - { 16800000, 1400000000, 1000, 12, 1, 8}, - { 19200000, 1400000000, 875, 12, 1, 8}, - { 26000000, 1400000000, 700, 13, 1, 8}, - - /* 1.3 GHz */ - { 12000000, 1300000000, 975, 9, 1, 8}, - { 13000000, 1300000000, 1000, 10, 1, 8}, - { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */ - { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */ - { 26000000, 1300000000, 650, 13, 1, 8}, - - /* 1.2 GHz */ - { 12000000, 1200000000, 1000, 10, 1, 8}, - { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */ - { 16800000, 1200000000, 1000, 14, 1, 8}, - { 19200000, 1200000000, 1000, 16, 1, 8}, - { 26000000, 1200000000, 600, 13, 1, 8}, - - /* 1.1 GHz */ - { 12000000, 1100000000, 825, 9, 1, 8}, - { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */ - { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */ - { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */ - { 26000000, 1100000000, 550, 13, 1, 8}, - - /* 1 GHz */ - { 12000000, 1000000000, 1000, 12, 1, 8}, - { 13000000, 1000000000, 1000, 13, 1, 8}, - { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */ - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 8}, - - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX, 0xe0, 1700000000, - 2000000, 31000000, 1000000, 6000000, 20000000, 1700000000, - tegra_pll_x_freq_table, 300, tegra30_pll_ops, 0, NULL, pll_ref); - -DEFINE_PLL_OUT(pll_x_out0, DIV_2 | PLLX, 0, 0, 850000000, tegra30_pll_div_ops, - pll_x, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED); - -static struct clk_pll_freq_table tegra_pll_e_freq_table[] = { - /* PLLE special case: use cpcon field to store cml divider value */ - { 12000000, 100000000, 150, 1, 18, 11}, - { 216000000, 100000000, 200, 18, 24, 13}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 2000000, 216000000, - 12000000, 12000000, 1200000000, 2400000000U, - tegra_pll_e_freq_table, 300, tegra30_plle_ops, 100000000, NULL, - pll_ref); - -static const char *mux_plle[] = { - "pll_e", -}; - -static struct clk *mux_plle_p[] = { - &tegra_pll_e, -}; - -static struct clk tegra_cml0; -static struct clk_tegra tegra_cml0_hw = { - .hw = { - .clk = &tegra_cml0, - }, - .reg = 0x48c, - .fixed_rate = 100000000, - .u.periph = { - .clk_num = 0, - }, -}; -DEFINE_CLK_TEGRA(cml0, 0, &tegra_cml_clk_ops, 0, mux_plle, - mux_plle_p, &tegra_pll_e); - -static struct clk tegra_cml1; -static struct clk_tegra tegra_cml1_hw = { - .hw = { - .clk = &tegra_cml1, - }, - .reg = 0x48c, - .fixed_rate = 100000000, - .u.periph = { - .clk_num = 1, - }, -}; -DEFINE_CLK_TEGRA(cml1, 0, &tegra_cml_clk_ops, 0, mux_plle, - mux_plle_p, &tegra_pll_e); - -static struct clk tegra_pciex; -static struct clk_tegra tegra_pciex_hw = { - .hw = { - .clk = &tegra_pciex, - }, - .reg = 0x48c, - .fixed_rate = 100000000, - .reset = tegra30_periph_clk_reset, - .u.periph = { - .clk_num = 74, - }, -}; -DEFINE_CLK_TEGRA(pciex, 0, &tegra_pciex_clk_ops, 0, mux_plle, - mux_plle_p, &tegra_pll_e); - -#define SYNC_SOURCE(_name) \ - static struct clk tegra_##_name##_sync; \ - static struct clk_tegra tegra_##_name##_sync_hw = { \ - .hw = { \ - .clk = &tegra_##_name##_sync, \ - }, \ - .max_rate = 24000000, \ - .fixed_rate = 24000000, \ - }; \ - static struct clk tegra_##_name##_sync = { \ - .name = #_name "_sync", \ - .hw = &tegra_##_name##_sync_hw.hw, \ - .ops = &tegra_sync_source_ops, \ - .flags = CLK_IS_ROOT, \ - }; - -SYNC_SOURCE(spdif_in); -SYNC_SOURCE(i2s0); -SYNC_SOURCE(i2s1); -SYNC_SOURCE(i2s2); -SYNC_SOURCE(i2s3); -SYNC_SOURCE(i2s4); -SYNC_SOURCE(vimclk); - -static struct clk *tegra_sync_source_list[] = { - &tegra_spdif_in_sync, - &tegra_i2s0_sync, - &tegra_i2s1_sync, - &tegra_i2s2_sync, - &tegra_i2s3_sync, - &tegra_i2s4_sync, - &tegra_vimclk_sync, -}; - -static const char *mux_audio_sync_clk[] = { - "spdif_in_sync", - "i2s0_sync", - "i2s1_sync", - "i2s2_sync", - "i2s3_sync", - "i2s4_sync", - "vimclk_sync", -}; - -#define AUDIO_SYNC_CLK(_name, _index) \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .max_rate = 24000000, \ - .reg = 0x4A0 + (_index) * 4, \ - }; \ - static struct clk tegra_##_name = { \ - .name = #_name, \ - .ops = &tegra30_audio_sync_clk_ops, \ - .hw = &tegra_##_name##_hw.hw, \ - .parent_names = mux_audio_sync_clk, \ - .parents = tegra_sync_source_list, \ - .num_parents = ARRAY_SIZE(mux_audio_sync_clk), \ - }; - -AUDIO_SYNC_CLK(audio0, 0); -AUDIO_SYNC_CLK(audio1, 1); -AUDIO_SYNC_CLK(audio2, 2); -AUDIO_SYNC_CLK(audio3, 3); -AUDIO_SYNC_CLK(audio4, 4); -AUDIO_SYNC_CLK(audio5, 5); - -static struct clk *tegra_clk_audio_list[] = { - &tegra_audio0, - &tegra_audio1, - &tegra_audio2, - &tegra_audio3, - &tegra_audio4, - &tegra_audio5, /* SPDIF */ -}; - -#define AUDIO_SYNC_2X_CLK(_name, _index) \ - static const char *_name##_parent_names[] = { \ - "tegra_" #_name, \ - }; \ - static struct clk *_name##_parents[] = { \ - &tegra_##_name, \ - }; \ - static struct clk tegra_##_name##_2x; \ - static struct clk_tegra tegra_##_name##_2x_hw = { \ - .hw = { \ - .clk = &tegra_##_name##_2x, \ - }, \ - .flags = PERIPH_NO_RESET, \ - .max_rate = 48000000, \ - .reg = 0x49C, \ - .reg_shift = 24 + (_index), \ - .u.periph = { \ - .clk_num = 113 + (_index), \ - }, \ - }; \ - static struct clk tegra_##_name##_2x = { \ - .name = #_name "_2x", \ - .ops = &tegra30_clk_double_ops, \ - .hw = &tegra_##_name##_2x_hw.hw, \ - .parent_names = _name##_parent_names, \ - .parents = _name##_parents, \ - .parent = &tegra_##_name, \ - .num_parents = 1, \ - }; - -AUDIO_SYNC_2X_CLK(audio0, 0); -AUDIO_SYNC_2X_CLK(audio1, 1); -AUDIO_SYNC_2X_CLK(audio2, 2); -AUDIO_SYNC_2X_CLK(audio3, 3); -AUDIO_SYNC_2X_CLK(audio4, 4); -AUDIO_SYNC_2X_CLK(audio5, 5); /* SPDIF */ - -static struct clk *tegra_clk_audio_2x_list[] = { - &tegra_audio0_2x, - &tegra_audio1_2x, - &tegra_audio2_2x, - &tegra_audio3_2x, - &tegra_audio4_2x, - &tegra_audio5_2x, /* SPDIF */ -}; - -#define MUX_I2S_SPDIF(_id) \ -static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { \ - "pll_a_out0", \ - #_id "_2x", \ - "pll_p", \ - "clk_m", \ -}; \ -static struct clk *mux_pllaout0_##_id##_2x_pllp_clkm_p[] = { \ - &tegra_pll_a_out0, \ - &tegra_##_id##_2x, \ - &tegra_pll_p, \ - &tegra_clk_m, \ -}; - -MUX_I2S_SPDIF(audio0); -MUX_I2S_SPDIF(audio1); -MUX_I2S_SPDIF(audio2); -MUX_I2S_SPDIF(audio3); -MUX_I2S_SPDIF(audio4); -MUX_I2S_SPDIF(audio5); /* SPDIF */ - -static struct clk tegra_extern1; -static struct clk tegra_extern2; -static struct clk tegra_extern3; - -/* External clock outputs (through PMC) */ -#define MUX_EXTERN_OUT(_id) \ -static const char *mux_clkm_clkm2_clkm4_extern##_id[] = { \ - "clk_m", \ - "clk_m_div2", \ - "clk_m_div4", \ - "extern" #_id, \ -}; \ -static struct clk *mux_clkm_clkm2_clkm4_extern##_id##_p[] = { \ - &tegra_clk_m, \ - &tegra_clk_m_div2, \ - &tegra_clk_m_div4, \ - &tegra_extern##_id, \ -}; - -MUX_EXTERN_OUT(1); -MUX_EXTERN_OUT(2); -MUX_EXTERN_OUT(3); - -#define CLK_OUT_CLK(_name, _index) \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .lookup = { \ - .dev_id = #_name, \ - .con_id = "extern" #_index, \ - }, \ - .flags = MUX_CLK_OUT, \ - .fixed_rate = 216000000, \ - .reg = 0x1a8, \ - .u.periph = { \ - .clk_num = (_index - 1) * 8 + 2, \ - }, \ - }; \ - static struct clk tegra_##_name = { \ - .name = #_name, \ - .ops = &tegra_clk_out_ops, \ - .hw = &tegra_##_name##_hw.hw, \ - .parent_names = mux_clkm_clkm2_clkm4_extern##_index, \ - .parents = mux_clkm_clkm2_clkm4_extern##_index##_p, \ - .num_parents = ARRAY_SIZE(mux_clkm_clkm2_clkm4_extern##_index),\ - }; - -CLK_OUT_CLK(clk_out_1, 1); -CLK_OUT_CLK(clk_out_2, 2); -CLK_OUT_CLK(clk_out_3, 3); - -static struct clk *tegra_clk_out_list[] = { - &tegra_clk_out_1, - &tegra_clk_out_2, - &tegra_clk_out_3, -}; - -static const char *mux_sclk[] = { - "clk_m", - "pll_c_out1", - "pll_p_out4", - "pll_p_out3", - "pll_p_out2", - "dummy", - "clk_32k", - "pll_m_out1", -}; - -static struct clk *mux_sclk_p[] = { - &tegra_clk_m, - &tegra_pll_c_out1, - &tegra_pll_p_out4, - &tegra_pll_p_out3, - &tegra_pll_p_out2, - NULL, - &tegra_clk_32k, - &tegra_pll_m_out1, -}; - -static struct clk tegra_clk_sclk; -static struct clk_tegra tegra_clk_sclk_hw = { - .hw = { - .clk = &tegra_clk_sclk, - }, - .reg = 0x28, - .max_rate = 334000000, - .min_rate = 40000000, -}; - -static struct clk tegra_clk_sclk = { - .name = "sclk", - .ops = &tegra30_super_ops, - .hw = &tegra_clk_sclk_hw.hw, - .parent_names = mux_sclk, - .parents = mux_sclk_p, - .num_parents = ARRAY_SIZE(mux_sclk), -}; - -static const char *tegra_hclk_parent_names[] = { - "tegra_sclk", -}; - -static struct clk *tegra_hclk_parents[] = { - &tegra_clk_sclk, -}; - -static struct clk tegra_hclk; -static struct clk_tegra tegra_hclk_hw = { - .hw = { - .clk = &tegra_hclk, - }, - .flags = DIV_BUS, - .reg = 0x30, - .reg_shift = 4, - .max_rate = 378000000, - .min_rate = 12000000, -}; -DEFINE_CLK_TEGRA(hclk, 0, &tegra30_bus_ops, 0, tegra_hclk_parent_names, - tegra_hclk_parents, &tegra_clk_sclk); - -static const char *tegra_pclk_parent_names[] = { - "tegra_hclk", -}; - -static struct clk *tegra_pclk_parents[] = { - &tegra_hclk, -}; - -static struct clk tegra_pclk; -static struct clk_tegra tegra_pclk_hw = { - .hw = { - .clk = &tegra_pclk, - }, - .flags = DIV_BUS, - .reg = 0x30, - .reg_shift = 0, - .max_rate = 167000000, - .min_rate = 12000000, -}; -DEFINE_CLK_TEGRA(pclk, 0, &tegra30_bus_ops, 0, tegra_pclk_parent_names, - tegra_pclk_parents, &tegra_hclk); - -static const char *mux_blink[] = { - "clk_32k", -}; - -static struct clk *mux_blink_p[] = { - &tegra_clk_32k, -}; - -static struct clk tegra_clk_blink; -static struct clk_tegra tegra_clk_blink_hw = { - .hw = { - .clk = &tegra_clk_blink, - }, - .reg = 0x40, - .max_rate = 32768, -}; -static struct clk tegra_clk_blink = { - .name = "blink", - .ops = &tegra30_blink_clk_ops, - .hw = &tegra_clk_blink_hw.hw, - .parent = &tegra_clk_32k, - .parent_names = mux_blink, - .parents = mux_blink_p, - .num_parents = ARRAY_SIZE(mux_blink), -}; - -static const char *mux_pllm_pllc_pllp_plla[] = { - "pll_m", - "pll_c", - "pll_p", - "pll_a_out0", -}; - -static const char *mux_pllp_pllc_pllm_clkm[] = { - "pll_p", - "pll_c", - "pll_m", - "clk_m", -}; - -static const char *mux_pllp_clkm[] = { - "pll_p", - "dummy", - "dummy", - "clk_m", -}; - -static const char *mux_pllp_plld_pllc_clkm[] = { - "pll_p", - "pll_d_out0", - "pll_c", - "clk_m", -}; - -static const char *mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = { - "pll_p", - "pll_m", - "pll_d_out0", - "pll_a_out0", - "pll_c", - "pll_d2_out0", - "clk_m", -}; - -static const char *mux_plla_pllc_pllp_clkm[] = { - "pll_a_out0", - "dummy", - "pll_p", - "clk_m" -}; - -static const char *mux_pllp_pllc_clk32_clkm[] = { - "pll_p", - "pll_c", - "clk_32k", - "clk_m", -}; - -static const char *mux_pllp_pllc_clkm_clk32[] = { - "pll_p", - "pll_c", - "clk_m", - "clk_32k", -}; - -static const char *mux_pllp_pllc_pllm[] = { - "pll_p", - "pll_c", - "pll_m", -}; - -static const char *mux_clk_m[] = { - "clk_m", -}; - -static const char *mux_pllp_out3[] = { - "pll_p_out3", -}; - -static const char *mux_plld_out0[] = { - "pll_d_out0", -}; - -static const char *mux_plld_out0_plld2_out0[] = { - "pll_d_out0", - "pll_d2_out0", -}; - -static const char *mux_clk_32k[] = { - "clk_32k", -}; - -static const char *mux_plla_clk32_pllp_clkm_plle[] = { - "pll_a_out0", - "clk_32k", - "pll_p", - "clk_m", - "pll_e", -}; - -static const char *mux_cclk_g[] = { - "clk_m", - "pll_c", - "clk_32k", - "pll_m", - "pll_p", - "pll_p_out4", - "pll_p_out3", - "dummy", - "pll_x", -}; - -static struct clk *mux_pllm_pllc_pllp_plla_p[] = { - &tegra_pll_m, - &tegra_pll_c, - &tegra_pll_p, - &tegra_pll_a_out0, -}; - -static struct clk *mux_pllp_pllc_pllm_clkm_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_pll_m, - &tegra_clk_m, -}; - -static struct clk *mux_pllp_clkm_p[] = { - &tegra_pll_p, - NULL, - NULL, - &tegra_clk_m, -}; - -static struct clk *mux_pllp_plld_pllc_clkm_p[] = { - &tegra_pll_p, - &tegra_pll_d_out0, - &tegra_pll_c, - &tegra_clk_m, -}; - -static struct clk *mux_pllp_pllm_plld_plla_pllc_plld2_clkm_p[] = { - &tegra_pll_p, - &tegra_pll_m, - &tegra_pll_d_out0, - &tegra_pll_a_out0, - &tegra_pll_c, - &tegra_pll_d2_out0, - &tegra_clk_m, -}; - -static struct clk *mux_plla_pllc_pllp_clkm_p[] = { - &tegra_pll_a_out0, - NULL, - &tegra_pll_p, - &tegra_clk_m, -}; - -static struct clk *mux_pllp_pllc_clk32_clkm_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_clk_32k, - &tegra_clk_m, -}; - -static struct clk *mux_pllp_pllc_clkm_clk32_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_clk_m, - &tegra_clk_32k, -}; - -static struct clk *mux_pllp_pllc_pllm_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_pll_m, -}; - -static struct clk *mux_clk_m_p[] = { - &tegra_clk_m, -}; - -static struct clk *mux_pllp_out3_p[] = { - &tegra_pll_p_out3, -}; - -static struct clk *mux_plld_out0_p[] = { - &tegra_pll_d_out0, -}; - -static struct clk *mux_plld_out0_plld2_out0_p[] = { - &tegra_pll_d_out0, - &tegra_pll_d2_out0, -}; - -static struct clk *mux_clk_32k_p[] = { - &tegra_clk_32k, -}; - -static struct clk *mux_plla_clk32_pllp_clkm_plle_p[] = { - &tegra_pll_a_out0, - &tegra_clk_32k, - &tegra_pll_p, - &tegra_clk_m, - &tegra_pll_e, -}; - -static struct clk *mux_cclk_g_p[] = { - &tegra_clk_m, - &tegra_pll_c, - &tegra_clk_32k, - &tegra_pll_m, - &tegra_pll_p, - &tegra_pll_p_out4, - &tegra_pll_p_out3, - NULL, - &tegra_pll_x, -}; - -static struct clk tegra_clk_cclk_g; -static struct clk_tegra tegra_clk_cclk_g_hw = { - .hw = { - .clk = &tegra_clk_cclk_g, - }, - .flags = DIV_U71 | DIV_U71_INT, - .reg = 0x368, - .max_rate = 1700000000, -}; -static struct clk tegra_clk_cclk_g = { - .name = "cclk_g", - .ops = &tegra30_super_ops, - .hw = &tegra_clk_cclk_g_hw.hw, - .parent_names = mux_cclk_g, - .parents = mux_cclk_g_p, - .num_parents = ARRAY_SIZE(mux_cclk_g), -}; - -static const char *mux_twd[] = { - "cclk_g", -}; - -static struct clk *mux_twd_p[] = { - &tegra_clk_cclk_g, -}; - -static struct clk tegra30_clk_twd; -static struct clk_tegra tegra30_clk_twd_hw = { - .hw = { - .clk = &tegra30_clk_twd, - }, - .max_rate = 1400000000, - .mul = 1, - .div = 2, -}; - -static struct clk tegra30_clk_twd = { - .name = "twd", - .ops = &tegra30_twd_ops, - .hw = &tegra30_clk_twd_hw.hw, - .parent = &tegra_clk_cclk_g, - .parent_names = mux_twd, - .parents = mux_twd_p, - .num_parents = ARRAY_SIZE(mux_twd), -}; - -#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, \ - _max, _inputs, _flags) \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .lookup = { \ - .dev_id = _dev, \ - .con_id = _con, \ - }, \ - .reg = _reg, \ - .flags = _flags, \ - .max_rate = _max, \ - .u.periph = { \ - .clk_num = _clk_num, \ - }, \ - .reset = &tegra30_periph_clk_reset, \ - }; \ - static struct clk tegra_##_name = { \ - .name = #_name, \ - .ops = &tegra30_periph_clk_ops, \ - .hw = &tegra_##_name##_hw.hw, \ - .parent_names = _inputs, \ - .parents = _inputs##_p, \ - .num_parents = ARRAY_SIZE(_inputs), \ - }; - -PERIPH_CLK(apbdma, "tegra-apbdma", NULL, 34, 0, 26000000, mux_clk_m, 0); -PERIPH_CLK(rtc, "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB); -PERIPH_CLK(kbc, "tegra-kbc", NULL, 36, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB); -PERIPH_CLK(timer, "timer", NULL, 5, 0, 26000000, mux_clk_m, 0); -PERIPH_CLK(kfuse, "kfuse-tegra", NULL, 40, 0, 26000000, mux_clk_m, 0); -PERIPH_CLK(fuse, "fuse-tegra", "fuse", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB); -PERIPH_CLK(fuse_burn, "fuse-tegra", "fuse_burn", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB); -PERIPH_CLK(apbif, "tegra30-ahub", "apbif", 107, 0, 26000000, mux_clk_m, 0); -PERIPH_CLK(i2s0, "tegra30-i2s.0", NULL, 30, 0x1d8, 26000000, mux_pllaout0_audio0_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(i2s1, "tegra30-i2s.1", NULL, 11, 0x100, 26000000, mux_pllaout0_audio1_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(i2s2, "tegra30-i2s.2", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(i2s3, "tegra30-i2s.3", NULL, 101, 0x3bc, 26000000, mux_pllaout0_audio3_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(i2s4, "tegra30-i2s.4", NULL, 102, 0x3c0, 26000000, mux_pllaout0_audio4_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(spdif_out, "tegra30-spdif", "spdif_out", 10, 0x108, 100000000, mux_pllaout0_audio5_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(spdif_in, "tegra30-spdif", "spdif_in", 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(pwm, "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_clk32_clkm, MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(d_audio, "tegra30-ahub", "d_audio", 106, 0x3d0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(dam0, "tegra30-dam.0", NULL, 108, 0x3d8, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(dam1, "tegra30-dam.1", NULL, 109, 0x3dc, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(dam2, "tegra30-dam.2", NULL, 110, 0x3e0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(hda, "tegra30-hda", "hda", 125, 0x428, 108000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(hda2codec_2x, "tegra30-hda", "hda2codec", 111, 0x3e4, 48000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(hda2hdmi, "tegra30-hda", "hda2hdmi", 128, 0, 48000000, mux_clk_m, 0); -PERIPH_CLK(sbc1, "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sbc2, "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sbc3, "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sbc4, "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sbc5, "spi_tegra.4", NULL, 104, 0x3c8, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sbc6, "spi_tegra.5", NULL, 105, 0x3cc, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sata_oob, "tegra_sata_oob", NULL, 123, 0x420, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sata, "tegra_sata", NULL, 124, 0x424, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sata_cold, "tegra_sata_cold", NULL, 129, 0, 48000000, mux_clk_m, 0); -PERIPH_CLK(ndflash, "tegra_nand", NULL, 13, 0x160, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(ndspeed, "tegra_nand_speed", NULL, 80, 0x3f8, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(vfir, "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sdmmc1, "sdhci-tegra.0", NULL, 14, 0x150, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(sdmmc2, "sdhci-tegra.1", NULL, 9, 0x154, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(sdmmc3, "sdhci-tegra.2", NULL, 69, 0x1bc, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(sdmmc4, "sdhci-tegra.3", NULL, 15, 0x164, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(vcp, "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(bsea, "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(bsev, "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(vde, "vde", NULL, 61, 0x1c8, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT); -PERIPH_CLK(csite, "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* max rate ??? */ -PERIPH_CLK(la, "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(owr, "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(nor, "nor", NULL, 42, 0x1d0, 127000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(mipi, "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); /* scales with voltage */ -PERIPH_CLK(i2c1, "tegra-i2c.0", "div-clk", 12, 0x124, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(i2c2, "tegra-i2c.1", "div-clk", 54, 0x198, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(i2c3, "tegra-i2c.2", "div-clk", 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(i2c4, "tegra-i2c.3", "div-clk", 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(i2c5, "tegra-i2c.4", "div-clk", 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(uarta, "tegra-uart.0", NULL, 6, 0x178, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); -PERIPH_CLK(uartb, "tegra-uart.1", NULL, 7, 0x17c, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); -PERIPH_CLK(uartc, "tegra-uart.2", NULL, 55, 0x1a0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); -PERIPH_CLK(uartd, "tegra-uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); -PERIPH_CLK(uarte, "tegra-uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); -PERIPH_CLK(vi, "tegra_camera", "vi", 20, 0x148, 425000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT); -PERIPH_CLK(3d, "3d", NULL, 24, 0x158, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET); -PERIPH_CLK(3d2, "3d2", NULL, 98, 0x3b0, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET); -PERIPH_CLK(2d, "2d", NULL, 21, 0x15c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE); -PERIPH_CLK(vi_sensor, "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET); -PERIPH_CLK(epp, "epp", NULL, 19, 0x16c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT); -PERIPH_CLK(mpe, "mpe", NULL, 60, 0x170, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT); -PERIPH_CLK(host1x, "host1x", NULL, 28, 0x180, 260000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT); -PERIPH_CLK(cve, "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(tvo, "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(dtv, "dtv", NULL, 79, 0x1dc, 250000000, mux_clk_m, 0); -PERIPH_CLK(hdmi, "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8 | DIV_U71); -PERIPH_CLK(tvdac, "tvdac", NULL, 53, 0x194, 220000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(disp1, "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8); -PERIPH_CLK(disp2, "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8); -PERIPH_CLK(usbd, "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0); /* requires min voltage */ -PERIPH_CLK(usb2, "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0); /* requires min voltage */ -PERIPH_CLK(usb3, "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0); /* requires min voltage */ -PERIPH_CLK(dsia, "tegradc.0", "dsia", 48, 0, 500000000, mux_plld_out0, 0); -PERIPH_CLK(csi, "tegra_camera", "csi", 52, 0, 102000000, mux_pllp_out3, 0); -PERIPH_CLK(isp, "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0); /* same frequency as VI */ -PERIPH_CLK(csus, "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET); -PERIPH_CLK(tsensor, "tegra-tsensor", NULL, 100, 0x3b8, 216000000, mux_pllp_pllc_clkm_clk32, MUX | DIV_U71); -PERIPH_CLK(actmon, "actmon", NULL, 119, 0x3e8, 216000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71); -PERIPH_CLK(extern1, "extern1", NULL, 120, 0x3ec, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71); -PERIPH_CLK(extern2, "extern2", NULL, 121, 0x3f0, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71); -PERIPH_CLK(extern3, "extern3", NULL, 122, 0x3f4, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71); -PERIPH_CLK(i2cslow, "i2cslow", NULL, 81, 0x3fc, 26000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(pcie, "tegra-pcie", "pcie", 70, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(afi, "tegra-pcie", "afi", 72, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(se, "se", NULL, 127, 0x42c, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT); - -static struct clk tegra_dsib; -static struct clk_tegra tegra_dsib_hw = { - .hw = { - .clk = &tegra_dsib, - }, - .lookup = { - .dev_id = "tegradc.1", - .con_id = "dsib", - }, - .reg = 0xd0, - .flags = MUX | PLLD, - .max_rate = 500000000, - .u.periph = { - .clk_num = 82, - }, - .reset = &tegra30_periph_clk_reset, -}; -static struct clk tegra_dsib = { - .name = "dsib", - .ops = &tegra30_dsib_clk_ops, - .hw = &tegra_dsib_hw.hw, - .parent_names = mux_plld_out0_plld2_out0, - .parents = mux_plld_out0_plld2_out0_p, - .num_parents = ARRAY_SIZE(mux_plld_out0_plld2_out0), -}; - -static struct clk *tegra_list_clks[] = { - &tegra_apbdma, - &tegra_rtc, - &tegra_kbc, - &tegra_timer, - &tegra_kfuse, - &tegra_fuse, - &tegra_fuse_burn, - &tegra_apbif, - &tegra_i2s0, - &tegra_i2s1, - &tegra_i2s2, - &tegra_i2s3, - &tegra_i2s4, - &tegra_spdif_out, - &tegra_spdif_in, - &tegra_pwm, - &tegra_d_audio, - &tegra_dam0, - &tegra_dam1, - &tegra_dam2, - &tegra_hda, - &tegra_hda2codec_2x, - &tegra_hda2hdmi, - &tegra_sbc1, - &tegra_sbc2, - &tegra_sbc3, - &tegra_sbc4, - &tegra_sbc5, - &tegra_sbc6, - &tegra_sata_oob, - &tegra_sata, - &tegra_sata_cold, - &tegra_ndflash, - &tegra_ndspeed, - &tegra_vfir, - &tegra_sdmmc1, - &tegra_sdmmc2, - &tegra_sdmmc3, - &tegra_sdmmc4, - &tegra_vcp, - &tegra_bsea, - &tegra_bsev, - &tegra_vde, - &tegra_csite, - &tegra_la, - &tegra_owr, - &tegra_nor, - &tegra_mipi, - &tegra_i2c1, - &tegra_i2c2, - &tegra_i2c3, - &tegra_i2c4, - &tegra_i2c5, - &tegra_uarta, - &tegra_uartb, - &tegra_uartc, - &tegra_uartd, - &tegra_uarte, - &tegra_vi, - &tegra_3d, - &tegra_3d2, - &tegra_2d, - &tegra_vi_sensor, - &tegra_epp, - &tegra_mpe, - &tegra_host1x, - &tegra_cve, - &tegra_tvo, - &tegra_dtv, - &tegra_hdmi, - &tegra_tvdac, - &tegra_disp1, - &tegra_disp2, - &tegra_usbd, - &tegra_usb2, - &tegra_usb3, - &tegra_dsia, - &tegra_dsib, - &tegra_csi, - &tegra_isp, - &tegra_csus, - &tegra_tsensor, - &tegra_actmon, - &tegra_extern1, - &tegra_extern2, - &tegra_extern3, - &tegra_i2cslow, - &tegra_pcie, - &tegra_afi, - &tegra_se, -}; - -#define CLK_DUPLICATE(_name, _dev, _con) \ - { \ - .name = _name, \ - .lookup = { \ - .dev_id = _dev, \ - .con_id = _con, \ - }, \ - } - -/* Some clocks may be used by different drivers depending on the board - * configuration. List those here to register them twice in the clock lookup - * table under two names. - */ -static struct clk_duplicate tegra_clk_duplicates[] = { - CLK_DUPLICATE("uarta", "serial8250.0", NULL), - CLK_DUPLICATE("uartb", "serial8250.1", NULL), - CLK_DUPLICATE("uartc", "serial8250.2", NULL), - CLK_DUPLICATE("uartd", "serial8250.3", NULL), - CLK_DUPLICATE("uarte", "serial8250.4", NULL), - CLK_DUPLICATE("usbd", "utmip-pad", NULL), - CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL), - CLK_DUPLICATE("usbd", "tegra-otg", NULL), - CLK_DUPLICATE("dsib", "tegradc.0", "dsib"), - CLK_DUPLICATE("dsia", "tegradc.1", "dsia"), - CLK_DUPLICATE("bsev", "tegra-avp", "bsev"), - CLK_DUPLICATE("bsev", "nvavp", "bsev"), - CLK_DUPLICATE("vde", "tegra-aes", "vde"), - CLK_DUPLICATE("bsea", "tegra-aes", "bsea"), - CLK_DUPLICATE("bsea", "nvavp", "bsea"), - CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL), - CLK_DUPLICATE("cml0", "tegra_pcie", "cml"), - CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"), - CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL), - CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL), - CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL), - CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL), - CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL), - CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL), - CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL), - CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL), - CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL), - CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL), - CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL), - CLK_DUPLICATE("twd", "smp_twd", NULL), - CLK_DUPLICATE("vcp", "nvavp", "vcp"), - CLK_DUPLICATE("i2s0", NULL, "i2s0"), - CLK_DUPLICATE("i2s1", NULL, "i2s1"), - CLK_DUPLICATE("i2s2", NULL, "i2s2"), - CLK_DUPLICATE("i2s3", NULL, "i2s3"), - CLK_DUPLICATE("i2s4", NULL, "i2s4"), - CLK_DUPLICATE("dam0", NULL, "dam0"), - CLK_DUPLICATE("dam1", NULL, "dam1"), - CLK_DUPLICATE("dam2", NULL, "dam2"), - CLK_DUPLICATE("spdif_in", NULL, "spdif_in"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.0", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.4", "fast-clk"), - CLK_DUPLICATE("pll_p", "tegradc.0", "parent"), - CLK_DUPLICATE("pll_p", "tegradc.1", "parent"), - CLK_DUPLICATE("pll_d2_out0", "hdmi", "parent"), -}; - -static struct clk *tegra_ptr_clks[] = { - &tegra_clk_32k, - &tegra_clk_m, - &tegra_clk_m_div2, - &tegra_clk_m_div4, - &tegra_pll_ref, - &tegra_pll_m, - &tegra_pll_m_out1, - &tegra_pll_c, - &tegra_pll_c_out1, - &tegra_pll_p, - &tegra_pll_p_out1, - &tegra_pll_p_out2, - &tegra_pll_p_out3, - &tegra_pll_p_out4, - &tegra_pll_a, - &tegra_pll_a_out0, - &tegra_pll_d, - &tegra_pll_d_out0, - &tegra_pll_d2, - &tegra_pll_d2_out0, - &tegra_pll_u, - &tegra_pll_x, - &tegra_pll_x_out0, - &tegra_pll_e, - &tegra_clk_cclk_g, - &tegra_cml0, - &tegra_cml1, - &tegra_pciex, - &tegra_clk_sclk, - &tegra_hclk, - &tegra_pclk, - &tegra_clk_blink, - &tegra30_clk_twd, -}; - -static void tegra30_init_one_clock(struct clk *c) -{ - struct clk_tegra *clk = to_clk_tegra(c->hw); - __clk_init(NULL, c); - INIT_LIST_HEAD(&clk->shared_bus_list); - if (!clk->lookup.dev_id && !clk->lookup.con_id) - clk->lookup.con_id = c->name; - clk->lookup.clk = c; - clkdev_add(&clk->lookup); - tegra_clk_add(c); -} - -void __init tegra30_init_clocks(void) -{ - int i; - struct clk *c; - - for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++) - tegra30_init_one_clock(tegra_ptr_clks[i]); - - for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++) - tegra30_init_one_clock(tegra_list_clks[i]); - - for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) { - c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name); - if (!c) { - pr_err("%s: Unknown duplicate clock %s\n", __func__, - tegra_clk_duplicates[i].name); - continue; - } - - tegra_clk_duplicates[i].lookup.clk = c; - clkdev_add(&tegra_clk_duplicates[i].lookup); - } - - for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++) - tegra30_init_one_clock(tegra_sync_source_list[i]); - for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++) - tegra30_init_one_clock(tegra_clk_audio_list[i]); - for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++) - tegra30_init_one_clock(tegra_clk_audio_2x_list[i]); - - for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) - tegra30_init_one_clock(tegra_clk_out_list[i]); - - tegra30_cpu_car_ops_init(); -} diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index a7e5a3999099..404d6f940872 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -120,8 +120,6 @@ static inline void tegra_cpu_clock_resume(void) } #endif -void tegra20_cpu_car_ops_init(void); -void tegra30_cpu_car_ops_init(void); void tegra_periph_reset_deassert(struct clk *c); void tegra_periph_reset_assert(struct clk *c); void tegra_clocks_init(void); From 3cb919022a7ab7628fcd69c28d475d2dbb1cb150 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:20 +0530 Subject: [PATCH 22/31] spi: tegra: do not use clock name to get clock Since Tegra spi devices do not have multiple clocks, no need to use clock name to get the clock. Signed-off-by: Prashant Gaikwad Acked-by: Grant Likely Signed-off-by: Stephen Warren --- drivers/spi/spi-tegra20-sflash.c | 2 +- drivers/spi/spi-tegra20-slink.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 02feaa51a0fa..e5dce91b74ca 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -525,7 +525,7 @@ static int tegra_sflash_probe(struct platform_device *pdev) goto exit_free_master; } - tsd->clk = devm_clk_get(&pdev->dev, "spi"); + tsd->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(tsd->clk)) { dev_err(&pdev->dev, "can not get clock\n"); ret = PTR_ERR(tsd->clk); diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index fa208a5cc612..e255e7a35678 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1191,7 +1191,7 @@ static int tegra_slink_probe(struct platform_device *pdev) goto exit_free_master; } - tspi->clk = devm_clk_get(&pdev->dev, "slink"); + tspi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(tspi->clk)) { dev_err(&pdev->dev, "can not get clock\n"); ret = PTR_ERR(tspi->clk); From 8d8b43dae3b714582cbdb99d88847cc1757952ee Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:21 +0530 Subject: [PATCH 23/31] ARM: tegra: add clock properties to Tegra20 DT Add clock information to device nodes. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra20.dtsi | 44 ++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 5b104f1d5003..d665a67d4358 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -9,6 +9,7 @@ host1x { reg = <0x50000000 0x00024000>; interrupts = <0 65 0x04 /* mpcore syncpt */ 0 67 0x04>; /* mpcore general */ + clocks = <&tegra_car 28>; #address-cells = <1>; #size-cells = <1>; @@ -19,41 +20,49 @@ mpe { compatible = "nvidia,tegra20-mpe"; reg = <0x54040000 0x00040000>; interrupts = <0 68 0x04>; + clocks = <&tegra_car 60>; }; vi { compatible = "nvidia,tegra20-vi"; reg = <0x54080000 0x00040000>; interrupts = <0 69 0x04>; + clocks = <&tegra_car 100>; }; epp { compatible = "nvidia,tegra20-epp"; reg = <0x540c0000 0x00040000>; interrupts = <0 70 0x04>; + clocks = <&tegra_car 19>; }; isp { compatible = "nvidia,tegra20-isp"; reg = <0x54100000 0x00040000>; interrupts = <0 71 0x04>; + clocks = <&tegra_car 23>; }; gr2d { compatible = "nvidia,tegra20-gr2d"; reg = <0x54140000 0x00040000>; interrupts = <0 72 0x04>; + clocks = <&tegra_car 21>; }; gr3d { compatible = "nvidia,tegra20-gr3d"; reg = <0x54180000 0x00040000>; + clocks = <&tegra_car 24>; }; dc@54200000 { compatible = "nvidia,tegra20-dc"; reg = <0x54200000 0x00040000>; interrupts = <0 73 0x04>; + clocks = <&tegra_car 27>, <&tegra_car 121>; + clock-names = "disp1", "parent"; rgb { status = "disabled"; @@ -64,6 +73,8 @@ dc@54240000 { compatible = "nvidia,tegra20-dc"; reg = <0x54240000 0x00040000>; interrupts = <0 74 0x04>; + clocks = <&tegra_car 26>, <&tegra_car 121>; + clock-names = "disp2", "parent"; rgb { status = "disabled"; @@ -74,6 +85,8 @@ hdmi { compatible = "nvidia,tegra20-hdmi"; reg = <0x54280000 0x00040000>; interrupts = <0 75 0x04>; + clocks = <&tegra_car 51>, <&tegra_car 117>; + clock-names = "hdmi", "parent"; status = "disabled"; }; @@ -81,12 +94,14 @@ tvo { compatible = "nvidia,tegra20-tvo"; reg = <0x542c0000 0x00040000>; interrupts = <0 76 0x04>; + clocks = <&tegra_car 102>; status = "disabled"; }; dsi { compatible = "nvidia,tegra20-dsi"; reg = <0x54300000 0x00040000>; + clocks = <&tegra_car 48>; status = "disabled"; }; }; @@ -148,6 +163,7 @@ apbdma: dma { 0 117 0x04 0 118 0x04 0 119 0x04>; + clocks = <&tegra_car 34>; }; ahb { @@ -189,6 +205,7 @@ tegra_i2s1: i2s@70002800 { reg = <0x70002800 0x200>; interrupts = <0 13 0x04>; nvidia,dma-request-selector = <&apbdma 2>; + clocks = <&tegra_car 11>; status = "disabled"; }; @@ -197,6 +214,7 @@ tegra_i2s2: i2s@70002a00 { reg = <0x70002a00 0x200>; interrupts = <0 3 0x04>; nvidia,dma-request-selector = <&apbdma 1>; + clocks = <&tegra_car 18>; status = "disabled"; }; @@ -205,6 +223,7 @@ serial@70006000 { reg = <0x70006000 0x40>; reg-shift = <2>; interrupts = <0 36 0x04>; + clocks = <&tegra_car 6>; status = "disabled"; }; @@ -213,6 +232,7 @@ serial@70006040 { reg = <0x70006040 0x40>; reg-shift = <2>; interrupts = <0 37 0x04>; + clocks = <&tegra_car 96>; status = "disabled"; }; @@ -221,6 +241,7 @@ serial@70006200 { reg = <0x70006200 0x100>; reg-shift = <2>; interrupts = <0 46 0x04>; + clocks = <&tegra_car 55>; status = "disabled"; }; @@ -229,6 +250,7 @@ serial@70006300 { reg = <0x70006300 0x100>; reg-shift = <2>; interrupts = <0 90 0x04>; + clocks = <&tegra_car 65>; status = "disabled"; }; @@ -237,6 +259,7 @@ serial@70006400 { reg = <0x70006400 0x100>; reg-shift = <2>; interrupts = <0 91 0x04>; + clocks = <&tegra_car 66>; status = "disabled"; }; @@ -244,6 +267,7 @@ pwm: pwm { compatible = "nvidia,tegra20-pwm"; reg = <0x7000a000 0x100>; #pwm-cells = <2>; + clocks = <&tegra_car 17>; }; rtc { @@ -258,6 +282,8 @@ i2c@7000c000 { interrupts = <0 38 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 12>, <&tegra_car 124>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -268,6 +294,7 @@ spi@7000c380 { nvidia,dma-request-selector = <&apbdma 11>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 43>; status = "disabled"; }; @@ -277,6 +304,8 @@ i2c@7000c400 { interrupts = <0 84 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 54>, <&tegra_car 124>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -286,6 +315,8 @@ i2c@7000c500 { interrupts = <0 92 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 67>, <&tegra_car 124>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -295,6 +326,8 @@ i2c@7000d000 { interrupts = <0 53 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 47>, <&tegra_car 124>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -305,6 +338,7 @@ spi@7000d400 { nvidia,dma-request-selector = <&apbdma 15>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 41>; status = "disabled"; }; @@ -315,6 +349,7 @@ spi@7000d600 { nvidia,dma-request-selector = <&apbdma 16>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 44>; status = "disabled"; }; @@ -325,6 +360,7 @@ spi@7000d800 { nvidia,dma-request-selector = <&apbdma 17>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 46>; status = "disabled"; }; @@ -335,6 +371,7 @@ spi@7000da00 { nvidia,dma-request-selector = <&apbdma 18>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 68>; status = "disabled"; }; @@ -369,6 +406,7 @@ usb@c5000000 { interrupts = <0 20 0x04>; phy_type = "utmi"; nvidia,has-legacy-mode; + clocks = <&tegra_car 22>; status = "disabled"; }; @@ -377,6 +415,7 @@ usb@c5004000 { reg = <0xc5004000 0x4000>; interrupts = <0 21 0x04>; phy_type = "ulpi"; + clocks = <&tegra_car 58>; status = "disabled"; }; @@ -385,6 +424,7 @@ usb@c5008000 { reg = <0xc5008000 0x4000>; interrupts = <0 97 0x04>; phy_type = "utmi"; + clocks = <&tegra_car 59>; status = "disabled"; }; @@ -392,6 +432,7 @@ sdhci@c8000000 { compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000000 0x200>; interrupts = <0 14 0x04>; + clocks = <&tegra_car 14>; status = "disabled"; }; @@ -399,6 +440,7 @@ sdhci@c8000200 { compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000200 0x200>; interrupts = <0 15 0x04>; + clocks = <&tegra_car 9>; status = "disabled"; }; @@ -406,6 +448,7 @@ sdhci@c8000400 { compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000400 0x200>; interrupts = <0 19 0x04>; + clocks = <&tegra_car 69>; status = "disabled"; }; @@ -413,6 +456,7 @@ sdhci@c8000600 { compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000600 0x200>; interrupts = <0 31 0x04>; + clocks = <&tegra_car 15>; status = "disabled"; }; From 1cbc733d1e6626efa9b20231668fa2523f3eafeb Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:22 +0530 Subject: [PATCH 24/31] ARM: tegra: add clock properties to Tegra30 DT Add clock information to device nodes. Signed-off-by: Prashant Gaikwad [swarren: added second clock to 3d node] Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra30.dtsi | 56 +++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 6765646c2248..b1483d925878 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -9,6 +9,7 @@ host1x { reg = <0x50000000 0x00024000>; interrupts = <0 65 0x04 /* mpcore syncpt */ 0 67 0x04>; /* mpcore general */ + clocks = <&tegra_car 28>; #address-cells = <1>; #size-cells = <1>; @@ -19,41 +20,50 @@ mpe { compatible = "nvidia,tegra30-mpe"; reg = <0x54040000 0x00040000>; interrupts = <0 68 0x04>; + clocks = <&tegra_car 60>; }; vi { compatible = "nvidia,tegra30-vi"; reg = <0x54080000 0x00040000>; interrupts = <0 69 0x04>; + clocks = <&tegra_car 164>; }; epp { compatible = "nvidia,tegra30-epp"; reg = <0x540c0000 0x00040000>; interrupts = <0 70 0x04>; + clocks = <&tegra_car 19>; }; isp { compatible = "nvidia,tegra30-isp"; reg = <0x54100000 0x00040000>; interrupts = <0 71 0x04>; + clocks = <&tegra_car 23>; }; gr2d { compatible = "nvidia,tegra30-gr2d"; reg = <0x54140000 0x00040000>; interrupts = <0 72 0x04>; + clocks = <&tegra_car 21>; }; gr3d { compatible = "nvidia,tegra30-gr3d"; reg = <0x54180000 0x00040000>; + clocks = <&tegra_car 24 &tegra_car 98>; + clock-names = "3d", "3d2"; }; dc@54200000 { compatible = "nvidia,tegra30-dc"; reg = <0x54200000 0x00040000>; interrupts = <0 73 0x04>; + clocks = <&tegra_car 27>, <&tegra_car 179>; + clock-names = "disp1", "parent"; rgb { status = "disabled"; @@ -64,6 +74,8 @@ dc@54240000 { compatible = "nvidia,tegra30-dc"; reg = <0x54240000 0x00040000>; interrupts = <0 74 0x04>; + clocks = <&tegra_car 26>, <&tegra_car 179>; + clock-names = "disp2", "parent"; rgb { status = "disabled"; @@ -74,6 +86,8 @@ hdmi { compatible = "nvidia,tegra30-hdmi"; reg = <0x54280000 0x00040000>; interrupts = <0 75 0x04>; + clocks = <&tegra_car 51>, <&tegra_car 189>; + clock-names = "hdmi", "parent"; status = "disabled"; }; @@ -81,12 +95,14 @@ tvo { compatible = "nvidia,tegra30-tvo"; reg = <0x542c0000 0x00040000>; interrupts = <0 76 0x04>; + clocks = <&tegra_car 169>; status = "disabled"; }; dsi { compatible = "nvidia,tegra30-dsi"; reg = <0x54300000 0x00040000>; + clocks = <&tegra_car 48>; status = "disabled"; }; }; @@ -166,6 +182,7 @@ apbdma: dma { 0 141 0x04 0 142 0x04 0 143 0x04>; + clocks = <&tegra_car 34>; }; ahb: ahb { @@ -201,6 +218,7 @@ serial@70006000 { reg = <0x70006000 0x40>; reg-shift = <2>; interrupts = <0 36 0x04>; + clocks = <&tegra_car 6>; status = "disabled"; }; @@ -209,6 +227,7 @@ serial@70006040 { reg = <0x70006040 0x40>; reg-shift = <2>; interrupts = <0 37 0x04>; + clocks = <&tegra_car 160>; status = "disabled"; }; @@ -217,6 +236,7 @@ serial@70006200 { reg = <0x70006200 0x100>; reg-shift = <2>; interrupts = <0 46 0x04>; + clocks = <&tegra_car 55>; status = "disabled"; }; @@ -225,6 +245,7 @@ serial@70006300 { reg = <0x70006300 0x100>; reg-shift = <2>; interrupts = <0 90 0x04>; + clocks = <&tegra_car 65>; status = "disabled"; }; @@ -233,6 +254,7 @@ serial@70006400 { reg = <0x70006400 0x100>; reg-shift = <2>; interrupts = <0 91 0x04>; + clocks = <&tegra_car 66>; status = "disabled"; }; @@ -240,6 +262,7 @@ pwm: pwm { compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm"; reg = <0x7000a000 0x100>; #pwm-cells = <2>; + clocks = <&tegra_car 17>; }; rtc { @@ -254,6 +277,8 @@ i2c@7000c000 { interrupts = <0 38 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 12>, <&tegra_car 182>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -263,6 +288,8 @@ i2c@7000c400 { interrupts = <0 84 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 54>, <&tegra_car 182>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -272,6 +299,8 @@ i2c@7000c500 { interrupts = <0 92 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 67>, <&tegra_car 182>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -281,6 +310,8 @@ i2c@7000c700 { interrupts = <0 120 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 103>, <&tegra_car 182>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -290,6 +321,8 @@ i2c@7000d000 { interrupts = <0 53 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 47>, <&tegra_car 182>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -300,6 +333,7 @@ spi@7000d400 { nvidia,dma-request-selector = <&apbdma 15>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 41>; status = "disabled"; }; @@ -310,6 +344,7 @@ spi@7000d600 { nvidia,dma-request-selector = <&apbdma 16>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 44>; status = "disabled"; }; @@ -320,6 +355,7 @@ spi@7000d800 { nvidia,dma-request-selector = <&apbdma 17>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 46>; status = "disabled"; }; @@ -330,6 +366,7 @@ spi@7000da00 { nvidia,dma-request-selector = <&apbdma 18>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 68>; status = "disabled"; }; @@ -340,6 +377,7 @@ spi@7000dc00 { nvidia,dma-request-selector = <&apbdma 27>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 104>; status = "disabled"; }; @@ -350,6 +388,7 @@ spi@7000de00 { nvidia,dma-request-selector = <&apbdma 28>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 105>; status = "disabled"; }; @@ -383,7 +422,13 @@ ahub { 0x70080200 0x100>; interrupts = <0 103 0x04>; nvidia,dma-request-selector = <&apbdma 1>; - + clocks = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>, + <&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>, + <&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>, + <&tegra_car 110>, <&tegra_car 162>; + clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", + "i2s3", "i2s4", "dam0", "dam1", "dam2", + "spdif_in"; ranges; #address-cells = <1>; #size-cells = <1>; @@ -392,6 +437,7 @@ tegra_i2s0: i2s@70080300 { compatible = "nvidia,tegra30-i2s"; reg = <0x70080300 0x100>; nvidia,ahub-cif-ids = <4 4>; + clocks = <&tegra_car 30>; status = "disabled"; }; @@ -399,6 +445,7 @@ tegra_i2s1: i2s@70080400 { compatible = "nvidia,tegra30-i2s"; reg = <0x70080400 0x100>; nvidia,ahub-cif-ids = <5 5>; + clocks = <&tegra_car 11>; status = "disabled"; }; @@ -406,6 +453,7 @@ tegra_i2s2: i2s@70080500 { compatible = "nvidia,tegra30-i2s"; reg = <0x70080500 0x100>; nvidia,ahub-cif-ids = <6 6>; + clocks = <&tegra_car 18>; status = "disabled"; }; @@ -413,6 +461,7 @@ tegra_i2s3: i2s@70080600 { compatible = "nvidia,tegra30-i2s"; reg = <0x70080600 0x100>; nvidia,ahub-cif-ids = <7 7>; + clocks = <&tegra_car 101>; status = "disabled"; }; @@ -420,6 +469,7 @@ tegra_i2s4: i2s@70080700 { compatible = "nvidia,tegra30-i2s"; reg = <0x70080700 0x100>; nvidia,ahub-cif-ids = <8 8>; + clocks = <&tegra_car 102>; status = "disabled"; }; }; @@ -428,6 +478,7 @@ sdhci@78000000 { compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000000 0x200>; interrupts = <0 14 0x04>; + clocks = <&tegra_car 14>; status = "disabled"; }; @@ -435,6 +486,7 @@ sdhci@78000200 { compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000200 0x200>; interrupts = <0 15 0x04>; + clocks = <&tegra_car 9>; status = "disabled"; }; @@ -442,6 +494,7 @@ sdhci@78000400 { compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000400 0x200>; interrupts = <0 19 0x04>; + clocks = <&tegra_car 69>; status = "disabled"; }; @@ -449,6 +502,7 @@ sdhci@78000600 { compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000600 0x200>; interrupts = <0 31 0x04>; + clocks = <&tegra_car 15>; status = "disabled"; }; From d409b3af89e93f1e08acf157126fc77188e2b89c Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:23 +0530 Subject: [PATCH 25/31] ARM: tegra: paz00: add clock information to DT Add clock i2c clock information to device node. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra20-paz00.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index 6a93d1404c76..a965fe9c7aa1 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts @@ -266,6 +266,8 @@ nvec { clock-frequency = <80000>; request-gpios = <&gpio 170 0>; /* gpio PV2 */ slave-addr = <138>; + clocks = <&tegra_car 67>, <&tegra_car 124>; + clock-names = "div-clk", "fast-clk"; }; i2c@7000d000 { From 1e54f0a21e7debcd8acb0fe39adc6f81751e1b57 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:24 +0530 Subject: [PATCH 26/31] staging: nvec: remove use of clk_get_sys As clock information is added to device tree clock can be looked up using clk_get. Remove use of clk_get_sys. Signed-off-by: Prashant Gaikwad Acked-by: Greg Kroah-Hartman Acked-by: Marc Dietrich Acked-by: Julian Andres Klode [swarren: updated TODO file to remove entry that requested this change] Signed-off-by: Stephen Warren --- drivers/staging/nvec/TODO | 4 ---- drivers/staging/nvec/nvec.c | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/staging/nvec/TODO b/drivers/staging/nvec/TODO index f950ab890e2e..e5ae42a0b44a 100644 --- a/drivers/staging/nvec/TODO +++ b/drivers/staging/nvec/TODO @@ -1,9 +1,5 @@ ToDo list (incomplete, unordered) - add compile as module support - - fix clk usage - should not be using clk_get_sys(), but clk_get(&pdev->dev, conn) - where conn is either NULL if the device only has one clock, or - the device specific name if it has multiple clocks. - move half of the nvec init stuff to i2c-tegra.c - move event handling to nvec_events - finish suspend/resume support diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index d51615b19797..9417941974f7 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -770,7 +770,7 @@ static int tegra_nvec_probe(struct platform_device *pdev) return -ENODEV; } - i2c_clk = clk_get_sys("tegra-i2c.2", "div-clk"); + i2c_clk = clk_get(&pdev->dev, "div-clk"); if (IS_ERR(i2c_clk)) { dev_err(nvec->dev, "failed to get controller clock\n"); return -ENODEV; From 79cf5918aaed097144fe7e0e455958c817c8a534 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:25 +0530 Subject: [PATCH 27/31] ASoC: tegra: remove auxdata Configlink clock information is added to device tree. Get the clocks using device node. Remove AUXDATA. Signed-off-by: Prashant Gaikwad Acked-by: Mark Brown Signed-off-by: Stephen Warren --- sound/soc/tegra/tegra30_ahub.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index bb31c4123a7b..2355630367f7 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -299,15 +299,6 @@ static const char * const configlink_clocks[] = { "spdif_in", }; -struct of_dev_auxdata ahub_auxdata[] = { - OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080300, "tegra30-i2s.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080400, "tegra30-i2s.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080500, "tegra30-i2s.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080600, "tegra30-i2s.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080700, "tegra30-i2s.4", NULL), - {} -}; - #define LAST_REG(name) \ (TEGRA30_AHUB_##name + \ (TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4) @@ -451,7 +442,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) * Ensure that here. */ for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) { - clk = clk_get_sys(NULL, configlink_clocks[i]); + clk = clk_get(&pdev->dev, configlink_clocks[i]); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Can't get clock %s\n", configlink_clocks[i]); @@ -569,8 +560,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) goto err_pm_disable; } - of_platform_populate(pdev->dev.of_node, NULL, ahub_auxdata, - &pdev->dev); + of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); return 0; From 0d4b5ba525827731cfb2682404633b38f0a0e18c Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:26 +0530 Subject: [PATCH 28/31] ARM: tegra20: remove auxdata Remove AUXDATA as clock are initialized from device node. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/board-dt-tegra20.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index 0c11b8af3af3..5049edf68f4f 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -70,36 +70,12 @@ static struct tegra_ehci_platform_data tegra_ehci3_pdata = { }; static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC2_BASE, "sdhci-tegra.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC3_BASE, "sdhci-tegra.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC4_BASE, "sdhci-tegra.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C_BASE, "tegra-i2c.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C2_BASE, "tegra-i2c.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C3_BASE, "tegra-i2c.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c-dvc", TEGRA_DVC_BASE, "tegra-i2c.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra20-i2s.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra20-i2s.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra20-das", NULL), OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0", &tegra_ehci1_pdata), OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1", &tegra_ehci2_pdata), OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2", &tegra_ehci3_pdata), - OF_DEV_AUXDATA("nvidia,tegra20-apbdma", TEGRA_APB_DMA_BASE, "tegra-apbdma", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sflash", 0x7000c380, "spi", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D400, "spi_tegra.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D600, "spi_tegra.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D800, "spi_tegra.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000DA00, "spi_tegra.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-host1x", 0x50000000, "host1x", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-dc", 0x54200000, "tegradc.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-dc", 0x54240000, "tegradc.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-hdmi", 0x54280000, "hdmi", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-dsi", 0x54300000, "dsi", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-tvo", 0x542c0000, "tvo", NULL), {} }; From 3c3a8aa9ccc47c4c2c53ab35a87db3bb93c6e450 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:27 +0530 Subject: [PATCH 29/31] ARM: tegra30: remove auxdata Remove AUXDATA as clocks are initialized from device node. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/board-dt-tegra30.c | 31 +------------------------- 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index 92f6014d22a1..5b58b6439db6 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -38,38 +38,9 @@ #include "common.h" #include "iomap.h" -static struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000000, "sdhci-tegra.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000200, "sdhci-tegra.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000400, "sdhci-tegra.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000600, "sdhci-tegra.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C000, "tegra-i2c.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C400, "tegra-i2c.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C500, "tegra-i2c.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-apbdma", 0x6000a000, "tegra-apbdma", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D400, "spi_tegra.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D600, "spi_tegra.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D800, "spi_tegra.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DA00, "spi_tegra.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DC00, "spi_tegra.4", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DE00, "spi_tegra.5", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-host1x", 0x50000000, "host1x", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-dc", 0x54200000, "tegradc.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-dc", 0x54240000, "tegradc.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-hdmi", 0x54280000, "hdmi", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-dsi", 0x54300000, "dsi", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-tvo", 0x542c0000, "tvo", NULL), - {} -}; - static void __init tegra30_dt_init(void) { - of_platform_populate(NULL, of_default_bus_match_table, - tegra30_auxdata_lookup, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } static const char *tegra30_dt_board_compat[] = { From e5dd26302275562d8bedf885e7aa91bd73bfa041 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:28 +0530 Subject: [PATCH 30/31] clk: tegra20: remove unused TEGRA_CLK_DUPLICATE()s With device tree support added for Tegra clocks look up is done from device tree, remove unused TEGRA_CLK_DUPLICATE()s. Signed-off-by: Prashant Gaikwad Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-tegra20.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 4ae8287b0f81..077d5b9ffe22 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -1189,28 +1189,11 @@ static __initdata struct tegra_clk_init_table init_table[] = { * table under two names. */ static struct tegra_clk_duplicate tegra_clk_duplicates[] = { - TEGRA_CLK_DUPLICATE(uarta, "serial8250.0", NULL), - TEGRA_CLK_DUPLICATE(uartb, "serial8250.1", NULL), - TEGRA_CLK_DUPLICATE(uartc, "serial8250.2", NULL), - TEGRA_CLK_DUPLICATE(uartd, "serial8250.3", NULL), - TEGRA_CLK_DUPLICATE(uarte, "serial8250.4", NULL), TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL), TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), - TEGRA_CLK_DUPLICATE(pll_p, "tegradc.0", "parent"), - TEGRA_CLK_DUPLICATE(pll_p, "tegradc.1", "parent"), - TEGRA_CLK_DUPLICATE(pll_d_out0, "hdmi", "parent"), - TEGRA_CLK_DUPLICATE(gr2d, "tegra_grhost", "gr2d"), - TEGRA_CLK_DUPLICATE(gr3d, "tegra_grhost", "gr3d"), - TEGRA_CLK_DUPLICATE(epp, "tegra_grhost", "epp"), - TEGRA_CLK_DUPLICATE(mpe, "tegra_grhost", "mpe"), - TEGRA_CLK_DUPLICATE(vde, "tegra-aes", "vde"), TEGRA_CLK_DUPLICATE(cclk, NULL, "cpu"), TEGRA_CLK_DUPLICATE(twd, "smp_twd", NULL), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.0", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.1", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.2", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.3", "fast-clk"), TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* Must be the last entry */ }; From ef3ffe5a0458606c488def757bb7f6dd013c2db5 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:29 +0530 Subject: [PATCH 31/31] clk: tegra30: remove unused TEGRA_CLK_DUPLICATE()s With device tree support added for Tegra clocks look up is done from device tree, remove unused TEGRA_CLK_DUPLICATE()s. Signed-off-by: Prashant Gaikwad Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-tegra30.c | 70 --------------------------------- 1 file changed, 70 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 1c2765db1199..a1638129eba4 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -1654,41 +1654,6 @@ static void __init tegra30_periph_clk_init(void) clk_register_clkdev(clk, "emc", NULL); clks[emc] = clk; - /* i2c1-fast */ - clk = clk_register_fixed_factor(NULL, "i2c1-fast", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "fast-clk", "tegra-i2c.0"); - - /* i2c2-fast */ - clk = clk_register_fixed_factor(NULL, "i2c2-fast", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "fast-clk", "tegra-i2c.1"); - - /* i2c3-fast */ - clk = clk_register_fixed_factor(NULL, "i2c3-fast", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "fast-clk", "tegra-i2c.2"); - - /* i2c4-fast */ - clk = clk_register_fixed_factor(NULL, "i2c4-fast", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "fast-clk", "tegra-i2c.3"); - - /* i2c5-fast */ - clk = clk_register_fixed_factor(NULL, "i2c5-fast", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "fast-clk", "tegra-i2c.5"); - - /* dsi1-fixed */ - clk = clk_register_fixed_factor(NULL, "dsi1-fixed", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "dsi-fixed", "tegradc.0"); - - /* dsi2-fixed */ - clk = clk_register_fixed_factor(NULL, "dsi2-fixed", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "dsi-fixed", "tegradc.1"); - for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { data = &tegra_periph_clk_list[i]; clk = tegra_clk_register_periph(data->name, data->parent_names, @@ -1948,19 +1913,9 @@ static __initdata struct tegra_clk_init_table init_table[] = { * table under two names. */ static struct tegra_clk_duplicate tegra_clk_duplicates[] = { - TEGRA_CLK_DUPLICATE(uarta, "serial8250.0", NULL), - TEGRA_CLK_DUPLICATE(uartb, "serial8250.1", NULL), - TEGRA_CLK_DUPLICATE(uartc, "serial8250.2", NULL), - TEGRA_CLK_DUPLICATE(uartd, "serial8250.3", NULL), - TEGRA_CLK_DUPLICATE(uarte, "serial8250.4", NULL), TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL), TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), - TEGRA_CLK_DUPLICATE(pll_p, "tegradc.0", "parent"), - TEGRA_CLK_DUPLICATE(pll_p, "tegradc.1", "parent"), - TEGRA_CLK_DUPLICATE(pll_d2_out0, "hdmi", "parent"), - TEGRA_CLK_DUPLICATE(dsib, "tegradc.0", "dsib"), - TEGRA_CLK_DUPLICATE(dsia, "tegradc.1", "dsia"), TEGRA_CLK_DUPLICATE(bsev, "tegra-avp", "bsev"), TEGRA_CLK_DUPLICATE(bsev, "nvavp", "bsev"), TEGRA_CLK_DUPLICATE(vde, "tegra-aes", "vde"), @@ -1969,33 +1924,8 @@ static struct tegra_clk_duplicate tegra_clk_duplicates[] = { TEGRA_CLK_DUPLICATE(cml1, "tegra_sata_cml", NULL), TEGRA_CLK_DUPLICATE(cml0, "tegra_pcie", "cml"), TEGRA_CLK_DUPLICATE(pciex, "tegra_pcie", "pciex"), - TEGRA_CLK_DUPLICATE(i2c1, "tegra-i2c-slave.0", NULL), - TEGRA_CLK_DUPLICATE(i2c2, "tegra-i2c-slave.1", NULL), - TEGRA_CLK_DUPLICATE(i2c3, "tegra-i2c-slave.2", NULL), - TEGRA_CLK_DUPLICATE(i2c4, "tegra-i2c-slave.3", NULL), - TEGRA_CLK_DUPLICATE(i2c5, "tegra-i2c-slave.4", NULL), - TEGRA_CLK_DUPLICATE(sbc1, "spi_slave_tegra.0", NULL), - TEGRA_CLK_DUPLICATE(sbc2, "spi_slave_tegra.1", NULL), - TEGRA_CLK_DUPLICATE(sbc3, "spi_slave_tegra.2", NULL), - TEGRA_CLK_DUPLICATE(sbc4, "spi_slave_tegra.3", NULL), - TEGRA_CLK_DUPLICATE(sbc5, "spi_slave_tegra.4", NULL), - TEGRA_CLK_DUPLICATE(sbc6, "spi_slave_tegra.5", NULL), TEGRA_CLK_DUPLICATE(twd, "smp_twd", NULL), TEGRA_CLK_DUPLICATE(vcp, "nvavp", "vcp"), - TEGRA_CLK_DUPLICATE(i2s0, NULL, "i2s0"), - TEGRA_CLK_DUPLICATE(i2s1, NULL, "i2s1"), - TEGRA_CLK_DUPLICATE(i2s2, NULL, "i2s2"), - TEGRA_CLK_DUPLICATE(i2s3, NULL, "i2s3"), - TEGRA_CLK_DUPLICATE(i2s4, NULL, "i2s4"), - TEGRA_CLK_DUPLICATE(dam0, NULL, "dam0"), - TEGRA_CLK_DUPLICATE(dam1, NULL, "dam1"), - TEGRA_CLK_DUPLICATE(dam2, NULL, "dam2"), - TEGRA_CLK_DUPLICATE(spdif_in, NULL, "spdif_in"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.0", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.1", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.2", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.3", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.4", "fast-clk"), TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* MUST be the last entry */ };