LKML Archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type
@ 2011-02-19 22:25 Colin Cross
  2011-02-19 22:25 ` [PATCH v2 01/21] ARM: tegra: clock: enable clk reset for non-peripheral clocks Colin Cross
                   ` (21 more replies)
  0 siblings, 22 replies; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:25 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, sboyd, Russell King,
	linux-kernel

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.

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/clock.h         |    8 +++
 arch/arm/mach-tegra/tegra2_clocks.c |  116 +++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index a63dbf9..bb755c2 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -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;
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index a1c86d8..dd53af3 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -1188,6 +1188,110 @@ static struct clk_ops tegra_cdev_clk_ops = {
 	.disable		= &tegra2_cdev_clk_disable,
 };
 
+/* shared bus ops */
+/*
+ * 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.
+ */
+static int tegra_clk_shared_bus_update(struct clk *bus)
+{
+	struct clk *c;
+	unsigned long rate = bus->min_rate;
+
+	list_for_each_entry(c, &bus->shared_bus_list, u.shared_bus_user.node)
+		if (c->u.shared_bus_user.enabled)
+			rate = max(c->u.shared_bus_user.rate, rate);
+
+	if (rate == clk_get_rate_locked(bus))
+		return 0;
+
+	return clk_set_rate_locked(bus, rate);
+};
+
+static void tegra_clk_shared_bus_init(struct clk *c)
+{
+	unsigned long flags;
+
+	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
+
+	spin_lock_irqsave(&c->parent->spinlock, flags);
+
+	list_add_tail(&c->u.shared_bus_user.node,
+		&c->parent->shared_bus_list);
+
+	spin_unlock_irqrestore(&c->parent->spinlock, flags);
+}
+
+static int tegra_clk_shared_bus_set_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long flags;
+	int ret;
+
+	rate = clk_round_rate(c->parent, rate);
+	if (rate < 0)
+		return rate;
+
+	spin_lock_irqsave(&c->parent->spinlock, flags);
+
+	c->u.shared_bus_user.rate = rate;
+	ret = tegra_clk_shared_bus_update(c->parent);
+
+	spin_unlock_irqrestore(&c->parent->spinlock, flags);
+
+	return ret;
+}
+
+static long tegra_clk_shared_bus_round_rate(struct clk *c, unsigned long rate)
+{
+	return clk_round_rate(c->parent, rate);
+}
+
+static int tegra_clk_shared_bus_enable(struct clk *c)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&c->parent->spinlock, flags);
+
+	c->u.shared_bus_user.enabled = true;
+	ret = tegra_clk_shared_bus_update(c->parent);
+
+	spin_unlock_irqrestore(&c->parent->spinlock, flags);
+
+	return ret;
+}
+
+static void tegra_clk_shared_bus_disable(struct clk *c)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&c->parent->spinlock, flags);
+
+	c->u.shared_bus_user.enabled = false;
+	ret = tegra_clk_shared_bus_update(c->parent);
+	WARN_ON_ONCE(ret);
+
+	spin_unlock_irqrestore(&c->parent->spinlock, flags);
+}
+
+static struct clk_ops tegra_clk_shared_bus_ops = {
+	.init = tegra_clk_shared_bus_init,
+	.enable = tegra_clk_shared_bus_enable,
+	.disable = tegra_clk_shared_bus_disable,
+	.set_rate = tegra_clk_shared_bus_set_rate,
+	.round_rate = tegra_clk_shared_bus_round_rate,
+};
+
+
 /* Clock definitions */
 static struct clk tegra_clk_32k = {
 	.name = "clk_32k",
@@ -1858,6 +1962,17 @@ static struct clk_mux_sel mux_clk_32k[] = {
 		},					\
 	}
 
+#define SHARED_CLK(_name, _dev, _con, _parent)		\
+	{						\
+		.name      = _name,			\
+		.lookup    = {				\
+			.dev_id    = _dev,		\
+			.con_id    = _con,		\
+		},					\
+		.ops       = &tegra_clk_shared_bus_ops,	\
+		.parent = _parent,			\
+	}
+
 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),
@@ -2001,6 +2116,7 @@ struct clk *tegra_ptr_clks[] = {
 static void tegra2_init_one_clock(struct clk *c)
 {
 	clk_init(c);
+	INIT_LIST_HEAD(&c->shared_bus_list);
 	if (!c->lookup.dev_id && !c->lookup.con_id)
 		c->lookup.con_id = c->name;
 	c->lookup.clk = c;
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 01/21] ARM: tegra: clock: enable clk reset for non-peripheral clocks
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
@ 2011-02-19 22:25 ` Colin Cross
  2011-02-21  4:05   ` Olof Johansson
  2011-02-19 22:25 ` [PATCH v2 02/21] ARM: tegra: clock: Don't BUG on changing an enabled PLL Colin Cross
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:25 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Dima Zavin, Colin Cross,
	Russell King, linux-kernel

From: Dima Zavin <dima@android.com>

Add a new 'reset' clk op. This can be provided for any clock,
not just peripherals.

Signed-off-by: Dima Zavin <dima@android.com>
Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/clock.h         |    1 +
 arch/arm/mach-tegra/tegra2_clocks.c |   29 ++++++++++++++++++-----------
 2 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index 083a4cf..42f00c0 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -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 {
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 7a2926a..240f921 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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 */
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 02/21] ARM: tegra: clock: Don't BUG on changing an enabled PLL
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
  2011-02-19 22:25 ` [PATCH v2 01/21] ARM: tegra: clock: enable clk reset for non-peripheral clocks Colin Cross
@ 2011-02-19 22:25 ` Colin Cross
  2011-02-21  4:06   ` Olof Johansson
  2011-02-19 22:25 ` [PATCH v2 03/21] ARM: tegra: clock: Drop debugging Colin Cross
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:25 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/tegra2_clocks.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 240f921..db27e59 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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++) {
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 03/21] ARM: tegra: clock: Drop debugging
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
  2011-02-19 22:25 ` [PATCH v2 01/21] ARM: tegra: clock: enable clk reset for non-peripheral clocks Colin Cross
  2011-02-19 22:25 ` [PATCH v2 02/21] ARM: tegra: clock: Don't BUG on changing an enabled PLL Colin Cross
@ 2011-02-19 22:25 ` Colin Cross
  2011-02-21  4:07   ` Olof Johansson
  2011-02-19 22:25 ` [PATCH v2 04/21] ARM: tegra: clock: Don't use PLL lock bits Colin Cross
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:25 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/clock.c |   19 ++-----------------
 1 files changed, 2 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 77948e0..f55bb83 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -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;
 
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 04/21] ARM: tegra: clock: Don't use PLL lock bits
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (2 preceding siblings ...)
  2011-02-19 22:25 ` [PATCH v2 03/21] ARM: tegra: clock: Drop debugging Colin Cross
@ 2011-02-19 22:25 ` Colin Cross
  2011-02-21  4:07   ` Olof Johansson
  2011-02-19 22:25 ` [PATCH v2 05/21] ARM: tegra: clock: Disable clocks left on by bootloader Colin Cross
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:25 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

The PLL lock bits are not reliable, use per-PLL timeouts instead.

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/clock.h         |    2 +-
 arch/arm/mach-tegra/tegra2_clocks.c |   31 +++++++++----------------------
 2 files changed, 10 insertions(+), 23 deletions(-)

diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index 42f00c0..b76d33d 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -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;
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index db27e59..36da2e8 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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)
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 05/21] ARM: tegra: clock: Disable clocks left on by bootloader
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (3 preceding siblings ...)
  2011-02-19 22:25 ` [PATCH v2 04/21] ARM: tegra: clock: Don't use PLL lock bits Colin Cross
@ 2011-02-19 22:25 ` Colin Cross
  2011-02-21  0:40   ` Olof Johansson
  2011-02-19 22:25 ` [PATCH v2 06/21] ARM: tegra: clock: Initialize clocks that have no enable Colin Cross
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:25 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

Adds 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.

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/Kconfig |    6 ++++++
 arch/arm/mach-tegra/clock.c |   30 ++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index f0fda77..9f4fc6b 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -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
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index f55bb83..0ea5d92 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -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;
 
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 06/21] ARM: tegra: clock: Initialize clocks that have no enable
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (4 preceding siblings ...)
  2011-02-19 22:25 ` [PATCH v2 05/21] ARM: tegra: clock: Disable clocks left on by bootloader Colin Cross
@ 2011-02-19 22:25 ` Colin Cross
  2011-02-21  4:08   ` Olof Johansson
  2011-02-19 22:25 ` [PATCH v2 07/21] ARM: tegra: clock: Drop CPU dvfs Colin Cross
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:25 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

Assume that any clock that has no enable op is always on.

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/clock.c |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 0ea5d92..79c0bd8 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -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);
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 07/21] ARM: tegra: clock: Drop CPU dvfs
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (5 preceding siblings ...)
  2011-02-19 22:25 ` [PATCH v2 06/21] ARM: tegra: clock: Initialize clocks that have no enable Colin Cross
@ 2011-02-19 22:25 ` Colin Cross
  2011-02-21  4:09   ` Olof Johansson
  2011-02-19 22:25 ` [PATCH v2 08/21] ARM: tegra: clock: Rearrange static clock tables Colin Cross
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:25 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

The 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.

Signed-off-by: Colin Cross <ccross@android.com>
---
 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

diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 6b537de..23de060 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -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
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 79c0bd8..a1193f9 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -24,81 +24,14 @@
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
-#include <linux/regulator/consumer.h>
 #include <linux/clkdev.h>
 
-#include "clock.h"
 #include "board.h"
-#include "fuse.h"
+#include "clock.h"
 
 static LIST_HEAD(clocks);
 
 static DEFINE_SPINLOCK(clock_lock);
-static DEFINE_MUTEX(dvfs_lock);
-
-static int clk_is_dvfs(struct clk *c)
-{
-	return (c->dvfs != NULL);
-};
-
-static int dvfs_set_rate(struct dvfs *d, unsigned long rate)
-{
-	struct dvfs_table *t;
-
-	if (d->table == NULL)
-		return -ENODEV;
-
-	for (t = d->table; t->rate != 0; t++) {
-		if (rate <= t->rate) {
-			if (!d->reg)
-				return 0;
-
-			return regulator_set_voltage(d->reg,
-				t->millivolts * 1000,
-				d->max_millivolts * 1000);
-		}
-	}
-
-	return -EINVAL;
-}
-
-static void dvfs_init(struct clk *c)
-{
-	int process_id;
-	int i;
-	struct dvfs_table *table;
-
-	process_id = c->dvfs->cpu ? tegra_core_process_id() :
-		tegra_cpu_process_id();
-
-	for (i = 0; i < c->dvfs->process_id_table_length; i++)
-		if (process_id == c->dvfs->process_id_table[i].process_id)
-			c->dvfs->table = c->dvfs->process_id_table[i].table;
-
-	if (c->dvfs->table == NULL) {
-		pr_err("Failed to find dvfs table for clock %s process %d\n",
-			c->name, process_id);
-		return;
-	}
-
-	c->dvfs->max_millivolts = 0;
-	for (table = c->dvfs->table; table->rate != 0; table++)
-		if (c->dvfs->max_millivolts < table->millivolts)
-			c->dvfs->max_millivolts = table->millivolts;
-
-	c->dvfs->reg = regulator_get(NULL, c->dvfs->reg_id);
-
-	if (IS_ERR(c->dvfs->reg)) {
-		pr_err("Failed to get regulator %s for clock %s\n",
-			c->dvfs->reg_id, c->name);
-		c->dvfs->reg = NULL;
-		return;
-	}
-
-	if (c->refcnt > 0)
-		dvfs_set_rate(c->dvfs, c->rate);
-}
-
 struct clk *tegra_get_clock_by_name(const char *name)
 {
 	struct clk *c;
@@ -214,34 +147,11 @@ int clk_enable_locked(struct clk *c)
 	return 0;
 }
 
-int clk_enable_cansleep(struct clk *c)
-{
-	int ret;
-	unsigned long flags;
-
-	mutex_lock(&dvfs_lock);
-
-	if (clk_is_dvfs(c) && c->refcnt > 0)
-		dvfs_set_rate(c->dvfs, c->rate);
-
-	spin_lock_irqsave(&clock_lock, flags);
-	ret = clk_enable_locked(c);
-	spin_unlock_irqrestore(&clock_lock, flags);
-
-	mutex_unlock(&dvfs_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL(clk_enable_cansleep);
-
 int clk_enable(struct clk *c)
 {
 	int ret;
 	unsigned long flags;
 
-	if (clk_is_dvfs(c))
-		BUG();
-
 	spin_lock_irqsave(&clock_lock, flags);
 	ret = clk_enable_locked(c);
 	spin_unlock_irqrestore(&clock_lock, flags);
@@ -268,30 +178,10 @@ void clk_disable_locked(struct clk *c)
 	c->refcnt--;
 }
 
-void clk_disable_cansleep(struct clk *c)
-{
-	unsigned long flags;
-
-	mutex_lock(&dvfs_lock);
-
-	spin_lock_irqsave(&clock_lock, flags);
-	clk_disable_locked(c);
-	spin_unlock_irqrestore(&clock_lock, flags);
-
-	if (clk_is_dvfs(c) && c->refcnt == 0)
-		dvfs_set_rate(c->dvfs, c->rate);
-
-	mutex_unlock(&dvfs_lock);
-}
-EXPORT_SYMBOL(clk_disable_cansleep);
-
 void clk_disable(struct clk *c)
 {
 	unsigned long flags;
 
-	if (clk_is_dvfs(c))
-		BUG();
-
 	spin_lock_irqsave(&clock_lock, flags);
 	clk_disable_locked(c);
 	spin_unlock_irqrestore(&clock_lock, flags);
@@ -356,41 +246,11 @@ int clk_set_rate_locked(struct clk *c, unsigned long rate)
 	return 0;
 }
 
-int clk_set_rate_cansleep(struct clk *c, unsigned long rate)
-{
-	int ret = 0;
-	unsigned long flags;
-
-	mutex_lock(&dvfs_lock);
-
-	if (rate > c->rate)
-		ret = dvfs_set_rate(c->dvfs, rate);
-	if (ret)
-		goto out;
-
-	spin_lock_irqsave(&clock_lock, flags);
-	ret = clk_set_rate_locked(c, rate);
-	spin_unlock_irqrestore(&clock_lock, flags);
-
-	if (ret)
-		goto out;
-
-	ret = dvfs_set_rate(c->dvfs, rate);
-
-out:
-	mutex_unlock(&dvfs_lock);
-	return ret;
-}
-EXPORT_SYMBOL(clk_set_rate_cansleep);
-
 int clk_set_rate(struct clk *c, unsigned long rate)
 {
 	int ret = 0;
 	unsigned long flags;
 
-	if (clk_is_dvfs(c))
-		BUG();
-
 	spin_lock_irqsave(&clock_lock, flags);
 	ret = clk_set_rate_locked(c, rate);
 	spin_unlock_irqrestore(&clock_lock, flags);
@@ -503,23 +363,6 @@ void __init tegra_init_clock(void)
 	tegra2_init_clocks();
 }
 
-int __init tegra_init_dvfs(void)
-{
-	struct clk *c, *safe;
-
-	mutex_lock(&dvfs_lock);
-
-	list_for_each_entry_safe(c, safe, &clocks, node)
-		if (c->dvfs)
-			dvfs_init(c);
-
-	mutex_unlock(&dvfs_lock);
-
-	return 0;
-}
-
-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.
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index b76d33d..198f234 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -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;
 };
 
 
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index ad26a9f..cda03f1 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -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);
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
index a217f68..6338652 100644
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ b/arch/arm/mach-tegra/include/mach/clk.h
@@ -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
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 36da2e8..e1e0d81f 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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 = {
diff --git a/arch/arm/mach-tegra/tegra2_dvfs.c b/arch/arm/mach-tegra/tegra2_dvfs.c
deleted file mode 100644
index 5529c23..0000000
--- a/arch/arm/mach-tegra/tegra2_dvfs.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * arch/arm/mach-tegra/tegra2_dvfs.c
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- *	Colin Cross <ccross@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-
-#include "clock.h"
-#include "tegra2_dvfs.h"
-
-static struct dvfs_table virtual_cpu_process_0[] = {
-	{314000000,  750},
-	{456000000,  825},
-	{608000000,  900},
-	{760000000,  975},
-	{817000000,  1000},
-	{912000000,  1050},
-	{1000000000, 1100},
-	{0, 0},
-};
-
-static struct dvfs_table virtual_cpu_process_1[] = {
-	{314000000,  750},
-	{456000000,  825},
-	{618000000,  900},
-	{770000000,  975},
-	{827000000,  1000},
-	{922000000,  1050},
-	{1000000000, 1100},
-	{0, 0},
-};
-
-static struct dvfs_table virtual_cpu_process_2[] = {
-	{494000000,  750},
-	{675000000,  825},
-	{817000000,  875},
-	{922000000,  925},
-	{1000000000, 975},
-	{0, 0},
-};
-
-static struct dvfs_table virtual_cpu_process_3[] = {
-	{730000000,  750},
-	{760000000,  775},
-	{845000000,  800},
-	{1000000000, 875},
-	{0, 0},
-};
-
-struct dvfs tegra_dvfs_virtual_cpu_dvfs = {
-	.reg_id = "vdd_cpu",
-	.process_id_table = {
-		{
-			.process_id = 0,
-			.table = virtual_cpu_process_0,
-		},
-		{
-			.process_id = 1,
-			.table = virtual_cpu_process_1,
-		},
-		{
-			.process_id = 2,
-			.table = virtual_cpu_process_2,
-		},
-		{
-			.process_id = 3,
-			.table = virtual_cpu_process_3,
-		},
-	},
-	.process_id_table_length = 4,
-	.cpu = 1,
-};
diff --git a/arch/arm/mach-tegra/tegra2_dvfs.h b/arch/arm/mach-tegra/tegra2_dvfs.h
deleted file mode 100644
index f8c1adb..0000000
--- a/arch/arm/mach-tegra/tegra2_dvfs.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * arch/arm/mach-tegra/tegra2_dvfs.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- *	Colin Cross <ccross@google.com>
- *
- * 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;
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 08/21] ARM: tegra: clock: Rearrange static clock tables
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (6 preceding siblings ...)
  2011-02-19 22:25 ` [PATCH v2 07/21] ARM: tegra: clock: Drop CPU dvfs Colin Cross
@ 2011-02-19 22:25 ` Colin Cross
  2011-02-21  4:09   ` Olof Johansson
  2011-02-19 22:25 ` [PATCH v2 09/21] ARM: tegra: clock: Move unshared clk struct members into union Colin Cross
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:25 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

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 <ccross@android.com>
---
 arch/arm/mach-tegra/tegra2_clocks.c |  106 +++++++++++++++++------------------
 1 files changed, 51 insertions(+), 55 deletions(-)

diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index e1e0d81f..62ec3fb 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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();
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 09/21] ARM: tegra: clock: Move unshared clk struct members into union
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (7 preceding siblings ...)
  2011-02-19 22:25 ` [PATCH v2 08/21] ARM: tegra: clock: Rearrange static clock tables Colin Cross
@ 2011-02-19 22:25 ` Colin Cross
  2011-02-21  4:10   ` Olof Johansson
  2011-02-19 22:25 ` [PATCH v2 10/21] ARM: tegra: clock: Convert global lock to a lock per clock Colin Cross
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:25 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/clock.h         |   85 +++++++------
 arch/arm/mach-tegra/tegra2_clocks.c |  234 ++++++++++++++++++++---------------
 2 files changed, 176 insertions(+), 143 deletions(-)

diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index 198f234..20f0ce6 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -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;
 };
 
 
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 62ec3fb..f03c712 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -109,9 +109,9 @@
 
 #define PLLE_MISC_READY			(1 << 15)
 
-#define PERIPH_CLK_TO_ENB_REG(c)	((c->clk_num / 32) * 4)
-#define PERIPH_CLK_TO_ENB_SET_REG(c)	((c->clk_num / 32) * 8)
-#define PERIPH_CLK_TO_ENB_BIT(c)	(1 << (c->clk_num % 32))
+#define PERIPH_CLK_TO_ENB_REG(c)	((c->u.periph.clk_num / 32) * 4)
+#define PERIPH_CLK_TO_ENB_SET_REG(c)	((c->u.periph.clk_num / 32) * 8)
+#define PERIPH_CLK_TO_ENB_BIT(c)	(1 << (c->u.periph.clk_num % 32))
 
 #define SUPER_CLK_MUX			0x00
 #define SUPER_STATE_SHIFT		28
@@ -378,24 +378,24 @@ static void tegra2_cpu_clk_disable(struct clk *c)
 static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate)
 {
 	int ret;
-	ret = clk_set_parent_locked(c->parent, c->backup);
+	ret = clk_set_parent_locked(c->parent, c->u.cpu.backup);
 	if (ret) {
-		pr_err("Failed to switch cpu to clock %s\n", c->backup->name);
+		pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.backup->name);
 		return ret;
 	}
 
-	if (rate == c->backup->rate)
+	if (rate == c->u.cpu.backup->rate)
 		goto out;
 
-	ret = clk_set_rate_locked(c->main, rate);
+	ret = clk_set_rate_locked(c->u.cpu.main, rate);
 	if (ret) {
 		pr_err("Failed to change cpu pll to %lu\n", rate);
 		return ret;
 	}
 
-	ret = clk_set_parent_locked(c->parent, c->main);
+	ret = clk_set_parent_locked(c->parent, c->u.cpu.main);
 	if (ret) {
-		pr_err("Failed to switch cpu to clock %s\n", c->main->name);
+		pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.main->name);
 		return ret;
 	}
 
@@ -543,7 +543,7 @@ static struct clk_ops tegra_blink_clk_ops = {
 /* PLL Functions */
 static int tegra2_pll_clk_wait_for_lock(struct clk *c)
 {
-	udelay(c->pll_lock_delay);
+	udelay(c->u.pll.lock_delay);
 
 	return 0;
 }
@@ -600,12 +600,12 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
 {
 	u32 val;
 	unsigned long input_rate;
-	const struct clk_pll_table *sel;
+	const struct clk_pll_freq_table *sel;
 
 	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
 
 	input_rate = c->parent->rate;
-	for (sel = c->pll_table; sel->input_rate != 0; sel++) {
+	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
 		if (sel->input_rate == input_rate && sel->output_rate == rate) {
 			c->mul = sel->n;
 			c->div = sel->m * sel->p;
@@ -1138,7 +1138,7 @@ static struct clk tegra_clk_32k = {
 	.max_rate = 32768,
 };
 
-static struct clk_pll_table tegra_pll_s_table[] = {
+static struct clk_pll_freq_table tegra_pll_s_freq_table[] = {
 	{32768, 12000000, 366, 1, 1, 0},
 	{32768, 13000000, 397, 1, 1, 0},
 	{32768, 19200000, 586, 1, 1, 0},
@@ -1150,17 +1150,19 @@ static struct clk tegra_pll_s = {
 	.name      = "pll_s",
 	.flags     = PLL_ALT_MISC_REG,
 	.ops       = &tegra_pll_ops,
-	.reg       = 0xf0,
-	.input_min = 32768,
-	.input_max = 32768,
 	.parent    = &tegra_clk_32k,
-	.cf_min    = 0, /* FIXME */
-	.cf_max    = 0, /* FIXME */
-	.vco_min   = 12000000,
-	.vco_max   = 26000000,
-	.pll_table = tegra_pll_s_table,
 	.max_rate  = 26000000,
-	.pll_lock_delay = 300,
+	.reg       = 0xf0,
+	.u.pll = {
+		.input_min = 32768,
+		.input_max = 32768,
+		.cf_min    = 0, /* FIXME */
+		.cf_max    = 0, /* FIXME */
+		.vco_min   = 12000000,
+		.vco_max   = 26000000,
+		.freq_table = tegra_pll_s_freq_table,
+		.lock_delay = 300,
+	},
 };
 
 static struct clk_mux_sel tegra_clk_m_sel[] = {
@@ -1168,18 +1170,18 @@ static struct clk_mux_sel tegra_clk_m_sel[] = {
 	{ .input = &tegra_pll_s,  .value = 1},
 	{ 0, 0},
 };
+
 static struct clk tegra_clk_m = {
 	.name      = "clk_m",
 	.flags     = ENABLE_ON_INIT,
 	.ops       = &tegra_clk_m_ops,
 	.inputs    = tegra_clk_m_sel,
 	.reg       = 0x1fc,
-	.reg_mask  = (1<<28),
 	.reg_shift = 28,
 	.max_rate  = 26000000,
 };
 
-static struct clk_pll_table tegra_pll_c_table[] = {
+static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
 	{ 0, 0, 0, 0, 0, 0 },
 };
 
@@ -1188,16 +1190,18 @@ static struct clk tegra_pll_c = {
 	.flags	   = PLL_HAS_CPCON,
 	.ops       = &tegra_pll_ops,
 	.reg       = 0x80,
-	.input_min = 2000000,
-	.input_max = 31000000,
 	.parent    = &tegra_clk_m,
-	.cf_min    = 1000000,
-	.cf_max    = 6000000,
-	.vco_min   = 20000000,
-	.vco_max   = 1400000000,
-	.pll_table = tegra_pll_c_table,
 	.max_rate  = 600000000,
-	.pll_lock_delay = 300,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 31000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 20000000,
+		.vco_max   = 1400000000,
+		.freq_table = tegra_pll_c_freq_table,
+		.lock_delay = 300,
+	},
 };
 
 static struct clk tegra_pll_c_out1 = {
@@ -1210,7 +1214,7 @@ static struct clk tegra_pll_c_out1 = {
 	.max_rate  = 600000000,
 };
 
-static struct clk_pll_table tegra_pll_m_table[] = {
+static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
 	{ 12000000, 666000000, 666, 12, 1, 8},
 	{ 13000000, 666000000, 666, 13, 1, 8},
 	{ 19200000, 666000000, 555, 16, 1, 8},
@@ -1227,16 +1231,18 @@ static struct clk tegra_pll_m = {
 	.flags     = PLL_HAS_CPCON,
 	.ops       = &tegra_pll_ops,
 	.reg       = 0x90,
-	.input_min = 2000000,
-	.input_max = 31000000,
 	.parent    = &tegra_clk_m,
-	.cf_min    = 1000000,
-	.cf_max    = 6000000,
-	.vco_min   = 20000000,
-	.vco_max   = 1200000000,
-	.pll_table = tegra_pll_m_table,
 	.max_rate  = 800000000,
-	.pll_lock_delay = 300,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 31000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 20000000,
+		.vco_max   = 1200000000,
+		.freq_table = tegra_pll_m_freq_table,
+		.lock_delay = 300,
+	},
 };
 
 static struct clk tegra_pll_m_out1 = {
@@ -1249,7 +1255,7 @@ static struct clk tegra_pll_m_out1 = {
 	.max_rate  = 600000000,
 };
 
-static struct clk_pll_table tegra_pll_p_table[] = {
+static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
 	{ 12000000, 216000000, 432, 12, 2, 8},
 	{ 13000000, 216000000, 432, 13, 2, 8},
 	{ 19200000, 216000000, 90,   4, 2, 1},
@@ -1266,16 +1272,18 @@ static struct clk tegra_pll_p = {
 	.flags     = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
 	.ops       = &tegra_pll_ops,
 	.reg       = 0xa0,
-	.input_min = 2000000,
-	.input_max = 31000000,
 	.parent    = &tegra_clk_m,
-	.cf_min    = 1000000,
-	.cf_max    = 6000000,
-	.vco_min   = 20000000,
-	.vco_max   = 1400000000,
-	.pll_table = tegra_pll_p_table,
 	.max_rate  = 432000000,
-	.pll_lock_delay = 300,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 31000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 20000000,
+		.vco_max   = 1400000000,
+		.freq_table = tegra_pll_p_freq_table,
+		.lock_delay = 300,
+	},
 };
 
 static struct clk tegra_pll_p_out1 = {
@@ -1318,7 +1326,7 @@ static struct clk tegra_pll_p_out4 = {
 	.max_rate  = 432000000,
 };
 
-static struct clk_pll_table tegra_pll_a_table[] = {
+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},
@@ -1332,16 +1340,18 @@ static struct clk tegra_pll_a = {
 	.flags     = PLL_HAS_CPCON,
 	.ops       = &tegra_pll_ops,
 	.reg       = 0xb0,
-	.input_min = 2000000,
-	.input_max = 31000000,
 	.parent    = &tegra_pll_p_out1,
-	.cf_min    = 1000000,
-	.cf_max    = 6000000,
-	.vco_min   = 20000000,
-	.vco_max   = 1400000000,
-	.pll_table = tegra_pll_a_table,
 	.max_rate  = 56448000,
-	.pll_lock_delay = 300,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 31000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 20000000,
+		.vco_max   = 1400000000,
+		.freq_table = tegra_pll_a_freq_table,
+		.lock_delay = 300,
+	},
 };
 
 static struct clk tegra_pll_a_out0 = {
@@ -1354,7 +1364,7 @@ static struct clk tegra_pll_a_out0 = {
 	.max_rate  = 56448000,
 };
 
-static struct clk_pll_table tegra_pll_d_table[] = {
+static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
 	{ 12000000, 216000000, 216, 12, 1, 4},
 	{ 13000000, 216000000, 216, 13, 1, 4},
 	{ 19200000, 216000000, 135, 12, 1, 3},
@@ -1378,16 +1388,18 @@ static struct clk tegra_pll_d = {
 	.flags     = PLL_HAS_CPCON | PLLD,
 	.ops       = &tegra_pll_ops,
 	.reg       = 0xd0,
-	.input_min = 2000000,
-	.input_max = 40000000,
 	.parent    = &tegra_clk_m,
-	.cf_min    = 1000000,
-	.cf_max    = 6000000,
-	.vco_min   = 40000000,
-	.vco_max   = 1000000000,
-	.pll_table = tegra_pll_d_table,
 	.max_rate  = 1000000000,
-	.pll_lock_delay = 1000,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 40000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 40000000,
+		.vco_max   = 1000000000,
+		.freq_table = tegra_pll_d_freq_table,
+		.lock_delay = 1000,
+	},
 };
 
 static struct clk tegra_pll_d_out0 = {
@@ -1398,7 +1410,7 @@ static struct clk tegra_pll_d_out0 = {
 	.max_rate  = 500000000,
 };
 
-static struct clk_pll_table tegra_pll_u_table[] = {
+static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
 	{ 12000000, 480000000, 960, 12, 2, 0},
 	{ 13000000, 480000000, 960, 13, 2, 0},
 	{ 19200000, 480000000, 200, 4,  2, 0},
@@ -1411,19 +1423,21 @@ static struct clk tegra_pll_u = {
 	.flags     = PLLU,
 	.ops       = &tegra_pll_ops,
 	.reg       = 0xc0,
-	.input_min = 2000000,
-	.input_max = 40000000,
 	.parent    = &tegra_clk_m,
-	.cf_min    = 1000000,
-	.cf_max    = 6000000,
-	.vco_min   = 480000000,
-	.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[] = {
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 40000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 480000000,
+		.vco_max   = 960000000,
+		.freq_table = tegra_pll_u_freq_table,
+		.lock_delay = 1000,
+	},
+};
+
+static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
 	/* 1 GHz */
 	{ 12000000, 1000000000, 1000, 12, 1, 12},
 	{ 13000000, 1000000000, 1000, 13, 1, 12},
@@ -1474,19 +1488,21 @@ static struct clk tegra_pll_x = {
 	.flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG,
 	.ops       = &tegra_pllx_ops,
 	.reg       = 0xe0,
-	.input_min = 2000000,
-	.input_max = 31000000,
 	.parent    = &tegra_clk_m,
-	.cf_min    = 1000000,
-	.cf_max    = 6000000,
-	.vco_min   = 20000000,
-	.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[] = {
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 31000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 20000000,
+		.vco_max   = 1200000000,
+		.freq_table = tegra_pll_x_freq_table,
+		.lock_delay = 300,
+	},
+};
+
+static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
 	{ 12000000, 100000000,  200,  24, 1, 0 },
 	{ 0, 0, 0, 0, 0, 0 },
 };
@@ -1495,41 +1511,49 @@ static struct clk tegra_pll_e = {
 	.name      = "pll_e",
 	.flags	   = PLL_ALT_MISC_REG,
 	.ops       = &tegra_plle_ops,
-	.input_min = 12000000,
-	.input_max = 12000000,
-	.max_rate  = 100000000,
 	.parent    = &tegra_clk_m,
 	.reg       = 0xe8,
-	.pll_table = tegra_pll_e_table,
+	.max_rate  = 100000000,
+	.u.pll = {
+		.input_min = 12000000,
+		.input_max = 12000000,
+		.freq_table = tegra_pll_e_freq_table,
+	},
 };
 
 static struct clk tegra_clk_d = {
 	.name      = "clk_d",
 	.flags     = PERIPH_NO_RESET,
 	.ops       = &tegra_clk_double_ops,
-	.clk_num   = 90,
 	.reg       = 0x34,
 	.reg_shift = 12,
 	.parent    = &tegra_clk_m,
 	.max_rate  = 52000000,
+	.u.periph  = {
+		.clk_num = 90,
+	},
 };
 
 /* dap_mclk1, belongs to the cdev1 pingroup. */
 static struct clk tegra_dev1_clk = {
 	.name      = "clk_dev1",
 	.ops       = &tegra_cdev_clk_ops,
-	.clk_num   = 94,
 	.rate      = 26000000,
 	.max_rate  = 26000000,
+	.u.periph  = {
+		.clk_num = 94,
+	},
 };
 
 /* dap_mclk2, belongs to the cdev2 pingroup. */
 static struct clk tegra_dev2_clk = {
 	.name      = "clk_dev2",
 	.ops       = &tegra_cdev_clk_ops,
-	.clk_num   = 93,
 	.rate      = 26000000,
 	.max_rate  = 26000000,
+	.u.periph  = {
+		.clk_num   = 93,
+	},
 };
 
 /* initialized before peripheral clocks */
@@ -1564,10 +1588,12 @@ static struct clk tegra_clk_audio_2x = {
 	.flags     = PERIPH_NO_RESET,
 	.max_rate  = 48000000,
 	.ops       = &tegra_clk_double_ops,
-	.clk_num   = 89,
 	.reg       = 0x34,
 	.reg_shift = 8,
 	.parent    = &tegra_clk_audio,
+	.u.periph = {
+		.clk_num = 89,
+	},
 };
 
 struct clk_lookup tegra_audio_clk_lookups[] = {
@@ -1645,10 +1671,12 @@ static struct clk tegra_clk_sclk = {
 static struct clk tegra_clk_virtual_cpu = {
 	.name      = "cpu",
 	.parent    = &tegra_clk_cclk,
-	.main      = &tegra_pll_x,
-	.backup    = &tegra_pll_p,
 	.ops       = &tegra_cpu_ops,
 	.max_rate  = 1000000000,
+	.u.cpu = {
+		.main      = &tegra_pll_x,
+		.backup    = &tegra_pll_p,
+	},
 };
 
 static struct clk tegra_clk_hclk = {
@@ -1763,11 +1791,13 @@ static struct clk_mux_sel mux_clk_32k[] = {
 			.con_id	   = _con,		\
 		},					\
 		.ops       = &tegra_periph_clk_ops,	\
-		.clk_num   = _clk_num,			\
 		.reg       = _reg,			\
 		.inputs    = _inputs,			\
 		.flags     = _flags,			\
 		.max_rate  = _max,			\
+		.u.periph = {				\
+			.clk_num   = _clk_num,		\
+		},					\
 	}
 
 struct clk tegra_list_clks[] = {
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 10/21] ARM: tegra: clock: Convert global lock to a lock per clock
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (8 preceding siblings ...)
  2011-02-19 22:25 ` [PATCH v2 09/21] ARM: tegra: clock: Move unshared clk struct members into union Colin Cross
@ 2011-02-19 22:25 ` Colin Cross
  2011-02-21  4:11   ` Olof Johansson
  2011-02-19 22:26 ` [PATCH v2 11/21] ARM: tegra: cpufreq: Take an extra reference to pllx Colin Cross
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:25 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

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 <ccross@android.com>
---
 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(-)

diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index a1193f9..f6c934a 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -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;
 }
 
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index 20f0ce6..a63dbf9 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -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
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
index 6338652..fa7f9ca 100644
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ b/arch/arm/mach-tegra/include/mach/clk.h
@@ -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
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index f03c712..ab013b1 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -23,8 +23,8 @@
 #include <linux/spinlock.h>
 #include <linux/delay.h>
 #include <linux/io.h>
-#include <linux/hrtimer.h>
 #include <linux/clkdev.h>
+#include <linux/clk.h>
 
 #include <mach/iomap.h>
 #include <mach/suspend.h>
@@ -147,6 +147,13 @@
 static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
 static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
 
+/*
+ * Some clocks share a register with other clocks.  Any clock op that
+ * non-atomically modifies a register used by another clock must lock
+ * clock_register_lock first.
+ */
+static DEFINE_SPINLOCK(clock_register_lock);
+
 #define clk_writel(value, reg) \
 	__raw_writel(value, (u32)reg_clk_base + (reg))
 #define clk_readl(reg) \
@@ -330,12 +337,12 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
 			val |= sel->value << shift;
 
 			if (c->refcnt)
-				clk_enable_locked(p);
+				clk_enable(p);
 
 			clk_writel(val, c->reg);
 
 			if (c->refcnt && c->parent)
-				clk_disable_locked(c->parent);
+				clk_disable(c->parent);
 
 			clk_reparent(c, p);
 			return 0;
@@ -378,22 +385,22 @@ static void tegra2_cpu_clk_disable(struct clk *c)
 static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate)
 {
 	int ret;
-	ret = clk_set_parent_locked(c->parent, c->u.cpu.backup);
+	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;
 	}
 
-	if (rate == c->u.cpu.backup->rate)
+	if (rate == clk_get_rate(c->u.cpu.backup))
 		goto out;
 
-	ret = clk_set_rate_locked(c->u.cpu.main, 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;
 	}
 
-	ret = clk_set_parent_locked(c->parent, c->u.cpu.main);
+	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;
@@ -421,24 +428,45 @@ static void tegra2_bus_clk_init(struct clk *c)
 
 static int tegra2_bus_clk_enable(struct clk *c)
 {
-	u32 val = clk_readl(c->reg);
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	val = clk_readl(c->reg);
 	val &= ~(BUS_CLK_DISABLE << c->reg_shift);
 	clk_writel(val, c->reg);
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
+
 	return 0;
 }
 
 static void tegra2_bus_clk_disable(struct clk *c)
 {
-	u32 val = clk_readl(c->reg);
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	val = clk_readl(c->reg);
 	val |= BUS_CLK_DISABLE << c->reg_shift;
 	clk_writel(val, c->reg);
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
 }
 
 static int tegra2_bus_clk_set_rate(struct clk *c, unsigned long rate)
 {
-	u32 val = clk_readl(c->reg);
-	unsigned long parent_rate = c->parent->rate;
+	u32 val;
+	unsigned long parent_rate = clk_get_rate(c->parent);
+	unsigned long flags;
+	int ret = -EINVAL;
 	int i;
+
+	spin_lock_irqsave(&clock_register_lock, flags);
+
+	val = clk_readl(c->reg);
 	for (i = 1; i <= 4; i++) {
 		if (rate == parent_rate / i) {
 			val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
@@ -446,10 +474,14 @@ static int tegra2_bus_clk_set_rate(struct clk *c, unsigned long rate)
 			clk_writel(val, c->reg);
 			c->div = i;
 			c->mul = 1;
-			return 0;
+			ret = 0;
+			break;
 		}
 	}
-	return -EINVAL;
+
+	spin_unlock_irqrestore(&clock_register_lock, flags);
+
+	return ret;
 }
 
 static struct clk_ops tegra_bus_ops = {
@@ -511,14 +543,15 @@ static void tegra2_blink_clk_disable(struct clk *c)
 
 static int tegra2_blink_clk_set_rate(struct clk *c, unsigned long rate)
 {
-	if (rate >= c->parent->rate) {
+	unsigned long parent_rate = clk_get_rate(c->parent);
+	if (rate >= parent_rate) {
 		c->div = 1;
 		pmc_writel(0, c->reg);
 	} else {
 		unsigned int on_off;
 		u32 val;
 
-		on_off = DIV_ROUND_UP(c->parent->rate / 8, rate);
+		on_off = DIV_ROUND_UP(parent_rate / 8, rate);
 		c->div = on_off * 8;
 
 		val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
@@ -604,7 +637,7 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
 
 	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
 
-	input_rate = c->parent->rate;
+	input_rate = clk_get_rate(c->parent);
 	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
 		if (sel->input_rate == input_rate && sel->output_rate == rate) {
 			c->mul = sel->n;
@@ -717,9 +750,11 @@ static int tegra2_pll_div_clk_enable(struct clk *c)
 {
 	u32 val;
 	u32 new_val;
+	unsigned long flags;
 
 	pr_debug("%s: %s\n", __func__, c->name);
 	if (c->flags & DIV_U71) {
+		spin_lock_irqsave(&clock_register_lock, flags);
 		val = clk_readl(c->reg);
 		new_val = val >> c->reg_shift;
 		new_val &= 0xFFFF;
@@ -729,12 +764,15 @@ static int tegra2_pll_div_clk_enable(struct clk *c)
 		val &= ~(0xFFFF << c->reg_shift);
 		val |= new_val << c->reg_shift;
 		clk_writel(val, c->reg);
+		spin_unlock_irqrestore(&clock_register_lock, flags);
 		return 0;
 	} else if (c->flags & DIV_2) {
 		BUG_ON(!(c->flags & PLLD));
+		spin_lock_irqsave(&clock_register_lock, flags);
 		val = clk_readl(c->reg);
 		val &= ~PLLD_MISC_DIV_RST;
 		clk_writel(val, c->reg);
+		spin_unlock_irqrestore(&clock_register_lock, flags);
 		return 0;
 	}
 	return -EINVAL;
@@ -744,9 +782,11 @@ static void tegra2_pll_div_clk_disable(struct clk *c)
 {
 	u32 val;
 	u32 new_val;
+	unsigned long flags;
 
 	pr_debug("%s: %s\n", __func__, c->name);
 	if (c->flags & DIV_U71) {
+		spin_lock_irqsave(&clock_register_lock, flags);
 		val = clk_readl(c->reg);
 		new_val = val >> c->reg_shift;
 		new_val &= 0xFFFF;
@@ -756,11 +796,14 @@ static void tegra2_pll_div_clk_disable(struct clk *c)
 		val &= ~(0xFFFF << c->reg_shift);
 		val |= new_val << c->reg_shift;
 		clk_writel(val, c->reg);
+		spin_unlock_irqrestore(&clock_register_lock, flags);
 	} else if (c->flags & DIV_2) {
 		BUG_ON(!(c->flags & PLLD));
+		spin_lock_irqsave(&clock_register_lock, flags);
 		val = clk_readl(c->reg);
 		val |= PLLD_MISC_DIV_RST;
 		clk_writel(val, c->reg);
+		spin_unlock_irqrestore(&clock_register_lock, flags);
 	}
 }
 
@@ -769,10 +812,14 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
 	u32 val;
 	u32 new_val;
 	int divider_u71;
+	unsigned long parent_rate = clk_get_rate(c->parent);
+	unsigned long flags;
+
 	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
 	if (c->flags & DIV_U71) {
-		divider_u71 = clk_div71_get_divider(c->parent->rate, rate);
+		divider_u71 = clk_div71_get_divider(parent_rate, rate);
 		if (divider_u71 >= 0) {
+			spin_lock_irqsave(&clock_register_lock, flags);
 			val = clk_readl(c->reg);
 			new_val = val >> c->reg_shift;
 			new_val &= 0xFFFF;
@@ -786,10 +833,11 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
 			clk_writel(val, c->reg);
 			c->div = divider_u71 + 2;
 			c->mul = 2;
+			spin_unlock_irqrestore(&clock_register_lock, flags);
 			return 0;
 		}
 	} else if (c->flags & DIV_2) {
-		if (c->parent->rate == rate * 2)
+		if (parent_rate == rate * 2)
 			return 0;
 	}
 	return -EINVAL;
@@ -798,15 +846,16 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
 static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
 {
 	int divider;
+	unsigned long parent_rate = clk_get_rate(c->parent);
 	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
 
 	if (c->flags & DIV_U71) {
-		divider = clk_div71_get_divider(c->parent->rate, rate);
+		divider = clk_div71_get_divider(parent_rate, rate);
 		if (divider < 0)
 			return divider;
-		return c->parent->rate * 2 / (divider + 2);
+		return parent_rate * 2 / (divider + 2);
 	} else if (c->flags & DIV_2) {
-		return c->parent->rate / 2;
+		return parent_rate / 2;
 	}
 	return -EINVAL;
 }
@@ -912,12 +961,12 @@ static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
 			val |= (sel->value) << PERIPH_CLK_SOURCE_SHIFT;
 
 			if (c->refcnt)
-				clk_enable_locked(p);
+				clk_enable(p);
 
 			clk_writel(val, c->reg);
 
 			if (c->refcnt && c->parent)
-				clk_disable_locked(c->parent);
+				clk_disable(c->parent);
 
 			clk_reparent(c, p);
 			return 0;
@@ -931,9 +980,10 @@ static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
 {
 	u32 val;
 	int divider;
-	pr_debug("%s: %lu\n", __func__, rate);
+	unsigned long parent_rate = clk_get_rate(c->parent);
+
 	if (c->flags & DIV_U71) {
-		divider = clk_div71_get_divider(c->parent->rate, rate);
+		divider = clk_div71_get_divider(parent_rate, rate);
 		if (divider >= 0) {
 			val = clk_readl(c->reg);
 			val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
@@ -944,7 +994,7 @@ static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
 			return 0;
 		}
 	} else if (c->flags & DIV_U16) {
-		divider = clk_div16_get_divider(c->parent->rate, rate);
+		divider = clk_div16_get_divider(parent_rate, rate);
 		if (divider >= 0) {
 			val = clk_readl(c->reg);
 			val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
@@ -954,7 +1004,7 @@ static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
 			c->mul = 1;
 			return 0;
 		}
-	} else if (c->parent->rate <= rate) {
+	} else if (parent_rate <= rate) {
 		c->div = 1;
 		c->mul = 1;
 		return 0;
@@ -966,19 +1016,20 @@ static long tegra2_periph_clk_round_rate(struct clk *c,
 	unsigned long rate)
 {
 	int divider;
+	unsigned long parent_rate = clk_get_rate(c->parent);
 	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
 
 	if (c->flags & DIV_U71) {
-		divider = clk_div71_get_divider(c->parent->rate, rate);
+		divider = clk_div71_get_divider(parent_rate, rate);
 		if (divider < 0)
 			return divider;
 
-		return c->parent->rate * 2 / (divider + 2);
+		return parent_rate * 2 / (divider + 2);
 	} else if (c->flags & DIV_U16) {
-		divider = clk_div16_get_divider(c->parent->rate, rate);
+		divider = clk_div16_get_divider(parent_rate, rate);
 		if (divider < 0)
 			return divider;
-		return c->parent->rate / (divider + 1);
+		return parent_rate / (divider + 1);
 	}
 	return -EINVAL;
 }
@@ -1006,7 +1057,7 @@ static void tegra2_clk_double_init(struct clk *c)
 
 static int tegra2_clk_double_set_rate(struct clk *c, unsigned long rate)
 {
-	if (rate != 2 * c->parent->rate)
+	if (rate != 2 * clk_get_rate(c->parent))
 		return -EINVAL;
 	c->mul = 2;
 	c->div = 1;
@@ -1057,12 +1108,12 @@ static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
 			val |= sel->value;
 
 			if (c->refcnt)
-				clk_enable_locked(p);
+				clk_enable(p);
 
 			clk_writel(val, c->reg);
 
 			if (c->refcnt && c->parent)
-				clk_disable_locked(c->parent);
+				clk_disable(c->parent);
 
 			clk_reparent(c, p);
 			return 0;
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 11/21] ARM: tegra: cpufreq: Take an extra reference to pllx
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (9 preceding siblings ...)
  2011-02-19 22:25 ` [PATCH v2 10/21] ARM: tegra: clock: Convert global lock to a lock per clock Colin Cross
@ 2011-02-19 22:26 ` Colin Cross
  2011-02-21  4:12   ` Olof Johansson
  2011-02-19 22:26 ` [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:26 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

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 <ccross@android.com>
---
 arch/arm/mach-tegra/cpu-tegra.c     |    2 ++
 arch/arm/mach-tegra/tegra2_clocks.c |   15 +++++++++++----
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index cda03f1..f02ba60 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -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);
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index ab013b1..a1c86d8 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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 = {
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (10 preceding siblings ...)
  2011-02-19 22:26 ` [PATCH v2 11/21] ARM: tegra: cpufreq: Take an extra reference to pllx Colin Cross
@ 2011-02-19 22:26 ` Colin Cross
  2011-02-19 22:26 ` [PATCH v2 13/21] ARM: tegra: clock: Remove unnecessary uses of #ifdef CONFIG_DEBUG_FS Colin Cross
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:26 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, sboyd, Russell King,
	linux-kernel

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.

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/clock.h         |    8 +++
 arch/arm/mach-tegra/tegra2_clocks.c |  116 +++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index a63dbf9..bb755c2 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -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;
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index a1c86d8..dd53af3 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -1188,6 +1188,110 @@ static struct clk_ops tegra_cdev_clk_ops = {
 	.disable		= &tegra2_cdev_clk_disable,
 };
 
+/* shared bus ops */
+/*
+ * 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.
+ */
+static int tegra_clk_shared_bus_update(struct clk *bus)
+{
+	struct clk *c;
+	unsigned long rate = bus->min_rate;
+
+	list_for_each_entry(c, &bus->shared_bus_list, u.shared_bus_user.node)
+		if (c->u.shared_bus_user.enabled)
+			rate = max(c->u.shared_bus_user.rate, rate);
+
+	if (rate == clk_get_rate_locked(bus))
+		return 0;
+
+	return clk_set_rate_locked(bus, rate);
+};
+
+static void tegra_clk_shared_bus_init(struct clk *c)
+{
+	unsigned long flags;
+
+	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
+
+	spin_lock_irqsave(&c->parent->spinlock, flags);
+
+	list_add_tail(&c->u.shared_bus_user.node,
+		&c->parent->shared_bus_list);
+
+	spin_unlock_irqrestore(&c->parent->spinlock, flags);
+}
+
+static int tegra_clk_shared_bus_set_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long flags;
+	int ret;
+
+	rate = clk_round_rate(c->parent, rate);
+	if (rate < 0)
+		return rate;
+
+	spin_lock_irqsave(&c->parent->spinlock, flags);
+
+	c->u.shared_bus_user.rate = rate;
+	ret = tegra_clk_shared_bus_update(c->parent);
+
+	spin_unlock_irqrestore(&c->parent->spinlock, flags);
+
+	return ret;
+}
+
+static long tegra_clk_shared_bus_round_rate(struct clk *c, unsigned long rate)
+{
+	return clk_round_rate(c->parent, rate);
+}
+
+static int tegra_clk_shared_bus_enable(struct clk *c)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&c->parent->spinlock, flags);
+
+	c->u.shared_bus_user.enabled = true;
+	ret = tegra_clk_shared_bus_update(c->parent);
+
+	spin_unlock_irqrestore(&c->parent->spinlock, flags);
+
+	return ret;
+}
+
+static void tegra_clk_shared_bus_disable(struct clk *c)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&c->parent->spinlock, flags);
+
+	c->u.shared_bus_user.enabled = false;
+	ret = tegra_clk_shared_bus_update(c->parent);
+	WARN_ON_ONCE(ret);
+
+	spin_unlock_irqrestore(&c->parent->spinlock, flags);
+}
+
+static struct clk_ops tegra_clk_shared_bus_ops = {
+	.init = tegra_clk_shared_bus_init,
+	.enable = tegra_clk_shared_bus_enable,
+	.disable = tegra_clk_shared_bus_disable,
+	.set_rate = tegra_clk_shared_bus_set_rate,
+	.round_rate = tegra_clk_shared_bus_round_rate,
+};
+
+
 /* Clock definitions */
 static struct clk tegra_clk_32k = {
 	.name = "clk_32k",
@@ -1858,6 +1962,17 @@ static struct clk_mux_sel mux_clk_32k[] = {
 		},					\
 	}
 
+#define SHARED_CLK(_name, _dev, _con, _parent)		\
+	{						\
+		.name      = _name,			\
+		.lookup    = {				\
+			.dev_id    = _dev,		\
+			.con_id    = _con,		\
+		},					\
+		.ops       = &tegra_clk_shared_bus_ops,	\
+		.parent = _parent,			\
+	}
+
 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),
@@ -2001,6 +2116,7 @@ struct clk *tegra_ptr_clks[] = {
 static void tegra2_init_one_clock(struct clk *c)
 {
 	clk_init(c);
+	INIT_LIST_HEAD(&c->shared_bus_list);
 	if (!c->lookup.dev_id && !c->lookup.con_id)
 		c->lookup.con_id = c->name;
 	c->lookup.clk = c;
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 13/21] ARM: tegra: clock: Remove unnecessary uses of #ifdef CONFIG_DEBUG_FS
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (11 preceding siblings ...)
  2011-02-19 22:26 ` [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
@ 2011-02-19 22:26 ` Colin Cross
  2011-02-21  4:17   ` Olof Johansson
  2011-02-19 22:26 ` [PATCH v2 14/21] ARM: tegra: clock: Refcount periph clock enables Colin Cross
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:26 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

Signed-off-by: Colin Cross <ccross@android.com>
---
 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(-)

diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index f6c934a..8d01a49 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -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++;
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index bb755c2..ebe6ea8 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -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;
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index dd53af3..196c249 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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);
 
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 14/21] ARM: tegra: clock: Refcount periph clock enables
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (12 preceding siblings ...)
  2011-02-19 22:26 ` [PATCH v2 13/21] ARM: tegra: clock: Remove unnecessary uses of #ifdef CONFIG_DEBUG_FS Colin Cross
@ 2011-02-19 22:26 ` Colin Cross
  2011-02-21  4:18   ` Olof Johansson
  2011-02-19 22:26 ` [PATCH v2 15/21] ARM: tegra: clock: Round rate before setting rate Colin Cross
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:26 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

Some peripheral clocks share enable bits.  Refcount the enables so
that calling clk_disable on one clock will not turn off another
clock.

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/tegra2_clocks.c |   35 +++++++++++++++++++++++++++++------
 1 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 196c249..2734889 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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 */
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 15/21] ARM: tegra: clock: Round rate before setting rate
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (13 preceding siblings ...)
  2011-02-19 22:26 ` [PATCH v2 14/21] ARM: tegra: clock: Refcount periph clock enables Colin Cross
@ 2011-02-19 22:26 ` Colin Cross
  2011-02-21  4:19   ` Olof Johansson
  2011-02-19 22:26 ` [PATCH v2 16/21] ARM: tegra: Add external memory controller driver Colin Cross
                   ` (6 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:26 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

Call 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.

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/clock.c         |   12 ++++++++++++
 arch/arm/mach-tegra/tegra2_clocks.c |    8 ++++----
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 8d01a49..9798585 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -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);
 }
 
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 2734889..480c0f6 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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;
 }
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 16/21] ARM: tegra: Add external memory controller driver
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (14 preceding siblings ...)
  2011-02-19 22:26 ` [PATCH v2 15/21] ARM: tegra: clock: Round rate before setting rate Colin Cross
@ 2011-02-19 22:26 ` Colin Cross
  2011-02-21  4:20   ` Olof Johansson
  2011-02-19 22:26 ` [PATCH v2 17/21] ARM: tegra: clocks: Add emc scaling Colin Cross
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:26 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

Signed-off-by: Colin Cross <ccross@android.com>
---
 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

diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 9f4fc6b..42d44c7 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -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
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 23de060..3fe357b 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -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
diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c
new file mode 100644
index 0000000..bd4fa27
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra2_emc.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *	Colin Cross <ccross@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+#include <mach/iomap.h>
+
+#include "tegra2_emc.h"
+
+#ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
+static bool emc_enable = true;
+#else
+static bool emc_enable;
+#endif
+module_param(emc_enable, bool, 0644);
+
+static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE);
+static const struct tegra_emc_table *tegra_emc_table;
+static int tegra_emc_table_size;
+
+static inline void emc_writel(u32 val, unsigned long addr)
+{
+	writel(val, emc + addr);
+}
+
+static inline u32 emc_readl(unsigned long addr)
+{
+	return readl(emc + addr);
+}
+
+static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
+	0x2c,	/* RC */
+	0x30,	/* RFC */
+	0x34,	/* RAS */
+	0x38,	/* RP */
+	0x3c,	/* R2W */
+	0x40,	/* W2R */
+	0x44,	/* R2P */
+	0x48,	/* W2P */
+	0x4c,	/* RD_RCD */
+	0x50,	/* WR_RCD */
+	0x54,	/* RRD */
+	0x58,	/* REXT */
+	0x5c,	/* WDV */
+	0x60,	/* QUSE */
+	0x64,	/* QRST */
+	0x68,	/* QSAFE */
+	0x6c,	/* RDV */
+	0x70,	/* REFRESH */
+	0x74,	/* BURST_REFRESH_NUM */
+	0x78,	/* PDEX2WR */
+	0x7c,	/* PDEX2RD */
+	0x80,	/* PCHG2PDEN */
+	0x84,	/* ACT2PDEN */
+	0x88,	/* AR2PDEN */
+	0x8c,	/* RW2PDEN */
+	0x90,	/* TXSR */
+	0x94,	/* TCKE */
+	0x98,	/* TFAW */
+	0x9c,	/* TRPAB */
+	0xa0,	/* TCLKSTABLE */
+	0xa4,	/* TCLKSTOP */
+	0xa8,	/* TREFBW */
+	0xac,	/* QUSE_EXTRA */
+	0x114,	/* FBIO_CFG6 */
+	0xb0,	/* ODT_WRITE */
+	0xb4,	/* ODT_READ */
+	0x104,	/* FBIO_CFG5 */
+	0x2bc,	/* CFG_DIG_DLL */
+	0x2c0,	/* DLL_XFORM_DQS */
+	0x2c4,	/* DLL_XFORM_QUSE */
+	0x2e0,	/* ZCAL_REF_CNT */
+	0x2e4,	/* ZCAL_WAIT_CNT */
+	0x2a8,	/* AUTO_CAL_INTERVAL */
+	0x2d0,	/* CFG_CLKTRIM_0 */
+	0x2d4,	/* CFG_CLKTRIM_1 */
+	0x2d8,	/* CFG_CLKTRIM_2 */
+};
+
+/* Select the closest EMC rate that is higher than the requested rate */
+long tegra_emc_round_rate(unsigned long rate)
+{
+	int i;
+	int best = -1;
+	unsigned long distance = ULONG_MAX;
+
+	if (!tegra_emc_table)
+		return -EINVAL;
+
+	if (!emc_enable)
+		return -EINVAL;
+
+	pr_debug("%s: %lu\n", __func__, rate);
+
+	/* The EMC clock rate is twice the bus rate, and the bus rate is
+	 * measured in kHz */
+	rate = rate / 2 / 1000;
+
+	for (i = 0; i < tegra_emc_table_size; i++) {
+		if (tegra_emc_table[i].rate >= rate &&
+		    (tegra_emc_table[i].rate - rate) < distance) {
+			distance = tegra_emc_table[i].rate - rate;
+			best = i;
+		}
+	}
+
+	if (best < 0)
+		return -EINVAL;
+
+	pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate);
+
+	return tegra_emc_table[best].rate * 2 * 1000;
+}
+
+/* The EMC registers have shadow registers.  When the EMC clock is updated
+ * in the clock controller, the shadow registers are copied to the active
+ * registers, allowing glitchless memory bus frequency changes.
+ * This function updates the shadow registers for a new clock frequency,
+ * and relies on the clock lock on the emc clock to avoid races between
+ * multiple frequency changes */
+int tegra_emc_set_rate(unsigned long rate)
+{
+	int i;
+	int j;
+
+	if (!tegra_emc_table)
+		return -EINVAL;
+
+	/* The EMC clock rate is twice the bus rate, and the bus rate is
+	 * measured in kHz */
+	rate = rate / 2 / 1000;
+
+	for (i = 0; i < tegra_emc_table_size; i++)
+		if (tegra_emc_table[i].rate == rate)
+			break;
+
+	if (i >= tegra_emc_table_size)
+		return -EINVAL;
+
+	pr_debug("%s: setting to %lu\n", __func__, rate);
+
+	for (j = 0; j < TEGRA_EMC_NUM_REGS; j++)
+		emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]);
+
+	emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]);
+
+	return 0;
+}
+
+void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
+{
+	tegra_emc_table = table;
+	tegra_emc_table_size = table_size;
+}
diff --git a/arch/arm/mach-tegra/tegra2_emc.h b/arch/arm/mach-tegra/tegra2_emc.h
new file mode 100644
index 0000000..3515e57
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra2_emc.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *	Colin Cross <ccross@google.com>
+ *
+ * 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);
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 17/21] ARM: tegra: clocks: Add emc scaling
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (15 preceding siblings ...)
  2011-02-19 22:26 ` [PATCH v2 16/21] ARM: tegra: Add external memory controller driver Colin Cross
@ 2011-02-19 22:26 ` Colin Cross
  2011-02-21  4:21   ` Olof Johansson
  2011-02-19 22:26 ` [PATCH v2 18/21] ARM: tegra: cpufreq: Adjust memory frequency with cpu frequency Colin Cross
                   ` (4 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:26 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/tegra2_clocks.c |   62 ++++++++++++++++++++++++++++++++++-
 1 files changed, 61 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 480c0f6..395d006 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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)
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 18/21] ARM: tegra: cpufreq: Adjust memory frequency with cpu frequency
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (16 preceding siblings ...)
  2011-02-19 22:26 ` [PATCH v2 17/21] ARM: tegra: clocks: Add emc scaling Colin Cross
@ 2011-02-19 22:26 ` Colin Cross
  2011-02-21  4:23   ` Olof Johansson
  2011-02-19 22:26 ` [PATCH v2 19/21] ARM: tegra: clock: Add function to set SDMMC tap delay Colin Cross
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:26 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/cpu-tegra.c |   21 +++++++++++++++++++++
 1 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index f02ba60..0e1016a 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -51,6 +51,7 @@ static struct cpufreq_frequency_table freq_table[] = {
 #define NUM_CPUS	2
 
 static 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;
 }
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 19/21] ARM: tegra: clock: Add function to set SDMMC tap delay
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (17 preceding siblings ...)
  2011-02-19 22:26 ` [PATCH v2 18/21] ARM: tegra: cpufreq: Adjust memory frequency with cpu frequency Colin Cross
@ 2011-02-19 22:26 ` Colin Cross
  2011-02-21  4:26   ` Olof Johansson
  2011-02-19 22:26 ` [PATCH v2 20/21] ARM: tegra: clock: Fix clock issues in suspend Colin Cross
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:26 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

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 <ccross@android.com>
---
 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(-)

diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 9798585..0df6206 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -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)
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index ebe6ea8..688316a 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -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
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
index fa7f9ca..c8baf8f 100644
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ b/arch/arm/mach-tegra/include/mach/clk.h
@@ -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
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 395d006..cc2616c 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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)
 {
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 20/21] ARM: tegra: clock: Fix clock issues in suspend
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (18 preceding siblings ...)
  2011-02-19 22:26 ` [PATCH v2 19/21] ARM: tegra: clock: Add function to set SDMMC tap delay Colin Cross
@ 2011-02-19 22:26 ` Colin Cross
  2011-02-21  4:28   ` Olof Johansson
  2011-02-19 22:26 ` [PATCH v2 21/21] ARM: tegra: clock: Miscellaneous clock updates Colin Cross
  2011-02-21  4:15 ` [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Olof Johansson
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:26 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

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.

Save plld, plls, pllu, and audio clock during suspend (originally
fixed by Mayuresh Kulkarni <mkulkarni@nvidia.com>)

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.

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/tegra2_clocks.c |   30 ++++++++++++++++++++----------
 1 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index cc2616c..d5fbc42 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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);
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v2 21/21] ARM: tegra: clock: Miscellaneous clock updates
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (19 preceding siblings ...)
  2011-02-19 22:26 ` [PATCH v2 20/21] ARM: tegra: clock: Fix clock issues in suspend Colin Cross
@ 2011-02-19 22:26 ` Colin Cross
  2011-02-21  4:28   ` Olof Johansson
  2011-02-21  4:15 ` [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Olof Johansson
  21 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-19 22:26 UTC (permalink / raw
  To: linux-tegra, linux-tegra
  Cc: linux-arm-kernel, konkers, olof, Colin Cross, Russell King,
	linux-kernel

Correct max rates for pclk and sclk (Originally fixed by
  Dima Zavin <dima@android.com>)

Correct max rate for plla (Originally fixed by
  Stephen Warren <swarren@nvidia.com>)

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 <dima@android.com>)

Pass set_rate on super clocks through to parent

Fix pllx frequency table entry for 608 MHz

Remove incorrect plla frequency table entries

Signed-off-by: Colin Cross <ccross@android.com>
---
 arch/arm/mach-tegra/tegra2_clocks.c |   98 ++++++++++++++++++++++++-----------
 1 files changed, 67 insertions(+), 31 deletions(-)

diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index d5fbc42..85e03fa 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -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,
 };
 
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 05/21] ARM: tegra: clock: Disable clocks left on by bootloader
  2011-02-19 22:25 ` [PATCH v2 05/21] ARM: tegra: clock: Disable clocks left on by bootloader Colin Cross
@ 2011-02-21  0:40   ` Olof Johansson
  2011-02-21  3:43     ` Colin Cross
  0 siblings, 1 reply; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  0:40 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

Hi,

On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
> Adds 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.


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

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 05/21] ARM: tegra: clock: Disable clocks left on by bootloader
  2011-02-21  0:40   ` Olof Johansson
@ 2011-02-21  3:43     ` Colin Cross
  2011-02-21  4:03       ` Olof Johansson
  0 siblings, 1 reply; 51+ messages in thread
From: Colin Cross @ 2011-02-21  3:43 UTC (permalink / raw
  To: Olof Johansson
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sun, Feb 20, 2011 at 4:40 PM, Olof Johansson <olof@lixom.net> wrote:
> Hi,
>
> On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
>> Adds 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.
>
>
> 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).

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.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 05/21] ARM: tegra: clock: Disable clocks left on by bootloader
  2011-02-21  3:43     ` Colin Cross
@ 2011-02-21  4:03       ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:03 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sun, Feb 20, 2011 at 7:43 PM, Colin Cross <ccross@android.com> wrote:
> On Sun, Feb 20, 2011 at 4:40 PM, Olof Johansson <olof@lixom.net> wrote:
>> Hi,
>>
>> On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
>>> Adds 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.
>>
>>
>> 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).
>
> 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

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 01/21] ARM: tegra: clock: enable clk reset for non-peripheral clocks
  2011-02-19 22:25 ` [PATCH v2 01/21] ARM: tegra: clock: enable clk reset for non-peripheral clocks Colin Cross
@ 2011-02-21  4:05   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:05 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Dima Zavin, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
> From: Dima Zavin <dima@android.com>
>
> Add a new 'reset' clk op. This can be provided for any clock,
> not just peripherals.
>
> Signed-off-by: Dima Zavin <dima@android.com>
> Signed-off-by: Colin Cross <ccross@android.com>

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 02/21] ARM: tegra: clock: Don't BUG on changing an enabled PLL
  2011-02-19 22:25 ` [PATCH v2 02/21] ARM: tegra: clock: Don't BUG on changing an enabled PLL Colin Cross
@ 2011-02-21  4:06   ` Olof Johansson
  2011-02-21  6:46     ` Colin Cross
  0 siblings, 1 reply; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:06 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
> Signed-off-by: Colin Cross <ccross@android.com>

Please add a 1-line description of why bugging doesn't make sense.

Patch itself:

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 03/21] ARM: tegra: clock: Drop debugging
  2011-02-19 22:25 ` [PATCH v2 03/21] ARM: tegra: clock: Drop debugging Colin Cross
@ 2011-02-21  4:07   ` Olof Johansson
  2011-02-21  6:56     ` Colin Cross
  0 siblings, 1 reply; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:07 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
> Signed-off-by: Colin Cross <ccross@android.com>

Same here, I know the patch is obvious but just a one-liner in the
patch description is common practice.

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 04/21] ARM: tegra: clock: Don't use PLL lock bits
  2011-02-19 22:25 ` [PATCH v2 04/21] ARM: tegra: clock: Don't use PLL lock bits Colin Cross
@ 2011-02-21  4:07   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:07 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
> The PLL lock bits are not reliable, use per-PLL timeouts instead.
>
> Signed-off-by: Colin Cross <ccross@android.com>

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 06/21] ARM: tegra: clock: Initialize clocks that have no enable
  2011-02-19 22:25 ` [PATCH v2 06/21] ARM: tegra: clock: Initialize clocks that have no enable Colin Cross
@ 2011-02-21  4:08   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:08 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
> Assume that any clock that has no enable op is always on.
>
> Signed-off-by: Colin Cross <ccross@android.com>

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 07/21] ARM: tegra: clock: Drop CPU dvfs
  2011-02-19 22:25 ` [PATCH v2 07/21] ARM: tegra: clock: Drop CPU dvfs Colin Cross
@ 2011-02-21  4:09   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:09 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
> The 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.
>
> Signed-off-by: Colin Cross <ccross@android.com>

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 08/21] ARM: tegra: clock: Rearrange static clock tables
  2011-02-19 22:25 ` [PATCH v2 08/21] ARM: tegra: clock: Rearrange static clock tables Colin Cross
@ 2011-02-21  4:09   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:09 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
> 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 <ccross@android.com>

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 09/21] ARM: tegra: clock: Move unshared clk struct members into union
  2011-02-19 22:25 ` [PATCH v2 09/21] ARM: tegra: clock: Move unshared clk struct members into union Colin Cross
@ 2011-02-21  4:10   ` Olof Johansson
  2011-02-21  7:00     ` Colin Cross
  0 siblings, 1 reply; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:10 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
> Signed-off-by: Colin Cross <ccross@android.com>

Same here, short description. With that:

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 10/21] ARM: tegra: clock: Convert global lock to a lock per clock
  2011-02-19 22:25 ` [PATCH v2 10/21] ARM: tegra: clock: Convert global lock to a lock per clock Colin Cross
@ 2011-02-21  4:11   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:11 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
> 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 <ccross@android.com>

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 11/21] ARM: tegra: cpufreq: Take an extra reference to pllx
  2011-02-19 22:26 ` [PATCH v2 11/21] ARM: tegra: cpufreq: Take an extra reference to pllx Colin Cross
@ 2011-02-21  4:12   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:12 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:26 PM, Colin Cross <ccross@android.com> wrote:
> 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 <ccross@android.com>

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type
  2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
                   ` (20 preceding siblings ...)
  2011-02-19 22:26 ` [PATCH v2 21/21] ARM: tegra: clock: Miscellaneous clock updates Colin Cross
@ 2011-02-21  4:15 ` Olof Johansson
  2011-02-21  7:02   ` Colin Cross
  21 siblings, 1 reply; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:15 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, sboyd, Russell King,
	linux-kernel

Hi,

On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
> 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.
>
> Signed-off-by: Colin Cross <ccross@android.com>

[...]
> diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
> index a1c86d8..dd53af3 100644
> --- a/arch/arm/mach-tegra/tegra2_clocks.c
> +++ b/arch/arm/mach-tegra/tegra2_clocks.c
[...]

> +       c->u.shared_bus_user.rate = c->parent->max_rate;
> +       c->state = OFF;
> +#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:

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 13/21] ARM: tegra: clock: Remove unnecessary uses of #ifdef CONFIG_DEBUG_FS
  2011-02-19 22:26 ` [PATCH v2 13/21] ARM: tegra: clock: Remove unnecessary uses of #ifdef CONFIG_DEBUG_FS Colin Cross
@ 2011-02-21  4:17   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:17 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

Hi,

On Sat, Feb 19, 2011 at 2:26 PM, Colin Cross <ccross@android.com> wrote:
> Signed-off-by: Colin Cross <ccross@android.com>

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:

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 14/21] ARM: tegra: clock: Refcount periph clock enables
  2011-02-19 22:26 ` [PATCH v2 14/21] ARM: tegra: clock: Refcount periph clock enables Colin Cross
@ 2011-02-21  4:18   ` Olof Johansson
  2011-02-21  7:06     ` Colin Cross
  0 siblings, 1 reply; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:18 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

Hi,

On Sat, Feb 19, 2011 at 2:26 PM, Colin Cross <ccross@android.com> wrote:
> Some peripheral clocks share enable bits.  Refcount the enables so
> that calling clk_disable on one clock will not turn off another
> clock.
>
> Signed-off-by: Colin Cross <ccross@android.com>
> ---
>  arch/arm/mach-tegra/tegra2_clocks.c |   35 +++++++++++++++++++++++++++++------
>  1 files changed, 29 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
> index 196c249..2734889 100644
> --- a/arch/arm/mach-tegra/tegra2_clocks.c
> +++ b/arch/arm/mach-tegra/tegra2_clocks.c
> @@ -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];

Given that this is always locked when incrementing/decrementing,
should it just be switched to an array of atomics instead?


-Olof

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 15/21] ARM: tegra: clock: Round rate before setting rate
  2011-02-19 22:26 ` [PATCH v2 15/21] ARM: tegra: clock: Round rate before setting rate Colin Cross
@ 2011-02-21  4:19   ` Olof Johansson
  2011-02-21  7:52     ` Colin Cross
  0 siblings, 1 reply; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:19 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

Hi,

On Sat, Feb 19, 2011 at 2:26 PM, Colin Cross <ccross@android.com> wrote:

> diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
> index 8d01a49..9798585 100644
> --- a/arch/arm/mach-tegra/clock.c
> +++ b/arch/arm/mach-tegra/clock.c
> @@ -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

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 16/21] ARM: tegra: Add external memory controller driver
  2011-02-19 22:26 ` [PATCH v2 16/21] ARM: tegra: Add external memory controller driver Colin Cross
@ 2011-02-21  4:20   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:20 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:26 PM, Colin Cross <ccross@android.com> wrote:
> Signed-off-by: Colin Cross <ccross@android.com>

Patch description requested. Besides that:

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 17/21] ARM: tegra: clocks: Add emc scaling
  2011-02-19 22:26 ` [PATCH v2 17/21] ARM: tegra: clocks: Add emc scaling Colin Cross
@ 2011-02-21  4:21   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:21 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:26 PM, Colin Cross <ccross@android.com> wrote:
> Signed-off-by: Colin Cross <ccross@android.com>

Patch description please. Besides that:

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 18/21] ARM: tegra: cpufreq: Adjust memory frequency with cpu frequency
  2011-02-19 22:26 ` [PATCH v2 18/21] ARM: tegra: cpufreq: Adjust memory frequency with cpu frequency Colin Cross
@ 2011-02-21  4:23   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:23 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:26 PM, Colin Cross <ccross@android.com> wrote:
> Signed-off-by: Colin Cross <ccross@android.com>

Patch description please. Besides that:

Acked-by: Olof Johansson <olof@lixom.net>

But note for future work:


> +       /*
> +        * 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

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 19/21] ARM: tegra: clock: Add function to set SDMMC tap delay
  2011-02-19 22:26 ` [PATCH v2 19/21] ARM: tegra: clock: Add function to set SDMMC tap delay Colin Cross
@ 2011-02-21  4:26   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:26 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

Hi,

On Sat, Feb 19, 2011 at 2:26 PM, Colin Cross <ccross@android.com> wrote:
> 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 <ccross@android.com>

This is going in without any in-tree consumers of the functions.
Still, it'll likely be added shortly, so:

Acked-by: Olof Johansson <olof@lixom.net>

(If they don't show up, it'll be easy to drop it again if need be).



-Olof

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 20/21] ARM: tegra: clock: Fix clock issues in suspend
  2011-02-19 22:26 ` [PATCH v2 20/21] ARM: tegra: clock: Fix clock issues in suspend Colin Cross
@ 2011-02-21  4:28   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:28 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:26 PM, Colin Cross <ccross@android.com> wrote:
> 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.
>
> Save plld, plls, pllu, and audio clock during suspend (originally
> fixed by Mayuresh Kulkarni <mkulkarni@nvidia.com>)
>
> 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.

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.


> Signed-off-by: Colin Cross <ccross@android.com>

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 21/21] ARM: tegra: clock: Miscellaneous clock updates
  2011-02-19 22:26 ` [PATCH v2 21/21] ARM: tegra: clock: Miscellaneous clock updates Colin Cross
@ 2011-02-21  4:28   ` Olof Johansson
  0 siblings, 0 replies; 51+ messages in thread
From: Olof Johansson @ 2011-02-21  4:28 UTC (permalink / raw
  To: Colin Cross
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sat, Feb 19, 2011 at 2:26 PM, Colin Cross <ccross@android.com> wrote:
> Correct max rates for pclk and sclk (Originally fixed by
>  Dima Zavin <dima@android.com>)
>
> Correct max rate for plla (Originally fixed by
>  Stephen Warren <swarren@nvidia.com>)
>
> 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 <dima@android.com>)
>
> Pass set_rate on super clocks through to parent
>
> Fix pllx frequency table entry for 608 MHz
>
> Remove incorrect plla frequency table entries
>
> Signed-off-by: Colin Cross <ccross@android.com>

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 02/21] ARM: tegra: clock: Don't BUG on changing an enabled PLL
  2011-02-21  4:06   ` Olof Johansson
@ 2011-02-21  6:46     ` Colin Cross
  0 siblings, 0 replies; 51+ messages in thread
From: Colin Cross @ 2011-02-21  6:46 UTC (permalink / raw
  To: Olof Johansson
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sun, Feb 20, 2011 at 8:06 PM, Olof Johansson <olof@lixom.net> wrote:
> On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
>> Signed-off-by: Colin Cross <ccross@android.com>
>
> Please add a 1-line description of why bugging doesn't make sense.
>
> Patch itself:
>
> Acked-by: Olof Johansson <olof@lixom.net>
>

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.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 03/21] ARM: tegra: clock: Drop debugging
  2011-02-21  4:07   ` Olof Johansson
@ 2011-02-21  6:56     ` Colin Cross
  0 siblings, 0 replies; 51+ messages in thread
From: Colin Cross @ 2011-02-21  6:56 UTC (permalink / raw
  To: Olof Johansson
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sun, Feb 20, 2011 at 8:07 PM, Olof Johansson <olof@lixom.net> wrote:
> On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
>> Signed-off-by: Colin Cross <ccross@android.com>
>
> Same here, I know the patch is obvious but just a one-liner in the
> patch description is common practice.
>
> Acked-by: Olof Johansson <olof@lixom.net>

I will add:
Drop the unnecessary pr_debug calls to avoid having to maintain them.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 09/21] ARM: tegra: clock: Move unshared clk struct members into union
  2011-02-21  4:10   ` Olof Johansson
@ 2011-02-21  7:00     ` Colin Cross
  0 siblings, 0 replies; 51+ messages in thread
From: Colin Cross @ 2011-02-21  7:00 UTC (permalink / raw
  To: Olof Johansson
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sun, Feb 20, 2011 at 8:10 PM, Olof Johansson <olof@lixom.net> wrote:
> On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
>> Signed-off-by: Colin Cross <ccross@android.com>
>
> Same here, short description. With that:
>
> Acked-by: Olof Johansson <olof@lixom.net>
>

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.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type
  2011-02-21  4:15 ` [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Olof Johansson
@ 2011-02-21  7:02   ` Colin Cross
  0 siblings, 0 replies; 51+ messages in thread
From: Colin Cross @ 2011-02-21  7:02 UTC (permalink / raw
  To: Olof Johansson
  Cc: linux-tegra, linux-arm-kernel, konkers, sboyd, Russell King,
	linux-kernel

On Sun, Feb 20, 2011 at 8:15 PM, Olof Johansson <olof@lixom.net> wrote:
> Hi,
>
> On Sat, Feb 19, 2011 at 2:25 PM, Colin Cross <ccross@android.com> wrote:
>> 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.
>>
>> Signed-off-by: Colin Cross <ccross@android.com>
>
> [...]
>> diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
>> index a1c86d8..dd53af3 100644
>> --- a/arch/arm/mach-tegra/tegra2_clocks.c
>> +++ b/arch/arm/mach-tegra/tegra2_clocks.c
> [...]
>
>> +       c->u.shared_bus_user.rate = c->parent->max_rate;
>> +       c->state = OFF;
>> +#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.

> With that fixed:
>
> Acked-by: Olof Johansson <olof@lixom.net>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 14/21] ARM: tegra: clock: Refcount periph clock enables
  2011-02-21  4:18   ` Olof Johansson
@ 2011-02-21  7:06     ` Colin Cross
  0 siblings, 0 replies; 51+ messages in thread
From: Colin Cross @ 2011-02-21  7:06 UTC (permalink / raw
  To: Olof Johansson
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sun, Feb 20, 2011 at 8:18 PM, Olof Johansson <olof@lixom.net> wrote:
> Hi,
>
> On Sat, Feb 19, 2011 at 2:26 PM, Colin Cross <ccross@android.com> wrote:
>> Some peripheral clocks share enable bits.  Refcount the enables so
>> that calling clk_disable on one clock will not turn off another
>> clock.
>>
>> Signed-off-by: Colin Cross <ccross@android.com>
>> ---
>>  arch/arm/mach-tegra/tegra2_clocks.c |   35 +++++++++++++++++++++++++++++------
>>  1 files changed, 29 insertions(+), 6 deletions(-)
>>
>> diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
>> index 196c249..2734889 100644
>> --- a/arch/arm/mach-tegra/tegra2_clocks.c
>> +++ b/arch/arm/mach-tegra/tegra2_clocks.c
>> @@ -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];
>
> 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.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 15/21] ARM: tegra: clock: Round rate before setting rate
  2011-02-21  4:19   ` Olof Johansson
@ 2011-02-21  7:52     ` Colin Cross
  0 siblings, 0 replies; 51+ messages in thread
From: Colin Cross @ 2011-02-21  7:52 UTC (permalink / raw
  To: Olof Johansson
  Cc: linux-tegra, linux-arm-kernel, konkers, Russell King,
	linux-kernel

On Sun, Feb 20, 2011 at 8:19 PM, Olof Johansson <olof@lixom.net> wrote:
> Hi,
>
> On Sat, Feb 19, 2011 at 2:26 PM, Colin Cross <ccross@android.com> wrote:
>
>> diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
>> index 8d01a49..9798585 100644
>> --- a/arch/arm/mach-tegra/clock.c
>> +++ b/arch/arm/mach-tegra/clock.c
>> @@ -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;"?
Yes, will fix

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2011-02-21  7:52 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-02-19 22:25 [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
2011-02-19 22:25 ` [PATCH v2 01/21] ARM: tegra: clock: enable clk reset for non-peripheral clocks Colin Cross
2011-02-21  4:05   ` Olof Johansson
2011-02-19 22:25 ` [PATCH v2 02/21] ARM: tegra: clock: Don't BUG on changing an enabled PLL Colin Cross
2011-02-21  4:06   ` Olof Johansson
2011-02-21  6:46     ` Colin Cross
2011-02-19 22:25 ` [PATCH v2 03/21] ARM: tegra: clock: Drop debugging Colin Cross
2011-02-21  4:07   ` Olof Johansson
2011-02-21  6:56     ` Colin Cross
2011-02-19 22:25 ` [PATCH v2 04/21] ARM: tegra: clock: Don't use PLL lock bits Colin Cross
2011-02-21  4:07   ` Olof Johansson
2011-02-19 22:25 ` [PATCH v2 05/21] ARM: tegra: clock: Disable clocks left on by bootloader Colin Cross
2011-02-21  0:40   ` Olof Johansson
2011-02-21  3:43     ` Colin Cross
2011-02-21  4:03       ` Olof Johansson
2011-02-19 22:25 ` [PATCH v2 06/21] ARM: tegra: clock: Initialize clocks that have no enable Colin Cross
2011-02-21  4:08   ` Olof Johansson
2011-02-19 22:25 ` [PATCH v2 07/21] ARM: tegra: clock: Drop CPU dvfs Colin Cross
2011-02-21  4:09   ` Olof Johansson
2011-02-19 22:25 ` [PATCH v2 08/21] ARM: tegra: clock: Rearrange static clock tables Colin Cross
2011-02-21  4:09   ` Olof Johansson
2011-02-19 22:25 ` [PATCH v2 09/21] ARM: tegra: clock: Move unshared clk struct members into union Colin Cross
2011-02-21  4:10   ` Olof Johansson
2011-02-21  7:00     ` Colin Cross
2011-02-19 22:25 ` [PATCH v2 10/21] ARM: tegra: clock: Convert global lock to a lock per clock Colin Cross
2011-02-21  4:11   ` Olof Johansson
2011-02-19 22:26 ` [PATCH v2 11/21] ARM: tegra: cpufreq: Take an extra reference to pllx Colin Cross
2011-02-21  4:12   ` Olof Johansson
2011-02-19 22:26 ` [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Colin Cross
2011-02-19 22:26 ` [PATCH v2 13/21] ARM: tegra: clock: Remove unnecessary uses of #ifdef CONFIG_DEBUG_FS Colin Cross
2011-02-21  4:17   ` Olof Johansson
2011-02-19 22:26 ` [PATCH v2 14/21] ARM: tegra: clock: Refcount periph clock enables Colin Cross
2011-02-21  4:18   ` Olof Johansson
2011-02-21  7:06     ` Colin Cross
2011-02-19 22:26 ` [PATCH v2 15/21] ARM: tegra: clock: Round rate before setting rate Colin Cross
2011-02-21  4:19   ` Olof Johansson
2011-02-21  7:52     ` Colin Cross
2011-02-19 22:26 ` [PATCH v2 16/21] ARM: tegra: Add external memory controller driver Colin Cross
2011-02-21  4:20   ` Olof Johansson
2011-02-19 22:26 ` [PATCH v2 17/21] ARM: tegra: clocks: Add emc scaling Colin Cross
2011-02-21  4:21   ` Olof Johansson
2011-02-19 22:26 ` [PATCH v2 18/21] ARM: tegra: cpufreq: Adjust memory frequency with cpu frequency Colin Cross
2011-02-21  4:23   ` Olof Johansson
2011-02-19 22:26 ` [PATCH v2 19/21] ARM: tegra: clock: Add function to set SDMMC tap delay Colin Cross
2011-02-21  4:26   ` Olof Johansson
2011-02-19 22:26 ` [PATCH v2 20/21] ARM: tegra: clock: Fix clock issues in suspend Colin Cross
2011-02-21  4:28   ` Olof Johansson
2011-02-19 22:26 ` [PATCH v2 21/21] ARM: tegra: clock: Miscellaneous clock updates Colin Cross
2011-02-21  4:28   ` Olof Johansson
2011-02-21  4:15 ` [PATCH v2 12/21] ARM: tegra: clock: Add shared bus clock type Olof Johansson
2011-02-21  7:02   ` Colin Cross

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).