[U-Boot] [PATCH 15/21] ARM: tegra: add APIs the clock uclass driver will need

Stephen Warren swarren at wwwdotorg.org
Tue Sep 13 18:45:56 CEST 2016


From: Stephen Warren <swarren at nvidia.com>

A future patch will implement a clock uclass driver for Tegra. That driver
will call into Tegra's existing clock code to simplify the transition;
this avoids tieing the clock uclass patches into significant refactoring
of the existing custom clock API implementation.

Some of the Tegra clock APIs that manipulate peripheral clocks require
both the peripheral clock ID and parent clock ID to be passed in together.
However, the clock uclass API does not require any such "parent"
parameter, so the clock driver must determine this information itself.
This patch implements new Tegra- specific clock API
clock_get_periph_parent() for this purpose.

The new API is implemented in the core Tegra clock code rather than SoC-
specific clock code. The implementation uses various SoC-/clock-specific
data. That data is only available in SoC-specific clock code.
Consequently, two new internal APIs are added that enable the core clock
code to retrieve this information from the SoC-specific clock code. Due to
the structure of the Tegra clock code, this leads to some unfortunate code
duplication. However, this situation predates this patch.

Ideally, future work will de-duplicate the Tegra clock code, and migrate
it into drivers/clk/tegra. However, such refactoring is kept separate from
this series.

Signed-off-by: Stephen Warren <swarren at nvidia.com>
---
 arch/arm/include/asm/arch-tegra/clock.h | 40 +++++++++++++++++
 arch/arm/mach-tegra/clock.c             | 37 ++++++++++++++++
 arch/arm/mach-tegra/tegra114/clock.c    | 64 ++++++++++++++++++++-------
 arch/arm/mach-tegra/tegra124/clock.c    | 64 ++++++++++++++++++++-------
 arch/arm/mach-tegra/tegra20/clock.c     | 76 +++++++++++++++++++++++----------
 arch/arm/mach-tegra/tegra210/clock.c    | 64 ++++++++++++++++++++-------
 arch/arm/mach-tegra/tegra30/clock.c     | 64 ++++++++++++++++++++-------
 7 files changed, 323 insertions(+), 86 deletions(-)

diff --git a/arch/arm/include/asm/arch-tegra/clock.h b/arch/arm/include/asm/arch-tegra/clock.h
index e0737f574add..388afcb72316 100644
--- a/arch/arm/include/asm/arch-tegra/clock.h
+++ b/arch/arm/include/asm/arch-tegra/clock.h
@@ -187,6 +187,16 @@ void clock_ll_set_source_divisor(enum periph_id periph_id, unsigned source,
 		unsigned divisor);
 
 /**
+ * Returns the current parent clock ID of a given peripheral. This can be
+ * useful in order to call clock_*_periph_*() from generic code that has no
+ * specific knowledge of system-level clock tree structure.
+ *
+ * @param periph_id	peripheral to query
+ * @return clock ID of the peripheral's current parent clock
+ */
+enum clock_id clock_get_periph_parent(enum periph_id periph_id);
+
+/**
  * Start a peripheral PLL clock at the given rate. This also resets the
  * peripheral.
  *
@@ -284,6 +294,36 @@ u32 *get_periph_source_reg(enum periph_id periph_id);
 /* Returns a pointer to the given 'simple' PLL */
 struct clk_pll_simple *clock_get_simple_pll(enum clock_id clkid);
 
+/*
+ * Given a peripheral ID, determine where the mux bits are in the peripheral
+ * clock's register, the number of divider bits the clock has, and the SoC-
+ * specific clock type.
+ *
+ * This is an internal API between the core Tegra clock code and the SoC-
+ * specific clock code.
+ *
+ * @param periph_id     peripheral to query
+ * @param mux_bits      Set to number of bits in mux register
+ * @param divider_bits  Set to the relevant MASK_BITS_* value
+ * @param type          Set to the SoC-specific clock type
+ * @return 0 on success, -1 on error
+ */
+int get_periph_clock_info(enum periph_id periph_id, int *mux_bits,
+			  int *divider_bits, int *type);
+
+/*
+ * Given a peripheral ID and clock source mux value, determine the clock_id
+ * of that peripheral's parent.
+ *
+ * This is an internal API between the core Tegra clock code and the SoC-
+ * specific clock code.
+ *
+ * @param periph_id     peripheral to query
+ * @param source        raw clock source mux value
+ * @return the CLOCK_ID_* value @source represents
+ */
+enum clock_id get_periph_clock_id(enum periph_id periph_id, int source);
+
 /**
  * Given a peripheral ID and the required source clock, this returns which
  * value should be programmed into the source mux for that peripheral.
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 597f6286d6c1..cf8bc38925d2 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -206,6 +206,29 @@ int clock_ll_set_source_bits(enum periph_id periph_id, int mux_bits,
 	return 0;
 }
 
+static int clock_ll_get_source_bits(enum periph_id periph_id, int mux_bits)
+{
+	u32 *reg = get_periph_source_reg(periph_id);
+	u32 val = readl(reg);
+
+	switch (mux_bits) {
+	case MASK_BITS_31_30:
+		val >>= OUT_CLK_SOURCE_31_30_SHIFT;
+		val &= OUT_CLK_SOURCE_31_30_MASK;
+		return val;
+	case MASK_BITS_31_29:
+		val >>= OUT_CLK_SOURCE_31_29_SHIFT;
+		val &= OUT_CLK_SOURCE_31_29_MASK;
+		return val;
+	case MASK_BITS_31_28:
+		val >>= OUT_CLK_SOURCE_31_28_SHIFT;
+		val &= OUT_CLK_SOURCE_31_28_MASK;
+		return val;
+	default:
+		return -1;
+	}
+}
+
 void clock_ll_set_source(enum periph_id periph_id, unsigned source)
 {
 	clock_ll_set_source_bits(periph_id, MASK_BITS_31_30, source);
@@ -363,6 +386,20 @@ static int adjust_periph_pll(enum periph_id periph_id, int source,
 	return 0;
 }
 
+enum clock_id clock_get_periph_parent(enum periph_id periph_id)
+{
+	int err, mux_bits, divider_bits, type;
+	int source;
+
+	err = get_periph_clock_info(periph_id, &mux_bits, &divider_bits, &type);
+	if (err)
+		return CLOCK_ID_NONE;
+
+	source = clock_ll_get_source_bits(periph_id, mux_bits);
+
+	return get_periph_clock_id(periph_id, source);
+}
+
 unsigned clock_adjust_periph_pll_div(enum periph_id periph_id,
 		enum clock_id parent, unsigned rate, int *extra_div)
 {
diff --git a/arch/arm/mach-tegra/tegra114/clock.c b/arch/arm/mach-tegra/tegra114/clock.c
index 6620206be0ba..177ab6b55b0c 100644
--- a/arch/arm/mach-tegra/tegra114/clock.c
+++ b/arch/arm/mach-tegra/tegra114/clock.c
@@ -496,6 +496,51 @@ u32 *get_periph_source_reg(enum periph_id periph_id)
 		return &clkrst->crc_clk_src[internal_id];
 }
 
+int get_periph_clock_info(enum periph_id periph_id, int *mux_bits,
+			  int *divider_bits, int *type)
+{
+	enum periphc_internal_id internal_id;
+
+	if (!clock_periph_id_isvalid(periph_id))
+		return -1;
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	if (!periphc_internal_id_isvalid(internal_id))
+		return -1;
+
+	*type = clock_periph_type[internal_id];
+	if (!clock_type_id_isvalid(*type))
+		return -1;
+
+	*mux_bits = clock_source[*type][CLOCK_MAX_MUX];
+
+	if (*type == CLOCK_TYPE_PCMT16)
+		*divider_bits = 16;
+	else
+		*divider_bits = 8;
+
+	return 0;
+}
+
+enum clock_id get_periph_clock_id(enum periph_id periph_id, int source)
+{
+	enum periphc_internal_id internal_id;
+	int type;
+
+	if (!clock_periph_id_isvalid(periph_id))
+		return CLOCK_ID_NONE;
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	if (!periphc_internal_id_isvalid(internal_id))
+		return CLOCK_ID_NONE;
+
+	type = clock_periph_type[internal_id];
+	if (!clock_type_id_isvalid(type))
+		return CLOCK_ID_NONE;
+
+	return clock_source[type][source];
+}
+
 /**
  * Given a peripheral ID and the required source clock, this returns which
  * value should be programmed into the source mux for that peripheral.
@@ -512,23 +557,10 @@ int get_periph_clock_source(enum periph_id periph_id,
 	enum clock_id parent, int *mux_bits, int *divider_bits)
 {
 	enum clock_type_id type;
-	enum periphc_internal_id internal_id;
-	int mux;
-
-	assert(clock_periph_id_isvalid(periph_id));
+	int mux, err;
 
-	internal_id = periph_id_to_internal_id[periph_id];
-	assert(periphc_internal_id_isvalid(internal_id));
-
-	type = clock_periph_type[internal_id];
-	assert(clock_type_id_isvalid(type));
-
-	*mux_bits = clock_source[type][CLOCK_MAX_MUX];
-
-	if (type == CLOCK_TYPE_PCMT16)
-		*divider_bits = 16;
-	else
-		*divider_bits = 8;
+	err = get_periph_clock_info(periph_id, mux_bits, divider_bits, &type);
+	assert(!err);
 
 	for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
 		if (clock_source[type][mux] == parent)
diff --git a/arch/arm/mach-tegra/tegra124/clock.c b/arch/arm/mach-tegra/tegra124/clock.c
index 84b679c1c54b..5e4406102f1f 100644
--- a/arch/arm/mach-tegra/tegra124/clock.c
+++ b/arch/arm/mach-tegra/tegra124/clock.c
@@ -642,6 +642,51 @@ u32 *get_periph_source_reg(enum periph_id periph_id)
 	}
 }
 
+int get_periph_clock_info(enum periph_id periph_id, int *mux_bits,
+			  int *divider_bits, int *type)
+{
+	enum periphc_internal_id internal_id;
+
+	if (!clock_periph_id_isvalid(periph_id))
+		return -1;
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	if (!periphc_internal_id_isvalid(internal_id))
+		return -1;
+
+	*type = clock_periph_type[internal_id];
+	if (!clock_type_id_isvalid(*type))
+		return -1;
+
+	*mux_bits = clock_source[*type][CLOCK_MAX_MUX];
+
+	if (*type == CLOCK_TYPE_PC2CC3M_T16)
+		*divider_bits = 16;
+	else
+		*divider_bits = 8;
+
+	return 0;
+}
+
+enum clock_id get_periph_clock_id(enum periph_id periph_id, int source)
+{
+	enum periphc_internal_id internal_id;
+	int type;
+
+	if (!clock_periph_id_isvalid(periph_id))
+		return CLOCK_ID_NONE;
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	if (!periphc_internal_id_isvalid(internal_id))
+		return CLOCK_ID_NONE;
+
+	type = clock_periph_type[internal_id];
+	if (!clock_type_id_isvalid(type))
+		return CLOCK_ID_NONE;
+
+	return clock_source[type][source];
+}
+
 /**
  * Given a peripheral ID and the required source clock, this returns which
  * value should be programmed into the source mux for that peripheral.
@@ -658,23 +703,10 @@ int get_periph_clock_source(enum periph_id periph_id,
 	enum clock_id parent, int *mux_bits, int *divider_bits)
 {
 	enum clock_type_id type;
-	enum periphc_internal_id internal_id;
-	int mux;
-
-	assert(clock_periph_id_isvalid(periph_id));
-
-	internal_id = periph_id_to_internal_id[periph_id];
-	assert(periphc_internal_id_isvalid(internal_id));
-
-	type = clock_periph_type[internal_id];
-	assert(clock_type_id_isvalid(type));
+	int mux, err;
 
-	*mux_bits = clock_source[type][CLOCK_MAX_MUX];
-
-	if (type == CLOCK_TYPE_PC2CC3M_T16)
-		*divider_bits = 16;
-	else
-		*divider_bits = 8;
+	err = get_periph_clock_info(periph_id, mux_bits, divider_bits, &type);
+	assert(!err);
 
 	for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
 		if (clock_source[type][mux] == parent)
diff --git a/arch/arm/mach-tegra/tegra20/clock.c b/arch/arm/mach-tegra/tegra20/clock.c
index d11e89bd253f..ec04cf5261f7 100644
--- a/arch/arm/mach-tegra/tegra20/clock.c
+++ b/arch/arm/mach-tegra/tegra20/clock.c
@@ -413,46 +413,78 @@ u32 *get_periph_source_reg(enum periph_id periph_id)
 	return &clkrst->crc_clk_src[internal_id];
 }
 
-/**
- * Given a peripheral ID and the required source clock, this returns which
- * value should be programmed into the source mux for that peripheral.
- *
- * There is special code here to handle the one source type with 5 sources.
- *
- * @param periph_id	peripheral to start
- * @param source	PLL id of required parent clock
- * @param mux_bits	Set to number of bits in mux register: 2 or 4
- * @param divider_bits	Set to number of divider bits (8 or 16)
- * @return mux value (0-4, or -1 if not found)
- */
-int get_periph_clock_source(enum periph_id periph_id,
-		enum clock_id parent, int *mux_bits, int *divider_bits)
+int get_periph_clock_info(enum periph_id periph_id, int *mux_bits,
+			  int *divider_bits, int *type)
 {
-	enum clock_type_id type;
 	enum periphc_internal_id internal_id;
-	int mux;
 
-	assert(clock_periph_id_isvalid(periph_id));
+	if (!clock_periph_id_isvalid(periph_id))
+		return -1;
 
 	internal_id = periph_id_to_internal_id[periph_id];
-	assert(periphc_internal_id_isvalid(internal_id));
+	if (!periphc_internal_id_isvalid(internal_id))
+		return -1;
 
-	type = clock_periph_type[internal_id];
-	assert(clock_type_id_isvalid(type));
+	*type = clock_periph_type[internal_id];
+	if (!clock_type_id_isvalid(*type))
+		return -1;
 
 	/*
 	 * Special cases here for the clock with a 4-bit source mux and I2C
 	 * with its 16-bit divisor
 	 */
-	if (type == CLOCK_TYPE_PCXTS)
+	if (*type == CLOCK_TYPE_PCXTS)
 		*mux_bits = MASK_BITS_31_28;
 	else
 		*mux_bits = MASK_BITS_31_30;
-	if (type == CLOCK_TYPE_PCMT16)
+	if (*type == CLOCK_TYPE_PCMT16)
 		*divider_bits = 16;
 	else
 		*divider_bits = 8;
 
+	return 0;
+}
+
+enum clock_id get_periph_clock_id(enum periph_id periph_id, int source)
+{
+	enum periphc_internal_id internal_id;
+	int type;
+
+	if (!clock_periph_id_isvalid(periph_id))
+		return CLOCK_ID_NONE;
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	if (!periphc_internal_id_isvalid(internal_id))
+		return CLOCK_ID_NONE;
+
+	type = clock_periph_type[internal_id];
+	if (!clock_type_id_isvalid(type))
+		return CLOCK_ID_NONE;
+
+	return clock_source[type][source];
+}
+
+/**
+ * Given a peripheral ID and the required source clock, this returns which
+ * value should be programmed into the source mux for that peripheral.
+ *
+ * There is special code here to handle the one source type with 5 sources.
+ *
+ * @param periph_id	peripheral to start
+ * @param source	PLL id of required parent clock
+ * @param mux_bits	Set to number of bits in mux register: 2 or 4
+ * @param divider_bits	Set to number of divider bits (8 or 16)
+ * @return mux value (0-4, or -1 if not found)
+ */
+int get_periph_clock_source(enum periph_id periph_id,
+		enum clock_id parent, int *mux_bits, int *divider_bits)
+{
+	enum clock_type_id type;
+	int mux, err;
+
+	err = get_periph_clock_info(periph_id, mux_bits, divider_bits, &type);
+	assert(!err);
+
 	for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
 		if (clock_source[type][mux] == parent)
 			return mux;
diff --git a/arch/arm/mach-tegra/tegra210/clock.c b/arch/arm/mach-tegra/tegra210/clock.c
index d51c1481ea20..c8bb94626ef6 100644
--- a/arch/arm/mach-tegra/tegra210/clock.c
+++ b/arch/arm/mach-tegra/tegra210/clock.c
@@ -732,6 +732,51 @@ u32 *get_periph_source_reg(enum periph_id periph_id)
 	return &clkrst->crc_clk_src_y[internal_id];
 }
 
+int get_periph_clock_info(enum periph_id periph_id, int *mux_bits,
+			  int *divider_bits, int *type)
+{
+	enum periphc_internal_id internal_id;
+
+	if (!clock_periph_id_isvalid(periph_id))
+		return -1;
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	if (!periphc_internal_id_isvalid(internal_id))
+		return -1;
+
+	*type = clock_periph_type[internal_id];
+	if (!clock_type_id_isvalid(*type))
+		return -1;
+
+	*mux_bits = clock_source[*type][CLOCK_MAX_MUX];
+
+	if (*type == CLOCK_TYPE_PC2CC3M_T16)
+		*divider_bits = 16;
+	else
+		*divider_bits = 8;
+
+	return 0;
+}
+
+enum clock_id get_periph_clock_id(enum periph_id periph_id, int source)
+{
+	enum periphc_internal_id internal_id;
+	int type;
+
+	if (!clock_periph_id_isvalid(periph_id))
+		return CLOCK_ID_NONE;
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	if (!periphc_internal_id_isvalid(internal_id))
+		return CLOCK_ID_NONE;
+
+	type = clock_periph_type[internal_id];
+	if (!clock_type_id_isvalid(type))
+		return CLOCK_ID_NONE;
+
+	return clock_source[type][source];
+}
+
 /**
  * Given a peripheral ID and the required source clock, this returns which
  * value should be programmed into the source mux for that peripheral.
@@ -748,23 +793,10 @@ int get_periph_clock_source(enum periph_id periph_id,
 	enum clock_id parent, int *mux_bits, int *divider_bits)
 {
 	enum clock_type_id type;
-	enum periphc_internal_id internal_id;
-	int mux;
-
-	assert(clock_periph_id_isvalid(periph_id));
+	int mux, err;
 
-	internal_id = INTERNAL_ID(periph_id_to_internal_id[periph_id]);
-	assert(periphc_internal_id_isvalid(internal_id));
-
-	type = clock_periph_type[internal_id];
-	assert(clock_type_id_isvalid(type));
-
-	*mux_bits = clock_source[type][CLOCK_MAX_MUX];
-
-	if (type == CLOCK_TYPE_PC2CC3M_T16)
-		*divider_bits = 16;
-	else
-		*divider_bits = 8;
+	err = get_periph_clock_info(periph_id, mux_bits, divider_bits, &type);
+	assert(!err);
 
 	for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
 		if (clock_source[type][mux] == parent)
diff --git a/arch/arm/mach-tegra/tegra30/clock.c b/arch/arm/mach-tegra/tegra30/clock.c
index 52a6dcebdfcd..4fd8b8a3b1fb 100644
--- a/arch/arm/mach-tegra/tegra30/clock.c
+++ b/arch/arm/mach-tegra/tegra30/clock.c
@@ -476,6 +476,51 @@ u32 *get_periph_source_reg(enum periph_id periph_id)
 		return &clkrst->crc_clk_src[internal_id];
 }
 
+int get_periph_clock_info(enum periph_id periph_id, int *mux_bits,
+			  int *divider_bits, int *type)
+{
+	enum periphc_internal_id internal_id;
+
+	if (!clock_periph_id_isvalid(periph_id))
+		return -1;
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	if (!periphc_internal_id_isvalid(internal_id))
+		return -1;
+
+	*type = clock_periph_type[internal_id];
+	if (!clock_type_id_isvalid(*type))
+		return -1;
+
+	*mux_bits = clock_source[*type][CLOCK_MAX_MUX];
+
+	if (*type == CLOCK_TYPE_PCMT16)
+		*divider_bits = 16;
+	else
+		*divider_bits = 8;
+
+	return 0;
+}
+
+enum clock_id get_periph_clock_id(enum periph_id periph_id, int source)
+{
+	enum periphc_internal_id internal_id;
+	int type;
+
+	if (!clock_periph_id_isvalid(periph_id))
+		return CLOCK_ID_NONE;
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	if (!periphc_internal_id_isvalid(internal_id))
+		return CLOCK_ID_NONE;
+
+	type = clock_periph_type[internal_id];
+	if (!clock_type_id_isvalid(type))
+		return CLOCK_ID_NONE;
+
+	return clock_source[type][source];
+}
+
 /**
  * Given a peripheral ID and the required source clock, this returns which
  * value should be programmed into the source mux for that peripheral.
@@ -492,23 +537,10 @@ int get_periph_clock_source(enum periph_id periph_id,
 	enum clock_id parent, int *mux_bits, int *divider_bits)
 {
 	enum clock_type_id type;
-	enum periphc_internal_id internal_id;
-	int mux;
-
-	assert(clock_periph_id_isvalid(periph_id));
-
-	internal_id = periph_id_to_internal_id[periph_id];
-	assert(periphc_internal_id_isvalid(internal_id));
-
-	type = clock_periph_type[internal_id];
-	assert(clock_type_id_isvalid(type));
+	int mux, err;
 
-	*mux_bits = clock_source[type][CLOCK_MAX_MUX];
-
-	if (type == CLOCK_TYPE_PCMT16)
-		*divider_bits = 16;
-	else
-		*divider_bits = 8;
+	err = get_periph_clock_info(periph_id, mux_bits, divider_bits, &type);
+	assert(!err);
 
 	for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
 		if (clock_source[type][mux] == parent)
-- 
2.9.3



More information about the U-Boot mailing list