ARM: tegra: clock: Add shared bus clock type
Subsystems (3)
PATCH v2 12/21 ARM: tegra: clock: Add shared bus clock type
Some clocks may have multiple downstream users that need to request a higher clock rate. Shared bus clocks provide a unique shared_bus_user clock to each user. The frequency of the bus is set to the highest enabled shared_bus_user clock, with a minimum value set by the shared bus. Drivers can use clk_enable and clk_disable to enable or disable their requirement, and clk_set_rate to set the minimum rate.
--- arch/arm/mach-tegra/clock.h | 8 +++ arch/arm/mach-tegra/tegra2_clocks.c | 116 +++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/clock.h +8 -0
@@ -85,6 +85,7 @@ struct clk {struct clk_ops *ops;unsigned long rate;unsigned long max_rate; +unsigned long min_rate;u32 flags;const char *name;
@@ -98,6 +99,8 @@ struct clk {u32 reg;u32 reg_shift; +struct list_head shared_bus_list; + union { struct { unsigned int clk_num;
@@ -120,6 +123,11 @@ struct clk {struct clk *main;struct clk *backup; } cpu; +struct { +struct list_head node; +bool enabled; +unsigned long rate; + } shared_bus_user; } u;spinlock_t spinlock;
arch/arm/mach-tegra/tegra2_clocks.c +116 -0
134 lines not on this page · raw message
Signature · 1 line
1.7.3.1
v2 cover Tegra clock updates for 2.6.39
This patch series brings the Tegra clock subsystem closer to the proposed common struct clk design, which should make converting easier. It also fixes a few bugs and adds new features including memory bus scaling, disabling clocks left on by the bootloader, and shared clocks.
V2 fixes locking issues in shared bus clocks pointed out by Stephen Boyd.
Colin Cross (20):
ARM: tegra: clock: Don't BUG on changing an enabled PLL
ARM: tegra: clock: Drop debugging
ARM: tegra: clock: Don't use PLL lock bits
ARM: tegra: clock: Disable clocks left on by bootloader
ARM: tegra: clock: Initialize clocks that have no enable
ARM: tegra: clock: Drop CPU dvfs
ARM: tegra: clock: Rearrange static clock tables
ARM: tegra: clock: Move unshared clk struct members into union
ARM: tegra: clock: Convert global lock to a lock per clock
ARM: tegra: cpufreq: Take an extra reference to pllx
ARM: tegra: clock: Add shared bus clock type
ARM: tegra: clock: Remove unnecessary uses of #ifdef CONFIG_DEBUG_FS
ARM: tegra: clock: Refcount periph clock enables
ARM: tegra: clock: Round rate before setting rate
ARM: tegra: Add external memory controller driver
ARM: tegra: clocks: Add emc scaling
ARM: tegra: cpufreq: Adjust memory frequency with cpu frequency
ARM: tegra: clock: Add function to set SDMMC tap delay
ARM: tegra: clock: Fix clock issues in suspend
ARM: tegra: clock: Miscellaneous clock updates
Dima Zavin (1):
ARM: tegra: clock: enable clk reset for non-peripheral clocks
arch/arm/mach-tegra/Kconfig | 10 +
arch/arm/mach-tegra/Makefile | 2 +-
arch/arm/mach-tegra/clock.c | 559 +++++++-------
arch/arm/mach-tegra/clock.h | 129 ++--
arch/arm/mach-tegra/cpu-tegra.c | 25 +-
arch/arm/mach-tegra/include/mach/clk.h | 6 +-
arch/arm/mach-tegra/tegra2_clocks.c | 865 ++++++++++++++------
arch/arm/mach-tegra/tegra2_dvfs.c | 86 --
arch/arm/mach-tegra/tegra2_emc.c | 172 ++++
.../arm/mach-tegra/{tegra2_dvfs.h => tegra2_emc.h} | 13 +-
10 files changed, 1153 insertions(+), 714 deletions(-)
delete mode 100644 arch/arm/mach-tegra/tegra2_dvfs.c
create mode 100644 arch/arm/mach-tegra/tegra2_emc.c
rename arch/arm/mach-tegra/{tegra2_dvfs.h => tegra2_emc.h} (66%)A message that is not in the archive (sent off-list or not yet received): 1298154371-5641-1-git-send-email-ccross-z5hGa2qSFaRBDgjK7y7TUQ@public.gmane.org
v2 cover Tegra clock updates for 2.6.39
This patch series brings the Tegra clock subsystem closer to the proposed common struct clk design, which should make converting easier. It also fixes a few bugs and adds new features including memory bus scaling, disabling clocks left on by the bootloader, and shared clocks.
V2 fixes locking issues in shared bus clocks pointed out by Stephen Boyd.
Colin Cross (20):
ARM: tegra: clock: Don't BUG on changing an enabled PLL
ARM: tegra: clock: Drop debugging
ARM: tegra: clock: Don't use PLL lock bits
ARM: tegra: clock: Disable clocks left on by bootloader
ARM: tegra: clock: Initialize clocks that have no enable
ARM: tegra: clock: Drop CPU dvfs
ARM: tegra: clock: Rearrange static clock tables
ARM: tegra: clock: Move unshared clk struct members into union
ARM: tegra: clock: Convert global lock to a lock per clock
ARM: tegra: cpufreq: Take an extra reference to pllx
ARM: tegra: clock: Add shared bus clock type
ARM: tegra: clock: Remove unnecessary uses of #ifdef CONFIG_DEBUG_FS
ARM: tegra: clock: Refcount periph clock enables
ARM: tegra: clock: Round rate before setting rate
ARM: tegra: Add external memory controller driver
ARM: tegra: clocks: Add emc scaling
ARM: tegra: cpufreq: Adjust memory frequency with cpu frequency
ARM: tegra: clock: Add function to set SDMMC tap delay
ARM: tegra: clock: Fix clock issues in suspend
ARM: tegra: clock: Miscellaneous clock updates
Dima Zavin (1):
ARM: tegra: clock: enable clk reset for non-peripheral clocks
arch/arm/mach-tegra/Kconfig | 10 +
arch/arm/mach-tegra/Makefile | 2 +-
arch/arm/mach-tegra/clock.c | 559 +++++++-------
arch/arm/mach-tegra/clock.h | 129 ++--
arch/arm/mach-tegra/cpu-tegra.c | 25 +-
arch/arm/mach-tegra/include/mach/clk.h | 6 +-
arch/arm/mach-tegra/tegra2_clocks.c | 865 ++++++++++++++------
arch/arm/mach-tegra/tegra2_dvfs.c | 86 --
arch/arm/mach-tegra/tegra2_emc.c | 172 ++++
.../arm/mach-tegra/{tegra2_dvfs.h => tegra2_emc.h} | 13 +-
10 files changed, 1153 insertions(+), 714 deletions(-)
delete mode 100644 arch/arm/mach-tegra/tegra2_dvfs.c
create mode 100644 arch/arm/mach-tegra/tegra2_emc.c
rename arch/arm/mach-tegra/{tegra2_dvfs.h => tegra2_emc.h} (66%)--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 2/21 ARM: tegra: clock: Don't BUG on changing an enabled PLL
In reply to a message not in the archive--- arch/arm/mach-tegra/tegra2_clocks.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +0 -1
@@ -620,7 +620,6 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)const struct clk_pll_table *sel;pr_debug ("%s: %s %lu\n" , __func__, c->name, rate); -BUG_ON (c->refcnt !=0 ); input_rate = c->parent->rate;for (sel = c->pll_table; sel->input_rate !=0 ; sel++) {
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 3/21 ARM: tegra: clock: Drop debugging
In reply to a message not in the archive--- arch/arm/mach-tegra/clock.c | 19 ++----------------- 1 files changed, 2 insertions(+), 17 deletions(-)
arch/arm/mach-tegra/clock.c +2 -17
@@ -138,7 +138,6 @@ static void clk_recalculate_rate(struct clk *c)int clk_reparent (struct clk *c,struct clk *parent) { -pr_debug ("%s: %s\n" , __func__, c->name); c->parent = parent;list_del (&c->sibling);list_add_tail (&c->sibling, &parent->children);
@@ -148,9 +147,8 @@ int clk_reparent(struct clk *c, struct clk *parent)static void propagate_rate (struct clk *c) {struct clk *clkp; -pr_debug ("%s: %s\n" , __func__, c->name); +list_for_each_entry (clkp, &c->children, sibling) { -pr_debug (" %s\n" , clkp->name);clk_recalculate_rate (clkp);propagate_rate (clkp); }
@@ -160,8 +158,6 @@ void clk_init(struct clk *c) {unsigned long flags; -pr_debug ("%s: %s\n" , __func__, c->name); -spin_lock_irqsave (&clock_lock, flags);INIT_LIST_HEAD (&c->children);
@@ -183,7 +179,7 @@ void clk_init(struct clk *c)int clk_enable_locked (struct clk *c) {int ret; -pr_debug ("%s: %s\n" , __func__, c->name); +if (c->refcnt ==0 ) {if (c->parent) { ret =clk_enable_locked (c->parent);
@@ -247,7 +243,6 @@ EXPORT_SYMBOL(clk_enable);void clk_disable_locked (struct clk *c) { -pr_debug ("%s: %s\n" , __func__, c->name);if (c->refcnt ==0 ) {WARN (1 ,"Attempting to disable clock %s with refcnt 0" , c->name);return ;
@@ -298,8 +293,6 @@ int clk_set_parent_locked(struct clk *c, struct clk *parent) {int ret; -pr_debug ("%s: %s\n" , __func__, c->name); -if (!c->ops || !c->ops->set_parent)return -ENOSYS ;
@@ -359,8 +352,6 @@ int clk_set_rate_cansleep(struct clk *c, unsigned long rate)int ret =0 ;unsigned long flags; -pr_debug ("%s: %s\n" , __func__, c->name); -mutex_lock (&dvfs_lock);if (rate > c->rate)
@@ -388,8 +379,6 @@ int clk_set_rate(struct clk *c, unsigned long rate)int ret =0 ;unsigned long flags; -pr_debug ("%s: %s\n" , __func__, c->name); -if (clk_is_dvfs (c))BUG ();
@@ -408,8 +397,6 @@ unsigned long clk_get_rate(struct clk *c)spin_lock_irqsave (&clock_lock, flags); -pr_debug ("%s: %s\n" , __func__, c->name); - ret = c->rate;spin_unlock_irqrestore (&clock_lock, flags);
@@ -419,8 +406,6 @@ EXPORT_SYMBOL(clk_get_rate);long clk_round_rate (struct clk *c,unsigned long rate) { -pr_debug ("%s: %s\n" , __func__, c->name); -if (!c->ops || !c->ops->round_rate)return -ENOSYS ;
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 4/21 ARM: tegra: clock: Don't use PLL lock bits
In reply to a message not in the archiveThe PLL lock bits are not reliable, use per-PLL timeouts instead.
--- arch/arm/mach-tegra/clock.h | 2 +- arch/arm/mach-tegra/tegra2_clocks.c | 31 +++++++++---------------------- 2 files changed, 10 insertions(+), 23 deletions(-)
arch/arm/mach-tegra/clock.h +1 -1
@@ -53,7 +53,6 @@ struct dvfs_process_id_table {struct dvfs_table *table; }; -struct dvfs {struct regulator *reg;struct dvfs_table *table;
@@ -128,6 +127,7 @@ struct clk {unsigned long vco_min;unsigned long vco_max;const struct clk_pll_table *pll_table; +int pll_lock_delay;/* DIV */ u32 div;
arch/arm/mach-tegra/tegra2_clocks.c +9 -22
@@ -79,7 +79,6 @@#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)
@@ -94,7 +93,6 @@#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) ? (1<<22) : (1<<18))#define PLL_MISC_DCCON_SHIFT 20#define PLL_MISC_CPCON_SHIFT 8
@@ -546,17 +544,7 @@ static struct clk_ops tegra_blink_clk_ops = {/* PLL Functions */ static int tegra2_pll_clk_wait_for_lock (struct clk *c) { -ktime_t before; - - before =ktime_get (); - -while (!(clk_readl (c->reg +PLL_BASE ) &PLL_BASE_LOCK )) { -if (ktime_us_delta (ktime_get (), before) >5000 ) { -pr_err ("Timed out waiting for lock bit on pll %s" , - c->name); -return -1 ; - } - } +udelay (c->pll_lock_delay);return 0 ; }
@@ -594,10 +582,6 @@ static int tegra2_pll_clk_enable(struct clk *c) val |=PLL_BASE_ENABLE ;clk_writel (val, c->reg +PLL_BASE ); - val =clk_readl (c->reg +PLL_MISC (c)); - val |=PLL_MISC_LOCK_ENABLE (c); -clk_writel (val, c->reg +PLL_MISC (c)); -tegra2_pll_clk_wait_for_lock (c);return 0 ;
@@ -1177,6 +1161,7 @@ static struct clk tegra_pll_s = { .vco_max = 26000000, .pll_table = tegra_pll_s_table, .max_rate = 26000000, + .pll_lock_delay = 300, };static struct clk_mux_sel tegra_clk_m_sel[] = {
@@ -1213,6 +1198,7 @@ static struct clk tegra_pll_c = { .vco_max = 1400000000, .pll_table = tegra_pll_c_table, .max_rate = 600000000, + .pll_lock_delay = 300, };static struct clk tegra_pll_c_out1 = {
@@ -1251,6 +1237,7 @@ static struct clk tegra_pll_m = { .vco_max = 1200000000, .pll_table = tegra_pll_m_table, .max_rate = 800000000, + .pll_lock_delay = 300, };static struct clk tegra_pll_m_out1 = {
@@ -1289,6 +1276,7 @@ static struct clk tegra_pll_p = { .vco_max = 1400000000, .pll_table = tegra_pll_p_table, .max_rate = 432000000, + .pll_lock_delay = 300, };static struct clk tegra_pll_p_out1 = {
@@ -1354,6 +1342,7 @@ static struct clk tegra_pll_a = { .vco_max = 1400000000, .pll_table = tegra_pll_a_table, .max_rate = 56448000, + .pll_lock_delay = 300, };static struct clk tegra_pll_a_out0 = {
@@ -1399,6 +1388,7 @@ static struct clk tegra_pll_d = { .vco_max = 1000000000, .pll_table = tegra_pll_d_table, .max_rate = 1000000000, + .pll_lock_delay = 1000, };static struct clk tegra_pll_d_out0 = {
@@ -1431,6 +1421,7 @@ static struct clk tegra_pll_u = { .vco_max = 960000000, .pll_table = tegra_pll_u_table, .max_rate = 480000000, + .pll_lock_delay = 1000, };static struct clk_pll_table tegra_pll_x_table[] = {
@@ -1493,6 +1484,7 @@ static struct clk tegra_pll_x = { .vco_max = 1200000000, .pll_table = tegra_pll_x_table, .max_rate = 1000000000, + .pll_lock_delay = 300, };static struct clk_pll_table tegra_pll_e_table[] = {
@@ -1966,7 +1958,6 @@ static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +void tegra_clk_suspend (void ) {unsigned long off, i; -u32 pllx_misc;u32 *ctx = clk_rst_suspend; *ctx++ =clk_readl (OSC_CTRL ) &OSC_CTRL_MASK ;
@@ -2007,10 +1998,6 @@ void tegra_clk_suspend(void) *ctx++ =clk_readl (MISC_CLK_ENB ); *ctx++ =clk_readl (CLK_MASK_ARM ); - - pllx_misc =clk_readl (tegra_pll_x.reg +PLL_MISC (&tegra_pll_x)); - pllx_misc &= ~PLL_MISC_LOCK_ENABLE (&tegra_pll_x); -clk_writel (pllx_misc, tegra_pll_x.reg +PLL_MISC (&tegra_pll_x)); }void tegra_clk_resume (void )
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 6/21 ARM: tegra: clock: Initialize clocks that have no enable
In reply to a message not in the archiveAssume that any clock that has no enable op is always on.
--- arch/arm/mach-tegra/clock.c | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/clock.c +9 -0
@@ -166,6 +166,15 @@ void clk_init(struct clk *c)if (c->ops && c->ops->init) c->ops->init (c); +if (!c->ops || !c->ops->enable) { + c->refcnt++; + c->set =1 ; +if (c->parent) + c->state = c->parent->state; +else + c->state =ON ; + } +clk_recalculate_rate (c);list_add (&c->node, &clocks);
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 7/21 ARM: tegra: clock: Drop CPU dvfs
In reply to a message not in the archiveThe existing version did not extend well to core dvfs, drop it for now until the new clk api with clk_prepare and clk_unprepare is ready and non-atomic clocks are possible.
--- arch/arm/mach-tegra/Makefile | 1 - arch/arm/mach-tegra/clock.c | 159 +------------------------------- arch/arm/mach-tegra/clock.h | 24 ----- arch/arm/mach-tegra/cpu-tegra.c | 2 +- arch/arm/mach-tegra/include/mach/clk.h | 5 - arch/arm/mach-tegra/tegra2_clocks.c | 2 - arch/arm/mach-tegra/tegra2_dvfs.c | 86 ----------------- arch/arm/mach-tegra/tegra2_dvfs.h | 20 ---- 8 files changed, 2 insertions(+), 297 deletions(-) delete mode 100644 arch/arm/mach-tegra/tegra2_dvfs.c delete mode 100644 arch/arm/mach-tegra/tegra2_dvfs.h
arch/arm/mach-tegra/Makefile +0 -1
@@ -9,7 +9,6 @@ obj-y += powergate.o obj-y += fuse.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clock.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o -obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_dvfs.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-t2-tables.o obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
arch/arm/mach-tegra/clock.c +1 -158
210 lines not on this page · raw message
arch/arm/mach-tegra/clock.h +0 -24
@@ -41,28 +41,6 @@#define ENABLE_ON_INIT (1 << 28)struct clk ; -struct regulator ; - -struct dvfs_table { -unsigned long rate; -int millivolts; -}; - -struct dvfs_process_id_table { -int process_id; -struct dvfs_table *table; -}; - -struct dvfs { -struct regulator *reg; -struct dvfs_table *table; -int max_millivolts; - -int process_id_table_length; -const char *reg_id; -bool cpu; -struct dvfs_process_id_table process_id_table[]; -};struct clk_mux_sel {struct clk *input;
@@ -141,8 +119,6 @@ struct clk {/* Virtual cpu clock */ struct clk *main;struct clk *backup; - -struct dvfs *dvfs; };
arch/arm/mach-tegra/cpu-tegra.c +1 -1
@@ -91,7 +91,7 @@ static int tegra_update_cpu_speed(unsigned long rate) freqs.old, freqs.new);#endif - ret =clk_set_rate_cansleep (cpu_clk, freqs.new *1000 ); + ret =clk_set_rate (cpu_clk, freqs.new *1000 );if (ret) {pr_err ("cpu-tegra: Failed to set cpu frequency to %d kHz\n" , freqs.new);
arch/arm/mach-tegra/include/mach/clk.h +0 -5
@@ -25,9 +25,4 @@ struct clk;void tegra_periph_reset_deassert (struct clk *c);void tegra_periph_reset_assert (struct clk *c); -int clk_enable_cansleep (struct clk *clk); -void clk_disable_cansleep (struct clk *clk); -int clk_set_rate_cansleep (struct clk *clk,unsigned long rate); -int clk_set_parent_cansleep (struct clk *clk,struct clk *parent); -#endif
arch/arm/mach-tegra/tegra2_clocks.c +0 -2
@@ -31,7 +31,6 @@#include "clock.h" #include "fuse.h" -#include "tegra2_dvfs.h" #define RST_DEVICES 0x004#define RST_DEVICES_SET 0x300
@@ -1650,7 +1649,6 @@ static struct clk tegra_clk_virtual_cpu = { .backup = &tegra_pll_p, .ops = &tegra_cpu_ops, .max_rate = 1000000000, - .dvfs = &tegra_dvfs_virtual_cpu_dvfs, };static struct clk tegra_clk_hclk = {
arch/arm/mach-tegra/tegra2_dvfs.c deleted +0 -86
86 lines not on this page · raw message
arch/arm/mach-tegra/tegra2_dvfs.h deleted +0 -20
@@ -1,20 +0,0 @@ -/* -* arch/arm/mach-tegra/tegra2_dvfs.h -* -* Copyright (C) 2010 Google, Inc. -* -* Author: -* Colin Cross <[email protected]> -* -* 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. -* -*/ - -extern struct dvfs tegra_dvfs_virtual_cpu_dvfs;
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 9/21 ARM: tegra: clock: Move unshared clk struct members into union
In reply to a message not in the archive--- arch/arm/mach-tegra/clock.h | 85 +++++++------ arch/arm/mach-tegra/tegra2_clocks.c | 234 ++++++++++++++++++++--------------- 2 files changed, 176 insertions(+), 143 deletions(-)
arch/arm/mach-tegra/clock.h +44 -41
@@ -47,7 +47,7 @@ struct clk_mux_sel {u32 value; }; -struct clk_pll_table { +struct clk_pll_freq_table {unsigned long input_rate;unsigned long output_rate;u16 n;
@@ -74,51 +74,54 @@ enum clk_state {struct clk {/* node for master clocks list */ -struct list_head node; -struct list_head children;/* list of children */ -struct list_head sibling;/* node for children */ -#ifdef CONFIG_DEBUG_FS -struct dentry *dent; -struct dentry *parent_dent; -#endif -struct clk_ops *ops; -struct clk *parent; -struct clk_lookup lookup; -unsigned long rate; -unsigned long max_rate; -u32 flags; -u32 refcnt; -const char *name; -u32 reg; -u32 reg_shift; -unsigned int clk_num; -enum clk_state state; +struct list_head node;/* node for list of all clocks */ +struct list_head children;/* list of children */ +struct list_head sibling;/* node for children */ +struct clk_lookup lookup; +#ifdef CONFIG_DEBUG_FS -bool set; +struct dentry *dent; +bool set;#endif +struct clk_ops *ops; +unsigned long rate; +unsigned long max_rate; +u32 flags; +const char *name; + +u32 refcnt; +enum clk_state state; +struct clk *parent; +u32 div; +u32 mul; -/* PLL */ -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_table *pll_table; -int pll_lock_delay; - -/* DIV */ -u32 div; -u32 mul; - -/* MUX */ const struct clk_mux_sel *inputs; -u32 sel; -u32 reg_mask; +u32 reg; +u32 reg_shift; -/* Virtual cpu clock */ -struct clk *main; -struct clk *backup; +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; + } pll; +struct { +u32 sel; +u32 reg_mask; + } mux; +struct { +struct clk *main; +struct clk *backup; + } cpu; + } u; };
arch/arm/mach-tegra/tegra2_clocks.c +132 -102
451 lines not on this page · raw message
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 11/21 ARM: tegra: cpufreq: Take an extra reference to pllx
In reply to a message not in the archiveDuring cpu frequency changes, take an extra reference to pllx so that it doesn't turn off and on while the cpu is temporarily on pllp. If the cpu is moved to pllp permanently, pllx will be turned off.
--- arch/arm/mach-tegra/cpu-tegra.c | 2 ++ arch/arm/mach-tegra/tegra2_clocks.c | 15 +++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-)
arch/arm/mach-tegra/cpu-tegra.c +2 -0
@@ -173,6 +173,8 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)if (IS_ERR (cpu_clk))return PTR_ERR (cpu_clk); +clk_enable (cpu_clk); +cpufreq_frequency_table_cpuinfo (policy, freq_table);cpufreq_frequency_table_get_attr (freq_table, policy->cpu); policy->cur =tegra_getspeed (policy->cpu);
arch/arm/mach-tegra/tegra2_clocks.c +11 -4
@@ -385,10 +385,16 @@ static void tegra2_cpu_clk_disable(struct clk *c)static int tegra2_cpu_clk_set_rate (struct clk *c,unsigned long rate) {int ret; +/* +* Take an extra reference to the main pll so it doesn't turn +* off when we move the cpu off of it +*/ +clk_enable (c->u.cpu.main); + ret =clk_set_parent (c->parent, c->u.cpu.backup);if (ret) {pr_err ("Failed to switch cpu to clock %s\n" , c->u.cpu.backup->name); -return ret; + goto out; }if (rate ==clk_get_rate (c->u.cpu.backup))
@@ -397,17 +403,18 @@ static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate) ret =clk_set_rate (c->u.cpu.main, rate);if (ret) {pr_err ("Failed to change cpu pll to %lu\n" , rate); -return ret; + goto out; } ret =clk_set_parent (c->parent, c->u.cpu.main);if (ret) {pr_err ("Failed to switch cpu to clock %s\n" , c->u.cpu.main->name); -return ret; + goto out; } out: -return 0 ; +clk_disable (c->u.cpu.main); +return ret; }static struct clk_ops tegra_cpu_ops = {
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 12/21 ARM: tegra: clock: Add shared bus clock type
In reply to a message not in the archiveSome clocks may have multiple downstream users that need to request a higher clock rate. Shared bus clocks provide a unique shared_bus_user clock to each user. The frequency of the bus is set to the highest enabled shared_bus_user clock, with a minimum value set by the shared bus. Drivers can use clk_enable and clk_disable to enable or disable their requirement, and clk_set_rate to set the minimum rate.
--- arch/arm/mach-tegra/clock.h | 8 +++ arch/arm/mach-tegra/tegra2_clocks.c | 116 +++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/clock.h +8 -0
@@ -85,6 +85,7 @@ struct clk {struct clk_ops *ops;unsigned long rate;unsigned long max_rate; +unsigned long min_rate;u32 flags;const char *name;
@@ -98,6 +99,8 @@ struct clk {u32 reg;u32 reg_shift; +struct list_head shared_bus_list; + union { struct { unsigned int clk_num;
@@ -120,6 +123,11 @@ struct clk {struct clk *main;struct clk *backup; } cpu; +struct { +struct list_head node; +bool enabled; +unsigned long rate; + } shared_bus_user; } u;spinlock_t spinlock;
arch/arm/mach-tegra/tegra2_clocks.c +116 -0
134 lines not on this page · raw message
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 13/21 ARM: tegra: clock: Remove unnecessary uses of #ifdef CONFIG_DEBUG_FS
In reply to a message not in the archive--- arch/arm/mach-tegra/clock.c | 6 ++---- arch/arm/mach-tegra/clock.h | 2 +- arch/arm/mach-tegra/tegra2_clocks.c | 4 +--- 3 files changed, 4 insertions(+), 8 deletions(-)
arch/arm/mach-tegra/clock.c +2 -4
@@ -135,7 +135,7 @@ void clk_init(struct clk *c)if (!c->ops || !c->ops->enable) { c->refcnt++; - c->set =1 ; + c->set = true;if (c->parent) c->state = c->parent->state;else
@@ -169,9 +169,7 @@ int clk_enable(struct clk *c) goto out; } c->state =ON ; -#ifdef CONFIG_DEBUG_FS - c->set =1 ; -#endif + c->set = true; } } c->refcnt++;
arch/arm/mach-tegra/clock.h +1 -1
@@ -80,8 +80,8 @@ struct clk {#ifdef CONFIG_DEBUG_FS struct dentry *dent; -bool set;#endif +bool set;struct clk_ops *ops;unsigned long rate;unsigned long max_rate;
arch/arm/mach-tegra/tegra2_clocks.c +1 -3
@@ -1218,9 +1218,7 @@ static void tegra_clk_shared_bus_init(struct clk *c) c->max_rate = c->parent->max_rate; c->u.shared_bus_user.rate = c->parent->max_rate; c->state =OFF ; -#ifdef CONFIG_DEBUG_FS - c->set =1 ; -#endif + c->set = true;spin_lock_irqsave (&c->parent->spinlock, flags);
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 14/21 ARM: tegra: clock: Refcount periph clock enables
In reply to a message not in the archiveSome peripheral clocks share enable bits. Refcount the enables so that calling clk_disable on one clock will not turn off another clock.
--- arch/arm/mach-tegra/tegra2_clocks.c | 35 +++++++++++++++++++++++++++++------ 1 files changed, 29 insertions(+), 6 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +29 -6
@@ -154,6 +154,12 @@ static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);*/ 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, (u32)reg_clk_base + (reg))#define clk_readl (reg) \
@@ -920,8 +926,19 @@ static void tegra2_periph_clk_init(struct clk *c)static int tegra2_periph_clk_enable (struct clk *c) {u32 val; +unsigned long flags; +int refcount;pr_debug ("%s on clock %s\n" , __func__, c->name); +spin_lock_irqsave (&clock_register_lock, flags); + + refcount = tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++; + +spin_unlock_irqrestore (&clock_register_lock, flags); + +if (refcount >1 ) +return 0 ; +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 ))
@@ -939,10 +956,20 @@ static int tegra2_periph_clk_enable(struct clk *c)static void tegra2_periph_clk_disable (struct clk *c) { +unsigned long flags; +pr_debug ("%s on clock %s\n" , __func__, c->name); -clk_writel (PERIPH_CLK_TO_ENB_BIT (c), -CLK_OUT_ENB_CLR +PERIPH_CLK_TO_ENB_SET_REG (c)); +spin_lock_irqsave (&clock_register_lock, flags); + +if (c->refcnt) + tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--; + +if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] ==0 ) +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); }static void tegra2_periph_clk_reset (struct clk *c,bool assert)
@@ -1976,7 +2003,6 @@ struct clk tegra_list_clks[] = {PERIPH_CLK ("timer" ,"timer" ,NULL ,5 ,0 ,26000000 , mux_clk_m,0 ),PERIPH_CLK ("i2s1" ,"i2s.0" ,NULL ,11 ,0x100 ,26000000 , mux_pllaout0_audio2x_pllp_clkm,MUX |DIV_U71 ),PERIPH_CLK ("i2s2" ,"i2s.1" ,NULL ,18 ,0x104 ,26000000 , mux_pllaout0_audio2x_pllp_clkm,MUX |DIV_U71 ), -/* FIXME: spdif has 2 clocks but 1 enable */ 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", "pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71),
@@ -1989,7 +2015,6 @@ struct clk tegra_list_clks[] = {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 */ -/* FIXME: vfir shares an enable with uartb */ 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 */
@@ -2017,13 +2042,11 @@ struct clk tegra_list_clks[] = {PERIPH_CLK ("uarte" ,"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 */ -/* FIXME: vi and vi_sensor share an enable */ 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 */ -/* FIXME: cve and tvo share an enable */ 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 */
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 15/21 ARM: tegra: clock: Round rate before setting rate
In reply to a message not in the archiveCall the clock's round_rate op, if it exists, before calling the set_rate op. This will help later when dvfs is added, dvfs needs to know what the final rate will be before the frequency changes.
Also requires fixes to the round rate functions to ensure calling round rate and then set rate will not cause the frequency to be rounded down twice. When picking clock divider values, the clock framework picks the closest frequency that is lower than the requested frequency. If the new frequency calculated from the divider value is rounded down, and then passed to set_rate, it will get rounded down again, possibly resulting in a frequency two steps lower than the original requested frequency.
Fix the problem by rounding up when calculating the frequency coming out of a clock divider, so if that frequency is requested again, the same divider value will be picked.
--- arch/arm/mach-tegra/clock.c | 12 ++++++++++++ arch/arm/mach-tegra/tegra2_clocks.c | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-)
arch/arm/mach-tegra/clock.c +12 -0
@@ -86,6 +86,7 @@ static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)if (c->mul !=0 && c->div !=0 ) { rate *= c->mul; + rate += c->div /2 ;/* round up */ do_div (rate, c->div); }
@@ -240,12 +241,23 @@ EXPORT_SYMBOL(clk_get_parent);int clk_set_rate_locked (struct clk *c,unsigned long rate) { +long new_rate; +if (!c->ops || !c->ops->set_rate)return -ENOSYS ;if (rate > c->max_rate) rate = c->max_rate; +if (c->ops && c->ops->round_rate) { + new_rate = c->ops->round_rate (c, rate); + +if (new_rate <0 ) +return new_rate; + + rate = new_rate; + } +return c->ops->set_rate (c, rate); }
arch/arm/mach-tegra/tegra2_clocks.c +4 -4
@@ -866,9 +866,9 @@ static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate) divider =clk_div71_get_divider (parent_rate, rate);if (divider <0 )return divider; -return parent_rate *2 / (divider +2 ); +return DIV_ROUND_UP (parent_rate *2 , divider +2 ); }else if (c->flags &DIV_2 ) { -return parent_rate /2 ; +return DIV_ROUND_UP (parent_rate,2 ); }return -EINVAL ; }
@@ -1058,12 +1058,12 @@ static long tegra2_periph_clk_round_rate(struct clk *c,if (divider <0 )return divider; -return parent_rate *2 / (divider +2 ); +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 parent_rate / (divider +1 ); +return DIV_ROUND_UP (parent_rate, divider +1 ); }return -EINVAL ; }
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 16/21 ARM: tegra: Add external memory controller driver
In reply to a message not in the archive--- arch/arm/mach-tegra/Kconfig | 4 + arch/arm/mach-tegra/Makefile | 1 + arch/arm/mach-tegra/tegra2_emc.c | 172 ++++++++++++++++++++++++++++++++++++++ arch/arm/mach-tegra/tegra2_emc.h | 27 ++++++ 4 files changed, 204 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-tegra/tegra2_emc.c create mode 100644 arch/arm/mach-tegra/tegra2_emc.h
arch/arm/mach-tegra/Kconfig +4 -0
@@ -71,3 +71,7 @@ config TEGRA_SYSTEM_DMA several Tegra device drivers endif + +config TEGRA_EMC_SCALING_ENABLE + bool "Enable scaling the memory frequency" + default n
arch/arm/mach-tegra/Makefile +1 -0
@@ -9,6 +9,7 @@ obj-y += powergate.o obj-y += fuse.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clock.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o +obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-t2-tables.o obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
arch/arm/mach-tegra/tegra2_emc.c new file +172 -0
172 lines not on this page · raw message
arch/arm/mach-tegra/tegra2_emc.h new file +27 -0
@@ -0,0 +1,27 @@ +/* +* Copyright (C) 2010 Google, Inc. +* +* Author: +* Colin Cross <[email protected]> +* +* 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. +* +*/ + +#define TEGRA_EMC_NUM_REGS 46 + +struct tegra_emc_table { +unsigned long rate; +u32 regs[TEGRA_EMC_NUM_REGS ]; +}; + +int tegra_emc_set_rate (unsigned long rate); +long tegra_emc_round_rate (unsigned long rate); +void tegra_init_emc (const struct tegra_emc_table *table,int table_size);
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 17/21 ARM: tegra: clocks: Add emc scaling
In reply to a message not in the archive--- arch/arm/mach-tegra/tegra2_clocks.c | 62 ++++++++++++++++++++++++++++++++++- 1 files changed, 61 insertions(+), 1 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +61 -1
@@ -31,6 +31,7 @@#include "clock.h" #include "fuse.h" +#include "tegra2_emc.h" #define RST_DEVICES 0x004#define RST_DEVICES_SET 0x300
@@ -1078,6 +1079,53 @@ static struct clk_ops tegra_periph_clk_ops = { .reset = &tegra2_periph_clk_reset, }; +/* External memory controller clock ops */ +static void tegra2_emc_clk_init (struct clk *c) +{ +tegra2_periph_clk_init (c); + c->max_rate =clk_get_rate_locked (c); +} + +static long tegra2_emc_clk_round_rate (struct clk *c,unsigned long rate) +{ +long new_rate = rate; + + new_rate =tegra_emc_round_rate (new_rate); +if (new_rate <0 ) +return c->max_rate; + +BUG_ON (new_rate !=tegra2_periph_clk_round_rate (c, new_rate)); + +return new_rate; +} + +static int tegra2_emc_clk_set_rate (struct clk *c,unsigned long 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 =tegra2_periph_clk_set_rate (c, rate); +udelay (1 ); + +return ret; +} + +static struct clk_ops tegra_emc_clk_ops = { + .init = &tegra2_emc_clk_init, + .enable = &tegra2_periph_clk_enable, + .disable = &tegra2_periph_clk_disable, + .set_parent = &tegra2_periph_clk_set_parent, + .set_rate = &tegra2_emc_clk_set_rate, + .round_rate = &tegra2_emc_clk_round_rate, + .reset = &tegra2_periph_clk_reset, +}; +/* Clock doubler ops */ static void tegra2_clk_double_init (struct clk *c) {
@@ -1970,6 +2018,18 @@ static struct clk_mux_sel mux_clk_32k[] = { { 0, 0}, }; +static struct clk tegra_clk_emc = { + .name ="emc" , + .ops = &tegra_emc_clk_ops, + .reg =0x19c , + .max_rate =800000000 , + .inputs = mux_pllm_pllc_pllp_clkm, + .flags =MUX |DIV_U71 |PERIPH_EMC_ENB , + .u.periph = { + .clk_num =57 , + }, +}; +#define PERIPH_CLK (_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \ { \ .name = _name, \
@@ -2056,7 +2116,6 @@ struct clk tegra_list_clks[] = {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 ("emc" ,"emc" ,NULL ,57 ,0x19c ,800000000 , mux_pllm_pllc_pllp_clkm,MUX |DIV_U71 |PERIPH_EMC_ENB ),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 */
@@ -2132,6 +2191,7 @@ struct clk *tegra_ptr_clks[] = { &tegra_dev2_clk, &tegra_clk_virtual_cpu, &tegra_clk_blink, + &tegra_clk_emc, };static void tegra2_init_one_clock (struct clk *c)
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 18/21 ARM: tegra: cpufreq: Adjust memory frequency with cpu frequency
In reply to a message not in the archive--- arch/arm/mach-tegra/cpu-tegra.c | 21 +++++++++++++++++++++ 1 files changed, 21 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/cpu-tegra.c +21 -0
@@ -51,6 +51,7 @@ static struct cpufreq_frequency_table freq_table[] = {#define NUM_CPUS 2static struct clk *cpu_clk; +static struct clk *emc_clk;static unsigned long target_cpu_speed[NUM_CPUS ];static DEFINE_MUTEX (tegra_cpu_lock);
@@ -83,6 +84,17 @@ static int tegra_update_cpu_speed(unsigned long rate)if (freqs.old == freqs.new)return ret; +/* +* Vote on memory bus frequency based on cpu frequency +* This sets the minimum frequency, display or avp may request higher +*/ +if (rate >=816000 ) +clk_set_rate (emc_clk,600000000 );/* cpu 816 MHz, emc max */ +else if (rate >=456000 ) +clk_set_rate (emc_clk,300000000 );/* cpu 456 MHz, emc 150Mhz */ +else +clk_set_rate (emc_clk,100000000 );/* emc 50Mhz */ +for_each_online_cpu (freqs.cpu)cpufreq_notify_transition (&freqs,CPUFREQ_PRECHANGE );
@@ -173,6 +185,13 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)if (IS_ERR (cpu_clk))return PTR_ERR (cpu_clk); + emc_clk =clk_get_sys ("cpu" ,"emc" ); +if (IS_ERR (emc_clk)) { +clk_put (cpu_clk); +return PTR_ERR (emc_clk); + } + +clk_enable (emc_clk);clk_enable (cpu_clk);cpufreq_frequency_table_cpuinfo (policy, freq_table);
@@ -195,6 +214,8 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)static int tegra_cpu_exit (struct cpufreq_policy *policy) {cpufreq_frequency_table_cpuinfo (policy, freq_table); +clk_disable (emc_clk); +clk_put (emc_clk);clk_put (cpu_clk);return 0 ; }
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 19/21 ARM: tegra: clock: Add function to set SDMMC tap delay
In reply to a message not in the archiveThe SDMMC controllers have extra bits in the clock source register that adjust the delay between the clock and data to compenstate for delays on the PCB. The values need to be set from the clock code so the clock can be locked during the read-modify-write on the clock source register.
--- arch/arm/mach-tegra/clock.c | 12 ++++++++++++ arch/arm/mach-tegra/clock.h | 1 + arch/arm/mach-tegra/include/mach/clk.h | 2 ++ arch/arm/mach-tegra/tegra2_clocks.c | 19 +++++++++++++++++++ 4 files changed, 34 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/clock.c +12 -0
@@ -433,6 +433,18 @@ int __init tegra_disable_boot_clocks(void)late_initcall (tegra_disable_boot_clocks);#endif +/* The SDMMC controllers have extra bits in the clock source register that +* adjust the delay between the clock and data to compenstate for delays +* on the PCB. */ +void tegra_sdmmc_tap_delay (struct clk *c,int delay) +{ +unsigned long flags; + +spin_lock_irqsave (&c->spinlock, flags); +tegra2_sdmmc_tap_delay (c, delay); +spin_unlock_irqrestore (&c->spinlock, flags); +} +#ifdef CONFIG_DEBUG_FS static int __clk_lock_all_spinlocks (void )
arch/arm/mach-tegra/clock.h +1 -0
@@ -155,5 +155,6 @@ int clk_reparent(struct clk *c, struct clk *parent);void tegra_clk_init_from_table (struct tegra_clk_init_table *table);unsigned long clk_get_rate_locked (struct clk *c);int clk_set_rate_locked (struct clk *c,unsigned long rate); +void tegra2_sdmmc_tap_delay (struct clk *c,int delay);#endif
arch/arm/mach-tegra/include/mach/clk.h +2 -0
@@ -26,4 +26,6 @@ void tegra_periph_reset_deassert(struct clk *c);void tegra_periph_reset_assert (struct clk *c);unsigned long clk_get_rate_all_locked (struct clk *c); +void tegra_sdmmc_tap_delay (struct clk *c,int delay); +#endif
arch/arm/mach-tegra/tegra2_clocks.c +19 -0
@@ -74,6 +74,10 @@#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)
@@ -1079,6 +1083,21 @@ static struct clk_ops tegra_periph_clk_ops = { .reset = &tegra2_periph_clk_reset, }; +/* The SDMMC controllers have extra bits in the clock source register that +* adjust the delay between the clock and data to compenstate for delays +* on the PCB. */ +void tegra2_sdmmc_tap_delay (struct clk *c,int delay) +{ +u32 reg; + + delay =clamp (delay,0 ,15 ); + reg =clk_readl (c->reg); + reg &= ~SDMMC_CLK_INT_FB_DLY_MASK ; + reg |=SDMMC_CLK_INT_FB_SEL ; + reg |= delay <<SDMMC_CLK_INT_FB_DLY_SHIFT ; +clk_writel (reg, c->reg); +} +/* External memory controller clock ops */ static void tegra2_emc_clk_init (struct clk *c) {
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 20/21 ARM: tegra: clock: Fix clock issues in suspend
In reply to a message not in the archiveThe PLLP registers are now being restored by the low-level resume code, and the CPU may be running off PLLP, so don't touch them during clock resume.
Save plld, plls, pllu, and audio clock during suspend (originally fixed by Mayuresh Kulkarni <[email protected]>)
The lock time for plld is 1000 us, so increase the delay after setting the PLLs.
Add a BUG_ON to ensure the size of the suspend context area is correct.
--- arch/arm/mach-tegra/tegra2_clocks.c | 30 ++++++++++++++++++++---------- 1 files changed, 20 insertions(+), 10 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +20 -10
@@ -2251,7 +2251,7 @@ void __init tegra2_init_clocks(void)#ifdef CONFIG_PM static u32 clk_rst_suspend[RST_DEVICES_NUM +CLK_OUT_ENB_NUM + -PERIPH_CLK_SOURCE_NUM +19 ]; +PERIPH_CLK_SOURCE_NUM +22 ];void tegra_clk_suspend (void ) {
@@ -2259,16 +2259,18 @@ void tegra_clk_suspend(void)u32 *ctx = clk_rst_suspend; *ctx++ =clk_readl (OSC_CTRL ) &OSC_CTRL_MASK ; - *ctx++ =clk_readl (tegra_pll_p.reg +PLL_BASE ); - *ctx++ =clk_readl (tegra_pll_p.reg +PLL_MISC (&tegra_pll_p)); *ctx++ =clk_readl (tegra_pll_c.reg +PLL_BASE ); *ctx++ =clk_readl (tegra_pll_c.reg +PLL_MISC (&tegra_pll_c)); *ctx++ =clk_readl (tegra_pll_a.reg +PLL_BASE ); *ctx++ =clk_readl (tegra_pll_a.reg +PLL_MISC (&tegra_pll_a)); + *ctx++ =clk_readl (tegra_pll_s.reg +PLL_BASE ); + *ctx++ =clk_readl (tegra_pll_s.reg +PLL_MISC (&tegra_pll_s)); + *ctx++ =clk_readl (tegra_pll_d.reg +PLL_BASE ); + *ctx++ =clk_readl (tegra_pll_d.reg +PLL_MISC (&tegra_pll_d)); + *ctx++ =clk_readl (tegra_pll_u.reg +PLL_BASE ); + *ctx++ =clk_readl (tegra_pll_u.reg +PLL_MISC (&tegra_pll_u)); *ctx++ =clk_readl (tegra_pll_m_out1.reg); - *ctx++ =clk_readl (tegra_pll_p_out1.reg); - *ctx++ =clk_readl (tegra_pll_p_out3.reg); *ctx++ =clk_readl (tegra_pll_a_out0.reg); *ctx++ =clk_readl (tegra_pll_c_out1.reg);
@@ -2279,6 +2281,8 @@ void tegra_clk_suspend(void) *ctx++ =clk_readl (tegra_clk_sclk.reg +SUPER_CLK_DIVIDER ); *ctx++ =clk_readl (tegra_clk_pclk.reg); + *ctx++ =clk_readl (tegra_clk_audio.reg); +for (off =PERIPH_CLK_SOURCE_I2S1 ; off <=PERIPH_CLK_SOURCE_OSC ; off +=4 ) {if (off ==PERIPH_CLK_SOURCE_EMC )
@@ -2296,6 +2300,8 @@ void tegra_clk_suspend(void) *ctx++ =clk_readl (MISC_CLK_ENB ); *ctx++ =clk_readl (CLK_MASK_ARM ); + +BUG_ON (ctx - clk_rst_suspend !=ARRAY_SIZE (clk_rst_suspend)); }void tegra_clk_resume (void )
@@ -2308,17 +2314,19 @@ void tegra_clk_resume(void) val |= *ctx++;clk_writel (val,OSC_CTRL ); -clk_writel (*ctx++, tegra_pll_p.reg +PLL_BASE ); -clk_writel (*ctx++, tegra_pll_p.reg +PLL_MISC (&tegra_pll_p));clk_writel (*ctx++, tegra_pll_c.reg +PLL_BASE );clk_writel (*ctx++, tegra_pll_c.reg +PLL_MISC (&tegra_pll_c));clk_writel (*ctx++, tegra_pll_a.reg +PLL_BASE );clk_writel (*ctx++, tegra_pll_a.reg +PLL_MISC (&tegra_pll_a)); -udelay (300 ); +clk_writel (*ctx++, tegra_pll_s.reg +PLL_BASE ); +clk_writel (*ctx++, tegra_pll_s.reg +PLL_MISC (&tegra_pll_s)); +clk_writel (*ctx++, tegra_pll_d.reg +PLL_BASE ); +clk_writel (*ctx++, tegra_pll_d.reg +PLL_MISC (&tegra_pll_d)); +clk_writel (*ctx++, tegra_pll_u.reg +PLL_BASE ); +clk_writel (*ctx++, tegra_pll_u.reg +PLL_MISC (&tegra_pll_u)); +udelay (1000 );clk_writel (*ctx++, tegra_pll_m_out1.reg); -clk_writel (*ctx++, tegra_pll_p_out1.reg); -clk_writel (*ctx++, tegra_pll_p_out3.reg);clk_writel (*ctx++, tegra_pll_a_out0.reg);clk_writel (*ctx++, tegra_pll_c_out1.reg);
@@ -2329,6 +2337,8 @@ void tegra_clk_resume(void)clk_writel (*ctx++, tegra_clk_sclk.reg +SUPER_CLK_DIVIDER );clk_writel (*ctx++, tegra_clk_pclk.reg); +clk_writel (*ctx++, tegra_clk_audio.reg); +/* enable all clocks before configuring clock sources */ clk_writel (0xbffffff9ul ,CLK_OUT_ENB );clk_writel (0xfefffff7ul ,CLK_OUT_ENB +4 );
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 21/21 ARM: tegra: clock: Miscellaneous clock updates
In reply to a message not in the archiveCorrect max rates for pclk and sclk (Originally fixed by
Dima Zavin <[email protected]>)
Correct max rate for plla (Originally fixed by
Stephen Warren <[email protected]>)
Remove unnecessary no-op set_rate on audio clocks
Add clock lookup entries for grhost, bsea, and vde clocks
Update clock clookup entries for vcp, bsea, and vde clocks
Add shared clock entries for sclk and emc
Add a virtual cop clock to provide a reset op (Originally fixed by
Dima Zavin <[email protected]>)
Pass set_rate on super clocks through to parent
Fix pllx frequency table entry for 608 MHz
Remove incorrect plla frequency table entries
--- arch/arm/mach-tegra/tegra2_clocks.c | 98 ++++++++++++++++++++++++----------- 1 files changed, 67 insertions(+), 31 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +67 -31
@@ -362,11 +362,24 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)return -EINVAL ; } +/* +* Super clocks have "clock skippers" instead of dividers. Dividing using +* a clock skipper does not allow the voltage to be scaled down, so 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. +*/ +static int tegra2_super_clk_set_rate (struct clk *c,unsigned long rate) +{ +return clk_set_rate (c->parent, rate); +} +static struct clk_ops tegra_super_ops = { .init = tegra2_super_clk_init, .enable = tegra2_super_clk_enable, .disable = tegra2_super_clk_disable, .set_parent = tegra2_super_clk_set_parent, + .set_rate = tegra2_super_clk_set_rate, };/* virtual cpu clock functions */
@@ -435,6 +448,20 @@ static struct clk_ops tegra_cpu_ops = { .set_rate = tegra2_cpu_clk_set_rate, }; +/* virtual cop clock functions. Used to acquire the fake 'cop' clock to +* reset the COP block (i.e. AVP) */ +static void tegra2_cop_clk_reset (struct clk *c,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); +} + +static struct clk_ops tegra_cop_ops = { + .reset = tegra2_cop_clk_reset, +}; +/* bus clock functions */ static void tegra2_bus_clk_init (struct clk *c) {
@@ -1224,30 +1251,10 @@ static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)return -EINVAL ; } -static int tegra2_audio_sync_clk_set_rate (struct clk *c,unsigned long rate) -{ -unsigned long parent_rate; -if (!c->parent) { -pr_err ("%s: clock has no parent\n" , __func__); -return -EINVAL ; - } - parent_rate = c->parent->rate; -if (rate != parent_rate) { -pr_err ("%s: %s/%ld differs from parent %s/%ld\n" , - __func__, - c->name, rate, - c->parent->name, parent_rate); -return -EINVAL ; - } - c->rate = parent_rate; -return 0 ; -} -static struct clk_ops tegra_audio_sync_clk_ops = { .init = tegra2_audio_sync_clk_init, .enable = tegra2_audio_sync_clk_enable, .disable = tegra2_audio_sync_clk_disable, - .set_rate = tegra2_audio_sync_clk_set_rate, .set_parent = tegra2_audio_sync_clk_set_parent, };
@@ -1583,8 +1590,6 @@ static struct clk tegra_pll_p_out4 = {static struct clk_pll_freq_table tegra_pll_a_freq_table[] = { {28800000 ,56448000 ,49 ,25 ,1 ,1 }, {28800000 ,73728000 ,64 ,25 ,1 ,1 }, - {28800000 ,11289600 ,49 ,25 ,1 ,1 }, - {28800000 ,12288000 ,64 ,25 ,1 ,1 }, {28800000 ,24000000 ,5 ,6 ,1 ,1 }, {0 ,0 ,0 ,0 ,0 ,0 }, };
@@ -1595,7 +1600,7 @@ static struct clk tegra_pll_a = { .ops = &tegra_pll_ops, .reg = 0xb0, .parent = &tegra_pll_p_out1, - .max_rate = 56448000, + .max_rate = 73728000, .u.pll = { .input_min = 2000000, .input_max = 31000000,
@@ -1615,7 +1620,7 @@ static struct clk tegra_pll_a_out0 = { .parent = &tegra_pll_a, .reg = 0xb4, .reg_shift = 0, - .max_rate = 56448000, + .max_rate = 73728000, };static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
@@ -1717,10 +1722,10 @@ static struct clk_pll_freq_table tegra_pll_x_freq_table[] = { { 26000000, 760000000, 760, 26, 1, 12},/* 608 MHz */ - { 12000000, 608000000, 760, 12, 1, 12}, - { 13000000, 608000000, 760, 13, 1, 12}, + { 12000000, 608000000, 608, 12, 1, 12}, + { 13000000, 608000000, 608, 13, 1, 12}, { 19200000, 608000000, 380, 12, 1, 8}, - { 26000000, 608000000, 760, 26, 1, 12}, + { 26000000, 608000000, 608, 26, 1, 12},/* 456 MHz */ { 12000000, 456000000, 456, 12, 1, 12},
@@ -1833,7 +1838,7 @@ static struct clk tegra_clk_audio = { .name = "audio", .inputs = mux_audio_sync_clk, .reg = 0x38, - .max_rate = 24000000, + .max_rate = 73728000, .ops = &tegra_audio_sync_clk_ops };
@@ -1919,7 +1924,8 @@ static struct clk tegra_clk_sclk = { .inputs = mux_sclk, .reg = 0x28, .ops = &tegra_super_ops, - .max_rate = 600000000, + .max_rate = 240000000, + .min_rate = 120000000, };static struct clk tegra_clk_virtual_cpu = {
@@ -1933,6 +1939,13 @@ static struct clk tegra_clk_virtual_cpu = { }, }; +static struct clk tegra_clk_cop = { + .name ="cop" , + .parent = &tegra_clk_sclk, + .ops = &tegra_cop_ops, + .max_rate =240000000 , +}; +static struct clk tegra_clk_hclk = { .name ="hclk" , .flags =DIV_BUS ,
@@ -1950,7 +1963,7 @@ static struct clk tegra_clk_pclk = { .reg = 0x30, .reg_shift = 0, .ops = &tegra_bus_ops, - .max_rate = 108000000, + .max_rate = 120000000, };static struct clk tegra_clk_blink = {
@@ -2099,7 +2112,10 @@ struct clk tegra_list_clks[] = {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 ("vde" ,"vde" ,NULL ,61 ,0x1c8 ,250000000 , mux_pllp_pllc_pllm_clkm,MUX |DIV_U71 ),/* scales with voltage and process_id */ +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),
@@ -2142,6 +2158,18 @@ struct clk tegra_list_clks[] = {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 ), + +SHARED_CLK ("avp.sclk" ,"tegra-avp" ,"sclk" , &tegra_clk_sclk), +SHARED_CLK ("avp.emc" ,"tegra-avp" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("cpu.emc" ,"cpu" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("disp1.emc" ,"tegradc.0" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("disp2.emc" ,"tegradc.1" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("hdmi.emc" ,"hdmi" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("host.emc" ,"tegra_grhost" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("usbd.emc" ,"fsl-tegra-udc" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("usb1.emc" ,"tegra-ehci.0" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("usb2.emc" ,"tegra-ehci.1" ,"emc" , &tegra_clk_emc), + SHARED_CLK("usb3.emc", "tegra-ehci.2", "emc", &tegra_clk_emc), };#define CLK_DUPLICATE (_name, _dev, _con) \
@@ -2172,6 +2200,13 @@ struct clk_duplicate tegra_clk_duplicates[] = {CLK_DUPLICATE ("pwm" ,"tegra_pwm.1" ,NULL ),CLK_DUPLICATE ("pwm" ,"tegra_pwm.2" ,NULL ),CLK_DUPLICATE ("pwm" ,"tegra_pwm.3" ,NULL ), +CLK_DUPLICATE ("host1x" ,"tegra_grhost" ,"host1x" ), +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"), };#define CLK (dev, con, ck) \
@@ -2210,6 +2245,7 @@ struct clk *tegra_ptr_clks[] = { &tegra_dev2_clk, &tegra_clk_virtual_cpu, &tegra_clk_blink, + &tegra_clk_cop, &tegra_clk_emc, };
Signature · 6 lines
1.7.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 1/21 ARM: tegra: clock: enable clk reset for non-peripheral clocks
In reply to Colin CrossFrom: Dima Zavin <[email protected]>
Add a new 'reset' clk op. This can be provided for any clock, not just peripherals.
--- arch/arm/mach-tegra/clock.h | 1 + arch/arm/mach-tegra/tegra2_clocks.c | 29 ++++++++++++++++++----------- 2 files changed, 19 insertions(+), 11 deletions(-)
arch/arm/mach-tegra/clock.h +1 -0
@@ -86,6 +86,7 @@ struct clk_ops {int (*set_parent)(struct clk *,struct clk *);int (*set_rate)(struct clk *,unsigned long );long (*round_rate)(struct clk *,unsigned long ); +void (*reset)(struct clk *,bool ); };enum clk_state {
arch/arm/mach-tegra/tegra2_clocks.c +18 -11
@@ -263,6 +263,18 @@ static struct clk_ops tegra_clk_m_ops = { .disable = tegra2_clk_m_disable, }; +void tegra2_periph_reset_assert (struct clk *c) +{ +BUG_ON (!c->ops->reset); + c->ops->reset (c, true); +} + +void tegra2_periph_reset_deassert (struct clk *c) +{ +BUG_ON (!c->ops->reset); + c->ops->reset (c, false); +} +/* 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
@@ -895,23 +907,17 @@ static void tegra2_periph_clk_disable(struct clk *c) CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c)); } -void tegra2_periph_reset_deassert (struct clk *c) +static void tegra2_periph_clk_reset (struct clk *c,bool assert) { -pr_debug ("%s on clock %s\n" , __func__, c->name); -if (!(c->flags &PERIPH_NO_RESET )) -clk_writel (PERIPH_CLK_TO_ENB_BIT (c), -RST_DEVICES_CLR +PERIPH_CLK_TO_ENB_SET_REG (c)); -} +unsigned long base = assert ?RST_DEVICES_SET :RST_DEVICES_CLR ; -void tegra2_periph_reset_assert (struct clk *c) -{ -pr_debug ("%s on clock %s\n" , __func__, c->name); +pr_debug ("%s %s on clock %s\n" , __func__, + assert ?"assert" :"deassert" , c->name);if (!(c->flags &PERIPH_NO_RESET ))clk_writel (PERIPH_CLK_TO_ENB_BIT (c), -RST_DEVICES_SET +PERIPH_CLK_TO_ENB_SET_REG (c)); + base +PERIPH_CLK_TO_ENB_SET_REG (c)); } -static int tegra2_periph_clk_set_parent (struct clk *c,struct clk *p) {u32 val;
@@ -1002,6 +1008,7 @@ static struct clk_ops tegra_periph_clk_ops = { .set_parent = &tegra2_periph_clk_set_parent, .set_rate = &tegra2_periph_clk_set_rate, .round_rate = &tegra2_periph_clk_round_rate, + .reset = &tegra2_periph_clk_reset, };/* Clock doubler ops */
Signature · 1 line
1.7.3.1
Re: [PATCH v2 01/21] ARM: tegra: clock: enable clk reset for non-peripheral clocks
Quoted 7 lines · Colin Cross
From: Dima Zavin <[email protected]>
Add a new 'reset' clk op. This can be provided for any clock, not just peripherals.
Signed-off-by Dima Zavin <[email protected]>Signed-off-by Colin Cross <[email protected]>
PATCH v2 1/21 ARM: tegra: clock: enable clk reset for non-peripheral clocks
In reply to Colin CrossFrom: Dima Zavin <[email protected]>
Add a new 'reset' clk op. This can be provided for any clock, not just peripherals.
--- arch/arm/mach-tegra/clock.h | 1 + arch/arm/mach-tegra/tegra2_clocks.c | 29 ++++++++++++++++++----------- 2 files changed, 19 insertions(+), 11 deletions(-)
arch/arm/mach-tegra/clock.h +1 -0
@@ -86,6 +86,7 @@ struct clk_ops {int (*set_parent)(struct clk *,struct clk *);int (*set_rate)(struct clk *,unsigned long );long (*round_rate)(struct clk *,unsigned long ); +void (*reset)(struct clk *,bool ); };enum clk_state {
arch/arm/mach-tegra/tegra2_clocks.c +18 -11
@@ -263,6 +263,18 @@ static struct clk_ops tegra_clk_m_ops = { .disable = tegra2_clk_m_disable, }; +void tegra2_periph_reset_assert (struct clk *c) +{ +BUG_ON (!c->ops->reset); + c->ops->reset (c, true); +} + +void tegra2_periph_reset_deassert (struct clk *c) +{ +BUG_ON (!c->ops->reset); + c->ops->reset (c, false); +} +/* 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
@@ -895,23 +907,17 @@ static void tegra2_periph_clk_disable(struct clk *c) CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c)); } -void tegra2_periph_reset_deassert (struct clk *c) +static void tegra2_periph_clk_reset (struct clk *c,bool assert) { -pr_debug ("%s on clock %s\n" , __func__, c->name); -if (!(c->flags &PERIPH_NO_RESET )) -clk_writel (PERIPH_CLK_TO_ENB_BIT (c), -RST_DEVICES_CLR +PERIPH_CLK_TO_ENB_SET_REG (c)); -} +unsigned long base = assert ?RST_DEVICES_SET :RST_DEVICES_CLR ; -void tegra2_periph_reset_assert (struct clk *c) -{ -pr_debug ("%s on clock %s\n" , __func__, c->name); +pr_debug ("%s %s on clock %s\n" , __func__, + assert ?"assert" :"deassert" , c->name);if (!(c->flags &PERIPH_NO_RESET ))clk_writel (PERIPH_CLK_TO_ENB_BIT (c), -RST_DEVICES_SET +PERIPH_CLK_TO_ENB_SET_REG (c)); + base +PERIPH_CLK_TO_ENB_SET_REG (c)); } -static int tegra2_periph_clk_set_parent (struct clk *c,struct clk *p) {u32 val;
@@ -1002,6 +1008,7 @@ static struct clk_ops tegra_periph_clk_ops = { .set_parent = &tegra2_periph_clk_set_parent, .set_rate = &tegra2_periph_clk_set_rate, .round_rate = &tegra2_periph_clk_round_rate, + .reset = &tegra2_periph_clk_reset, };/* Clock doubler ops */
Signature · 1 line
1.7.3.1
PATCH v2 1/21 ARM: tegra: clock: enable clk reset for non-peripheral clocks
In reply to Colin CrossFrom: Dima Zavin <[email protected]>
Add a new 'reset' clk op. This can be provided for any clock, not just peripherals.
--- arch/arm/mach-tegra/clock.h | 1 + arch/arm/mach-tegra/tegra2_clocks.c | 29 ++++++++++++++++++----------- 2 files changed, 19 insertions(+), 11 deletions(-)
arch/arm/mach-tegra/clock.h +1 -0
@@ -86,6 +86,7 @@ struct clk_ops {int (*set_parent)(struct clk *,struct clk *);int (*set_rate)(struct clk *,unsigned long );long (*round_rate)(struct clk *,unsigned long ); +void (*reset)(struct clk *,bool ); };enum clk_state {
arch/arm/mach-tegra/tegra2_clocks.c +18 -11
@@ -263,6 +263,18 @@ static struct clk_ops tegra_clk_m_ops = { .disable = tegra2_clk_m_disable, }; +void tegra2_periph_reset_assert (struct clk *c) +{ +BUG_ON (!c->ops->reset); + c->ops->reset (c, true); +} + +void tegra2_periph_reset_deassert (struct clk *c) +{ +BUG_ON (!c->ops->reset); + c->ops->reset (c, false); +} +/* 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
@@ -895,23 +907,17 @@ static void tegra2_periph_clk_disable(struct clk *c) CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c)); } -void tegra2_periph_reset_deassert (struct clk *c) +static void tegra2_periph_clk_reset (struct clk *c,bool assert) { -pr_debug ("%s on clock %s\n" , __func__, c->name); -if (!(c->flags &PERIPH_NO_RESET )) -clk_writel (PERIPH_CLK_TO_ENB_BIT (c), -RST_DEVICES_CLR +PERIPH_CLK_TO_ENB_SET_REG (c)); -} +unsigned long base = assert ?RST_DEVICES_SET :RST_DEVICES_CLR ; -void tegra2_periph_reset_assert (struct clk *c) -{ -pr_debug ("%s on clock %s\n" , __func__, c->name); +pr_debug ("%s %s on clock %s\n" , __func__, + assert ?"assert" :"deassert" , c->name);if (!(c->flags &PERIPH_NO_RESET ))clk_writel (PERIPH_CLK_TO_ENB_BIT (c), -RST_DEVICES_SET +PERIPH_CLK_TO_ENB_SET_REG (c)); + base +PERIPH_CLK_TO_ENB_SET_REG (c)); } -static int tegra2_periph_clk_set_parent (struct clk *c,struct clk *p) {u32 val;
@@ -1002,6 +1008,7 @@ static struct clk_ops tegra_periph_clk_ops = { .set_parent = &tegra2_periph_clk_set_parent, .set_rate = &tegra2_periph_clk_set_rate, .round_rate = &tegra2_periph_clk_round_rate, + .reset = &tegra2_periph_clk_reset, };/* Clock doubler ops */
Signature · 1 line
1.7.3.1
PATCH v2 2/21 ARM: tegra: clock: Don't BUG on changing an enabled PLL
In reply to Colin Cross--- arch/arm/mach-tegra/tegra2_clocks.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +0 -1
@@ -620,7 +620,6 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)const struct clk_pll_table *sel;pr_debug ("%s: %s %lu\n" , __func__, c->name, rate); -BUG_ON (c->refcnt !=0 ); input_rate = c->parent->rate;for (sel = c->pll_table; sel->input_rate !=0 ; sel++) {
Signature · 1 line
1.7.3.1
Re: [PATCH v2 02/21] ARM: tegra: clock: Don't BUG on changing an enabled PLL
Quoted 1 line · Colin Cross
Signed-off-by Colin Cross <[email protected]>
Please add a 1-line description of why bugging doesn't make sense.
Patch itself:
Re: [PATCH v2 02/21] ARM: tegra: clock: Don't BUG on changing an enabled PLL
Quoted 9 lines · Olof Johansson
Quoted 1 line · Colin Cross
Signed-off-by Colin Cross <[email protected]>Please add a 1-line description of why bugging doesn't make sense.
Patch itself:
Acked-by Olof Johansson <[email protected]>
I will add:
When updating the CPU PLL frequency, keeping the PLL enabled avoids ramping the PLL all the way down and back up again. Remove the BUG_ON in tegra2_pll_clk_set_rate to allow the rate to change while the PLL is enabled.
PATCH v2 2/21 ARM: tegra: clock: Don't BUG on changing an enabled PLL
In reply to Colin Cross--- arch/arm/mach-tegra/tegra2_clocks.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +0 -1
@@ -620,7 +620,6 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)const struct clk_pll_table *sel;pr_debug ("%s: %s %lu\n" , __func__, c->name, rate); -BUG_ON (c->refcnt !=0 ); input_rate = c->parent->rate;for (sel = c->pll_table; sel->input_rate !=0 ; sel++) {
Signature · 1 line
1.7.3.1
PATCH v2 3/21 ARM: tegra: clock: Drop debugging
In reply to Colin Cross--- arch/arm/mach-tegra/clock.c | 19 ++----------------- 1 files changed, 2 insertions(+), 17 deletions(-)
arch/arm/mach-tegra/clock.c +2 -17
@@ -138,7 +138,6 @@ static void clk_recalculate_rate(struct clk *c)int clk_reparent (struct clk *c,struct clk *parent) { -pr_debug ("%s: %s\n" , __func__, c->name); c->parent = parent;list_del (&c->sibling);list_add_tail (&c->sibling, &parent->children);
@@ -148,9 +147,8 @@ int clk_reparent(struct clk *c, struct clk *parent)static void propagate_rate (struct clk *c) {struct clk *clkp; -pr_debug ("%s: %s\n" , __func__, c->name); +list_for_each_entry (clkp, &c->children, sibling) { -pr_debug (" %s\n" , clkp->name);clk_recalculate_rate (clkp);propagate_rate (clkp); }
@@ -160,8 +158,6 @@ void clk_init(struct clk *c) {unsigned long flags; -pr_debug ("%s: %s\n" , __func__, c->name); -spin_lock_irqsave (&clock_lock, flags);INIT_LIST_HEAD (&c->children);
@@ -183,7 +179,7 @@ void clk_init(struct clk *c)int clk_enable_locked (struct clk *c) {int ret; -pr_debug ("%s: %s\n" , __func__, c->name); +if (c->refcnt ==0 ) {if (c->parent) { ret =clk_enable_locked (c->parent);
@@ -247,7 +243,6 @@ EXPORT_SYMBOL(clk_enable);void clk_disable_locked (struct clk *c) { -pr_debug ("%s: %s\n" , __func__, c->name);if (c->refcnt ==0 ) {WARN (1 ,"Attempting to disable clock %s with refcnt 0" , c->name);return ;
@@ -298,8 +293,6 @@ int clk_set_parent_locked(struct clk *c, struct clk *parent) {int ret; -pr_debug ("%s: %s\n" , __func__, c->name); -if (!c->ops || !c->ops->set_parent)return -ENOSYS ;
@@ -359,8 +352,6 @@ int clk_set_rate_cansleep(struct clk *c, unsigned long rate)int ret =0 ;unsigned long flags; -pr_debug ("%s: %s\n" , __func__, c->name); -mutex_lock (&dvfs_lock);if (rate > c->rate)
@@ -388,8 +379,6 @@ int clk_set_rate(struct clk *c, unsigned long rate)int ret =0 ;unsigned long flags; -pr_debug ("%s: %s\n" , __func__, c->name); -if (clk_is_dvfs (c))BUG ();
@@ -408,8 +397,6 @@ unsigned long clk_get_rate(struct clk *c)spin_lock_irqsave (&clock_lock, flags); -pr_debug ("%s: %s\n" , __func__, c->name); - ret = c->rate;spin_unlock_irqrestore (&clock_lock, flags);
@@ -419,8 +406,6 @@ EXPORT_SYMBOL(clk_get_rate);long clk_round_rate (struct clk *c,unsigned long rate) { -pr_debug ("%s: %s\n" , __func__, c->name); -if (!c->ops || !c->ops->round_rate)return -ENOSYS ;
Signature · 1 line
1.7.3.1
Re: [PATCH v2 03/21] ARM: tegra: clock: Drop debugging
Quoted 1 line · Colin Cross
Signed-off-by Colin Cross <[email protected]>
Same here, I know the patch is obvious but just a one-liner in the patch description is common practice.
Re: [PATCH v2 03/21] ARM: tegra: clock: Drop debugging
Quoted 7 lines · Olof Johansson
Quoted 1 line · Colin Cross
Signed-off-by Colin Cross <[email protected]>Same here, I know the patch is obvious but just a one-liner in the patch description is common practice.
Acked-by Olof Johansson <[email protected]>
I will add:
Drop the unnecessary pr_debug calls to avoid having to maintain them.
PATCH v2 3/21 ARM: tegra: clock: Drop debugging
In reply to Colin Cross--- arch/arm/mach-tegra/clock.c | 19 ++----------------- 1 files changed, 2 insertions(+), 17 deletions(-)
arch/arm/mach-tegra/clock.c +2 -17
@@ -138,7 +138,6 @@ static void clk_recalculate_rate(struct clk *c)int clk_reparent (struct clk *c,struct clk *parent) { -pr_debug ("%s: %s\n" , __func__, c->name); c->parent = parent;list_del (&c->sibling);list_add_tail (&c->sibling, &parent->children);
@@ -148,9 +147,8 @@ int clk_reparent(struct clk *c, struct clk *parent)static void propagate_rate (struct clk *c) {struct clk *clkp; -pr_debug ("%s: %s\n" , __func__, c->name); +list_for_each_entry (clkp, &c->children, sibling) { -pr_debug (" %s\n" , clkp->name);clk_recalculate_rate (clkp);propagate_rate (clkp); }
@@ -160,8 +158,6 @@ void clk_init(struct clk *c) {unsigned long flags; -pr_debug ("%s: %s\n" , __func__, c->name); -spin_lock_irqsave (&clock_lock, flags);INIT_LIST_HEAD (&c->children);
@@ -183,7 +179,7 @@ void clk_init(struct clk *c)int clk_enable_locked (struct clk *c) {int ret; -pr_debug ("%s: %s\n" , __func__, c->name); +if (c->refcnt ==0 ) {if (c->parent) { ret =clk_enable_locked (c->parent);
@@ -247,7 +243,6 @@ EXPORT_SYMBOL(clk_enable);void clk_disable_locked (struct clk *c) { -pr_debug ("%s: %s\n" , __func__, c->name);if (c->refcnt ==0 ) {WARN (1 ,"Attempting to disable clock %s with refcnt 0" , c->name);return ;
@@ -298,8 +293,6 @@ int clk_set_parent_locked(struct clk *c, struct clk *parent) {int ret; -pr_debug ("%s: %s\n" , __func__, c->name); -if (!c->ops || !c->ops->set_parent)return -ENOSYS ;
@@ -359,8 +352,6 @@ int clk_set_rate_cansleep(struct clk *c, unsigned long rate)int ret =0 ;unsigned long flags; -pr_debug ("%s: %s\n" , __func__, c->name); -mutex_lock (&dvfs_lock);if (rate > c->rate)
@@ -388,8 +379,6 @@ int clk_set_rate(struct clk *c, unsigned long rate)int ret =0 ;unsigned long flags; -pr_debug ("%s: %s\n" , __func__, c->name); -if (clk_is_dvfs (c))BUG ();
@@ -408,8 +397,6 @@ unsigned long clk_get_rate(struct clk *c)spin_lock_irqsave (&clock_lock, flags); -pr_debug ("%s: %s\n" , __func__, c->name); - ret = c->rate;spin_unlock_irqrestore (&clock_lock, flags);
@@ -419,8 +406,6 @@ EXPORT_SYMBOL(clk_get_rate);long clk_round_rate (struct clk *c,unsigned long rate) { -pr_debug ("%s: %s\n" , __func__, c->name); -if (!c->ops || !c->ops->round_rate)return -ENOSYS ;
Signature · 1 line
1.7.3.1
PATCH v2 4/21 ARM: tegra: clock: Don't use PLL lock bits
In reply to Colin CrossThe PLL lock bits are not reliable, use per-PLL timeouts instead.
--- arch/arm/mach-tegra/clock.h | 2 +- arch/arm/mach-tegra/tegra2_clocks.c | 31 +++++++++---------------------- 2 files changed, 10 insertions(+), 23 deletions(-)
arch/arm/mach-tegra/clock.h +1 -1
@@ -53,7 +53,6 @@ struct dvfs_process_id_table {struct dvfs_table *table; }; -struct dvfs {struct regulator *reg;struct dvfs_table *table;
@@ -128,6 +127,7 @@ struct clk {unsigned long vco_min;unsigned long vco_max;const struct clk_pll_table *pll_table; +int pll_lock_delay;/* DIV */ u32 div;
arch/arm/mach-tegra/tegra2_clocks.c +9 -22
@@ -79,7 +79,6 @@#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)
@@ -94,7 +93,6 @@#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) ? (1<<22) : (1<<18))#define PLL_MISC_DCCON_SHIFT 20#define PLL_MISC_CPCON_SHIFT 8
@@ -546,17 +544,7 @@ static struct clk_ops tegra_blink_clk_ops = {/* PLL Functions */ static int tegra2_pll_clk_wait_for_lock (struct clk *c) { -ktime_t before; - - before =ktime_get (); - -while (!(clk_readl (c->reg +PLL_BASE ) &PLL_BASE_LOCK )) { -if (ktime_us_delta (ktime_get (), before) >5000 ) { -pr_err ("Timed out waiting for lock bit on pll %s" , - c->name); -return -1 ; - } - } +udelay (c->pll_lock_delay);return 0 ; }
@@ -594,10 +582,6 @@ static int tegra2_pll_clk_enable(struct clk *c) val |=PLL_BASE_ENABLE ;clk_writel (val, c->reg +PLL_BASE ); - val =clk_readl (c->reg +PLL_MISC (c)); - val |=PLL_MISC_LOCK_ENABLE (c); -clk_writel (val, c->reg +PLL_MISC (c)); -tegra2_pll_clk_wait_for_lock (c);return 0 ;
@@ -1177,6 +1161,7 @@ static struct clk tegra_pll_s = { .vco_max = 26000000, .pll_table = tegra_pll_s_table, .max_rate = 26000000, + .pll_lock_delay = 300, };static struct clk_mux_sel tegra_clk_m_sel[] = {
@@ -1213,6 +1198,7 @@ static struct clk tegra_pll_c = { .vco_max = 1400000000, .pll_table = tegra_pll_c_table, .max_rate = 600000000, + .pll_lock_delay = 300, };static struct clk tegra_pll_c_out1 = {
@@ -1251,6 +1237,7 @@ static struct clk tegra_pll_m = { .vco_max = 1200000000, .pll_table = tegra_pll_m_table, .max_rate = 800000000, + .pll_lock_delay = 300, };static struct clk tegra_pll_m_out1 = {
@@ -1289,6 +1276,7 @@ static struct clk tegra_pll_p = { .vco_max = 1400000000, .pll_table = tegra_pll_p_table, .max_rate = 432000000, + .pll_lock_delay = 300, };static struct clk tegra_pll_p_out1 = {
@@ -1354,6 +1342,7 @@ static struct clk tegra_pll_a = { .vco_max = 1400000000, .pll_table = tegra_pll_a_table, .max_rate = 56448000, + .pll_lock_delay = 300, };static struct clk tegra_pll_a_out0 = {
@@ -1399,6 +1388,7 @@ static struct clk tegra_pll_d = { .vco_max = 1000000000, .pll_table = tegra_pll_d_table, .max_rate = 1000000000, + .pll_lock_delay = 1000, };static struct clk tegra_pll_d_out0 = {
@@ -1431,6 +1421,7 @@ static struct clk tegra_pll_u = { .vco_max = 960000000, .pll_table = tegra_pll_u_table, .max_rate = 480000000, + .pll_lock_delay = 1000, };static struct clk_pll_table tegra_pll_x_table[] = {
@@ -1493,6 +1484,7 @@ static struct clk tegra_pll_x = { .vco_max = 1200000000, .pll_table = tegra_pll_x_table, .max_rate = 1000000000, + .pll_lock_delay = 300, };static struct clk_pll_table tegra_pll_e_table[] = {
@@ -1966,7 +1958,6 @@ static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +void tegra_clk_suspend (void ) {unsigned long off, i; -u32 pllx_misc;u32 *ctx = clk_rst_suspend; *ctx++ =clk_readl (OSC_CTRL ) &OSC_CTRL_MASK ;
@@ -2007,10 +1998,6 @@ void tegra_clk_suspend(void) *ctx++ =clk_readl (MISC_CLK_ENB ); *ctx++ =clk_readl (CLK_MASK_ARM ); - - pllx_misc =clk_readl (tegra_pll_x.reg +PLL_MISC (&tegra_pll_x)); - pllx_misc &= ~PLL_MISC_LOCK_ENABLE (&tegra_pll_x); -clk_writel (pllx_misc, tegra_pll_x.reg +PLL_MISC (&tegra_pll_x)); }void tegra_clk_resume (void )
Signature · 1 line
1.7.3.1
Re: [PATCH v2 04/21] ARM: tegra: clock: Don't use PLL lock bits
Quoted 3 lines · Colin Cross
The PLL lock bits are not reliable, use per-PLL timeouts instead.
Signed-off-by Colin Cross <[email protected]>
PATCH v2 4/21 ARM: tegra: clock: Don't use PLL lock bits
In reply to Colin CrossThe PLL lock bits are not reliable, use per-PLL timeouts instead.
--- arch/arm/mach-tegra/clock.h | 2 +- arch/arm/mach-tegra/tegra2_clocks.c | 31 +++++++++---------------------- 2 files changed, 10 insertions(+), 23 deletions(-)
arch/arm/mach-tegra/clock.h +1 -1
@@ -53,7 +53,6 @@ struct dvfs_process_id_table {struct dvfs_table *table; }; -struct dvfs {struct regulator *reg;struct dvfs_table *table;
@@ -128,6 +127,7 @@ struct clk {unsigned long vco_min;unsigned long vco_max;const struct clk_pll_table *pll_table; +int pll_lock_delay;/* DIV */ u32 div;
arch/arm/mach-tegra/tegra2_clocks.c +9 -22
@@ -79,7 +79,6 @@#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)
@@ -94,7 +93,6 @@#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) ? (1<<22) : (1<<18))#define PLL_MISC_DCCON_SHIFT 20#define PLL_MISC_CPCON_SHIFT 8
@@ -546,17 +544,7 @@ static struct clk_ops tegra_blink_clk_ops = {/* PLL Functions */ static int tegra2_pll_clk_wait_for_lock (struct clk *c) { -ktime_t before; - - before =ktime_get (); - -while (!(clk_readl (c->reg +PLL_BASE ) &PLL_BASE_LOCK )) { -if (ktime_us_delta (ktime_get (), before) >5000 ) { -pr_err ("Timed out waiting for lock bit on pll %s" , - c->name); -return -1 ; - } - } +udelay (c->pll_lock_delay);return 0 ; }
@@ -594,10 +582,6 @@ static int tegra2_pll_clk_enable(struct clk *c) val |=PLL_BASE_ENABLE ;clk_writel (val, c->reg +PLL_BASE ); - val =clk_readl (c->reg +PLL_MISC (c)); - val |=PLL_MISC_LOCK_ENABLE (c); -clk_writel (val, c->reg +PLL_MISC (c)); -tegra2_pll_clk_wait_for_lock (c);return 0 ;
@@ -1177,6 +1161,7 @@ static struct clk tegra_pll_s = { .vco_max = 26000000, .pll_table = tegra_pll_s_table, .max_rate = 26000000, + .pll_lock_delay = 300, };static struct clk_mux_sel tegra_clk_m_sel[] = {
@@ -1213,6 +1198,7 @@ static struct clk tegra_pll_c = { .vco_max = 1400000000, .pll_table = tegra_pll_c_table, .max_rate = 600000000, + .pll_lock_delay = 300, };static struct clk tegra_pll_c_out1 = {
@@ -1251,6 +1237,7 @@ static struct clk tegra_pll_m = { .vco_max = 1200000000, .pll_table = tegra_pll_m_table, .max_rate = 800000000, + .pll_lock_delay = 300, };static struct clk tegra_pll_m_out1 = {
@@ -1289,6 +1276,7 @@ static struct clk tegra_pll_p = { .vco_max = 1400000000, .pll_table = tegra_pll_p_table, .max_rate = 432000000, + .pll_lock_delay = 300, };static struct clk tegra_pll_p_out1 = {
@@ -1354,6 +1342,7 @@ static struct clk tegra_pll_a = { .vco_max = 1400000000, .pll_table = tegra_pll_a_table, .max_rate = 56448000, + .pll_lock_delay = 300, };static struct clk tegra_pll_a_out0 = {
@@ -1399,6 +1388,7 @@ static struct clk tegra_pll_d = { .vco_max = 1000000000, .pll_table = tegra_pll_d_table, .max_rate = 1000000000, + .pll_lock_delay = 1000, };static struct clk tegra_pll_d_out0 = {
@@ -1431,6 +1421,7 @@ static struct clk tegra_pll_u = { .vco_max = 960000000, .pll_table = tegra_pll_u_table, .max_rate = 480000000, + .pll_lock_delay = 1000, };static struct clk_pll_table tegra_pll_x_table[] = {
@@ -1493,6 +1484,7 @@ static struct clk tegra_pll_x = { .vco_max = 1200000000, .pll_table = tegra_pll_x_table, .max_rate = 1000000000, + .pll_lock_delay = 300, };static struct clk_pll_table tegra_pll_e_table[] = {
@@ -1966,7 +1958,6 @@ static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +void tegra_clk_suspend (void ) {unsigned long off, i; -u32 pllx_misc;u32 *ctx = clk_rst_suspend; *ctx++ =clk_readl (OSC_CTRL ) &OSC_CTRL_MASK ;
@@ -2007,10 +1998,6 @@ void tegra_clk_suspend(void) *ctx++ =clk_readl (MISC_CLK_ENB ); *ctx++ =clk_readl (CLK_MASK_ARM ); - - pllx_misc =clk_readl (tegra_pll_x.reg +PLL_MISC (&tegra_pll_x)); - pllx_misc &= ~PLL_MISC_LOCK_ENABLE (&tegra_pll_x); -clk_writel (pllx_misc, tegra_pll_x.reg +PLL_MISC (&tegra_pll_x)); }void tegra_clk_resume (void )
Signature · 1 line
1.7.3.1
PATCH v2 5/21 ARM: tegra: clock: Disable clocks left on by bootloader
In reply to Colin CrossAdds CONFIG_TEGRA_DISABLE_BOOTLOADER_CLOCKS that iterates through all clocks, disabling any for which the refcount is 0 but the clock init detected the bootloader left the clock on.
--- arch/arm/mach-tegra/Kconfig | 6 ++++++ arch/arm/mach-tegra/clock.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/Kconfig +6 -0
@@ -57,6 +57,12 @@ config TEGRA_DEBUG_UARTE endchoice +config TEGRA_DISABLE_BOOTLOADER_CLOCKS + bool "Disable clocks left on by bootloader" + help + Disables clocks that are detected to be on but haven't + been requested by a kernel driver. + config TEGRA_SYSTEM_DMA bool "Enable system DMA driver for NVIDIA Tegra SoCs" default y
arch/arm/mach-tegra/clock.c +30 -0
@@ -511,6 +511,36 @@ int __init tegra_init_dvfs(void)late_initcall (tegra_init_dvfs); +/* +* Iterate through all clocks, disabling any for which the refcount is 0 +* but the clock init detected the bootloader left the clock on. +*/ +#ifdef CONFIG_TEGRA_DISABLE_BOOTLOADER_CLOCKS +int __init tegra_disable_boot_clocks (void ) +{ +unsigned long flags; + +struct clk *c; + +spin_lock_irqsave (&clock_lock, flags); + +list_for_each_entry (c, &clocks, node) { +if (c->refcnt ==0 && c->state ==ON && + c->ops && c->ops->disable) { +pr_warning ("Disabling clock %s left on by bootloader\n" , + c->name); + c->ops->disable (c); + c->state =OFF ; + } + } + +spin_unlock_irqrestore (&clock_lock, flags); + +return 0 ; +} +late_initcall (tegra_disable_boot_clocks); +#endif +#ifdef CONFIG_DEBUG_FS static struct dentry *clk_debugfs_root;
Signature · 1 line
1.7.3.1
Re: [PATCH v2 05/21] ARM: tegra: clock: Disable clocks left on by bootloader
Hi,
Quoted 4 lines · Colin Cross
Adds
CONFIG_TEGRA_DISABLE_BOOTLOADER_CLOCKSthat iterates through all clocks, disabling any for which the refcount is 0 but the clock init detected the bootloader left the clock on.
I would argue that any kernel functionality that relies on clocks being left on my bootloader is buggy, and/or should at least have those clocks enabled in the static clock tables for the boards in question, since it creates an undocumented dependency on firmware.
I would prefer if it disabled the clocks by default (after warning), but that there was a runtime way to override while debugging (i.e. add a bootarg 'keep_fwclocks' or similar to keep the firmware-enabled clocks running and just warn about them).
-Olof
Re: [PATCH v2 05/21] ARM: tegra: clock: Disable clocks left on by bootloader
Quoted 14 lines · Olof Johansson
Hi,
Quoted 4 lines · Colin Cross
Adds
CONFIG_TEGRA_DISABLE_BOOTLOADER_CLOCKSthat iterates through all clocks, disabling any for which the refcount is 0 but the clock init detected the bootloader left the clock on.I would argue that any kernel functionality that relies on clocks being left on my bootloader is buggy, and/or should at least have those clocks enabled in the static clock tables for the boards in question, since it creates an undocumented dependency on firmware.
Quoted 4 lines
I would prefer if it disabled the clocks by default (after warning), but that there was a runtime way to override while debugging (i.e. add a bootarg '
keep_fwclocks' or similar to keep the firmware-enabled clocks running and just warn about them).
That was the plan, but since many of the drivers are missing I didn't want to enable it by default yet. However, it turns out the problems I was seeing at boot from this patch were actually due to a bug in the clock code causing the cpu clock to be disabled for clocks that have no disable. I will drop this patch, and post a separate series after these that fixes the bug and turns off clocks by default, with a runtime argument like you suggested.
Re: [PATCH v2 05/21] ARM: tegra: clock: Disable clocks left on by bootloader
Quoted 20 lines · Colin Cross
Quoted 14 lines · Olof Johansson
Hi,
Quoted 4 lines · Colin Cross
Adds
CONFIG_TEGRA_DISABLE_BOOTLOADER_CLOCKSthat iterates through all clocks, disabling any for which the refcount is 0 but the clock init detected the bootloader left the clock on.I would argue that any kernel functionality that relies on clocks being left on my bootloader is buggy, and/or should at least have those clocks enabled in the static clock tables for the boards in question, since it creates an undocumented dependency on firmware.
Quoted 4 lines
I would prefer if it disabled the clocks by default (after warning), but that there was a runtime way to override while debugging (i.e. add a bootarg '
keep_fwclocks' or similar to keep the firmware-enabled clocks running and just warn about them).
Quoted 7 lines
That was the plan, but since many of the drivers are missing I didn't want to enable it by default yet. ?However, it turns out the problems I was seeing at boot from this patch were actually due to a bug in the clock code causing the cpu clock to be disabled for clocks that have no disable. ?I will drop this patch, and post a separate series after these that fixes the bug and turns off clocks by default, with a runtime argument like you suggested.
Sounds good. Alternatively, this can go in and be revisited with the above proposed changes; both approaches would be OK with me.
-Olof
PATCH v2 5/21 ARM: tegra: clock: Disable clocks left on by bootloader
In reply to Colin CrossAdds CONFIG_TEGRA_DISABLE_BOOTLOADER_CLOCKS that iterates through all clocks, disabling any for which the refcount is 0 but the clock init detected the bootloader left the clock on.
--- arch/arm/mach-tegra/Kconfig | 6 ++++++ arch/arm/mach-tegra/clock.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/Kconfig +6 -0
@@ -57,6 +57,12 @@ config TEGRA_DEBUG_UARTE endchoice +config TEGRA_DISABLE_BOOTLOADER_CLOCKS + bool "Disable clocks left on by bootloader" + help + Disables clocks that are detected to be on but haven't + been requested by a kernel driver. + config TEGRA_SYSTEM_DMA bool "Enable system DMA driver for NVIDIA Tegra SoCs" default y
arch/arm/mach-tegra/clock.c +30 -0
@@ -511,6 +511,36 @@ int __init tegra_init_dvfs(void)late_initcall (tegra_init_dvfs); +/* +* Iterate through all clocks, disabling any for which the refcount is 0 +* but the clock init detected the bootloader left the clock on. +*/ +#ifdef CONFIG_TEGRA_DISABLE_BOOTLOADER_CLOCKS +int __init tegra_disable_boot_clocks (void ) +{ +unsigned long flags; + +struct clk *c; + +spin_lock_irqsave (&clock_lock, flags); + +list_for_each_entry (c, &clocks, node) { +if (c->refcnt ==0 && c->state ==ON && + c->ops && c->ops->disable) { +pr_warning ("Disabling clock %s left on by bootloader\n" , + c->name); + c->ops->disable (c); + c->state =OFF ; + } + } + +spin_unlock_irqrestore (&clock_lock, flags); + +return 0 ; +} +late_initcall (tegra_disable_boot_clocks); +#endif +#ifdef CONFIG_DEBUG_FS static struct dentry *clk_debugfs_root;
Signature · 1 line
1.7.3.1
PATCH v2 5/21 ARM: tegra: clock: Disable clocks left on by bootloader
In reply to Colin CrossAdds CONFIG_TEGRA_DISABLE_BOOTLOADER_CLOCKS that iterates through all clocks, disabling any for which the refcount is 0 but the clock init detected the bootloader left the clock on.
--- arch/arm/mach-tegra/Kconfig | 6 ++++++ arch/arm/mach-tegra/clock.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/Kconfig +6 -0
@@ -57,6 +57,12 @@ config TEGRA_DEBUG_UARTE endchoice +config TEGRA_DISABLE_BOOTLOADER_CLOCKS + bool "Disable clocks left on by bootloader" + help + Disables clocks that are detected to be on but haven't + been requested by a kernel driver. + config TEGRA_SYSTEM_DMA bool "Enable system DMA driver for NVIDIA Tegra SoCs" default y
arch/arm/mach-tegra/clock.c +30 -0
@@ -511,6 +511,36 @@ int __init tegra_init_dvfs(void)late_initcall (tegra_init_dvfs); +/* +* Iterate through all clocks, disabling any for which the refcount is 0 +* but the clock init detected the bootloader left the clock on. +*/ +#ifdef CONFIG_TEGRA_DISABLE_BOOTLOADER_CLOCKS +int __init tegra_disable_boot_clocks (void ) +{ +unsigned long flags; + +struct clk *c; + +spin_lock_irqsave (&clock_lock, flags); + +list_for_each_entry (c, &clocks, node) { +if (c->refcnt ==0 && c->state ==ON && + c->ops && c->ops->disable) { +pr_warning ("Disabling clock %s left on by bootloader\n" , + c->name); + c->ops->disable (c); + c->state =OFF ; + } + } + +spin_unlock_irqrestore (&clock_lock, flags); + +return 0 ; +} +late_initcall (tegra_disable_boot_clocks); +#endif +#ifdef CONFIG_DEBUG_FS static struct dentry *clk_debugfs_root;
Signature · 1 line
1.7.3.1
PATCH v2 6/21 ARM: tegra: clock: Initialize clocks that have no enable
In reply to Colin CrossAssume that any clock that has no enable op is always on.
--- arch/arm/mach-tegra/clock.c | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/clock.c +9 -0
@@ -166,6 +166,15 @@ void clk_init(struct clk *c)if (c->ops && c->ops->init) c->ops->init (c); +if (!c->ops || !c->ops->enable) { + c->refcnt++; + c->set =1 ; +if (c->parent) + c->state = c->parent->state; +else + c->state =ON ; + } +clk_recalculate_rate (c);list_add (&c->node, &clocks);
Signature · 1 line
1.7.3.1
Re: [PATCH v2 06/21] ARM: tegra: clock: Initialize clocks that have no enable
Quoted 3 lines · Colin Cross
Assume that any clock that has no enable op is always on.
Signed-off-by Colin Cross <[email protected]>
PATCH v2 6/21 ARM: tegra: clock: Initialize clocks that have no enable
In reply to Colin CrossAssume that any clock that has no enable op is always on.
--- arch/arm/mach-tegra/clock.c | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/clock.c +9 -0
@@ -166,6 +166,15 @@ void clk_init(struct clk *c)if (c->ops && c->ops->init) c->ops->init (c); +if (!c->ops || !c->ops->enable) { + c->refcnt++; + c->set =1 ; +if (c->parent) + c->state = c->parent->state; +else + c->state =ON ; + } +clk_recalculate_rate (c);list_add (&c->node, &clocks);
Signature · 1 line
1.7.3.1
PATCH v2 7/21 ARM: tegra: clock: Drop CPU dvfs
In reply to Colin CrossThe existing version did not extend well to core dvfs, drop it for now until the new clk api with clk_prepare and clk_unprepare is ready and non-atomic clocks are possible.
--- arch/arm/mach-tegra/Makefile | 1 - arch/arm/mach-tegra/clock.c | 159 +------------------------------- arch/arm/mach-tegra/clock.h | 24 ----- arch/arm/mach-tegra/cpu-tegra.c | 2 +- arch/arm/mach-tegra/include/mach/clk.h | 5 - arch/arm/mach-tegra/tegra2_clocks.c | 2 - arch/arm/mach-tegra/tegra2_dvfs.c | 86 ----------------- arch/arm/mach-tegra/tegra2_dvfs.h | 20 ---- 8 files changed, 2 insertions(+), 297 deletions(-) delete mode 100644 arch/arm/mach-tegra/tegra2_dvfs.c delete mode 100644 arch/arm/mach-tegra/tegra2_dvfs.h
arch/arm/mach-tegra/Makefile +0 -1
@@ -9,7 +9,6 @@ obj-y += powergate.o obj-y += fuse.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clock.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o -obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_dvfs.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-t2-tables.o obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
arch/arm/mach-tegra/clock.c +1 -158
210 lines not on this page · raw message
arch/arm/mach-tegra/clock.h +0 -24
@@ -41,28 +41,6 @@#define ENABLE_ON_INIT (1 << 28)struct clk ; -struct regulator ; - -struct dvfs_table { -unsigned long rate; -int millivolts; -}; - -struct dvfs_process_id_table { -int process_id; -struct dvfs_table *table; -}; - -struct dvfs { -struct regulator *reg; -struct dvfs_table *table; -int max_millivolts; - -int process_id_table_length; -const char *reg_id; -bool cpu; -struct dvfs_process_id_table process_id_table[]; -};struct clk_mux_sel {struct clk *input;
@@ -141,8 +119,6 @@ struct clk {/* Virtual cpu clock */ struct clk *main;struct clk *backup; - -struct dvfs *dvfs; };
arch/arm/mach-tegra/cpu-tegra.c +1 -1
@@ -91,7 +91,7 @@ static int tegra_update_cpu_speed(unsigned long rate) freqs.old, freqs.new);#endif - ret =clk_set_rate_cansleep (cpu_clk, freqs.new *1000 ); + ret =clk_set_rate (cpu_clk, freqs.new *1000 );if (ret) {pr_err ("cpu-tegra: Failed to set cpu frequency to %d kHz\n" , freqs.new);
arch/arm/mach-tegra/include/mach/clk.h +0 -5
@@ -25,9 +25,4 @@ struct clk;void tegra_periph_reset_deassert (struct clk *c);void tegra_periph_reset_assert (struct clk *c); -int clk_enable_cansleep (struct clk *clk); -void clk_disable_cansleep (struct clk *clk); -int clk_set_rate_cansleep (struct clk *clk,unsigned long rate); -int clk_set_parent_cansleep (struct clk *clk,struct clk *parent); -#endif
arch/arm/mach-tegra/tegra2_clocks.c +0 -2
@@ -31,7 +31,6 @@#include "clock.h" #include "fuse.h" -#include "tegra2_dvfs.h" #define RST_DEVICES 0x004#define RST_DEVICES_SET 0x300
@@ -1650,7 +1649,6 @@ static struct clk tegra_clk_virtual_cpu = { .backup = &tegra_pll_p, .ops = &tegra_cpu_ops, .max_rate = 1000000000, - .dvfs = &tegra_dvfs_virtual_cpu_dvfs, };static struct clk tegra_clk_hclk = {
arch/arm/mach-tegra/tegra2_dvfs.c deleted +0 -86
86 lines not on this page · raw message
arch/arm/mach-tegra/tegra2_dvfs.h deleted +0 -20
@@ -1,20 +0,0 @@ -/* -* arch/arm/mach-tegra/tegra2_dvfs.h -* -* Copyright (C) 2010 Google, Inc. -* -* Author: -* Colin Cross <[email protected]> -* -* 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. -* -*/ - -extern struct dvfs tegra_dvfs_virtual_cpu_dvfs;
Signature · 1 line
1.7.3.1
Re: [PATCH v2 07/21] ARM: tegra: clock: Drop CPU dvfs
Quoted 5 lines · Colin Cross
The existing version did not extend well to core dvfs, drop it for now until the new clk api with
clk_prepareandclk_unprepareis ready and non-atomic clocks are possible.Signed-off-by Colin Cross <[email protected]>
PATCH v2 7/21 ARM: tegra: clock: Drop CPU dvfs
In reply to Colin CrossThe existing version did not extend well to core dvfs, drop it for now until the new clk api with clk_prepare and clk_unprepare is ready and non-atomic clocks are possible.
--- arch/arm/mach-tegra/Makefile | 1 - arch/arm/mach-tegra/clock.c | 159 +------------------------------- arch/arm/mach-tegra/clock.h | 24 ----- arch/arm/mach-tegra/cpu-tegra.c | 2 +- arch/arm/mach-tegra/include/mach/clk.h | 5 - arch/arm/mach-tegra/tegra2_clocks.c | 2 - arch/arm/mach-tegra/tegra2_dvfs.c | 86 ----------------- arch/arm/mach-tegra/tegra2_dvfs.h | 20 ---- 8 files changed, 2 insertions(+), 297 deletions(-) delete mode 100644 arch/arm/mach-tegra/tegra2_dvfs.c delete mode 100644 arch/arm/mach-tegra/tegra2_dvfs.h
arch/arm/mach-tegra/Makefile +0 -1
@@ -9,7 +9,6 @@ obj-y += powergate.o obj-y += fuse.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clock.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o -obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_dvfs.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-t2-tables.o obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
arch/arm/mach-tegra/clock.c +1 -158
210 lines not on this page · raw message
arch/arm/mach-tegra/clock.h +0 -24
@@ -41,28 +41,6 @@#define ENABLE_ON_INIT (1 << 28)struct clk ; -struct regulator ; - -struct dvfs_table { -unsigned long rate; -int millivolts; -}; - -struct dvfs_process_id_table { -int process_id; -struct dvfs_table *table; -}; - -struct dvfs { -struct regulator *reg; -struct dvfs_table *table; -int max_millivolts; - -int process_id_table_length; -const char *reg_id; -bool cpu; -struct dvfs_process_id_table process_id_table[]; -};struct clk_mux_sel {struct clk *input;
@@ -141,8 +119,6 @@ struct clk {/* Virtual cpu clock */ struct clk *main;struct clk *backup; - -struct dvfs *dvfs; };
arch/arm/mach-tegra/cpu-tegra.c +1 -1
@@ -91,7 +91,7 @@ static int tegra_update_cpu_speed(unsigned long rate) freqs.old, freqs.new);#endif - ret =clk_set_rate_cansleep (cpu_clk, freqs.new *1000 ); + ret =clk_set_rate (cpu_clk, freqs.new *1000 );if (ret) {pr_err ("cpu-tegra: Failed to set cpu frequency to %d kHz\n" , freqs.new);
arch/arm/mach-tegra/include/mach/clk.h +0 -5
@@ -25,9 +25,4 @@ struct clk;void tegra_periph_reset_deassert (struct clk *c);void tegra_periph_reset_assert (struct clk *c); -int clk_enable_cansleep (struct clk *clk); -void clk_disable_cansleep (struct clk *clk); -int clk_set_rate_cansleep (struct clk *clk,unsigned long rate); -int clk_set_parent_cansleep (struct clk *clk,struct clk *parent); -#endif
arch/arm/mach-tegra/tegra2_clocks.c +0 -2
@@ -31,7 +31,6 @@#include "clock.h" #include "fuse.h" -#include "tegra2_dvfs.h" #define RST_DEVICES 0x004#define RST_DEVICES_SET 0x300
@@ -1650,7 +1649,6 @@ static struct clk tegra_clk_virtual_cpu = { .backup = &tegra_pll_p, .ops = &tegra_cpu_ops, .max_rate = 1000000000, - .dvfs = &tegra_dvfs_virtual_cpu_dvfs, };static struct clk tegra_clk_hclk = {
arch/arm/mach-tegra/tegra2_dvfs.c deleted +0 -86
86 lines not on this page · raw message
arch/arm/mach-tegra/tegra2_dvfs.h deleted +0 -20
@@ -1,20 +0,0 @@ -/* -* arch/arm/mach-tegra/tegra2_dvfs.h -* -* Copyright (C) 2010 Google, Inc. -* -* Author: -* Colin Cross <[email protected]> -* -* 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. -* -*/ - -extern struct dvfs tegra_dvfs_virtual_cpu_dvfs;
Signature · 1 line
1.7.3.1
PATCH v2 8/21 ARM: tegra: clock: Rearrange static clock tables
In reply to Colin CrossMake the static clocks look more like the array of clocks so they can all be initalized with the same helper function.
--- arch/arm/mach-tegra/tegra2_clocks.c | 106 +++++++++++++++++------------------ 1 files changed, 51 insertions(+), 55 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +51 -55
@@ -1770,7 +1770,7 @@ static struct clk_mux_sel mux_clk_32k[] = { .max_rate = _max, \ } -struct clk tegra_periph_clks[] = { +struct clk tegra_list_clks[] = {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" ,"i2s.0" ,NULL ,11 ,0x100 ,26000000 , mux_pllaout0_audio2x_pllp_clkm,MUX |DIV_U71 ),
@@ -1879,71 +1879,67 @@ struct clk_duplicate tegra_clk_duplicates[] = { .clk = ck, \ } -struct clk_lookup tegra_clk_lookups[] = { -/* external root sources */ -CLK (NULL ,"32k_clk" , &tegra_clk_32k), -CLK (NULL ,"pll_s" , &tegra_pll_s), -CLK (NULL ,"clk_m" , &tegra_clk_m), -CLK (NULL ,"pll_m" , &tegra_pll_m), -CLK (NULL ,"pll_m_out1" , &tegra_pll_m_out1), -CLK (NULL ,"pll_c" , &tegra_pll_c), -CLK (NULL ,"pll_c_out1" , &tegra_pll_c_out1), -CLK (NULL ,"pll_p" , &tegra_pll_p), -CLK (NULL ,"pll_p_out1" , &tegra_pll_p_out1), -CLK (NULL ,"pll_p_out2" , &tegra_pll_p_out2), -CLK (NULL ,"pll_p_out3" , &tegra_pll_p_out3), -CLK (NULL ,"pll_p_out4" , &tegra_pll_p_out4), -CLK (NULL ,"pll_a" , &tegra_pll_a), -CLK (NULL ,"pll_a_out0" , &tegra_pll_a_out0), -CLK (NULL ,"pll_d" , &tegra_pll_d), -CLK (NULL ,"pll_d_out0" , &tegra_pll_d_out0), -CLK (NULL ,"pll_u" , &tegra_pll_u), -CLK (NULL ,"pll_x" , &tegra_pll_x), -CLK (NULL ,"pll_e" , &tegra_pll_e), -CLK (NULL ,"cclk" , &tegra_clk_cclk), -CLK (NULL ,"sclk" , &tegra_clk_sclk), -CLK (NULL ,"hclk" , &tegra_clk_hclk), -CLK (NULL ,"pclk" , &tegra_clk_pclk), -CLK (NULL ,"clk_d" , &tegra_clk_d), -CLK (NULL ,"clk_dev1" , &tegra_dev1_clk), -CLK (NULL ,"clk_dev2" , &tegra_dev2_clk), -CLK (NULL ,"cpu" , &tegra_clk_virtual_cpu), -CLK (NULL ,"blink" , &tegra_clk_blink), -}; +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_clk_cclk, + &tegra_clk_sclk, + &tegra_clk_hclk, + &tegra_clk_pclk, + &tegra_clk_d, + &tegra_dev1_clk, + &tegra_dev2_clk, + &tegra_clk_virtual_cpu, + &tegra_clk_blink, +}; + +static void tegra2_init_one_clock (struct clk *c) +{ +clk_init (c); +if (!c->lookup.dev_id && !c->lookup.con_id) + c->lookup.con_id = c->name; + c->lookup.clk = c; +clkdev_add (&c->lookup); +}void __init tegra2_init_clocks (void ) {int i; -struct clk_lookup *cl;struct clk *c; -struct clk_duplicate *cd; - -for (i =0 ; i <ARRAY_SIZE (tegra_clk_lookups); i++) { - cl = &tegra_clk_lookups[i]; -clk_init (cl->clk); -clkdev_add (cl); - } -for (i =0 ; i <ARRAY_SIZE (tegra_periph_clks); i++) { - c = &tegra_periph_clks[i]; - cl = &c->lookup; - cl->clk = c; +for (i =0 ; i <ARRAY_SIZE (tegra_ptr_clks); i++) +tegra2_init_one_clock (tegra_ptr_clks[i]); -clk_init (cl->clk); -clkdev_add (cl); - } +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++) { - cd = &tegra_clk_duplicates[i]; - c =tegra_get_clock_by_name (cd->name); -if (c) { - cl = &cd->lookup; - cl->clk = c; -clkdev_add (cl); - }else { + c =tegra_get_clock_by_name (tegra_clk_duplicates[i].name); +if (!c) {pr_err ("%s: Unknown duplicate clock %s\n" , __func__, - cd->name); + 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 ();
Signature · 1 line
1.7.3.1
Re: [PATCH v2 08/21] ARM: tegra: clock: Rearrange static clock tables
Quoted 4 lines · Colin Cross
Make the static clocks look more like the array of clocks so they can all be initalized with the same helper function.
Signed-off-by Colin Cross <[email protected]>
PATCH v2 8/21 ARM: tegra: clock: Rearrange static clock tables
In reply to Colin CrossMake the static clocks look more like the array of clocks so they can all be initalized with the same helper function.
--- arch/arm/mach-tegra/tegra2_clocks.c | 106 +++++++++++++++++------------------ 1 files changed, 51 insertions(+), 55 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +51 -55
@@ -1770,7 +1770,7 @@ static struct clk_mux_sel mux_clk_32k[] = { .max_rate = _max, \ } -struct clk tegra_periph_clks[] = { +struct clk tegra_list_clks[] = {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" ,"i2s.0" ,NULL ,11 ,0x100 ,26000000 , mux_pllaout0_audio2x_pllp_clkm,MUX |DIV_U71 ),
@@ -1879,71 +1879,67 @@ struct clk_duplicate tegra_clk_duplicates[] = { .clk = ck, \ } -struct clk_lookup tegra_clk_lookups[] = { -/* external root sources */ -CLK (NULL ,"32k_clk" , &tegra_clk_32k), -CLK (NULL ,"pll_s" , &tegra_pll_s), -CLK (NULL ,"clk_m" , &tegra_clk_m), -CLK (NULL ,"pll_m" , &tegra_pll_m), -CLK (NULL ,"pll_m_out1" , &tegra_pll_m_out1), -CLK (NULL ,"pll_c" , &tegra_pll_c), -CLK (NULL ,"pll_c_out1" , &tegra_pll_c_out1), -CLK (NULL ,"pll_p" , &tegra_pll_p), -CLK (NULL ,"pll_p_out1" , &tegra_pll_p_out1), -CLK (NULL ,"pll_p_out2" , &tegra_pll_p_out2), -CLK (NULL ,"pll_p_out3" , &tegra_pll_p_out3), -CLK (NULL ,"pll_p_out4" , &tegra_pll_p_out4), -CLK (NULL ,"pll_a" , &tegra_pll_a), -CLK (NULL ,"pll_a_out0" , &tegra_pll_a_out0), -CLK (NULL ,"pll_d" , &tegra_pll_d), -CLK (NULL ,"pll_d_out0" , &tegra_pll_d_out0), -CLK (NULL ,"pll_u" , &tegra_pll_u), -CLK (NULL ,"pll_x" , &tegra_pll_x), -CLK (NULL ,"pll_e" , &tegra_pll_e), -CLK (NULL ,"cclk" , &tegra_clk_cclk), -CLK (NULL ,"sclk" , &tegra_clk_sclk), -CLK (NULL ,"hclk" , &tegra_clk_hclk), -CLK (NULL ,"pclk" , &tegra_clk_pclk), -CLK (NULL ,"clk_d" , &tegra_clk_d), -CLK (NULL ,"clk_dev1" , &tegra_dev1_clk), -CLK (NULL ,"clk_dev2" , &tegra_dev2_clk), -CLK (NULL ,"cpu" , &tegra_clk_virtual_cpu), -CLK (NULL ,"blink" , &tegra_clk_blink), -}; +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_clk_cclk, + &tegra_clk_sclk, + &tegra_clk_hclk, + &tegra_clk_pclk, + &tegra_clk_d, + &tegra_dev1_clk, + &tegra_dev2_clk, + &tegra_clk_virtual_cpu, + &tegra_clk_blink, +}; + +static void tegra2_init_one_clock (struct clk *c) +{ +clk_init (c); +if (!c->lookup.dev_id && !c->lookup.con_id) + c->lookup.con_id = c->name; + c->lookup.clk = c; +clkdev_add (&c->lookup); +}void __init tegra2_init_clocks (void ) {int i; -struct clk_lookup *cl;struct clk *c; -struct clk_duplicate *cd; - -for (i =0 ; i <ARRAY_SIZE (tegra_clk_lookups); i++) { - cl = &tegra_clk_lookups[i]; -clk_init (cl->clk); -clkdev_add (cl); - } -for (i =0 ; i <ARRAY_SIZE (tegra_periph_clks); i++) { - c = &tegra_periph_clks[i]; - cl = &c->lookup; - cl->clk = c; +for (i =0 ; i <ARRAY_SIZE (tegra_ptr_clks); i++) +tegra2_init_one_clock (tegra_ptr_clks[i]); -clk_init (cl->clk); -clkdev_add (cl); - } +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++) { - cd = &tegra_clk_duplicates[i]; - c =tegra_get_clock_by_name (cd->name); -if (c) { - cl = &cd->lookup; - cl->clk = c; -clkdev_add (cl); - }else { + c =tegra_get_clock_by_name (tegra_clk_duplicates[i].name); +if (!c) {pr_err ("%s: Unknown duplicate clock %s\n" , __func__, - cd->name); + 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 ();
Signature · 1 line
1.7.3.1
PATCH v2 8/21 ARM: tegra: clock: Rearrange static clock tables
In reply to Colin CrossMake the static clocks look more like the array of clocks so they can all be initalized with the same helper function.
--- arch/arm/mach-tegra/tegra2_clocks.c | 106 +++++++++++++++++------------------ 1 files changed, 51 insertions(+), 55 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +51 -55
@@ -1770,7 +1770,7 @@ static struct clk_mux_sel mux_clk_32k[] = { .max_rate = _max, \ } -struct clk tegra_periph_clks[] = { +struct clk tegra_list_clks[] = {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" ,"i2s.0" ,NULL ,11 ,0x100 ,26000000 , mux_pllaout0_audio2x_pllp_clkm,MUX |DIV_U71 ),
@@ -1879,71 +1879,67 @@ struct clk_duplicate tegra_clk_duplicates[] = { .clk = ck, \ } -struct clk_lookup tegra_clk_lookups[] = { -/* external root sources */ -CLK (NULL ,"32k_clk" , &tegra_clk_32k), -CLK (NULL ,"pll_s" , &tegra_pll_s), -CLK (NULL ,"clk_m" , &tegra_clk_m), -CLK (NULL ,"pll_m" , &tegra_pll_m), -CLK (NULL ,"pll_m_out1" , &tegra_pll_m_out1), -CLK (NULL ,"pll_c" , &tegra_pll_c), -CLK (NULL ,"pll_c_out1" , &tegra_pll_c_out1), -CLK (NULL ,"pll_p" , &tegra_pll_p), -CLK (NULL ,"pll_p_out1" , &tegra_pll_p_out1), -CLK (NULL ,"pll_p_out2" , &tegra_pll_p_out2), -CLK (NULL ,"pll_p_out3" , &tegra_pll_p_out3), -CLK (NULL ,"pll_p_out4" , &tegra_pll_p_out4), -CLK (NULL ,"pll_a" , &tegra_pll_a), -CLK (NULL ,"pll_a_out0" , &tegra_pll_a_out0), -CLK (NULL ,"pll_d" , &tegra_pll_d), -CLK (NULL ,"pll_d_out0" , &tegra_pll_d_out0), -CLK (NULL ,"pll_u" , &tegra_pll_u), -CLK (NULL ,"pll_x" , &tegra_pll_x), -CLK (NULL ,"pll_e" , &tegra_pll_e), -CLK (NULL ,"cclk" , &tegra_clk_cclk), -CLK (NULL ,"sclk" , &tegra_clk_sclk), -CLK (NULL ,"hclk" , &tegra_clk_hclk), -CLK (NULL ,"pclk" , &tegra_clk_pclk), -CLK (NULL ,"clk_d" , &tegra_clk_d), -CLK (NULL ,"clk_dev1" , &tegra_dev1_clk), -CLK (NULL ,"clk_dev2" , &tegra_dev2_clk), -CLK (NULL ,"cpu" , &tegra_clk_virtual_cpu), -CLK (NULL ,"blink" , &tegra_clk_blink), -}; +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_clk_cclk, + &tegra_clk_sclk, + &tegra_clk_hclk, + &tegra_clk_pclk, + &tegra_clk_d, + &tegra_dev1_clk, + &tegra_dev2_clk, + &tegra_clk_virtual_cpu, + &tegra_clk_blink, +}; + +static void tegra2_init_one_clock (struct clk *c) +{ +clk_init (c); +if (!c->lookup.dev_id && !c->lookup.con_id) + c->lookup.con_id = c->name; + c->lookup.clk = c; +clkdev_add (&c->lookup); +}void __init tegra2_init_clocks (void ) {int i; -struct clk_lookup *cl;struct clk *c; -struct clk_duplicate *cd; - -for (i =0 ; i <ARRAY_SIZE (tegra_clk_lookups); i++) { - cl = &tegra_clk_lookups[i]; -clk_init (cl->clk); -clkdev_add (cl); - } -for (i =0 ; i <ARRAY_SIZE (tegra_periph_clks); i++) { - c = &tegra_periph_clks[i]; - cl = &c->lookup; - cl->clk = c; +for (i =0 ; i <ARRAY_SIZE (tegra_ptr_clks); i++) +tegra2_init_one_clock (tegra_ptr_clks[i]); -clk_init (cl->clk); -clkdev_add (cl); - } +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++) { - cd = &tegra_clk_duplicates[i]; - c =tegra_get_clock_by_name (cd->name); -if (c) { - cl = &cd->lookup; - cl->clk = c; -clkdev_add (cl); - }else { + c =tegra_get_clock_by_name (tegra_clk_duplicates[i].name); +if (!c) {pr_err ("%s: Unknown duplicate clock %s\n" , __func__, - cd->name); + 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 ();
Signature · 1 line
1.7.3.1
PATCH v2 9/21 ARM: tegra: clock: Move unshared clk struct members into union
In reply to Colin Cross--- arch/arm/mach-tegra/clock.h | 85 +++++++------ arch/arm/mach-tegra/tegra2_clocks.c | 234 ++++++++++++++++++++--------------- 2 files changed, 176 insertions(+), 143 deletions(-)
arch/arm/mach-tegra/clock.h +44 -41
@@ -47,7 +47,7 @@ struct clk_mux_sel {u32 value; }; -struct clk_pll_table { +struct clk_pll_freq_table {unsigned long input_rate;unsigned long output_rate;u16 n;
@@ -74,51 +74,54 @@ enum clk_state {struct clk {/* node for master clocks list */ -struct list_head node; -struct list_head children;/* list of children */ -struct list_head sibling;/* node for children */ -#ifdef CONFIG_DEBUG_FS -struct dentry *dent; -struct dentry *parent_dent; -#endif -struct clk_ops *ops; -struct clk *parent; -struct clk_lookup lookup; -unsigned long rate; -unsigned long max_rate; -u32 flags; -u32 refcnt; -const char *name; -u32 reg; -u32 reg_shift; -unsigned int clk_num; -enum clk_state state; +struct list_head node;/* node for list of all clocks */ +struct list_head children;/* list of children */ +struct list_head sibling;/* node for children */ +struct clk_lookup lookup; +#ifdef CONFIG_DEBUG_FS -bool set; +struct dentry *dent; +bool set;#endif +struct clk_ops *ops; +unsigned long rate; +unsigned long max_rate; +u32 flags; +const char *name; + +u32 refcnt; +enum clk_state state; +struct clk *parent; +u32 div; +u32 mul; -/* PLL */ -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_table *pll_table; -int pll_lock_delay; - -/* DIV */ -u32 div; -u32 mul; - -/* MUX */ const struct clk_mux_sel *inputs; -u32 sel; -u32 reg_mask; +u32 reg; +u32 reg_shift; -/* Virtual cpu clock */ -struct clk *main; -struct clk *backup; +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; + } pll; +struct { +u32 sel; +u32 reg_mask; + } mux; +struct { +struct clk *main; +struct clk *backup; + } cpu; + } u; };
arch/arm/mach-tegra/tegra2_clocks.c +132 -102
451 lines not on this page · raw message
Signature · 1 line
1.7.3.1
Re: [PATCH v2 09/21] ARM: tegra: clock: Move unshared clk struct members into union
Quoted 1 line · Colin Cross
Signed-off-by Colin Cross <[email protected]>
Same here, short description. With that:
Re: [PATCH v2 09/21] ARM: tegra: clock: Move unshared clk struct members into union
Quoted 7 lines · Olof Johansson
Quoted 1 line · Colin Cross
Signed-off-by Colin Cross <[email protected]>Same here, short description. With that:
Acked-by Olof Johansson <[email protected]>
I will add:
Creates a union of a struct for each type of clock to reduce memory usage and clarify which members are used by all clocks and which are used by a single type.
PATCH v2 9/21 ARM: tegra: clock: Move unshared clk struct members into union
In reply to Colin Cross--- arch/arm/mach-tegra/clock.h | 85 +++++++------ arch/arm/mach-tegra/tegra2_clocks.c | 234 ++++++++++++++++++++--------------- 2 files changed, 176 insertions(+), 143 deletions(-)
arch/arm/mach-tegra/clock.h +44 -41
@@ -47,7 +47,7 @@ struct clk_mux_sel {u32 value; }; -struct clk_pll_table { +struct clk_pll_freq_table {unsigned long input_rate;unsigned long output_rate;u16 n;
@@ -74,51 +74,54 @@ enum clk_state {struct clk {/* node for master clocks list */ -struct list_head node; -struct list_head children;/* list of children */ -struct list_head sibling;/* node for children */ -#ifdef CONFIG_DEBUG_FS -struct dentry *dent; -struct dentry *parent_dent; -#endif -struct clk_ops *ops; -struct clk *parent; -struct clk_lookup lookup; -unsigned long rate; -unsigned long max_rate; -u32 flags; -u32 refcnt; -const char *name; -u32 reg; -u32 reg_shift; -unsigned int clk_num; -enum clk_state state; +struct list_head node;/* node for list of all clocks */ +struct list_head children;/* list of children */ +struct list_head sibling;/* node for children */ +struct clk_lookup lookup; +#ifdef CONFIG_DEBUG_FS -bool set; +struct dentry *dent; +bool set;#endif +struct clk_ops *ops; +unsigned long rate; +unsigned long max_rate; +u32 flags; +const char *name; + +u32 refcnt; +enum clk_state state; +struct clk *parent; +u32 div; +u32 mul; -/* PLL */ -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_table *pll_table; -int pll_lock_delay; - -/* DIV */ -u32 div; -u32 mul; - -/* MUX */ const struct clk_mux_sel *inputs; -u32 sel; -u32 reg_mask; +u32 reg; +u32 reg_shift; -/* Virtual cpu clock */ -struct clk *main; -struct clk *backup; +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; + } pll; +struct { +u32 sel; +u32 reg_mask; + } mux; +struct { +struct clk *main; +struct clk *backup; + } cpu; + } u; };
arch/arm/mach-tegra/tegra2_clocks.c +132 -102
451 lines not on this page · raw message
Signature · 1 line
1.7.3.1
PATCH v2 10/21 ARM: tegra: clock: Convert global lock to a lock per clock
In reply to Colin CrossGive each clock its own lock, and remove all lock traversals from parent to child clocks to prevent AB-BA deadlocks.
This brings the locking in line with the common struct clk patches and should make conversion simple.
--- arch/arm/mach-tegra/clock.c | 358 ++++++++++++++++++++------------ arch/arm/mach-tegra/clock.h | 14 +- arch/arm/mach-tegra/include/mach/clk.h | 1 + arch/arm/mach-tegra/tegra2_clocks.c | 119 ++++++++--- 4 files changed, 322 insertions(+), 170 deletions(-)
arch/arm/mach-tegra/clock.c +230 -128
@@ -18,83 +18,117 @@#include <linux/kernel.h> #include <linux/clk.h> -#include <linux/list.h> +#include <linux/clkdev.h> +#include <linux/debugfs.h> +#include <linux/delay.h> #include <linux/init.h> +#include <linux/list.h> #include <linux/module.h> -#include <linux/debugfs.h> -#include <linux/slab.h> +#include <linux/sched.h> #include <linux/seq_file.h> -#include <linux/clkdev.h> +#include <linux/slab.h> + +#include <mach/clk.h> #include "board.h" #include "clock.h" +/* +* Locking: +* +* Each struct clk has a spinlock. +* +* To avoid AB-BA locking problems, locks must always be traversed from child +* clock to parent clock. For example, when enabling a clock, the clock's lock +* is taken, and then clk_enable is called on the parent, which take's the +* parent clock's lock. There is one exceptions to this ordering: When dumping +* the clock tree through debugfs. In this case, clk_lock_all is called, +* which attemps to iterate through the entire list of clocks and take every +* clock lock. If any call to spin_trylock fails, all locked clocks are +* unlocked, and the process is retried. When all the locks are held, +* the only clock operation that can be called is clk_get_rate_all_locked. +* +* Within a single clock, no clock operation can call another clock operation +* on itself, except for clk_get_rate_locked and clk_set_rate_locked. Any +* clock operation can call any other clock operation on any of it's possible +* parents. +* +* An additional mutex, clock_list_lock, is used to protect the list of all +* clocks. +* +* The clock operations must lock internally to protect against +* read-modify-write on registers that are shared by multiple clocks +*/ +static DEFINE_MUTEX (clock_list_lock);static LIST_HEAD (clocks); -static DEFINE_SPINLOCK (clock_lock);struct clk *tegra_get_clock_by_name (const char *name) {struct clk *c;struct clk *ret =NULL ; -unsigned long flags; -spin_lock_irqsave (&clock_lock, flags); +mutex_lock (&clock_list_lock);list_for_each_entry (c, &clocks, node) {if (strcmp (c->name, name) ==0 ) { ret = c;break ; } } -spin_unlock_irqrestore (&clock_lock, flags); +mutex_unlock (&clock_list_lock);return ret; } -static void clk_recalculate_rate (struct clk *c) +/* Must be called with c->spinlock held */ +static unsigned long clk_predict_rate_from_parent (struct clk *c,struct clk *p) {u64 rate; -if (!c->parent) -return ; - - rate = c->parent->rate; + rate =clk_get_rate (p);if (c->mul !=0 && c->div !=0 ) { - rate = rate * c->mul; + rate *= c->mul;do_div (rate, c->div); } -if (rate > c->max_rate) -pr_warn ("clocks: Set clock %s to rate %llu, max is %lu\n" , - c->name, rate, c->max_rate); - - c->rate = rate; +return rate; } -int clk_reparent (struct clk *c,struct clk *parent) +/* Must be called with c->spinlock held */ +unsigned long clk_get_rate_locked (struct clk *c) { - c->parent = parent; -list_del (&c->sibling); -list_add_tail (&c->sibling, &parent->children); -return 0 ; -} +unsigned long rate; -static void propagate_rate (struct clk *c) -{ -struct clk *clkp; +if (c->parent) + rate =clk_predict_rate_from_parent (c, c->parent); +else + rate = c->rate; -list_for_each_entry (clkp, &c->children, sibling) { -clk_recalculate_rate (clkp); -propagate_rate (clkp); - } +return rate; } -void clk_init (struct clk *c) +unsigned long clk_get_rate (struct clk *c) {unsigned long flags; +unsigned long rate; -spin_lock_irqsave (&clock_lock, flags); +spin_lock_irqsave (&c->spinlock, flags); -INIT_LIST_HEAD (&c->children); -INIT_LIST_HEAD (&c->sibling); + rate =clk_get_rate_locked (c); + +spin_unlock_irqrestore (&c->spinlock, flags); + +return rate; +} +EXPORT_SYMBOL (clk_get_rate); + +int clk_reparent (struct clk *c,struct clk *parent) +{ + c->parent = parent; +return 0 ; +} + +void clk_init (struct clk *c) +{ +spin_lock_init (&c->spinlock);if (c->ops && c->ops->init) c->ops->init (c);
@@ -108,33 +142,31 @@ void clk_init(struct clk *c) c->state =ON ; } -clk_recalculate_rate (c); - +mutex_lock (&clock_list_lock);list_add (&c->node, &clocks); - -if (c->parent) -list_add_tail (&c->sibling, &c->parent->children); - -spin_unlock_irqrestore (&clock_lock, flags); +mutex_unlock (&clock_list_lock); } -int clk_enable_locked (struct clk *c) +int clk_enable (struct clk *c) { -int ret; +int ret =0 ; +unsigned long flags; + +spin_lock_irqsave (&c->spinlock, flags);if (c->refcnt ==0 ) {if (c->parent) { - ret =clk_enable_locked (c->parent); + ret =clk_enable (c->parent);if (ret) -return ret; + goto out; }if (c->ops && c->ops->enable) { ret = c->ops->enable (c);if (ret) {if (c->parent) -clk_disable_locked (c->parent); -return ret; +clk_disable (c->parent); + goto out; } c->state =ON ;#ifdef CONFIG_DEBUG_FS
@@ -143,27 +175,21 @@ int clk_enable_locked(struct clk *c) } } c->refcnt++; - -return 0 ; +out: +spin_unlock_irqrestore (&c->spinlock, flags); +return ret; } +EXPORT_SYMBOL (clk_enable); -int clk_enable (struct clk *c) +void clk_disable (struct clk *c) { -int ret;unsigned long flags; -spin_lock_irqsave (&clock_lock, flags); - ret =clk_enable_locked (c); -spin_unlock_irqrestore (&clock_lock, flags); +spin_lock_irqsave (&c->spinlock, flags); -return ret; -} -EXPORT_SYMBOL (clk_enable); - -void clk_disable_locked (struct clk *c) -{if (c->refcnt ==0 ) {WARN (1 ,"Attempting to disable clock %s with refcnt 0" , c->name); +spin_unlock_irqrestore (&c->spinlock, flags);return ; }if (c->refcnt ==1 ) {
@@ -171,49 +197,39 @@ void clk_disable_locked(struct clk *c) c->ops->disable (c);if (c->parent) -clk_disable_locked (c->parent); +clk_disable (c->parent); c->state =OFF ; } c->refcnt--; -} -void clk_disable (struct clk *c) -{ -unsigned long flags; - -spin_lock_irqsave (&clock_lock, flags); -clk_disable_locked (c); -spin_unlock_irqrestore (&clock_lock, flags); +spin_unlock_irqrestore (&c->spinlock, flags); }EXPORT_SYMBOL (clk_disable); -int clk_set_parent_locked (struct clk *c,struct clk *parent) +int clk_set_parent (struct clk *c,struct clk *parent) {int ret; +unsigned long flags; +unsigned long new_rate; +unsigned long old_rate; -if (!c->ops || !c->ops->set_parent) -return -ENOSYS ; +spin_lock_irqsave (&c->spinlock, flags); - ret = c->ops->set_parent (c, parent); - -if (ret) -return ret; - -clk_recalculate_rate (c); +if (!c->ops || !c->ops->set_parent) { + ret = -ENOSYS ; + goto out; + } -propagate_rate (c); + new_rate =clk_predict_rate_from_parent (c, parent); + old_rate =clk_get_rate_locked (c); -return 0 ; -} + ret = c->ops->set_parent (c, parent); +if (ret) + goto out; -int clk_set_parent (struct clk *c,struct clk *parent) -{ -int ret; -unsigned long flags; -spin_lock_irqsave (&clock_lock, flags); - ret =clk_set_parent_locked (c, parent); -spin_unlock_irqrestore (&clock_lock, flags); +out: +spin_unlock_irqrestore (&c->spinlock, flags);return ret; }EXPORT_SYMBOL (clk_set_parent);
@@ -226,62 +242,75 @@ EXPORT_SYMBOL(clk_get_parent);int clk_set_rate_locked (struct clk *c,unsigned long rate) { -int ret; - -if (rate > c->max_rate) - rate = c->max_rate; -if (!c->ops || !c->ops->set_rate)return -ENOSYS ; - ret = c->ops->set_rate (c, rate); - -if (ret) -return ret; - -clk_recalculate_rate (c); - -propagate_rate (c); +if (rate > c->max_rate) + rate = c->max_rate; -return 0 ; +return c->ops->set_rate (c, rate); }int clk_set_rate (struct clk *c,unsigned long rate) { -int ret =0 ; +int ret;unsigned long flags; -spin_lock_irqsave (&clock_lock, flags); +spin_lock_irqsave (&c->spinlock, flags); + ret =clk_set_rate_locked (c, rate); -spin_unlock_irqrestore (&clock_lock, flags); + +spin_unlock_irqrestore (&c->spinlock, flags);return ret; }EXPORT_SYMBOL (clk_set_rate); -unsigned long clk_get_rate (struct clk *c) -{ -unsigned long flags; -unsigned long ret; -spin_lock_irqsave (&clock_lock, flags); +/* Must be called with clocks lock and all indvidual clock locks held */ +unsigned long clk_get_rate_all_locked (struct clk *c) +{ +u64 rate; +int mul =1 ; +int div =1 ; +struct clk *p = c; + +while (p) { + c = p; +if (c->mul !=0 && c->div !=0 ) { + mul *= c->mul; + div *= c->div; + } + p = c->parent; + } - ret = c->rate; + rate = c->rate; + rate *= mul; +do_div (rate, div); -spin_unlock_irqrestore (&clock_lock, flags); -return ret; +return rate; } -EXPORT_SYMBOL (clk_get_rate);long clk_round_rate (struct clk *c,unsigned long rate) { -if (!c->ops || !c->ops->round_rate) -return -ENOSYS ; +unsigned long flags; +long ret; + +spin_lock_irqsave (&c->spinlock, flags); + +if (!c->ops || !c->ops->round_rate) { + ret = -ENOSYS ; + goto out; + }if (rate > c->max_rate) rate = c->max_rate; -return c->ops->round_rate (c, rate); + ret = c->ops->round_rate (c, rate); + +out: +spin_unlock_irqrestore (&c->spinlock, flags); +return ret; }EXPORT_SYMBOL (clk_round_rate);
@@ -374,9 +403,10 @@ int __init tegra_disable_boot_clocks(void)struct clk *c; -spin_lock_irqsave (&clock_lock, flags); +mutex_lock (&clock_list_lock);list_for_each_entry (c, &clocks, node) { +spin_lock_irqsave (&c->spinlock, flags);if (c->refcnt ==0 && c->state ==ON && c->ops && c->ops->disable) { pr_warning("Disabling clock %s left on by bootloader\n",
@@ -384,23 +414,85 @@ int __init tegra_disable_boot_clocks(void) c->ops->disable (c); c->state = OFF; } +spin_unlock_irqrestore (&c->spinlock, flags); } -spin_unlock_irqrestore (&clock_lock, flags); - +mutex_unlock (&clock_list_lock);return 0 ; }late_initcall (tegra_disable_boot_clocks);#endif #ifdef CONFIG_DEBUG_FS + +static int __clk_lock_all_spinlocks (void ) +{ +struct clk *c; + +list_for_each_entry (c, &clocks, node) +if (!spin_trylock (&c->spinlock)) + goto unlock_spinlocks; + +return 0 ; + +unlock_spinlocks: +list_for_each_entry_continue_reverse (c, &clocks, node) +spin_unlock (&c->spinlock); + +return -EAGAIN ; +} + +static void __clk_unlock_all_spinlocks (void ) +{ +struct clk *c; + +list_for_each_entry_reverse (c, &clocks, node) +spin_unlock (&c->spinlock); +} + +/* +* This function retries until it can take all locks, and may take +* an arbitrarily long time to complete. +* Must be called with irqs enabled, returns with irqs disabled +* Must be called with clock_list_lock held +*/ +static void clk_lock_all (void ) +{ +int ret; +retry: +local_irq_disable (); + + ret =__clk_lock_all_spinlocks (); +if (ret) + goto failed_spinlocks; + +/* All locks taken successfully, return */ +return ; + +failed_spinlocks: +local_irq_enable (); +yield (); + goto retry; +} + +/* +* Unlocks all clocks after a clk_lock_all +* Must be called with irqs disabled, returns with irqs enabled +* Must be called with clock_list_lock held +*/ +static void clk_unlock_all (void ) +{ +__clk_unlock_all_spinlocks (); + +local_irq_enable (); +} +static struct dentry *clk_debugfs_root;static void clock_tree_show_one (struct seq_file *s,struct clk *c,int level) {struct clk *child; -struct clk *safe;const char *state ="uninit" ;char div[8 ] = {0 };
@@ -431,8 +523,12 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level) c->rate > c->max_rate ?'!' :' ' , !c->set ?'*' :' ' ,30 - level *3 , c->name, - state, c->refcnt, div, c->rate); -list_for_each_entry_safe (child, safe, &c->children, sibling) { + state, c->refcnt, div, clk_get_rate_all_locked(c)); + +list_for_each_entry (child, &clocks, node) { +if (child->parent != c) +continue ; +clock_tree_show_one (s, child, level +1 ); } }
@@ -440,14 +536,20 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)static int clock_tree_show (struct seq_file *s,void *data) {struct clk *c; -unsigned long flags;seq_printf (s," clock state ref div rate\n" );seq_printf (s,"--------------------------------------------------------------\n" ); -spin_lock_irqsave (&clock_lock, flags); + +mutex_lock (&clock_list_lock); + +clk_lock_all (); +list_for_each_entry (c, &clocks, node)if (c->parent ==NULL )clock_tree_show_one (s, c,0 ); -spin_unlock_irqrestore (&clock_lock, flags); + +clk_unlock_all (); + +mutex_unlock (&clock_list_lock);return 0 ; }
arch/arm/mach-tegra/clock.h +6 -8
@@ -20,8 +20,9 @@#ifndef __MACH_TEGRA_CLOCK_H#define __MACH_TEGRA_CLOCK_H -#include <linux/list.h> #include <linux/clkdev.h> +#include <linux/list.h> +#include <linux/spinlock.h> #define DIV_BUS (1 << 0)#define DIV_U71 (1 << 1)
@@ -75,8 +76,6 @@ enum clk_state {struct clk {/* node for master clocks list */ struct list_head node;/* node for list of all clocks */ -struct list_head children;/* list of children */ -struct list_head sibling;/* node for children */ struct clk_lookup lookup;#ifdef CONFIG_DEBUG_FS
@@ -122,8 +121,9 @@ struct clk {struct clk *backup; } cpu; } u; -}; +spinlock_t spinlock; +};struct clk_duplicate {const char *name;
@@ -143,11 +143,9 @@ void tegra2_periph_reset_assert(struct clk *c);void clk_init (struct clk *clk);struct clk *tegra_get_clock_by_name (const char *name);unsigned long clk_measure_input_freq (void ); -void clk_disable_locked (struct clk *c); -int clk_enable_locked (struct clk *c); -int clk_set_parent_locked (struct clk *c,struct clk *parent); -int clk_set_rate_locked (struct clk *c,unsigned long rate);int clk_reparent (struct clk *c,struct clk *parent);void tegra_clk_init_from_table (struct tegra_clk_init_table *table); +unsigned long clk_get_rate_locked (struct clk *c); +int clk_set_rate_locked (struct clk *c,unsigned long rate);#endif
arch/arm/mach-tegra/include/mach/clk.h +1 -0
@@ -25,4 +25,5 @@ struct clk;void tegra_periph_reset_deassert (struct clk *c);void tegra_periph_reset_assert (struct clk *c); +unsigned long clk_get_rate_all_locked (struct clk *c);#endif
arch/arm/mach-tegra/tegra2_clocks.c +85 -34
337 lines not on this page · raw message
Signature · 1 line
1.7.3.1
Re: [PATCH v2 10/21] ARM: tegra: clock: Convert global lock to a lock per clock
Quoted 7 lines · Colin Cross
Give each clock its own lock, and remove all lock traversals from parent to child clocks to prevent AB-BA deadlocks.
This brings the locking in line with the common struct clk patches and should make conversion simple.
Signed-off-by Colin Cross <[email protected]>
PATCH v2 10/21 ARM: tegra: clock: Convert global lock to a lock per clock
In reply to Colin CrossGive each clock its own lock, and remove all lock traversals from parent to child clocks to prevent AB-BA deadlocks.
This brings the locking in line with the common struct clk patches and should make conversion simple.
--- arch/arm/mach-tegra/clock.c | 358 ++++++++++++++++++++------------ arch/arm/mach-tegra/clock.h | 14 +- arch/arm/mach-tegra/include/mach/clk.h | 1 + arch/arm/mach-tegra/tegra2_clocks.c | 119 ++++++++--- 4 files changed, 322 insertions(+), 170 deletions(-)
arch/arm/mach-tegra/clock.c +230 -128
@@ -18,83 +18,117 @@#include <linux/kernel.h> #include <linux/clk.h> -#include <linux/list.h> +#include <linux/clkdev.h> +#include <linux/debugfs.h> +#include <linux/delay.h> #include <linux/init.h> +#include <linux/list.h> #include <linux/module.h> -#include <linux/debugfs.h> -#include <linux/slab.h> +#include <linux/sched.h> #include <linux/seq_file.h> -#include <linux/clkdev.h> +#include <linux/slab.h> + +#include <mach/clk.h> #include "board.h" #include "clock.h" +/* +* Locking: +* +* Each struct clk has a spinlock. +* +* To avoid AB-BA locking problems, locks must always be traversed from child +* clock to parent clock. For example, when enabling a clock, the clock's lock +* is taken, and then clk_enable is called on the parent, which take's the +* parent clock's lock. There is one exceptions to this ordering: When dumping +* the clock tree through debugfs. In this case, clk_lock_all is called, +* which attemps to iterate through the entire list of clocks and take every +* clock lock. If any call to spin_trylock fails, all locked clocks are +* unlocked, and the process is retried. When all the locks are held, +* the only clock operation that can be called is clk_get_rate_all_locked. +* +* Within a single clock, no clock operation can call another clock operation +* on itself, except for clk_get_rate_locked and clk_set_rate_locked. Any +* clock operation can call any other clock operation on any of it's possible +* parents. +* +* An additional mutex, clock_list_lock, is used to protect the list of all +* clocks. +* +* The clock operations must lock internally to protect against +* read-modify-write on registers that are shared by multiple clocks +*/ +static DEFINE_MUTEX (clock_list_lock);static LIST_HEAD (clocks); -static DEFINE_SPINLOCK (clock_lock);struct clk *tegra_get_clock_by_name (const char *name) {struct clk *c;struct clk *ret =NULL ; -unsigned long flags; -spin_lock_irqsave (&clock_lock, flags); +mutex_lock (&clock_list_lock);list_for_each_entry (c, &clocks, node) {if (strcmp (c->name, name) ==0 ) { ret = c;break ; } } -spin_unlock_irqrestore (&clock_lock, flags); +mutex_unlock (&clock_list_lock);return ret; } -static void clk_recalculate_rate (struct clk *c) +/* Must be called with c->spinlock held */ +static unsigned long clk_predict_rate_from_parent (struct clk *c,struct clk *p) {u64 rate; -if (!c->parent) -return ; - - rate = c->parent->rate; + rate =clk_get_rate (p);if (c->mul !=0 && c->div !=0 ) { - rate = rate * c->mul; + rate *= c->mul;do_div (rate, c->div); } -if (rate > c->max_rate) -pr_warn ("clocks: Set clock %s to rate %llu, max is %lu\n" , - c->name, rate, c->max_rate); - - c->rate = rate; +return rate; } -int clk_reparent (struct clk *c,struct clk *parent) +/* Must be called with c->spinlock held */ +unsigned long clk_get_rate_locked (struct clk *c) { - c->parent = parent; -list_del (&c->sibling); -list_add_tail (&c->sibling, &parent->children); -return 0 ; -} +unsigned long rate; -static void propagate_rate (struct clk *c) -{ -struct clk *clkp; +if (c->parent) + rate =clk_predict_rate_from_parent (c, c->parent); +else + rate = c->rate; -list_for_each_entry (clkp, &c->children, sibling) { -clk_recalculate_rate (clkp); -propagate_rate (clkp); - } +return rate; } -void clk_init (struct clk *c) +unsigned long clk_get_rate (struct clk *c) {unsigned long flags; +unsigned long rate; -spin_lock_irqsave (&clock_lock, flags); +spin_lock_irqsave (&c->spinlock, flags); -INIT_LIST_HEAD (&c->children); -INIT_LIST_HEAD (&c->sibling); + rate =clk_get_rate_locked (c); + +spin_unlock_irqrestore (&c->spinlock, flags); + +return rate; +} +EXPORT_SYMBOL (clk_get_rate); + +int clk_reparent (struct clk *c,struct clk *parent) +{ + c->parent = parent; +return 0 ; +} + +void clk_init (struct clk *c) +{ +spin_lock_init (&c->spinlock);if (c->ops && c->ops->init) c->ops->init (c);
@@ -108,33 +142,31 @@ void clk_init(struct clk *c) c->state =ON ; } -clk_recalculate_rate (c); - +mutex_lock (&clock_list_lock);list_add (&c->node, &clocks); - -if (c->parent) -list_add_tail (&c->sibling, &c->parent->children); - -spin_unlock_irqrestore (&clock_lock, flags); +mutex_unlock (&clock_list_lock); } -int clk_enable_locked (struct clk *c) +int clk_enable (struct clk *c) { -int ret; +int ret =0 ; +unsigned long flags; + +spin_lock_irqsave (&c->spinlock, flags);if (c->refcnt ==0 ) {if (c->parent) { - ret =clk_enable_locked (c->parent); + ret =clk_enable (c->parent);if (ret) -return ret; + goto out; }if (c->ops && c->ops->enable) { ret = c->ops->enable (c);if (ret) {if (c->parent) -clk_disable_locked (c->parent); -return ret; +clk_disable (c->parent); + goto out; } c->state =ON ;#ifdef CONFIG_DEBUG_FS
@@ -143,27 +175,21 @@ int clk_enable_locked(struct clk *c) } } c->refcnt++; - -return 0 ; +out: +spin_unlock_irqrestore (&c->spinlock, flags); +return ret; } +EXPORT_SYMBOL (clk_enable); -int clk_enable (struct clk *c) +void clk_disable (struct clk *c) { -int ret;unsigned long flags; -spin_lock_irqsave (&clock_lock, flags); - ret =clk_enable_locked (c); -spin_unlock_irqrestore (&clock_lock, flags); +spin_lock_irqsave (&c->spinlock, flags); -return ret; -} -EXPORT_SYMBOL (clk_enable); - -void clk_disable_locked (struct clk *c) -{if (c->refcnt ==0 ) {WARN (1 ,"Attempting to disable clock %s with refcnt 0" , c->name); +spin_unlock_irqrestore (&c->spinlock, flags);return ; }if (c->refcnt ==1 ) {
@@ -171,49 +197,39 @@ void clk_disable_locked(struct clk *c) c->ops->disable (c);if (c->parent) -clk_disable_locked (c->parent); +clk_disable (c->parent); c->state =OFF ; } c->refcnt--; -} -void clk_disable (struct clk *c) -{ -unsigned long flags; - -spin_lock_irqsave (&clock_lock, flags); -clk_disable_locked (c); -spin_unlock_irqrestore (&clock_lock, flags); +spin_unlock_irqrestore (&c->spinlock, flags); }EXPORT_SYMBOL (clk_disable); -int clk_set_parent_locked (struct clk *c,struct clk *parent) +int clk_set_parent (struct clk *c,struct clk *parent) {int ret; +unsigned long flags; +unsigned long new_rate; +unsigned long old_rate; -if (!c->ops || !c->ops->set_parent) -return -ENOSYS ; +spin_lock_irqsave (&c->spinlock, flags); - ret = c->ops->set_parent (c, parent); - -if (ret) -return ret; - -clk_recalculate_rate (c); +if (!c->ops || !c->ops->set_parent) { + ret = -ENOSYS ; + goto out; + } -propagate_rate (c); + new_rate =clk_predict_rate_from_parent (c, parent); + old_rate =clk_get_rate_locked (c); -return 0 ; -} + ret = c->ops->set_parent (c, parent); +if (ret) + goto out; -int clk_set_parent (struct clk *c,struct clk *parent) -{ -int ret; -unsigned long flags; -spin_lock_irqsave (&clock_lock, flags); - ret =clk_set_parent_locked (c, parent); -spin_unlock_irqrestore (&clock_lock, flags); +out: +spin_unlock_irqrestore (&c->spinlock, flags);return ret; }EXPORT_SYMBOL (clk_set_parent);
@@ -226,62 +242,75 @@ EXPORT_SYMBOL(clk_get_parent);int clk_set_rate_locked (struct clk *c,unsigned long rate) { -int ret; - -if (rate > c->max_rate) - rate = c->max_rate; -if (!c->ops || !c->ops->set_rate)return -ENOSYS ; - ret = c->ops->set_rate (c, rate); - -if (ret) -return ret; - -clk_recalculate_rate (c); - -propagate_rate (c); +if (rate > c->max_rate) + rate = c->max_rate; -return 0 ; +return c->ops->set_rate (c, rate); }int clk_set_rate (struct clk *c,unsigned long rate) { -int ret =0 ; +int ret;unsigned long flags; -spin_lock_irqsave (&clock_lock, flags); +spin_lock_irqsave (&c->spinlock, flags); + ret =clk_set_rate_locked (c, rate); -spin_unlock_irqrestore (&clock_lock, flags); + +spin_unlock_irqrestore (&c->spinlock, flags);return ret; }EXPORT_SYMBOL (clk_set_rate); -unsigned long clk_get_rate (struct clk *c) -{ -unsigned long flags; -unsigned long ret; -spin_lock_irqsave (&clock_lock, flags); +/* Must be called with clocks lock and all indvidual clock locks held */ +unsigned long clk_get_rate_all_locked (struct clk *c) +{ +u64 rate; +int mul =1 ; +int div =1 ; +struct clk *p = c; + +while (p) { + c = p; +if (c->mul !=0 && c->div !=0 ) { + mul *= c->mul; + div *= c->div; + } + p = c->parent; + } - ret = c->rate; + rate = c->rate; + rate *= mul; +do_div (rate, div); -spin_unlock_irqrestore (&clock_lock, flags); -return ret; +return rate; } -EXPORT_SYMBOL (clk_get_rate);long clk_round_rate (struct clk *c,unsigned long rate) { -if (!c->ops || !c->ops->round_rate) -return -ENOSYS ; +unsigned long flags; +long ret; + +spin_lock_irqsave (&c->spinlock, flags); + +if (!c->ops || !c->ops->round_rate) { + ret = -ENOSYS ; + goto out; + }if (rate > c->max_rate) rate = c->max_rate; -return c->ops->round_rate (c, rate); + ret = c->ops->round_rate (c, rate); + +out: +spin_unlock_irqrestore (&c->spinlock, flags); +return ret; }EXPORT_SYMBOL (clk_round_rate);
@@ -374,9 +403,10 @@ int __init tegra_disable_boot_clocks(void)struct clk *c; -spin_lock_irqsave (&clock_lock, flags); +mutex_lock (&clock_list_lock);list_for_each_entry (c, &clocks, node) { +spin_lock_irqsave (&c->spinlock, flags);if (c->refcnt ==0 && c->state ==ON && c->ops && c->ops->disable) { pr_warning("Disabling clock %s left on by bootloader\n",
@@ -384,23 +414,85 @@ int __init tegra_disable_boot_clocks(void) c->ops->disable (c); c->state = OFF; } +spin_unlock_irqrestore (&c->spinlock, flags); } -spin_unlock_irqrestore (&clock_lock, flags); - +mutex_unlock (&clock_list_lock);return 0 ; }late_initcall (tegra_disable_boot_clocks);#endif #ifdef CONFIG_DEBUG_FS + +static int __clk_lock_all_spinlocks (void ) +{ +struct clk *c; + +list_for_each_entry (c, &clocks, node) +if (!spin_trylock (&c->spinlock)) + goto unlock_spinlocks; + +return 0 ; + +unlock_spinlocks: +list_for_each_entry_continue_reverse (c, &clocks, node) +spin_unlock (&c->spinlock); + +return -EAGAIN ; +} + +static void __clk_unlock_all_spinlocks (void ) +{ +struct clk *c; + +list_for_each_entry_reverse (c, &clocks, node) +spin_unlock (&c->spinlock); +} + +/* +* This function retries until it can take all locks, and may take +* an arbitrarily long time to complete. +* Must be called with irqs enabled, returns with irqs disabled +* Must be called with clock_list_lock held +*/ +static void clk_lock_all (void ) +{ +int ret; +retry: +local_irq_disable (); + + ret =__clk_lock_all_spinlocks (); +if (ret) + goto failed_spinlocks; + +/* All locks taken successfully, return */ +return ; + +failed_spinlocks: +local_irq_enable (); +yield (); + goto retry; +} + +/* +* Unlocks all clocks after a clk_lock_all +* Must be called with irqs disabled, returns with irqs enabled +* Must be called with clock_list_lock held +*/ +static void clk_unlock_all (void ) +{ +__clk_unlock_all_spinlocks (); + +local_irq_enable (); +} +static struct dentry *clk_debugfs_root;static void clock_tree_show_one (struct seq_file *s,struct clk *c,int level) {struct clk *child; -struct clk *safe;const char *state ="uninit" ;char div[8 ] = {0 };
@@ -431,8 +523,12 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level) c->rate > c->max_rate ?'!' :' ' , !c->set ?'*' :' ' ,30 - level *3 , c->name, - state, c->refcnt, div, c->rate); -list_for_each_entry_safe (child, safe, &c->children, sibling) { + state, c->refcnt, div, clk_get_rate_all_locked(c)); + +list_for_each_entry (child, &clocks, node) { +if (child->parent != c) +continue ; +clock_tree_show_one (s, child, level +1 ); } }
@@ -440,14 +536,20 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)static int clock_tree_show (struct seq_file *s,void *data) {struct clk *c; -unsigned long flags;seq_printf (s," clock state ref div rate\n" );seq_printf (s,"--------------------------------------------------------------\n" ); -spin_lock_irqsave (&clock_lock, flags); + +mutex_lock (&clock_list_lock); + +clk_lock_all (); +list_for_each_entry (c, &clocks, node)if (c->parent ==NULL )clock_tree_show_one (s, c,0 ); -spin_unlock_irqrestore (&clock_lock, flags); + +clk_unlock_all (); + +mutex_unlock (&clock_list_lock);return 0 ; }
arch/arm/mach-tegra/clock.h +6 -8
@@ -20,8 +20,9 @@#ifndef __MACH_TEGRA_CLOCK_H#define __MACH_TEGRA_CLOCK_H -#include <linux/list.h> #include <linux/clkdev.h> +#include <linux/list.h> +#include <linux/spinlock.h> #define DIV_BUS (1 << 0)#define DIV_U71 (1 << 1)
@@ -75,8 +76,6 @@ enum clk_state {struct clk {/* node for master clocks list */ struct list_head node;/* node for list of all clocks */ -struct list_head children;/* list of children */ -struct list_head sibling;/* node for children */ struct clk_lookup lookup;#ifdef CONFIG_DEBUG_FS
@@ -122,8 +121,9 @@ struct clk {struct clk *backup; } cpu; } u; -}; +spinlock_t spinlock; +};struct clk_duplicate {const char *name;
@@ -143,11 +143,9 @@ void tegra2_periph_reset_assert(struct clk *c);void clk_init (struct clk *clk);struct clk *tegra_get_clock_by_name (const char *name);unsigned long clk_measure_input_freq (void ); -void clk_disable_locked (struct clk *c); -int clk_enable_locked (struct clk *c); -int clk_set_parent_locked (struct clk *c,struct clk *parent); -int clk_set_rate_locked (struct clk *c,unsigned long rate);int clk_reparent (struct clk *c,struct clk *parent);void tegra_clk_init_from_table (struct tegra_clk_init_table *table); +unsigned long clk_get_rate_locked (struct clk *c); +int clk_set_rate_locked (struct clk *c,unsigned long rate);#endif
arch/arm/mach-tegra/include/mach/clk.h +1 -0
@@ -25,4 +25,5 @@ struct clk;void tegra_periph_reset_deassert (struct clk *c);void tegra_periph_reset_assert (struct clk *c); +unsigned long clk_get_rate_all_locked (struct clk *c);#endif
arch/arm/mach-tegra/tegra2_clocks.c +85 -34
337 lines not on this page · raw message
Signature · 1 line
1.7.3.1
PATCH v2 10/21 ARM: tegra: clock: Convert global lock to a lock per clock
In reply to Colin CrossGive each clock its own lock, and remove all lock traversals from parent to child clocks to prevent AB-BA deadlocks.
This brings the locking in line with the common struct clk patches and should make conversion simple.
--- arch/arm/mach-tegra/clock.c | 358 ++++++++++++++++++++------------ arch/arm/mach-tegra/clock.h | 14 +- arch/arm/mach-tegra/include/mach/clk.h | 1 + arch/arm/mach-tegra/tegra2_clocks.c | 119 ++++++++--- 4 files changed, 322 insertions(+), 170 deletions(-)
arch/arm/mach-tegra/clock.c +230 -128
@@ -18,83 +18,117 @@#include <linux/kernel.h> #include <linux/clk.h> -#include <linux/list.h> +#include <linux/clkdev.h> +#include <linux/debugfs.h> +#include <linux/delay.h> #include <linux/init.h> +#include <linux/list.h> #include <linux/module.h> -#include <linux/debugfs.h> -#include <linux/slab.h> +#include <linux/sched.h> #include <linux/seq_file.h> -#include <linux/clkdev.h> +#include <linux/slab.h> + +#include <mach/clk.h> #include "board.h" #include "clock.h" +/* +* Locking: +* +* Each struct clk has a spinlock. +* +* To avoid AB-BA locking problems, locks must always be traversed from child +* clock to parent clock. For example, when enabling a clock, the clock's lock +* is taken, and then clk_enable is called on the parent, which take's the +* parent clock's lock. There is one exceptions to this ordering: When dumping +* the clock tree through debugfs. In this case, clk_lock_all is called, +* which attemps to iterate through the entire list of clocks and take every +* clock lock. If any call to spin_trylock fails, all locked clocks are +* unlocked, and the process is retried. When all the locks are held, +* the only clock operation that can be called is clk_get_rate_all_locked. +* +* Within a single clock, no clock operation can call another clock operation +* on itself, except for clk_get_rate_locked and clk_set_rate_locked. Any +* clock operation can call any other clock operation on any of it's possible +* parents. +* +* An additional mutex, clock_list_lock, is used to protect the list of all +* clocks. +* +* The clock operations must lock internally to protect against +* read-modify-write on registers that are shared by multiple clocks +*/ +static DEFINE_MUTEX (clock_list_lock);static LIST_HEAD (clocks); -static DEFINE_SPINLOCK (clock_lock);struct clk *tegra_get_clock_by_name (const char *name) {struct clk *c;struct clk *ret =NULL ; -unsigned long flags; -spin_lock_irqsave (&clock_lock, flags); +mutex_lock (&clock_list_lock);list_for_each_entry (c, &clocks, node) {if (strcmp (c->name, name) ==0 ) { ret = c;break ; } } -spin_unlock_irqrestore (&clock_lock, flags); +mutex_unlock (&clock_list_lock);return ret; } -static void clk_recalculate_rate (struct clk *c) +/* Must be called with c->spinlock held */ +static unsigned long clk_predict_rate_from_parent (struct clk *c,struct clk *p) {u64 rate; -if (!c->parent) -return ; - - rate = c->parent->rate; + rate =clk_get_rate (p);if (c->mul !=0 && c->div !=0 ) { - rate = rate * c->mul; + rate *= c->mul;do_div (rate, c->div); } -if (rate > c->max_rate) -pr_warn ("clocks: Set clock %s to rate %llu, max is %lu\n" , - c->name, rate, c->max_rate); - - c->rate = rate; +return rate; } -int clk_reparent (struct clk *c,struct clk *parent) +/* Must be called with c->spinlock held */ +unsigned long clk_get_rate_locked (struct clk *c) { - c->parent = parent; -list_del (&c->sibling); -list_add_tail (&c->sibling, &parent->children); -return 0 ; -} +unsigned long rate; -static void propagate_rate (struct clk *c) -{ -struct clk *clkp; +if (c->parent) + rate =clk_predict_rate_from_parent (c, c->parent); +else + rate = c->rate; -list_for_each_entry (clkp, &c->children, sibling) { -clk_recalculate_rate (clkp); -propagate_rate (clkp); - } +return rate; } -void clk_init (struct clk *c) +unsigned long clk_get_rate (struct clk *c) {unsigned long flags; +unsigned long rate; -spin_lock_irqsave (&clock_lock, flags); +spin_lock_irqsave (&c->spinlock, flags); -INIT_LIST_HEAD (&c->children); -INIT_LIST_HEAD (&c->sibling); + rate =clk_get_rate_locked (c); + +spin_unlock_irqrestore (&c->spinlock, flags); + +return rate; +} +EXPORT_SYMBOL (clk_get_rate); + +int clk_reparent (struct clk *c,struct clk *parent) +{ + c->parent = parent; +return 0 ; +} + +void clk_init (struct clk *c) +{ +spin_lock_init (&c->spinlock);if (c->ops && c->ops->init) c->ops->init (c);
@@ -108,33 +142,31 @@ void clk_init(struct clk *c) c->state =ON ; } -clk_recalculate_rate (c); - +mutex_lock (&clock_list_lock);list_add (&c->node, &clocks); - -if (c->parent) -list_add_tail (&c->sibling, &c->parent->children); - -spin_unlock_irqrestore (&clock_lock, flags); +mutex_unlock (&clock_list_lock); } -int clk_enable_locked (struct clk *c) +int clk_enable (struct clk *c) { -int ret; +int ret =0 ; +unsigned long flags; + +spin_lock_irqsave (&c->spinlock, flags);if (c->refcnt ==0 ) {if (c->parent) { - ret =clk_enable_locked (c->parent); + ret =clk_enable (c->parent);if (ret) -return ret; + goto out; }if (c->ops && c->ops->enable) { ret = c->ops->enable (c);if (ret) {if (c->parent) -clk_disable_locked (c->parent); -return ret; +clk_disable (c->parent); + goto out; } c->state =ON ;#ifdef CONFIG_DEBUG_FS
@@ -143,27 +175,21 @@ int clk_enable_locked(struct clk *c) } } c->refcnt++; - -return 0 ; +out: +spin_unlock_irqrestore (&c->spinlock, flags); +return ret; } +EXPORT_SYMBOL (clk_enable); -int clk_enable (struct clk *c) +void clk_disable (struct clk *c) { -int ret;unsigned long flags; -spin_lock_irqsave (&clock_lock, flags); - ret =clk_enable_locked (c); -spin_unlock_irqrestore (&clock_lock, flags); +spin_lock_irqsave (&c->spinlock, flags); -return ret; -} -EXPORT_SYMBOL (clk_enable); - -void clk_disable_locked (struct clk *c) -{if (c->refcnt ==0 ) {WARN (1 ,"Attempting to disable clock %s with refcnt 0" , c->name); +spin_unlock_irqrestore (&c->spinlock, flags);return ; }if (c->refcnt ==1 ) {
@@ -171,49 +197,39 @@ void clk_disable_locked(struct clk *c) c->ops->disable (c);if (c->parent) -clk_disable_locked (c->parent); +clk_disable (c->parent); c->state =OFF ; } c->refcnt--; -} -void clk_disable (struct clk *c) -{ -unsigned long flags; - -spin_lock_irqsave (&clock_lock, flags); -clk_disable_locked (c); -spin_unlock_irqrestore (&clock_lock, flags); +spin_unlock_irqrestore (&c->spinlock, flags); }EXPORT_SYMBOL (clk_disable); -int clk_set_parent_locked (struct clk *c,struct clk *parent) +int clk_set_parent (struct clk *c,struct clk *parent) {int ret; +unsigned long flags; +unsigned long new_rate; +unsigned long old_rate; -if (!c->ops || !c->ops->set_parent) -return -ENOSYS ; +spin_lock_irqsave (&c->spinlock, flags); - ret = c->ops->set_parent (c, parent); - -if (ret) -return ret; - -clk_recalculate_rate (c); +if (!c->ops || !c->ops->set_parent) { + ret = -ENOSYS ; + goto out; + } -propagate_rate (c); + new_rate =clk_predict_rate_from_parent (c, parent); + old_rate =clk_get_rate_locked (c); -return 0 ; -} + ret = c->ops->set_parent (c, parent); +if (ret) + goto out; -int clk_set_parent (struct clk *c,struct clk *parent) -{ -int ret; -unsigned long flags; -spin_lock_irqsave (&clock_lock, flags); - ret =clk_set_parent_locked (c, parent); -spin_unlock_irqrestore (&clock_lock, flags); +out: +spin_unlock_irqrestore (&c->spinlock, flags);return ret; }EXPORT_SYMBOL (clk_set_parent);
@@ -226,62 +242,75 @@ EXPORT_SYMBOL(clk_get_parent);int clk_set_rate_locked (struct clk *c,unsigned long rate) { -int ret; - -if (rate > c->max_rate) - rate = c->max_rate; -if (!c->ops || !c->ops->set_rate)return -ENOSYS ; - ret = c->ops->set_rate (c, rate); - -if (ret) -return ret; - -clk_recalculate_rate (c); - -propagate_rate (c); +if (rate > c->max_rate) + rate = c->max_rate; -return 0 ; +return c->ops->set_rate (c, rate); }int clk_set_rate (struct clk *c,unsigned long rate) { -int ret =0 ; +int ret;unsigned long flags; -spin_lock_irqsave (&clock_lock, flags); +spin_lock_irqsave (&c->spinlock, flags); + ret =clk_set_rate_locked (c, rate); -spin_unlock_irqrestore (&clock_lock, flags); + +spin_unlock_irqrestore (&c->spinlock, flags);return ret; }EXPORT_SYMBOL (clk_set_rate); -unsigned long clk_get_rate (struct clk *c) -{ -unsigned long flags; -unsigned long ret; -spin_lock_irqsave (&clock_lock, flags); +/* Must be called with clocks lock and all indvidual clock locks held */ +unsigned long clk_get_rate_all_locked (struct clk *c) +{ +u64 rate; +int mul =1 ; +int div =1 ; +struct clk *p = c; + +while (p) { + c = p; +if (c->mul !=0 && c->div !=0 ) { + mul *= c->mul; + div *= c->div; + } + p = c->parent; + } - ret = c->rate; + rate = c->rate; + rate *= mul; +do_div (rate, div); -spin_unlock_irqrestore (&clock_lock, flags); -return ret; +return rate; } -EXPORT_SYMBOL (clk_get_rate);long clk_round_rate (struct clk *c,unsigned long rate) { -if (!c->ops || !c->ops->round_rate) -return -ENOSYS ; +unsigned long flags; +long ret; + +spin_lock_irqsave (&c->spinlock, flags); + +if (!c->ops || !c->ops->round_rate) { + ret = -ENOSYS ; + goto out; + }if (rate > c->max_rate) rate = c->max_rate; -return c->ops->round_rate (c, rate); + ret = c->ops->round_rate (c, rate); + +out: +spin_unlock_irqrestore (&c->spinlock, flags); +return ret; }EXPORT_SYMBOL (clk_round_rate);
@@ -374,9 +403,10 @@ int __init tegra_disable_boot_clocks(void)struct clk *c; -spin_lock_irqsave (&clock_lock, flags); +mutex_lock (&clock_list_lock);list_for_each_entry (c, &clocks, node) { +spin_lock_irqsave (&c->spinlock, flags);if (c->refcnt ==0 && c->state ==ON && c->ops && c->ops->disable) { pr_warning("Disabling clock %s left on by bootloader\n",
@@ -384,23 +414,85 @@ int __init tegra_disable_boot_clocks(void) c->ops->disable (c); c->state = OFF; } +spin_unlock_irqrestore (&c->spinlock, flags); } -spin_unlock_irqrestore (&clock_lock, flags); - +mutex_unlock (&clock_list_lock);return 0 ; }late_initcall (tegra_disable_boot_clocks);#endif #ifdef CONFIG_DEBUG_FS + +static int __clk_lock_all_spinlocks (void ) +{ +struct clk *c; + +list_for_each_entry (c, &clocks, node) +if (!spin_trylock (&c->spinlock)) + goto unlock_spinlocks; + +return 0 ; + +unlock_spinlocks: +list_for_each_entry_continue_reverse (c, &clocks, node) +spin_unlock (&c->spinlock); + +return -EAGAIN ; +} + +static void __clk_unlock_all_spinlocks (void ) +{ +struct clk *c; + +list_for_each_entry_reverse (c, &clocks, node) +spin_unlock (&c->spinlock); +} + +/* +* This function retries until it can take all locks, and may take +* an arbitrarily long time to complete. +* Must be called with irqs enabled, returns with irqs disabled +* Must be called with clock_list_lock held +*/ +static void clk_lock_all (void ) +{ +int ret; +retry: +local_irq_disable (); + + ret =__clk_lock_all_spinlocks (); +if (ret) + goto failed_spinlocks; + +/* All locks taken successfully, return */ +return ; + +failed_spinlocks: +local_irq_enable (); +yield (); + goto retry; +} + +/* +* Unlocks all clocks after a clk_lock_all +* Must be called with irqs disabled, returns with irqs enabled +* Must be called with clock_list_lock held +*/ +static void clk_unlock_all (void ) +{ +__clk_unlock_all_spinlocks (); + +local_irq_enable (); +} +static struct dentry *clk_debugfs_root;static void clock_tree_show_one (struct seq_file *s,struct clk *c,int level) {struct clk *child; -struct clk *safe;const char *state ="uninit" ;char div[8 ] = {0 };
@@ -431,8 +523,12 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level) c->rate > c->max_rate ?'!' :' ' , !c->set ?'*' :' ' ,30 - level *3 , c->name, - state, c->refcnt, div, c->rate); -list_for_each_entry_safe (child, safe, &c->children, sibling) { + state, c->refcnt, div, clk_get_rate_all_locked(c)); + +list_for_each_entry (child, &clocks, node) { +if (child->parent != c) +continue ; +clock_tree_show_one (s, child, level +1 ); } }
@@ -440,14 +536,20 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)static int clock_tree_show (struct seq_file *s,void *data) {struct clk *c; -unsigned long flags;seq_printf (s," clock state ref div rate\n" );seq_printf (s,"--------------------------------------------------------------\n" ); -spin_lock_irqsave (&clock_lock, flags); + +mutex_lock (&clock_list_lock); + +clk_lock_all (); +list_for_each_entry (c, &clocks, node)if (c->parent ==NULL )clock_tree_show_one (s, c,0 ); -spin_unlock_irqrestore (&clock_lock, flags); + +clk_unlock_all (); + +mutex_unlock (&clock_list_lock);return 0 ; }
arch/arm/mach-tegra/clock.h +6 -8
@@ -20,8 +20,9 @@#ifndef __MACH_TEGRA_CLOCK_H#define __MACH_TEGRA_CLOCK_H -#include <linux/list.h> #include <linux/clkdev.h> +#include <linux/list.h> +#include <linux/spinlock.h> #define DIV_BUS (1 << 0)#define DIV_U71 (1 << 1)
@@ -75,8 +76,6 @@ enum clk_state {struct clk {/* node for master clocks list */ struct list_head node;/* node for list of all clocks */ -struct list_head children;/* list of children */ -struct list_head sibling;/* node for children */ struct clk_lookup lookup;#ifdef CONFIG_DEBUG_FS
@@ -122,8 +121,9 @@ struct clk {struct clk *backup; } cpu; } u; -}; +spinlock_t spinlock; +};struct clk_duplicate {const char *name;
@@ -143,11 +143,9 @@ void tegra2_periph_reset_assert(struct clk *c);void clk_init (struct clk *clk);struct clk *tegra_get_clock_by_name (const char *name);unsigned long clk_measure_input_freq (void ); -void clk_disable_locked (struct clk *c); -int clk_enable_locked (struct clk *c); -int clk_set_parent_locked (struct clk *c,struct clk *parent); -int clk_set_rate_locked (struct clk *c,unsigned long rate);int clk_reparent (struct clk *c,struct clk *parent);void tegra_clk_init_from_table (struct tegra_clk_init_table *table); +unsigned long clk_get_rate_locked (struct clk *c); +int clk_set_rate_locked (struct clk *c,unsigned long rate);#endif
arch/arm/mach-tegra/include/mach/clk.h +1 -0
@@ -25,4 +25,5 @@ struct clk;void tegra_periph_reset_deassert (struct clk *c);void tegra_periph_reset_assert (struct clk *c); +unsigned long clk_get_rate_all_locked (struct clk *c);#endif
arch/arm/mach-tegra/tegra2_clocks.c +85 -34
337 lines not on this page · raw message
Signature · 1 line
1.7.3.1
PATCH v2 11/21 ARM: tegra: cpufreq: Take an extra reference to pllx
In reply to Colin CrossDuring cpu frequency changes, take an extra reference to pllx so that it doesn't turn off and on while the cpu is temporarily on pllp. If the cpu is moved to pllp permanently, pllx will be turned off.
--- arch/arm/mach-tegra/cpu-tegra.c | 2 ++ arch/arm/mach-tegra/tegra2_clocks.c | 15 +++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-)
arch/arm/mach-tegra/cpu-tegra.c +2 -0
@@ -173,6 +173,8 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)if (IS_ERR (cpu_clk))return PTR_ERR (cpu_clk); +clk_enable (cpu_clk); +cpufreq_frequency_table_cpuinfo (policy, freq_table);cpufreq_frequency_table_get_attr (freq_table, policy->cpu); policy->cur =tegra_getspeed (policy->cpu);
arch/arm/mach-tegra/tegra2_clocks.c +11 -4
@@ -385,10 +385,16 @@ static void tegra2_cpu_clk_disable(struct clk *c)static int tegra2_cpu_clk_set_rate (struct clk *c,unsigned long rate) {int ret; +/* +* Take an extra reference to the main pll so it doesn't turn +* off when we move the cpu off of it +*/ +clk_enable (c->u.cpu.main); + ret =clk_set_parent (c->parent, c->u.cpu.backup);if (ret) {pr_err ("Failed to switch cpu to clock %s\n" , c->u.cpu.backup->name); -return ret; + goto out; }if (rate ==clk_get_rate (c->u.cpu.backup))
@@ -397,17 +403,18 @@ static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate) ret =clk_set_rate (c->u.cpu.main, rate);if (ret) {pr_err ("Failed to change cpu pll to %lu\n" , rate); -return ret; + goto out; } ret =clk_set_parent (c->parent, c->u.cpu.main);if (ret) {pr_err ("Failed to switch cpu to clock %s\n" , c->u.cpu.main->name); -return ret; + goto out; } out: -return 0 ; +clk_disable (c->u.cpu.main); +return ret; }static struct clk_ops tegra_cpu_ops = {
Signature · 1 line
1.7.3.1
Re: [PATCH v2 11/21] ARM: tegra: cpufreq: Take an extra reference to pllx
Quoted 6 lines · Colin Cross
During cpu frequency changes, take an extra reference to pllx so that it doesn't turn off and on while the cpu is temporarily on pllp. ?If the cpu is moved to pllp permanently, pllx will be turned off.
Signed-off-by Colin Cross <[email protected]>
PATCH v2 11/21 ARM: tegra: cpufreq: Take an extra reference to pllx
In reply to Colin CrossDuring cpu frequency changes, take an extra reference to pllx so that it doesn't turn off and on while the cpu is temporarily on pllp. If the cpu is moved to pllp permanently, pllx will be turned off.
--- arch/arm/mach-tegra/cpu-tegra.c | 2 ++ arch/arm/mach-tegra/tegra2_clocks.c | 15 +++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-)
arch/arm/mach-tegra/cpu-tegra.c +2 -0
@@ -173,6 +173,8 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)if (IS_ERR (cpu_clk))return PTR_ERR (cpu_clk); +clk_enable (cpu_clk); +cpufreq_frequency_table_cpuinfo (policy, freq_table);cpufreq_frequency_table_get_attr (freq_table, policy->cpu); policy->cur =tegra_getspeed (policy->cpu);
arch/arm/mach-tegra/tegra2_clocks.c +11 -4
@@ -385,10 +385,16 @@ static void tegra2_cpu_clk_disable(struct clk *c)static int tegra2_cpu_clk_set_rate (struct clk *c,unsigned long rate) {int ret; +/* +* Take an extra reference to the main pll so it doesn't turn +* off when we move the cpu off of it +*/ +clk_enable (c->u.cpu.main); + ret =clk_set_parent (c->parent, c->u.cpu.backup);if (ret) {pr_err ("Failed to switch cpu to clock %s\n" , c->u.cpu.backup->name); -return ret; + goto out; }if (rate ==clk_get_rate (c->u.cpu.backup))
@@ -397,17 +403,18 @@ static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate) ret =clk_set_rate (c->u.cpu.main, rate);if (ret) {pr_err ("Failed to change cpu pll to %lu\n" , rate); -return ret; + goto out; } ret =clk_set_parent (c->parent, c->u.cpu.main);if (ret) {pr_err ("Failed to switch cpu to clock %s\n" , c->u.cpu.main->name); -return ret; + goto out; } out: -return 0 ; +clk_disable (c->u.cpu.main); +return ret; }static struct clk_ops tegra_cpu_ops = {
Signature · 1 line
1.7.3.1
PATCH v2 12/21 ARM: tegra: clock: Add shared bus clock type
In reply to Colin CrossSome clocks may have multiple downstream users that need to request a higher clock rate. Shared bus clocks provide a unique shared_bus_user clock to each user. The frequency of the bus is set to the highest enabled shared_bus_user clock, with a minimum value set by the shared bus. Drivers can use clk_enable and clk_disable to enable or disable their requirement, and clk_set_rate to set the minimum rate.
--- arch/arm/mach-tegra/clock.h | 8 +++ arch/arm/mach-tegra/tegra2_clocks.c | 116 +++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/clock.h +8 -0
@@ -85,6 +85,7 @@ struct clk {struct clk_ops *ops;unsigned long rate;unsigned long max_rate; +unsigned long min_rate;u32 flags;const char *name;
@@ -98,6 +99,8 @@ struct clk {u32 reg;u32 reg_shift; +struct list_head shared_bus_list; + union { struct { unsigned int clk_num;
@@ -120,6 +123,11 @@ struct clk {struct clk *main;struct clk *backup; } cpu; +struct { +struct list_head node; +bool enabled; +unsigned long rate; + } shared_bus_user; } u;spinlock_t spinlock;
arch/arm/mach-tegra/tegra2_clocks.c +116 -0
134 lines not on this page · raw message
Signature · 1 line
1.7.3.1
PATCH v2 12/21 ARM: tegra: clock: Add shared bus clock type
In reply to Colin CrossSome clocks may have multiple downstream users that need to request a higher clock rate. Shared bus clocks provide a unique shared_bus_user clock to each user. The frequency of the bus is set to the highest enabled shared_bus_user clock, with a minimum value set by the shared bus. Drivers can use clk_enable and clk_disable to enable or disable their requirement, and clk_set_rate to set the minimum rate.
--- arch/arm/mach-tegra/clock.h | 8 +++ arch/arm/mach-tegra/tegra2_clocks.c | 116 +++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/clock.h +8 -0
@@ -85,6 +85,7 @@ struct clk {struct clk_ops *ops;unsigned long rate;unsigned long max_rate; +unsigned long min_rate;u32 flags;const char *name;
@@ -98,6 +99,8 @@ struct clk {u32 reg;u32 reg_shift; +struct list_head shared_bus_list; + union { struct { unsigned int clk_num;
@@ -120,6 +123,11 @@ struct clk {struct clk *main;struct clk *backup; } cpu; +struct { +struct list_head node; +bool enabled; +unsigned long rate; + } shared_bus_user; } u;spinlock_t spinlock;
arch/arm/mach-tegra/tegra2_clocks.c +116 -0
134 lines not on this page · raw message
Signature · 1 line
1.7.3.1
PATCH v2 13/21 ARM: tegra: clock: Remove unnecessary uses of #ifdef CONFIG_DEBUG_FS
In reply to Colin Cross--- arch/arm/mach-tegra/clock.c | 6 ++---- arch/arm/mach-tegra/clock.h | 2 +- arch/arm/mach-tegra/tegra2_clocks.c | 4 +--- 3 files changed, 4 insertions(+), 8 deletions(-)
arch/arm/mach-tegra/clock.c +2 -4
@@ -135,7 +135,7 @@ void clk_init(struct clk *c)if (!c->ops || !c->ops->enable) { c->refcnt++; - c->set =1 ; + c->set = true;if (c->parent) c->state = c->parent->state;else
@@ -169,9 +169,7 @@ int clk_enable(struct clk *c) goto out; } c->state =ON ; -#ifdef CONFIG_DEBUG_FS - c->set =1 ; -#endif + c->set = true; } } c->refcnt++;
arch/arm/mach-tegra/clock.h +1 -1
@@ -80,8 +80,8 @@ struct clk {#ifdef CONFIG_DEBUG_FS struct dentry *dent; -bool set;#endif +bool set;struct clk_ops *ops;unsigned long rate;unsigned long max_rate;
arch/arm/mach-tegra/tegra2_clocks.c +1 -3
@@ -1218,9 +1218,7 @@ static void tegra_clk_shared_bus_init(struct clk *c) c->max_rate = c->parent->max_rate; c->u.shared_bus_user.rate = c->parent->max_rate; c->state =OFF ; -#ifdef CONFIG_DEBUG_FS - c->set =1 ; -#endif + c->set = true;spin_lock_irqsave (&c->parent->spinlock, flags);
Signature · 1 line
1.7.3.1
Re: [PATCH v2 13/21] ARM: tegra: clock: Remove unnecessary uses of #ifdef CONFIG_DEBUG_FS
Hi,
Quoted 1 line · Colin Cross
Signed-off-by Colin Cross <[email protected]>
Technically, this patch does not _just_ "remove unneccessary uses of #ifdef".
I'd say "tegra: clock: minor cleanups" as patch subject, and:
* Remove unneccessary uses of #ifdef CONFIG_DEBUG_FS
* "1" -> "true" for some bool assigments
as patch description.
With that fixed:
PATCH v2 13/21 ARM: tegra: clock: Remove unnecessary uses of #ifdef CONFIG_DEBUG_FS
In reply to Colin Cross--- arch/arm/mach-tegra/clock.c | 6 ++---- arch/arm/mach-tegra/clock.h | 2 +- arch/arm/mach-tegra/tegra2_clocks.c | 4 +--- 3 files changed, 4 insertions(+), 8 deletions(-)
arch/arm/mach-tegra/clock.c +2 -4
@@ -135,7 +135,7 @@ void clk_init(struct clk *c)if (!c->ops || !c->ops->enable) { c->refcnt++; - c->set =1 ; + c->set = true;if (c->parent) c->state = c->parent->state;else
@@ -169,9 +169,7 @@ int clk_enable(struct clk *c) goto out; } c->state =ON ; -#ifdef CONFIG_DEBUG_FS - c->set =1 ; -#endif + c->set = true; } } c->refcnt++;
arch/arm/mach-tegra/clock.h +1 -1
@@ -80,8 +80,8 @@ struct clk {#ifdef CONFIG_DEBUG_FS struct dentry *dent; -bool set;#endif +bool set;struct clk_ops *ops;unsigned long rate;unsigned long max_rate;
arch/arm/mach-tegra/tegra2_clocks.c +1 -3
@@ -1218,9 +1218,7 @@ static void tegra_clk_shared_bus_init(struct clk *c) c->max_rate = c->parent->max_rate; c->u.shared_bus_user.rate = c->parent->max_rate; c->state =OFF ; -#ifdef CONFIG_DEBUG_FS - c->set =1 ; -#endif + c->set = true;spin_lock_irqsave (&c->parent->spinlock, flags);
Signature · 1 line
1.7.3.1
PATCH v2 14/21 ARM: tegra: clock: Refcount periph clock enables
In reply to Colin CrossSome peripheral clocks share enable bits. Refcount the enables so that calling clk_disable on one clock will not turn off another clock.
--- arch/arm/mach-tegra/tegra2_clocks.c | 35 +++++++++++++++++++++++++++++------ 1 files changed, 29 insertions(+), 6 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +29 -6
@@ -154,6 +154,12 @@ static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);*/ 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, (u32)reg_clk_base + (reg))#define clk_readl (reg) \
@@ -920,8 +926,19 @@ static void tegra2_periph_clk_init(struct clk *c)static int tegra2_periph_clk_enable (struct clk *c) {u32 val; +unsigned long flags; +int refcount;pr_debug ("%s on clock %s\n" , __func__, c->name); +spin_lock_irqsave (&clock_register_lock, flags); + + refcount = tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++; + +spin_unlock_irqrestore (&clock_register_lock, flags); + +if (refcount >1 ) +return 0 ; +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 ))
@@ -939,10 +956,20 @@ static int tegra2_periph_clk_enable(struct clk *c)static void tegra2_periph_clk_disable (struct clk *c) { +unsigned long flags; +pr_debug ("%s on clock %s\n" , __func__, c->name); -clk_writel (PERIPH_CLK_TO_ENB_BIT (c), -CLK_OUT_ENB_CLR +PERIPH_CLK_TO_ENB_SET_REG (c)); +spin_lock_irqsave (&clock_register_lock, flags); + +if (c->refcnt) + tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--; + +if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] ==0 ) +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); }static void tegra2_periph_clk_reset (struct clk *c,bool assert)
@@ -1976,7 +2003,6 @@ struct clk tegra_list_clks[] = {PERIPH_CLK ("timer" ,"timer" ,NULL ,5 ,0 ,26000000 , mux_clk_m,0 ),PERIPH_CLK ("i2s1" ,"i2s.0" ,NULL ,11 ,0x100 ,26000000 , mux_pllaout0_audio2x_pllp_clkm,MUX |DIV_U71 ),PERIPH_CLK ("i2s2" ,"i2s.1" ,NULL ,18 ,0x104 ,26000000 , mux_pllaout0_audio2x_pllp_clkm,MUX |DIV_U71 ), -/* FIXME: spdif has 2 clocks but 1 enable */ 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", "pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71),
@@ -1989,7 +2015,6 @@ struct clk tegra_list_clks[] = {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 */ -/* FIXME: vfir shares an enable with uartb */ 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 */
@@ -2017,13 +2042,11 @@ struct clk tegra_list_clks[] = {PERIPH_CLK ("uarte" ,"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 */ -/* FIXME: vi and vi_sensor share an enable */ 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 */ -/* FIXME: cve and tvo share an enable */ 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 */
Signature · 1 line
1.7.3.1
Re: [PATCH v2 14/21] ARM: tegra: clock: Refcount periph clock enables
Hi,
Quoted 17 lines · Colin Cross
Some peripheral clocks share enable bits. ?Refcount the enables so that calling
clk_disableon one clock will not turn off another clock.Signed-off-by Colin Cross <[email protected]>---
?arch/arm/mach-tegra/tegra2_clocks.c | ? 35 +++++++++++++++++++++++++++++------ ?1 files changed, 29 insertions(+), 6 deletions(-)arch/arm/mach-tegra/tegra2_clocks.c +0
-0@@ -154,6 +154,12 @@ static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);?*/
?staticDEFINE_SPINLOCK(clock_register_lock);
arch/arm/mach-tegra/tegra2_clocks.c static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); · line 161
Quoted 5 lines
arch/arm/mach-tegra/tegra2_clocks.c +5
-0+/* +* 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 ];
Given that this is always locked when incrementing/decrementing, should it just be switched to an array of atomics instead?
-Olof
Re: [PATCH v2 14/21] ARM: tegra: clock: Refcount periph clock enables
Quoted 20 lines · Olof Johansson
Hi,
Quoted 17 lines · Colin Cross
Some peripheral clocks share enable bits. ?Refcount the enables so that calling
clk_disableon one clock will not turn off another clock.Signed-off-by Colin Cross <[email protected]>---
?arch/arm/mach-tegra/tegra2_clocks.c | ? 35 +++++++++++++++++++++++++++++------ ?1 files changed, 29 insertions(+), 6 deletions(-)arch/arm/mach-tegra/tegra2_clocks.c +0
-0@@ -154,6 +154,12 @@ static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);?*/
?staticDEFINE_SPINLOCK(clock_register_lock);
Quoted 8 lines
arch/arm/mach-tegra/tegra2_clocks.c static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); · line 161
Quoted 5 lines
arch/arm/mach-tegra/tegra2_clocks.c +5
-0+/* +* 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 ];Given that this is always locked when incrementing/decrementing, should it just be switched to an array of atomics instead?
No, the spinlock needs to be held between the increment/decrement and test and the actual register write. The spinlock release in the enable function needs to be moved after the register write.
PATCH v2 14/21 ARM: tegra: clock: Refcount periph clock enables
In reply to Colin CrossSome peripheral clocks share enable bits. Refcount the enables so that calling clk_disable on one clock will not turn off another clock.
--- arch/arm/mach-tegra/tegra2_clocks.c | 35 +++++++++++++++++++++++++++++------ 1 files changed, 29 insertions(+), 6 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +29 -6
@@ -154,6 +154,12 @@ static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);*/ 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, (u32)reg_clk_base + (reg))#define clk_readl (reg) \
@@ -920,8 +926,19 @@ static void tegra2_periph_clk_init(struct clk *c)static int tegra2_periph_clk_enable (struct clk *c) {u32 val; +unsigned long flags; +int refcount;pr_debug ("%s on clock %s\n" , __func__, c->name); +spin_lock_irqsave (&clock_register_lock, flags); + + refcount = tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++; + +spin_unlock_irqrestore (&clock_register_lock, flags); + +if (refcount >1 ) +return 0 ; +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 ))
@@ -939,10 +956,20 @@ static int tegra2_periph_clk_enable(struct clk *c)static void tegra2_periph_clk_disable (struct clk *c) { +unsigned long flags; +pr_debug ("%s on clock %s\n" , __func__, c->name); -clk_writel (PERIPH_CLK_TO_ENB_BIT (c), -CLK_OUT_ENB_CLR +PERIPH_CLK_TO_ENB_SET_REG (c)); +spin_lock_irqsave (&clock_register_lock, flags); + +if (c->refcnt) + tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--; + +if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] ==0 ) +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); }static void tegra2_periph_clk_reset (struct clk *c,bool assert)
@@ -1976,7 +2003,6 @@ struct clk tegra_list_clks[] = {PERIPH_CLK ("timer" ,"timer" ,NULL ,5 ,0 ,26000000 , mux_clk_m,0 ),PERIPH_CLK ("i2s1" ,"i2s.0" ,NULL ,11 ,0x100 ,26000000 , mux_pllaout0_audio2x_pllp_clkm,MUX |DIV_U71 ),PERIPH_CLK ("i2s2" ,"i2s.1" ,NULL ,18 ,0x104 ,26000000 , mux_pllaout0_audio2x_pllp_clkm,MUX |DIV_U71 ), -/* FIXME: spdif has 2 clocks but 1 enable */ 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", "pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71),
@@ -1989,7 +2015,6 @@ struct clk tegra_list_clks[] = {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 */ -/* FIXME: vfir shares an enable with uartb */ 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 */
@@ -2017,13 +2042,11 @@ struct clk tegra_list_clks[] = {PERIPH_CLK ("uarte" ,"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 */ -/* FIXME: vi and vi_sensor share an enable */ 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 */ -/* FIXME: cve and tvo share an enable */ 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 */
Signature · 1 line
1.7.3.1
PATCH v2 15/21 ARM: tegra: clock: Round rate before setting rate
In reply to Colin CrossCall the clock's round_rate op, if it exists, before calling the set_rate op. This will help later when dvfs is added, dvfs needs to know what the final rate will be before the frequency changes.
Also requires fixes to the round rate functions to ensure calling round rate and then set rate will not cause the frequency to be rounded down twice. When picking clock divider values, the clock framework picks the closest frequency that is lower than the requested frequency. If the new frequency calculated from the divider value is rounded down, and then passed to set_rate, it will get rounded down again, possibly resulting in a frequency two steps lower than the original requested frequency.
Fix the problem by rounding up when calculating the frequency coming out of a clock divider, so if that frequency is requested again, the same divider value will be picked.
--- arch/arm/mach-tegra/clock.c | 12 ++++++++++++ arch/arm/mach-tegra/tegra2_clocks.c | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-)
arch/arm/mach-tegra/clock.c +12 -0
@@ -86,6 +86,7 @@ static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)if (c->mul !=0 && c->div !=0 ) { rate *= c->mul; + rate += c->div /2 ;/* round up */ do_div (rate, c->div); }
@@ -240,12 +241,23 @@ EXPORT_SYMBOL(clk_get_parent);int clk_set_rate_locked (struct clk *c,unsigned long rate) { +long new_rate; +if (!c->ops || !c->ops->set_rate)return -ENOSYS ;if (rate > c->max_rate) rate = c->max_rate; +if (c->ops && c->ops->round_rate) { + new_rate = c->ops->round_rate (c, rate); + +if (new_rate <0 ) +return new_rate; + + rate = new_rate; + } +return c->ops->set_rate (c, rate); }
arch/arm/mach-tegra/tegra2_clocks.c +4 -4
@@ -866,9 +866,9 @@ static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate) divider =clk_div71_get_divider (parent_rate, rate);if (divider <0 )return divider; -return parent_rate *2 / (divider +2 ); +return DIV_ROUND_UP (parent_rate *2 , divider +2 ); }else if (c->flags &DIV_2 ) { -return parent_rate /2 ; +return DIV_ROUND_UP (parent_rate,2 ); }return -EINVAL ; }
@@ -1058,12 +1058,12 @@ static long tegra2_periph_clk_round_rate(struct clk *c,if (divider <0 )return divider; -return parent_rate *2 / (divider +2 ); +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 parent_rate / (divider +1 ); +return DIV_ROUND_UP (parent_rate, divider +1 ); }return -EINVAL ; }
Signature · 1 line
1.7.3.1
Re: [PATCH v2 15/21] ARM: tegra: clock: Round rate before setting rate
Hi,
arch/arm/mach-tegra/clock.c static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p) · line 89
Quoted 9 lines · Colin Cross
arch/arm/mach-tegra/clock.c +1
-0@@ -86,6 +86,7 @@ static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p) ? ? ? ?if (c->mul != 0 && c->div != 0) { ? ? ? ? ? ? ? ?rate *= c->mul; + ? ? ? ? ? ? ? rate += c->div / 2; /* round up */
Shouldn't this be "rate += c->div - 1;"?
-Olof
Re: [PATCH v2 15/21] ARM: tegra: clock: Round rate before setting rate
Quoted 10 lines · Olof Johansson
Hi,
Quoted 6 lines · Colin Cross
arch/arm/mach-tegra/clock.c +0
-0@@ -86,6 +86,7 @@ static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)
Quoted 5 lines
arch/arm/mach-tegra/clock.c static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p) · line 89
Quoted 3 lines
arch/arm/mach-tegra/clock.c +1
-0? ? ? ?if (c->mul != 0 && c->div != 0) { ? ? ? ? ? ? ? ?rate *= c->mul; + ? ? ? ? ? ? ? rate += c->div / 2; /* round up */Shouldn't this be "rate +=
c->div- 1;"?
Yes, will fix
PATCH v2 15/21 ARM: tegra: clock: Round rate before setting rate
In reply to Colin CrossCall the clock's round_rate op, if it exists, before calling the set_rate op. This will help later when dvfs is added, dvfs needs to know what the final rate will be before the frequency changes.
Also requires fixes to the round rate functions to ensure calling round rate and then set rate will not cause the frequency to be rounded down twice. When picking clock divider values, the clock framework picks the closest frequency that is lower than the requested frequency. If the new frequency calculated from the divider value is rounded down, and then passed to set_rate, it will get rounded down again, possibly resulting in a frequency two steps lower than the original requested frequency.
Fix the problem by rounding up when calculating the frequency coming out of a clock divider, so if that frequency is requested again, the same divider value will be picked.
--- arch/arm/mach-tegra/clock.c | 12 ++++++++++++ arch/arm/mach-tegra/tegra2_clocks.c | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-)
arch/arm/mach-tegra/clock.c +12 -0
@@ -86,6 +86,7 @@ static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)if (c->mul !=0 && c->div !=0 ) { rate *= c->mul; + rate += c->div /2 ;/* round up */ do_div (rate, c->div); }
@@ -240,12 +241,23 @@ EXPORT_SYMBOL(clk_get_parent);int clk_set_rate_locked (struct clk *c,unsigned long rate) { +long new_rate; +if (!c->ops || !c->ops->set_rate)return -ENOSYS ;if (rate > c->max_rate) rate = c->max_rate; +if (c->ops && c->ops->round_rate) { + new_rate = c->ops->round_rate (c, rate); + +if (new_rate <0 ) +return new_rate; + + rate = new_rate; + } +return c->ops->set_rate (c, rate); }
arch/arm/mach-tegra/tegra2_clocks.c +4 -4
@@ -866,9 +866,9 @@ static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate) divider =clk_div71_get_divider (parent_rate, rate);if (divider <0 )return divider; -return parent_rate *2 / (divider +2 ); +return DIV_ROUND_UP (parent_rate *2 , divider +2 ); }else if (c->flags &DIV_2 ) { -return parent_rate /2 ; +return DIV_ROUND_UP (parent_rate,2 ); }return -EINVAL ; }
@@ -1058,12 +1058,12 @@ static long tegra2_periph_clk_round_rate(struct clk *c,if (divider <0 )return divider; -return parent_rate *2 / (divider +2 ); +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 parent_rate / (divider +1 ); +return DIV_ROUND_UP (parent_rate, divider +1 ); }return -EINVAL ; }
Signature · 1 line
1.7.3.1
PATCH v2 16/21 ARM: tegra: Add external memory controller driver
In reply to Colin Cross--- arch/arm/mach-tegra/Kconfig | 4 + arch/arm/mach-tegra/Makefile | 1 + arch/arm/mach-tegra/tegra2_emc.c | 172 ++++++++++++++++++++++++++++++++++++++ arch/arm/mach-tegra/tegra2_emc.h | 27 ++++++ 4 files changed, 204 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-tegra/tegra2_emc.c create mode 100644 arch/arm/mach-tegra/tegra2_emc.h
arch/arm/mach-tegra/Kconfig +4 -0
@@ -71,3 +71,7 @@ config TEGRA_SYSTEM_DMA several Tegra device drivers endif + +config TEGRA_EMC_SCALING_ENABLE + bool "Enable scaling the memory frequency" + default n
arch/arm/mach-tegra/Makefile +1 -0
@@ -9,6 +9,7 @@ obj-y += powergate.o obj-y += fuse.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clock.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o +obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-t2-tables.o obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
arch/arm/mach-tegra/tegra2_emc.c new file +172 -0
172 lines not on this page · raw message
arch/arm/mach-tegra/tegra2_emc.h new file +27 -0
@@ -0,0 +1,27 @@ +/* +* Copyright (C) 2010 Google, Inc. +* +* Author: +* Colin Cross <[email protected]> +* +* 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. +* +*/ + +#define TEGRA_EMC_NUM_REGS 46 + +struct tegra_emc_table { +unsigned long rate; +u32 regs[TEGRA_EMC_NUM_REGS ]; +}; + +int tegra_emc_set_rate (unsigned long rate); +long tegra_emc_round_rate (unsigned long rate); +void tegra_init_emc (const struct tegra_emc_table *table,int table_size);
Signature · 1 line
1.7.3.1
Re: [PATCH v2 16/21] ARM: tegra: Add external memory controller driver
Quoted 1 line · Colin Cross
Signed-off-by Colin Cross <[email protected]>
Patch description requested. Besides that:
PATCH v2 16/21 ARM: tegra: Add external memory controller driver
In reply to Colin Cross--- arch/arm/mach-tegra/Kconfig | 4 + arch/arm/mach-tegra/Makefile | 1 + arch/arm/mach-tegra/tegra2_emc.c | 172 ++++++++++++++++++++++++++++++++++++++ arch/arm/mach-tegra/tegra2_emc.h | 27 ++++++ 4 files changed, 204 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-tegra/tegra2_emc.c create mode 100644 arch/arm/mach-tegra/tegra2_emc.h
arch/arm/mach-tegra/Kconfig +4 -0
@@ -71,3 +71,7 @@ config TEGRA_SYSTEM_DMA several Tegra device drivers endif + +config TEGRA_EMC_SCALING_ENABLE + bool "Enable scaling the memory frequency" + default n
arch/arm/mach-tegra/Makefile +1 -0
@@ -9,6 +9,7 @@ obj-y += powergate.o obj-y += fuse.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clock.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o +obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-t2-tables.o obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
arch/arm/mach-tegra/tegra2_emc.c new file +172 -0
172 lines not on this page · raw message
arch/arm/mach-tegra/tegra2_emc.h new file +27 -0
@@ -0,0 +1,27 @@ +/* +* Copyright (C) 2010 Google, Inc. +* +* Author: +* Colin Cross <[email protected]> +* +* 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. +* +*/ + +#define TEGRA_EMC_NUM_REGS 46 + +struct tegra_emc_table { +unsigned long rate; +u32 regs[TEGRA_EMC_NUM_REGS ]; +}; + +int tegra_emc_set_rate (unsigned long rate); +long tegra_emc_round_rate (unsigned long rate); +void tegra_init_emc (const struct tegra_emc_table *table,int table_size);
Signature · 1 line
1.7.3.1
PATCH v2 17/21 ARM: tegra: clocks: Add emc scaling
In reply to Colin Cross--- arch/arm/mach-tegra/tegra2_clocks.c | 62 ++++++++++++++++++++++++++++++++++- 1 files changed, 61 insertions(+), 1 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +61 -1
@@ -31,6 +31,7 @@#include "clock.h" #include "fuse.h" +#include "tegra2_emc.h" #define RST_DEVICES 0x004#define RST_DEVICES_SET 0x300
@@ -1078,6 +1079,53 @@ static struct clk_ops tegra_periph_clk_ops = { .reset = &tegra2_periph_clk_reset, }; +/* External memory controller clock ops */ +static void tegra2_emc_clk_init (struct clk *c) +{ +tegra2_periph_clk_init (c); + c->max_rate =clk_get_rate_locked (c); +} + +static long tegra2_emc_clk_round_rate (struct clk *c,unsigned long rate) +{ +long new_rate = rate; + + new_rate =tegra_emc_round_rate (new_rate); +if (new_rate <0 ) +return c->max_rate; + +BUG_ON (new_rate !=tegra2_periph_clk_round_rate (c, new_rate)); + +return new_rate; +} + +static int tegra2_emc_clk_set_rate (struct clk *c,unsigned long 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 =tegra2_periph_clk_set_rate (c, rate); +udelay (1 ); + +return ret; +} + +static struct clk_ops tegra_emc_clk_ops = { + .init = &tegra2_emc_clk_init, + .enable = &tegra2_periph_clk_enable, + .disable = &tegra2_periph_clk_disable, + .set_parent = &tegra2_periph_clk_set_parent, + .set_rate = &tegra2_emc_clk_set_rate, + .round_rate = &tegra2_emc_clk_round_rate, + .reset = &tegra2_periph_clk_reset, +}; +/* Clock doubler ops */ static void tegra2_clk_double_init (struct clk *c) {
@@ -1970,6 +2018,18 @@ static struct clk_mux_sel mux_clk_32k[] = { { 0, 0}, }; +static struct clk tegra_clk_emc = { + .name ="emc" , + .ops = &tegra_emc_clk_ops, + .reg =0x19c , + .max_rate =800000000 , + .inputs = mux_pllm_pllc_pllp_clkm, + .flags =MUX |DIV_U71 |PERIPH_EMC_ENB , + .u.periph = { + .clk_num =57 , + }, +}; +#define PERIPH_CLK (_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \ { \ .name = _name, \
@@ -2056,7 +2116,6 @@ struct clk tegra_list_clks[] = {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 ("emc" ,"emc" ,NULL ,57 ,0x19c ,800000000 , mux_pllm_pllc_pllp_clkm,MUX |DIV_U71 |PERIPH_EMC_ENB ),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 */
@@ -2132,6 +2191,7 @@ struct clk *tegra_ptr_clks[] = { &tegra_dev2_clk, &tegra_clk_virtual_cpu, &tegra_clk_blink, + &tegra_clk_emc, };static void tegra2_init_one_clock (struct clk *c)
Signature · 1 line
1.7.3.1
Re: [PATCH v2 17/21] ARM: tegra: clocks: Add emc scaling
Quoted 1 line · Colin Cross
Signed-off-by Colin Cross <[email protected]>
Patch description please. Besides that:
PATCH v2 17/21 ARM: tegra: clocks: Add emc scaling
In reply to Colin Cross--- arch/arm/mach-tegra/tegra2_clocks.c | 62 ++++++++++++++++++++++++++++++++++- 1 files changed, 61 insertions(+), 1 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +61 -1
@@ -31,6 +31,7 @@#include "clock.h" #include "fuse.h" +#include "tegra2_emc.h" #define RST_DEVICES 0x004#define RST_DEVICES_SET 0x300
@@ -1078,6 +1079,53 @@ static struct clk_ops tegra_periph_clk_ops = { .reset = &tegra2_periph_clk_reset, }; +/* External memory controller clock ops */ +static void tegra2_emc_clk_init (struct clk *c) +{ +tegra2_periph_clk_init (c); + c->max_rate =clk_get_rate_locked (c); +} + +static long tegra2_emc_clk_round_rate (struct clk *c,unsigned long rate) +{ +long new_rate = rate; + + new_rate =tegra_emc_round_rate (new_rate); +if (new_rate <0 ) +return c->max_rate; + +BUG_ON (new_rate !=tegra2_periph_clk_round_rate (c, new_rate)); + +return new_rate; +} + +static int tegra2_emc_clk_set_rate (struct clk *c,unsigned long 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 =tegra2_periph_clk_set_rate (c, rate); +udelay (1 ); + +return ret; +} + +static struct clk_ops tegra_emc_clk_ops = { + .init = &tegra2_emc_clk_init, + .enable = &tegra2_periph_clk_enable, + .disable = &tegra2_periph_clk_disable, + .set_parent = &tegra2_periph_clk_set_parent, + .set_rate = &tegra2_emc_clk_set_rate, + .round_rate = &tegra2_emc_clk_round_rate, + .reset = &tegra2_periph_clk_reset, +}; +/* Clock doubler ops */ static void tegra2_clk_double_init (struct clk *c) {
@@ -1970,6 +2018,18 @@ static struct clk_mux_sel mux_clk_32k[] = { { 0, 0}, }; +static struct clk tegra_clk_emc = { + .name ="emc" , + .ops = &tegra_emc_clk_ops, + .reg =0x19c , + .max_rate =800000000 , + .inputs = mux_pllm_pllc_pllp_clkm, + .flags =MUX |DIV_U71 |PERIPH_EMC_ENB , + .u.periph = { + .clk_num =57 , + }, +}; +#define PERIPH_CLK (_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \ { \ .name = _name, \
@@ -2056,7 +2116,6 @@ struct clk tegra_list_clks[] = {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 ("emc" ,"emc" ,NULL ,57 ,0x19c ,800000000 , mux_pllm_pllc_pllp_clkm,MUX |DIV_U71 |PERIPH_EMC_ENB ),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 */
@@ -2132,6 +2191,7 @@ struct clk *tegra_ptr_clks[] = { &tegra_dev2_clk, &tegra_clk_virtual_cpu, &tegra_clk_blink, + &tegra_clk_emc, };static void tegra2_init_one_clock (struct clk *c)
Signature · 1 line
1.7.3.1
PATCH v2 18/21 ARM: tegra: cpufreq: Adjust memory frequency with cpu frequency
In reply to Colin Cross--- arch/arm/mach-tegra/cpu-tegra.c | 21 +++++++++++++++++++++ 1 files changed, 21 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/cpu-tegra.c +21 -0
@@ -51,6 +51,7 @@ static struct cpufreq_frequency_table freq_table[] = {#define NUM_CPUS 2static struct clk *cpu_clk; +static struct clk *emc_clk;static unsigned long target_cpu_speed[NUM_CPUS ];static DEFINE_MUTEX (tegra_cpu_lock);
@@ -83,6 +84,17 @@ static int tegra_update_cpu_speed(unsigned long rate)if (freqs.old == freqs.new)return ret; +/* +* Vote on memory bus frequency based on cpu frequency +* This sets the minimum frequency, display or avp may request higher +*/ +if (rate >=816000 ) +clk_set_rate (emc_clk,600000000 );/* cpu 816 MHz, emc max */ +else if (rate >=456000 ) +clk_set_rate (emc_clk,300000000 );/* cpu 456 MHz, emc 150Mhz */ +else +clk_set_rate (emc_clk,100000000 );/* emc 50Mhz */ +for_each_online_cpu (freqs.cpu)cpufreq_notify_transition (&freqs,CPUFREQ_PRECHANGE );
@@ -173,6 +185,13 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)if (IS_ERR (cpu_clk))return PTR_ERR (cpu_clk); + emc_clk =clk_get_sys ("cpu" ,"emc" ); +if (IS_ERR (emc_clk)) { +clk_put (cpu_clk); +return PTR_ERR (emc_clk); + } + +clk_enable (emc_clk);clk_enable (cpu_clk);cpufreq_frequency_table_cpuinfo (policy, freq_table);
@@ -195,6 +214,8 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)static int tegra_cpu_exit (struct cpufreq_policy *policy) {cpufreq_frequency_table_cpuinfo (policy, freq_table); +clk_disable (emc_clk); +clk_put (emc_clk);clk_put (cpu_clk);return 0 ; }
Signature · 1 line
1.7.3.1
Re: [PATCH v2 18/21] ARM: tegra: cpufreq: Adjust memory frequency with cpu frequency
Quoted 1 line · Colin Cross
Signed-off-by Colin Cross <[email protected]>
Patch description please. Besides that:
But note for future work:
Quoted 11 lines
+ ? ? ? /*
+ ? ? ? ?* Vote on memory bus frequency based on cpu frequency
+ ? ? ? ?* This sets the minimum frequency, display or avp may request higher
+ ? ? ? ?*/
+ ? ? ? if (rate >= 816000)
+ ? ? ? ? ? ? ?clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */
+ ? ? ? else if (rate >= 456000)
+ ? ? ? ? ? ? ?clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */
+ ? ? ? else
+ ? ? ? ? ? ? ?clk_set_rate(emc_clk, 100000000); ?/* emc 50Mhz */ +
This hardcodes frequencies that might or might not be used on some systems and some parts. So it'll need to be revisited when enabling other configurations.
-Olof
PATCH v2 18/21 ARM: tegra: cpufreq: Adjust memory frequency with cpu frequency
In reply to Colin Cross--- arch/arm/mach-tegra/cpu-tegra.c | 21 +++++++++++++++++++++ 1 files changed, 21 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/cpu-tegra.c +21 -0
@@ -51,6 +51,7 @@ static struct cpufreq_frequency_table freq_table[] = {#define NUM_CPUS 2static struct clk *cpu_clk; +static struct clk *emc_clk;static unsigned long target_cpu_speed[NUM_CPUS ];static DEFINE_MUTEX (tegra_cpu_lock);
@@ -83,6 +84,17 @@ static int tegra_update_cpu_speed(unsigned long rate)if (freqs.old == freqs.new)return ret; +/* +* Vote on memory bus frequency based on cpu frequency +* This sets the minimum frequency, display or avp may request higher +*/ +if (rate >=816000 ) +clk_set_rate (emc_clk,600000000 );/* cpu 816 MHz, emc max */ +else if (rate >=456000 ) +clk_set_rate (emc_clk,300000000 );/* cpu 456 MHz, emc 150Mhz */ +else +clk_set_rate (emc_clk,100000000 );/* emc 50Mhz */ +for_each_online_cpu (freqs.cpu)cpufreq_notify_transition (&freqs,CPUFREQ_PRECHANGE );
@@ -173,6 +185,13 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)if (IS_ERR (cpu_clk))return PTR_ERR (cpu_clk); + emc_clk =clk_get_sys ("cpu" ,"emc" ); +if (IS_ERR (emc_clk)) { +clk_put (cpu_clk); +return PTR_ERR (emc_clk); + } + +clk_enable (emc_clk);clk_enable (cpu_clk);cpufreq_frequency_table_cpuinfo (policy, freq_table);
@@ -195,6 +214,8 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)static int tegra_cpu_exit (struct cpufreq_policy *policy) {cpufreq_frequency_table_cpuinfo (policy, freq_table); +clk_disable (emc_clk); +clk_put (emc_clk);clk_put (cpu_clk);return 0 ; }
Signature · 1 line
1.7.3.1
PATCH v2 19/21 ARM: tegra: clock: Add function to set SDMMC tap delay
In reply to Colin CrossThe SDMMC controllers have extra bits in the clock source register that adjust the delay between the clock and data to compenstate for delays on the PCB. The values need to be set from the clock code so the clock can be locked during the read-modify-write on the clock source register.
--- arch/arm/mach-tegra/clock.c | 12 ++++++++++++ arch/arm/mach-tegra/clock.h | 1 + arch/arm/mach-tegra/include/mach/clk.h | 2 ++ arch/arm/mach-tegra/tegra2_clocks.c | 19 +++++++++++++++++++ 4 files changed, 34 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/clock.c +12 -0
@@ -433,6 +433,18 @@ int __init tegra_disable_boot_clocks(void)late_initcall (tegra_disable_boot_clocks);#endif +/* The SDMMC controllers have extra bits in the clock source register that +* adjust the delay between the clock and data to compenstate for delays +* on the PCB. */ +void tegra_sdmmc_tap_delay (struct clk *c,int delay) +{ +unsigned long flags; + +spin_lock_irqsave (&c->spinlock, flags); +tegra2_sdmmc_tap_delay (c, delay); +spin_unlock_irqrestore (&c->spinlock, flags); +} +#ifdef CONFIG_DEBUG_FS static int __clk_lock_all_spinlocks (void )
arch/arm/mach-tegra/clock.h +1 -0
@@ -155,5 +155,6 @@ int clk_reparent(struct clk *c, struct clk *parent);void tegra_clk_init_from_table (struct tegra_clk_init_table *table);unsigned long clk_get_rate_locked (struct clk *c);int clk_set_rate_locked (struct clk *c,unsigned long rate); +void tegra2_sdmmc_tap_delay (struct clk *c,int delay);#endif
arch/arm/mach-tegra/include/mach/clk.h +2 -0
@@ -26,4 +26,6 @@ void tegra_periph_reset_deassert(struct clk *c);void tegra_periph_reset_assert (struct clk *c);unsigned long clk_get_rate_all_locked (struct clk *c); +void tegra_sdmmc_tap_delay (struct clk *c,int delay); +#endif
arch/arm/mach-tegra/tegra2_clocks.c +19 -0
@@ -74,6 +74,10 @@#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)
@@ -1079,6 +1083,21 @@ static struct clk_ops tegra_periph_clk_ops = { .reset = &tegra2_periph_clk_reset, }; +/* The SDMMC controllers have extra bits in the clock source register that +* adjust the delay between the clock and data to compenstate for delays +* on the PCB. */ +void tegra2_sdmmc_tap_delay (struct clk *c,int delay) +{ +u32 reg; + + delay =clamp (delay,0 ,15 ); + reg =clk_readl (c->reg); + reg &= ~SDMMC_CLK_INT_FB_DLY_MASK ; + reg |=SDMMC_CLK_INT_FB_SEL ; + reg |= delay <<SDMMC_CLK_INT_FB_DLY_SHIFT ; +clk_writel (reg, c->reg); +} +/* External memory controller clock ops */ static void tegra2_emc_clk_init (struct clk *c) {
Signature · 1 line
1.7.3.1
Re: [PATCH v2 19/21] ARM: tegra: clock: Add function to set SDMMC tap delay
Hi,
Quoted 7 lines · Colin Cross
The SDMMC controllers have extra bits in the clock source register that adjust the delay between the clock and data to compenstate for delays on the PCB. ?The values need to be set from the clock code so the clock can be locked during the read-modify-write on the clock source register.
Signed-off-by Colin Cross <[email protected]>
This is going in without any in-tree consumers of the functions. Still, it'll likely be added shortly, so:
(If they don't show up, it'll be easy to drop it again if need be).
-Olof
PATCH v2 19/21 ARM: tegra: clock: Add function to set SDMMC tap delay
In reply to Colin CrossThe SDMMC controllers have extra bits in the clock source register that adjust the delay between the clock and data to compenstate for delays on the PCB. The values need to be set from the clock code so the clock can be locked during the read-modify-write on the clock source register.
--- arch/arm/mach-tegra/clock.c | 12 ++++++++++++ arch/arm/mach-tegra/clock.h | 1 + arch/arm/mach-tegra/include/mach/clk.h | 2 ++ arch/arm/mach-tegra/tegra2_clocks.c | 19 +++++++++++++++++++ 4 files changed, 34 insertions(+), 0 deletions(-)
arch/arm/mach-tegra/clock.c +12 -0
@@ -433,6 +433,18 @@ int __init tegra_disable_boot_clocks(void)late_initcall (tegra_disable_boot_clocks);#endif +/* The SDMMC controllers have extra bits in the clock source register that +* adjust the delay between the clock and data to compenstate for delays +* on the PCB. */ +void tegra_sdmmc_tap_delay (struct clk *c,int delay) +{ +unsigned long flags; + +spin_lock_irqsave (&c->spinlock, flags); +tegra2_sdmmc_tap_delay (c, delay); +spin_unlock_irqrestore (&c->spinlock, flags); +} +#ifdef CONFIG_DEBUG_FS static int __clk_lock_all_spinlocks (void )
arch/arm/mach-tegra/clock.h +1 -0
@@ -155,5 +155,6 @@ int clk_reparent(struct clk *c, struct clk *parent);void tegra_clk_init_from_table (struct tegra_clk_init_table *table);unsigned long clk_get_rate_locked (struct clk *c);int clk_set_rate_locked (struct clk *c,unsigned long rate); +void tegra2_sdmmc_tap_delay (struct clk *c,int delay);#endif
arch/arm/mach-tegra/include/mach/clk.h +2 -0
@@ -26,4 +26,6 @@ void tegra_periph_reset_deassert(struct clk *c);void tegra_periph_reset_assert (struct clk *c);unsigned long clk_get_rate_all_locked (struct clk *c); +void tegra_sdmmc_tap_delay (struct clk *c,int delay); +#endif
arch/arm/mach-tegra/tegra2_clocks.c +19 -0
@@ -74,6 +74,10 @@#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)
@@ -1079,6 +1083,21 @@ static struct clk_ops tegra_periph_clk_ops = { .reset = &tegra2_periph_clk_reset, }; +/* The SDMMC controllers have extra bits in the clock source register that +* adjust the delay between the clock and data to compenstate for delays +* on the PCB. */ +void tegra2_sdmmc_tap_delay (struct clk *c,int delay) +{ +u32 reg; + + delay =clamp (delay,0 ,15 ); + reg =clk_readl (c->reg); + reg &= ~SDMMC_CLK_INT_FB_DLY_MASK ; + reg |=SDMMC_CLK_INT_FB_SEL ; + reg |= delay <<SDMMC_CLK_INT_FB_DLY_SHIFT ; +clk_writel (reg, c->reg); +} +/* External memory controller clock ops */ static void tegra2_emc_clk_init (struct clk *c) {
Signature · 1 line
1.7.3.1
PATCH v2 20/21 ARM: tegra: clock: Fix clock issues in suspend
In reply to Colin CrossThe PLLP registers are now being restored by the low-level resume code, and the CPU may be running off PLLP, so don't touch them during clock resume.
Save plld, plls, pllu, and audio clock during suspend (originally fixed by Mayuresh Kulkarni <[email protected]>)
The lock time for plld is 1000 us, so increase the delay after setting the PLLs.
Add a BUG_ON to ensure the size of the suspend context area is correct.
--- arch/arm/mach-tegra/tegra2_clocks.c | 30 ++++++++++++++++++++---------- 1 files changed, 20 insertions(+), 10 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +20 -10
@@ -2251,7 +2251,7 @@ void __init tegra2_init_clocks(void)#ifdef CONFIG_PM static u32 clk_rst_suspend[RST_DEVICES_NUM +CLK_OUT_ENB_NUM + -PERIPH_CLK_SOURCE_NUM +19 ]; +PERIPH_CLK_SOURCE_NUM +22 ];void tegra_clk_suspend (void ) {
@@ -2259,16 +2259,18 @@ void tegra_clk_suspend(void)u32 *ctx = clk_rst_suspend; *ctx++ =clk_readl (OSC_CTRL ) &OSC_CTRL_MASK ; - *ctx++ =clk_readl (tegra_pll_p.reg +PLL_BASE ); - *ctx++ =clk_readl (tegra_pll_p.reg +PLL_MISC (&tegra_pll_p)); *ctx++ =clk_readl (tegra_pll_c.reg +PLL_BASE ); *ctx++ =clk_readl (tegra_pll_c.reg +PLL_MISC (&tegra_pll_c)); *ctx++ =clk_readl (tegra_pll_a.reg +PLL_BASE ); *ctx++ =clk_readl (tegra_pll_a.reg +PLL_MISC (&tegra_pll_a)); + *ctx++ =clk_readl (tegra_pll_s.reg +PLL_BASE ); + *ctx++ =clk_readl (tegra_pll_s.reg +PLL_MISC (&tegra_pll_s)); + *ctx++ =clk_readl (tegra_pll_d.reg +PLL_BASE ); + *ctx++ =clk_readl (tegra_pll_d.reg +PLL_MISC (&tegra_pll_d)); + *ctx++ =clk_readl (tegra_pll_u.reg +PLL_BASE ); + *ctx++ =clk_readl (tegra_pll_u.reg +PLL_MISC (&tegra_pll_u)); *ctx++ =clk_readl (tegra_pll_m_out1.reg); - *ctx++ =clk_readl (tegra_pll_p_out1.reg); - *ctx++ =clk_readl (tegra_pll_p_out3.reg); *ctx++ =clk_readl (tegra_pll_a_out0.reg); *ctx++ =clk_readl (tegra_pll_c_out1.reg);
@@ -2279,6 +2281,8 @@ void tegra_clk_suspend(void) *ctx++ =clk_readl (tegra_clk_sclk.reg +SUPER_CLK_DIVIDER ); *ctx++ =clk_readl (tegra_clk_pclk.reg); + *ctx++ =clk_readl (tegra_clk_audio.reg); +for (off =PERIPH_CLK_SOURCE_I2S1 ; off <=PERIPH_CLK_SOURCE_OSC ; off +=4 ) {if (off ==PERIPH_CLK_SOURCE_EMC )
@@ -2296,6 +2300,8 @@ void tegra_clk_suspend(void) *ctx++ =clk_readl (MISC_CLK_ENB ); *ctx++ =clk_readl (CLK_MASK_ARM ); + +BUG_ON (ctx - clk_rst_suspend !=ARRAY_SIZE (clk_rst_suspend)); }void tegra_clk_resume (void )
@@ -2308,17 +2314,19 @@ void tegra_clk_resume(void) val |= *ctx++;clk_writel (val,OSC_CTRL ); -clk_writel (*ctx++, tegra_pll_p.reg +PLL_BASE ); -clk_writel (*ctx++, tegra_pll_p.reg +PLL_MISC (&tegra_pll_p));clk_writel (*ctx++, tegra_pll_c.reg +PLL_BASE );clk_writel (*ctx++, tegra_pll_c.reg +PLL_MISC (&tegra_pll_c));clk_writel (*ctx++, tegra_pll_a.reg +PLL_BASE );clk_writel (*ctx++, tegra_pll_a.reg +PLL_MISC (&tegra_pll_a)); -udelay (300 ); +clk_writel (*ctx++, tegra_pll_s.reg +PLL_BASE ); +clk_writel (*ctx++, tegra_pll_s.reg +PLL_MISC (&tegra_pll_s)); +clk_writel (*ctx++, tegra_pll_d.reg +PLL_BASE ); +clk_writel (*ctx++, tegra_pll_d.reg +PLL_MISC (&tegra_pll_d)); +clk_writel (*ctx++, tegra_pll_u.reg +PLL_BASE ); +clk_writel (*ctx++, tegra_pll_u.reg +PLL_MISC (&tegra_pll_u)); +udelay (1000 );clk_writel (*ctx++, tegra_pll_m_out1.reg); -clk_writel (*ctx++, tegra_pll_p_out1.reg); -clk_writel (*ctx++, tegra_pll_p_out3.reg);clk_writel (*ctx++, tegra_pll_a_out0.reg);clk_writel (*ctx++, tegra_pll_c_out1.reg);
@@ -2329,6 +2337,8 @@ void tegra_clk_resume(void)clk_writel (*ctx++, tegra_clk_sclk.reg +SUPER_CLK_DIVIDER );clk_writel (*ctx++, tegra_clk_pclk.reg); +clk_writel (*ctx++, tegra_clk_audio.reg); +/* enable all clocks before configuring clock sources */ clk_writel (0xbffffff9ul ,CLK_OUT_ENB );clk_writel (0xfefffff7ul ,CLK_OUT_ENB +4 );
Signature · 1 line
1.7.3.1
Re: [PATCH v2 20/21] ARM: tegra: clock: Fix clock issues in suspend
Quoted 4 lines · Colin Cross
The PLLP registers are now being restored by the low-level resume code, and the CPU may be running off PLLP, so don't touch them during clock resume.
Quoted 8 lines
Save plld, plls, pllu, and audio clock during suspend (originally fixed by Mayuresh Kulkarni <[email protected]>)
The lock time for plld is 1000 us, so increase the delay after setting the PLLs.
Add a
BUG_ONto ensure the size of the suspend context area is correct.
It's a bummer that this can't be done (easily) at build time, it'd be more useful. Oh well, still good to catch at runtime at least.
Quoted 1 line
Signed-off-by Colin Cross <[email protected]>
PATCH v2 20/21 ARM: tegra: clock: Fix clock issues in suspend
In reply to Colin CrossThe PLLP registers are now being restored by the low-level resume code, and the CPU may be running off PLLP, so don't touch them during clock resume.
Save plld, plls, pllu, and audio clock during suspend (originally fixed by Mayuresh Kulkarni <[email protected]>)
The lock time for plld is 1000 us, so increase the delay after setting the PLLs.
Add a BUG_ON to ensure the size of the suspend context area is correct.
--- arch/arm/mach-tegra/tegra2_clocks.c | 30 ++++++++++++++++++++---------- 1 files changed, 20 insertions(+), 10 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +20 -10
@@ -2251,7 +2251,7 @@ void __init tegra2_init_clocks(void)#ifdef CONFIG_PM static u32 clk_rst_suspend[RST_DEVICES_NUM +CLK_OUT_ENB_NUM + -PERIPH_CLK_SOURCE_NUM +19 ]; +PERIPH_CLK_SOURCE_NUM +22 ];void tegra_clk_suspend (void ) {
@@ -2259,16 +2259,18 @@ void tegra_clk_suspend(void)u32 *ctx = clk_rst_suspend; *ctx++ =clk_readl (OSC_CTRL ) &OSC_CTRL_MASK ; - *ctx++ =clk_readl (tegra_pll_p.reg +PLL_BASE ); - *ctx++ =clk_readl (tegra_pll_p.reg +PLL_MISC (&tegra_pll_p)); *ctx++ =clk_readl (tegra_pll_c.reg +PLL_BASE ); *ctx++ =clk_readl (tegra_pll_c.reg +PLL_MISC (&tegra_pll_c)); *ctx++ =clk_readl (tegra_pll_a.reg +PLL_BASE ); *ctx++ =clk_readl (tegra_pll_a.reg +PLL_MISC (&tegra_pll_a)); + *ctx++ =clk_readl (tegra_pll_s.reg +PLL_BASE ); + *ctx++ =clk_readl (tegra_pll_s.reg +PLL_MISC (&tegra_pll_s)); + *ctx++ =clk_readl (tegra_pll_d.reg +PLL_BASE ); + *ctx++ =clk_readl (tegra_pll_d.reg +PLL_MISC (&tegra_pll_d)); + *ctx++ =clk_readl (tegra_pll_u.reg +PLL_BASE ); + *ctx++ =clk_readl (tegra_pll_u.reg +PLL_MISC (&tegra_pll_u)); *ctx++ =clk_readl (tegra_pll_m_out1.reg); - *ctx++ =clk_readl (tegra_pll_p_out1.reg); - *ctx++ =clk_readl (tegra_pll_p_out3.reg); *ctx++ =clk_readl (tegra_pll_a_out0.reg); *ctx++ =clk_readl (tegra_pll_c_out1.reg);
@@ -2279,6 +2281,8 @@ void tegra_clk_suspend(void) *ctx++ =clk_readl (tegra_clk_sclk.reg +SUPER_CLK_DIVIDER ); *ctx++ =clk_readl (tegra_clk_pclk.reg); + *ctx++ =clk_readl (tegra_clk_audio.reg); +for (off =PERIPH_CLK_SOURCE_I2S1 ; off <=PERIPH_CLK_SOURCE_OSC ; off +=4 ) {if (off ==PERIPH_CLK_SOURCE_EMC )
@@ -2296,6 +2300,8 @@ void tegra_clk_suspend(void) *ctx++ =clk_readl (MISC_CLK_ENB ); *ctx++ =clk_readl (CLK_MASK_ARM ); + +BUG_ON (ctx - clk_rst_suspend !=ARRAY_SIZE (clk_rst_suspend)); }void tegra_clk_resume (void )
@@ -2308,17 +2314,19 @@ void tegra_clk_resume(void) val |= *ctx++;clk_writel (val,OSC_CTRL ); -clk_writel (*ctx++, tegra_pll_p.reg +PLL_BASE ); -clk_writel (*ctx++, tegra_pll_p.reg +PLL_MISC (&tegra_pll_p));clk_writel (*ctx++, tegra_pll_c.reg +PLL_BASE );clk_writel (*ctx++, tegra_pll_c.reg +PLL_MISC (&tegra_pll_c));clk_writel (*ctx++, tegra_pll_a.reg +PLL_BASE );clk_writel (*ctx++, tegra_pll_a.reg +PLL_MISC (&tegra_pll_a)); -udelay (300 ); +clk_writel (*ctx++, tegra_pll_s.reg +PLL_BASE ); +clk_writel (*ctx++, tegra_pll_s.reg +PLL_MISC (&tegra_pll_s)); +clk_writel (*ctx++, tegra_pll_d.reg +PLL_BASE ); +clk_writel (*ctx++, tegra_pll_d.reg +PLL_MISC (&tegra_pll_d)); +clk_writel (*ctx++, tegra_pll_u.reg +PLL_BASE ); +clk_writel (*ctx++, tegra_pll_u.reg +PLL_MISC (&tegra_pll_u)); +udelay (1000 );clk_writel (*ctx++, tegra_pll_m_out1.reg); -clk_writel (*ctx++, tegra_pll_p_out1.reg); -clk_writel (*ctx++, tegra_pll_p_out3.reg);clk_writel (*ctx++, tegra_pll_a_out0.reg);clk_writel (*ctx++, tegra_pll_c_out1.reg);
@@ -2329,6 +2337,8 @@ void tegra_clk_resume(void)clk_writel (*ctx++, tegra_clk_sclk.reg +SUPER_CLK_DIVIDER );clk_writel (*ctx++, tegra_clk_pclk.reg); +clk_writel (*ctx++, tegra_clk_audio.reg); +/* enable all clocks before configuring clock sources */ clk_writel (0xbffffff9ul ,CLK_OUT_ENB );clk_writel (0xfefffff7ul ,CLK_OUT_ENB +4 );
Signature · 1 line
1.7.3.1
PATCH v2 21/21 ARM: tegra: clock: Miscellaneous clock updates
In reply to Colin CrossCorrect max rates for pclk and sclk (Originally fixed by
Dima Zavin <[email protected]>)
Correct max rate for plla (Originally fixed by
Stephen Warren <[email protected]>)
Remove unnecessary no-op set_rate on audio clocks
Add clock lookup entries for grhost, bsea, and vde clocks
Update clock clookup entries for vcp, bsea, and vde clocks
Add shared clock entries for sclk and emc
Add a virtual cop clock to provide a reset op (Originally fixed by
Dima Zavin <[email protected]>)
Pass set_rate on super clocks through to parent
Fix pllx frequency table entry for 608 MHz
Remove incorrect plla frequency table entries
--- arch/arm/mach-tegra/tegra2_clocks.c | 98 ++++++++++++++++++++++++----------- 1 files changed, 67 insertions(+), 31 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +67 -31
@@ -362,11 +362,24 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)return -EINVAL ; } +/* +* Super clocks have "clock skippers" instead of dividers. Dividing using +* a clock skipper does not allow the voltage to be scaled down, so 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. +*/ +static int tegra2_super_clk_set_rate (struct clk *c,unsigned long rate) +{ +return clk_set_rate (c->parent, rate); +} +static struct clk_ops tegra_super_ops = { .init = tegra2_super_clk_init, .enable = tegra2_super_clk_enable, .disable = tegra2_super_clk_disable, .set_parent = tegra2_super_clk_set_parent, + .set_rate = tegra2_super_clk_set_rate, };/* virtual cpu clock functions */
@@ -435,6 +448,20 @@ static struct clk_ops tegra_cpu_ops = { .set_rate = tegra2_cpu_clk_set_rate, }; +/* virtual cop clock functions. Used to acquire the fake 'cop' clock to +* reset the COP block (i.e. AVP) */ +static void tegra2_cop_clk_reset (struct clk *c,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); +} + +static struct clk_ops tegra_cop_ops = { + .reset = tegra2_cop_clk_reset, +}; +/* bus clock functions */ static void tegra2_bus_clk_init (struct clk *c) {
@@ -1224,30 +1251,10 @@ static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)return -EINVAL ; } -static int tegra2_audio_sync_clk_set_rate (struct clk *c,unsigned long rate) -{ -unsigned long parent_rate; -if (!c->parent) { -pr_err ("%s: clock has no parent\n" , __func__); -return -EINVAL ; - } - parent_rate = c->parent->rate; -if (rate != parent_rate) { -pr_err ("%s: %s/%ld differs from parent %s/%ld\n" , - __func__, - c->name, rate, - c->parent->name, parent_rate); -return -EINVAL ; - } - c->rate = parent_rate; -return 0 ; -} -static struct clk_ops tegra_audio_sync_clk_ops = { .init = tegra2_audio_sync_clk_init, .enable = tegra2_audio_sync_clk_enable, .disable = tegra2_audio_sync_clk_disable, - .set_rate = tegra2_audio_sync_clk_set_rate, .set_parent = tegra2_audio_sync_clk_set_parent, };
@@ -1583,8 +1590,6 @@ static struct clk tegra_pll_p_out4 = {static struct clk_pll_freq_table tegra_pll_a_freq_table[] = { {28800000 ,56448000 ,49 ,25 ,1 ,1 }, {28800000 ,73728000 ,64 ,25 ,1 ,1 }, - {28800000 ,11289600 ,49 ,25 ,1 ,1 }, - {28800000 ,12288000 ,64 ,25 ,1 ,1 }, {28800000 ,24000000 ,5 ,6 ,1 ,1 }, {0 ,0 ,0 ,0 ,0 ,0 }, };
@@ -1595,7 +1600,7 @@ static struct clk tegra_pll_a = { .ops = &tegra_pll_ops, .reg = 0xb0, .parent = &tegra_pll_p_out1, - .max_rate = 56448000, + .max_rate = 73728000, .u.pll = { .input_min = 2000000, .input_max = 31000000,
@@ -1615,7 +1620,7 @@ static struct clk tegra_pll_a_out0 = { .parent = &tegra_pll_a, .reg = 0xb4, .reg_shift = 0, - .max_rate = 56448000, + .max_rate = 73728000, };static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
@@ -1717,10 +1722,10 @@ static struct clk_pll_freq_table tegra_pll_x_freq_table[] = { { 26000000, 760000000, 760, 26, 1, 12},/* 608 MHz */ - { 12000000, 608000000, 760, 12, 1, 12}, - { 13000000, 608000000, 760, 13, 1, 12}, + { 12000000, 608000000, 608, 12, 1, 12}, + { 13000000, 608000000, 608, 13, 1, 12}, { 19200000, 608000000, 380, 12, 1, 8}, - { 26000000, 608000000, 760, 26, 1, 12}, + { 26000000, 608000000, 608, 26, 1, 12},/* 456 MHz */ { 12000000, 456000000, 456, 12, 1, 12},
@@ -1833,7 +1838,7 @@ static struct clk tegra_clk_audio = { .name = "audio", .inputs = mux_audio_sync_clk, .reg = 0x38, - .max_rate = 24000000, + .max_rate = 73728000, .ops = &tegra_audio_sync_clk_ops };
@@ -1919,7 +1924,8 @@ static struct clk tegra_clk_sclk = { .inputs = mux_sclk, .reg = 0x28, .ops = &tegra_super_ops, - .max_rate = 600000000, + .max_rate = 240000000, + .min_rate = 120000000, };static struct clk tegra_clk_virtual_cpu = {
@@ -1933,6 +1939,13 @@ static struct clk tegra_clk_virtual_cpu = { }, }; +static struct clk tegra_clk_cop = { + .name ="cop" , + .parent = &tegra_clk_sclk, + .ops = &tegra_cop_ops, + .max_rate =240000000 , +}; +static struct clk tegra_clk_hclk = { .name ="hclk" , .flags =DIV_BUS ,
@@ -1950,7 +1963,7 @@ static struct clk tegra_clk_pclk = { .reg = 0x30, .reg_shift = 0, .ops = &tegra_bus_ops, - .max_rate = 108000000, + .max_rate = 120000000, };static struct clk tegra_clk_blink = {
@@ -2099,7 +2112,10 @@ struct clk tegra_list_clks[] = {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 ("vde" ,"vde" ,NULL ,61 ,0x1c8 ,250000000 , mux_pllp_pllc_pllm_clkm,MUX |DIV_U71 ),/* scales with voltage and process_id */ +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),
@@ -2142,6 +2158,18 @@ struct clk tegra_list_clks[] = {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 ), + +SHARED_CLK ("avp.sclk" ,"tegra-avp" ,"sclk" , &tegra_clk_sclk), +SHARED_CLK ("avp.emc" ,"tegra-avp" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("cpu.emc" ,"cpu" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("disp1.emc" ,"tegradc.0" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("disp2.emc" ,"tegradc.1" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("hdmi.emc" ,"hdmi" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("host.emc" ,"tegra_grhost" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("usbd.emc" ,"fsl-tegra-udc" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("usb1.emc" ,"tegra-ehci.0" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("usb2.emc" ,"tegra-ehci.1" ,"emc" , &tegra_clk_emc), + SHARED_CLK("usb3.emc", "tegra-ehci.2", "emc", &tegra_clk_emc), };#define CLK_DUPLICATE (_name, _dev, _con) \
@@ -2172,6 +2200,13 @@ struct clk_duplicate tegra_clk_duplicates[] = {CLK_DUPLICATE ("pwm" ,"tegra_pwm.1" ,NULL ),CLK_DUPLICATE ("pwm" ,"tegra_pwm.2" ,NULL ),CLK_DUPLICATE ("pwm" ,"tegra_pwm.3" ,NULL ), +CLK_DUPLICATE ("host1x" ,"tegra_grhost" ,"host1x" ), +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"), };#define CLK (dev, con, ck) \
@@ -2210,6 +2245,7 @@ struct clk *tegra_ptr_clks[] = { &tegra_dev2_clk, &tegra_clk_virtual_cpu, &tegra_clk_blink, + &tegra_clk_cop, &tegra_clk_emc, };
Signature · 1 line
1.7.3.1
Re: [PATCH v2 21/21] ARM: tegra: clock: Miscellaneous clock updates
Quoted 17 lines · Colin Cross
Correct max rates for pclk and sclk (Originally fixed by ?Dima Zavin <[email protected]>)
Correct max rate for plla (Originally fixed by
?Stephen Warren <[email protected]>)Remove unnecessary no-op
set_rateon audio clocksAdd clock lookup entries for grhost, bsea, and vde clocks
Update clock clookup entries for vcp, bsea, and vde clocks
Add shared clock entries for sclk and emc
Add a virtual cop clock to provide a reset op (Originally fixed by ?Dima Zavin <[email protected]>)
Quoted 7 lines
Pass
set_rateon super clocks through to parentFix pllx frequency table entry for 608 MHz
Remove incorrect plla frequency table entries
Signed-off-by Colin Cross <[email protected]>
PATCH v2 21/21 ARM: tegra: clock: Miscellaneous clock updates
In reply to Colin CrossCorrect max rates for pclk and sclk (Originally fixed by
Dima Zavin <[email protected]>)
Correct max rate for plla (Originally fixed by
Stephen Warren <[email protected]>)
Remove unnecessary no-op set_rate on audio clocks
Add clock lookup entries for grhost, bsea, and vde clocks
Update clock clookup entries for vcp, bsea, and vde clocks
Add shared clock entries for sclk and emc
Add a virtual cop clock to provide a reset op (Originally fixed by
Dima Zavin <[email protected]>)
Pass set_rate on super clocks through to parent
Fix pllx frequency table entry for 608 MHz
Remove incorrect plla frequency table entries
--- arch/arm/mach-tegra/tegra2_clocks.c | 98 ++++++++++++++++++++++++----------- 1 files changed, 67 insertions(+), 31 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +67 -31
@@ -362,11 +362,24 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)return -EINVAL ; } +/* +* Super clocks have "clock skippers" instead of dividers. Dividing using +* a clock skipper does not allow the voltage to be scaled down, so 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. +*/ +static int tegra2_super_clk_set_rate (struct clk *c,unsigned long rate) +{ +return clk_set_rate (c->parent, rate); +} +static struct clk_ops tegra_super_ops = { .init = tegra2_super_clk_init, .enable = tegra2_super_clk_enable, .disable = tegra2_super_clk_disable, .set_parent = tegra2_super_clk_set_parent, + .set_rate = tegra2_super_clk_set_rate, };/* virtual cpu clock functions */
@@ -435,6 +448,20 @@ static struct clk_ops tegra_cpu_ops = { .set_rate = tegra2_cpu_clk_set_rate, }; +/* virtual cop clock functions. Used to acquire the fake 'cop' clock to +* reset the COP block (i.e. AVP) */ +static void tegra2_cop_clk_reset (struct clk *c,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); +} + +static struct clk_ops tegra_cop_ops = { + .reset = tegra2_cop_clk_reset, +}; +/* bus clock functions */ static void tegra2_bus_clk_init (struct clk *c) {
@@ -1224,30 +1251,10 @@ static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)return -EINVAL ; } -static int tegra2_audio_sync_clk_set_rate (struct clk *c,unsigned long rate) -{ -unsigned long parent_rate; -if (!c->parent) { -pr_err ("%s: clock has no parent\n" , __func__); -return -EINVAL ; - } - parent_rate = c->parent->rate; -if (rate != parent_rate) { -pr_err ("%s: %s/%ld differs from parent %s/%ld\n" , - __func__, - c->name, rate, - c->parent->name, parent_rate); -return -EINVAL ; - } - c->rate = parent_rate; -return 0 ; -} -static struct clk_ops tegra_audio_sync_clk_ops = { .init = tegra2_audio_sync_clk_init, .enable = tegra2_audio_sync_clk_enable, .disable = tegra2_audio_sync_clk_disable, - .set_rate = tegra2_audio_sync_clk_set_rate, .set_parent = tegra2_audio_sync_clk_set_parent, };
@@ -1583,8 +1590,6 @@ static struct clk tegra_pll_p_out4 = {static struct clk_pll_freq_table tegra_pll_a_freq_table[] = { {28800000 ,56448000 ,49 ,25 ,1 ,1 }, {28800000 ,73728000 ,64 ,25 ,1 ,1 }, - {28800000 ,11289600 ,49 ,25 ,1 ,1 }, - {28800000 ,12288000 ,64 ,25 ,1 ,1 }, {28800000 ,24000000 ,5 ,6 ,1 ,1 }, {0 ,0 ,0 ,0 ,0 ,0 }, };
@@ -1595,7 +1600,7 @@ static struct clk tegra_pll_a = { .ops = &tegra_pll_ops, .reg = 0xb0, .parent = &tegra_pll_p_out1, - .max_rate = 56448000, + .max_rate = 73728000, .u.pll = { .input_min = 2000000, .input_max = 31000000,
@@ -1615,7 +1620,7 @@ static struct clk tegra_pll_a_out0 = { .parent = &tegra_pll_a, .reg = 0xb4, .reg_shift = 0, - .max_rate = 56448000, + .max_rate = 73728000, };static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
@@ -1717,10 +1722,10 @@ static struct clk_pll_freq_table tegra_pll_x_freq_table[] = { { 26000000, 760000000, 760, 26, 1, 12},/* 608 MHz */ - { 12000000, 608000000, 760, 12, 1, 12}, - { 13000000, 608000000, 760, 13, 1, 12}, + { 12000000, 608000000, 608, 12, 1, 12}, + { 13000000, 608000000, 608, 13, 1, 12}, { 19200000, 608000000, 380, 12, 1, 8}, - { 26000000, 608000000, 760, 26, 1, 12}, + { 26000000, 608000000, 608, 26, 1, 12},/* 456 MHz */ { 12000000, 456000000, 456, 12, 1, 12},
@@ -1833,7 +1838,7 @@ static struct clk tegra_clk_audio = { .name = "audio", .inputs = mux_audio_sync_clk, .reg = 0x38, - .max_rate = 24000000, + .max_rate = 73728000, .ops = &tegra_audio_sync_clk_ops };
@@ -1919,7 +1924,8 @@ static struct clk tegra_clk_sclk = { .inputs = mux_sclk, .reg = 0x28, .ops = &tegra_super_ops, - .max_rate = 600000000, + .max_rate = 240000000, + .min_rate = 120000000, };static struct clk tegra_clk_virtual_cpu = {
@@ -1933,6 +1939,13 @@ static struct clk tegra_clk_virtual_cpu = { }, }; +static struct clk tegra_clk_cop = { + .name ="cop" , + .parent = &tegra_clk_sclk, + .ops = &tegra_cop_ops, + .max_rate =240000000 , +}; +static struct clk tegra_clk_hclk = { .name ="hclk" , .flags =DIV_BUS ,
@@ -1950,7 +1963,7 @@ static struct clk tegra_clk_pclk = { .reg = 0x30, .reg_shift = 0, .ops = &tegra_bus_ops, - .max_rate = 108000000, + .max_rate = 120000000, };static struct clk tegra_clk_blink = {
@@ -2099,7 +2112,10 @@ struct clk tegra_list_clks[] = {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 ("vde" ,"vde" ,NULL ,61 ,0x1c8 ,250000000 , mux_pllp_pllc_pllm_clkm,MUX |DIV_U71 ),/* scales with voltage and process_id */ +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),
@@ -2142,6 +2158,18 @@ struct clk tegra_list_clks[] = {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 ), + +SHARED_CLK ("avp.sclk" ,"tegra-avp" ,"sclk" , &tegra_clk_sclk), +SHARED_CLK ("avp.emc" ,"tegra-avp" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("cpu.emc" ,"cpu" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("disp1.emc" ,"tegradc.0" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("disp2.emc" ,"tegradc.1" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("hdmi.emc" ,"hdmi" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("host.emc" ,"tegra_grhost" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("usbd.emc" ,"fsl-tegra-udc" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("usb1.emc" ,"tegra-ehci.0" ,"emc" , &tegra_clk_emc), +SHARED_CLK ("usb2.emc" ,"tegra-ehci.1" ,"emc" , &tegra_clk_emc), + SHARED_CLK("usb3.emc", "tegra-ehci.2", "emc", &tegra_clk_emc), };#define CLK_DUPLICATE (_name, _dev, _con) \
@@ -2172,6 +2200,13 @@ struct clk_duplicate tegra_clk_duplicates[] = {CLK_DUPLICATE ("pwm" ,"tegra_pwm.1" ,NULL ),CLK_DUPLICATE ("pwm" ,"tegra_pwm.2" ,NULL ),CLK_DUPLICATE ("pwm" ,"tegra_pwm.3" ,NULL ), +CLK_DUPLICATE ("host1x" ,"tegra_grhost" ,"host1x" ), +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"), };#define CLK (dev, con, ck) \
@@ -2210,6 +2245,7 @@ struct clk *tegra_ptr_clks[] = { &tegra_dev2_clk, &tegra_clk_virtual_cpu, &tegra_clk_blink, + &tegra_clk_cop, &tegra_clk_emc, };
Signature · 1 line
1.7.3.1
Hi,
Quoted 8 lines · Colin Cross
Some clocks may have multiple downstream users that need to request a higher clock rate. ?Shared bus clocks provide a unique
shared_bus_userclock to each user. ?The frequency of the bus is set to the highest enabledshared_bus_userclock, with a minimum value set by the shared bus. ?Drivers can useclk_enableandclk_disableto enable or disable their requirement, andclk_set_rateto set the minimum rate.Signed-off-by Colin Cross <[email protected]>
[...]
Quoted 4 lines
arch/arm/mach-tegra/tegra2_clocks.c +0
-0
[...]
arch/arm/mach-tegra/tegra2_clocks.c static struct clk_ops tegra_cdev_clk_ops = {
Quoted 7 lines
+ ? ? ?
c->u.shared_bus_user.rate=c->parent->max_rate;
+ ? ? ?c->state= OFF;arch/arm/mach-tegra/tegra2_clocks.c +5
-0+#ifdef CONFIG_DEBUG_FS + ? ? ? c->set = 1; +#endif + + ? ? ? spin_lock_irqsave(&c->parent->spinlock, flags);
A later patch in the series removes the ifdef. Might as well remove it here. Also, should be c->set = true, which that patch also does. :)
With that fixed:
Quoted 19 lines · Olof Johansson
Hi,
Quoted 8 lines · Colin Cross
Some clocks may have multiple downstream users that need to request a higher clock rate. ?Shared bus clocks provide a unique
shared_bus_userclock to each user. ?The frequency of the bus is set to the highest enabledshared_bus_userclock, with a minimum value set by the shared bus. ?Drivers can useclk_enableandclk_disableto enable or disable their requirement, andclk_set_rateto set the minimum rate.Signed-off-by Colin Cross <[email protected]>[...]
Quoted 4 lines
arch/arm/mach-tegra/tegra2_clocks.c +0
-0[...]
Quoted 11 lines
arch/arm/mach-tegra/tegra2_clocks.c static struct clk_ops tegra_cdev_clk_ops = {
Quoted 7 lines
+ ? ? ?
c->u.shared_bus_user.rate=c->parent->max_rate;
+ ? ? ?c->state= OFF;arch/arm/mach-tegra/tegra2_clocks.c +5
-0+#ifdef CONFIG_DEBUG_FS + ? ? ? c->set = 1; +#endif + + ? ? ? spin_lock_irqsave(&c->parent->spinlock, flags);A later patch in the series removes the ifdef. Might as well remove it here. Also, should be
c->set= true, which that patch also does. :)
At this point in the series c->set is not defined for CONFIG_DEBUG_FS=n, so dropping the #ifdef would break bisection, and I left the = 1 in for consistency.
Quoted 8 lines
With that fixed:
Acked-by Olof Johansson <[email protected]>--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html