Krait clocks + Krait CPUfreq
Subsystems (6)
v3 cover Krait clocks + Krait CPUfreq
These patches provide cpufreq scaling on devices with Krait CPUs. In Krait CPU designs there's one PLL and two muxes per CPU, allowing us to switch CPU frequencies independently.
secondary +-----+ + | QSB |-------+------------|\ +-----+ | | |-+ | +-------|/ | | | + | +-----+ | | | | PLL |----+-------+ | primary +-----+ | | | + | | +-----|\ +------+ +-------+ | | | \ | | | HFPLL |----------+-----------------| |-----| CPU0 | +-------+ | | | | | | | | | | +-----+ | / +------+ | | +-| / 2 |---------|/ | | +-----+ + | | secondary | | + | +------------|\ | | |-+ +---------------|/ | primary + | + +-----|\ +------+ +-------+ | \ | | | HFPLL |----------------------------| |-----| CPU1 | +-------+ | | | | | | +-----+ | / +------+ +-| / 2 |---------|/ +-----+ +
To support this in the common clock framework we model the muxes, dividers, and PLLs as different clocks. CPUfreq only interacts with the primary mux (farthest right in the diagram). When CPUfreq sets a rate, the mux code finds the best parent that can provide the rate. Due to the design, QSB and the top PLL are always a fixed rate and thus only support one frequency each. These sources provide the lowest frequencies for the CPUs. The HFPLLs are where we can make the CPU go faster (GHz range). Sometimes we need to run the HFPLL twice as fast and divide it by two to get a particular frequency.
When switching rates we can't leave the CPU clocked by the HFPLL because we need to turn off the output of the PLL when changing its frequency. This means we have to switch over to the secondary mux and use one of the fixed sources. This is why we need something like the safe parent patch.
I plan to submit the DTS changes through arm-soc, but I've included everything here to make it easier to pick things up for testing, etc. If anything can be picked up right now it would be better to reduce the churn over time as other pieces settle. Some things are not done, but I'm posting this now to get it out there and because the clock framework patches needed some rework due to recent changes.
Changes since v2:
* Switched to cpufreq-dt
* Ported over PVS binding
* Stripped out cpu logical map to make modules work
* Dropped patches that merged upstream
Changes since v1:
* Added IPQ and APQ8064 support
* Switched to cpufreq-generic
* Added OPP parsing from DT (need to write binding though)
* New patches to make clk-generic.c go away
* Made mux and divider reusable for non-MMIO devices
* Added a mux_determine_rate_closest (not sure if this is really needed)
* Added unregistration of muxes
* New patch to avoid sending high frequencies down to devices using clocks
TODO:
* Add Krait regulator voltage scaling (not strictly necessary)
* Add some thermal awareness
* Use efuse/eeprom API instead of hardcoding the location in the driver
* Figure out how to express number of CPUs without relying on linux's concept of number of CPUs and logical CPU mapping
* Trim down the probe code for krait-cc so that we just register clocks and don't enable or set rates
Stephen Boyd (13):
ARM: Add Krait L2 register accessor functions
clk: mux: Split out register accessors for reuse
clk: Avoid sending high rates to downstream clocks during set_rate
clk: Add safe switch hook
clk: qcom: Add support for High-Frequency PLLs (HFPLLs)
clk: qcom: Add HFPLL driver
clk: qcom: Add MSM8960/APQ8064's HFPLLs
clk: qcom: Add IPQ806X's HFPLLs
clk: qcom: Add support for Krait clocks
clk: qcom: Add KPSS ACC/GCC driver
clk: qcom: Add Krait clock controller driver
cpufreq: Add module to register cpufreq on Krait CPUs
ARM: dts: qcom: Add necessary DT data for Krait cpufreq
.../devicetree/bindings/arm/msm/qcom,kpss-acc.txt | 7 + .../devicetree/bindings/arm/msm/qcom,kpss-gcc.txt | 28 ++ .../devicetree/bindings/arm/msm/qcom,pvs.txt | 38 +++ .../devicetree/bindings/clock/qcom,hfpll.txt | 40 +++ .../devicetree/bindings/clock/qcom,krait-cc.txt | 22 ++ arch/arm/boot/dts/qcom-apq8064.dtsi | 230 ++++++++++++++ arch/arm/boot/dts/qcom-msm8960.dtsi | 49 +++ arch/arm/boot/dts/qcom-msm8974.dtsi | 311 +++++++++++++++++- arch/arm/common/Kconfig | 3 + arch/arm/common/Makefile | 1 + arch/arm/common/krait-l2-accessors.c | 58 ++++ arch/arm/include/asm/krait-l2-accessors.h | 20 ++ drivers/clk/clk-mux.c | 76 +++-- drivers/clk/clk.c | 95 ++++-- drivers/clk/qcom/Kconfig | 28 ++ drivers/clk/qcom/Makefile | 5 + drivers/clk/qcom/clk-hfpll.c | 253 +++++++++++++++ drivers/clk/qcom/clk-hfpll.h | 54 ++++ drivers/clk/qcom/clk-krait.c | 166 ++++++++++ drivers/clk/qcom/clk-krait.h | 49 +++ drivers/clk/qcom/gcc-ipq806x.c | 83 +++++ drivers/clk/qcom/gcc-msm8960.c | 172 ++++++++++ drivers/clk/qcom/hfpll.c | 109 +++++++ drivers/clk/qcom/kpss-xcc.c | 95 ++++++ drivers/clk/qcom/krait-cc.c | 352 +++++++++++++++++++++ drivers/cpufreq/Kconfig.arm | 9 + drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq.c | 204 ++++++++++++ include/dt-bindings/clock/qcom,gcc-msm8960.h | 2 + include/linux/clk-provider.h | 10 +- 30 files changed, 2515 insertions(+), 55 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,pvs.txt create mode 100644 Documentation/devicetree/bindings/clock/qcom,hfpll.txt create mode 100644 Documentation/devicetree/bindings/clock/qcom,krait-cc.txt create mode 100644 arch/arm/common/krait-l2-accessors.c create mode 100644 arch/arm/include/asm/krait-l2-accessors.h create mode 100644 drivers/clk/qcom/clk-hfpll.c create mode 100644 drivers/clk/qcom/clk-hfpll.h create mode 100644 drivers/clk/qcom/clk-krait.c create mode 100644 drivers/clk/qcom/clk-krait.h create mode 100644 drivers/clk/qcom/hfpll.c create mode 100644 drivers/clk/qcom/kpss-xcc.c create mode 100644 drivers/clk/qcom/krait-cc.c create mode 100644 drivers/cpufreq/qcom-cpufreq.c
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 1/13 ARM: Add Krait L2 register accessor functions
Krait CPUs have a handful of L2 cache controller registers that live behind a cp15 based indirection register. First you program the indirection register (l2cpselr) to point the L2 'window' register (l2cpdr) at what you want to read/write. Then you read/write the 'window' register to do what you want. The l2cpselr register is not banked per-cpu so we must lock around accesses to it to prevent other CPUs from re-pointing l2cpdr underneath us.
--- arch/arm/common/Kconfig | 3 ++ arch/arm/common/Makefile | 1 + arch/arm/common/krait-l2-accessors.c | 58 +++++++++++++++++++++++++++++++ arch/arm/include/asm/krait-l2-accessors.h | 20 +++++++++++ 4 files changed, 82 insertions(+) create mode 100644 arch/arm/common/krait-l2-accessors.c create mode 100644 arch/arm/include/asm/krait-l2-accessors.h
arch/arm/common/Kconfig +3 -0
@@ -9,6 +9,9 @@ config DMABOUNCE bool select ZONE_DMA +config KRAIT_L2_ACCESSORS + bool + config SHARP_LOCOMO bool
arch/arm/common/Makefile +1 -0
@@ -7,6 +7,7 @@ obj-y += firmware.o obj-$(CONFIG_ICST) += icst.o obj-$(CONFIG_SA1111) += sa1111.o obj-$(CONFIG_DMABOUNCE) += dmabounce.o +obj-$(CONFIG_KRAIT_L2_ACCESSORS) += krait-l2-accessors.o obj-$(CONFIG_SHARP_LOCOMO) += locomo.o obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o obj-$(CONFIG_SHARP_SCOOP) += scoop.o
arch/arm/common/krait-l2-accessors.c new file +58 -0
58 lines not on this page · raw message
arch/arm/include/asm/krait-l2-accessors.h new file +20 -0
@@ -0,0 +1,20 @@ +/* +* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#ifndef __ASMARM_KRAIT_L2_ACCESSORS_H +#define __ASMARM_KRAIT_L2_ACCESSORS_H + +extern void krait_set_l2_indirect_reg (u32 addr,u32 val); +extern u32 krait_get_l2_indirect_reg (u32 addr); + +#endif
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 2/13 clk: mux: Split out register accessors for reuse
In reply to Stephen BoydWe want to reuse the logic in clk-mux.c for other clock drivers that don't use readl as register accessors. Fortunately, there really isn't much to the mux code besides the table indirection and quirk flags if you assume any bit shifting and masking has been done already. Pull that logic out into reusable functions that operate on an optional table and some flags so that other drivers can use the same logic.
--- drivers/clk/clk-mux.c | 76 +++++++++++++++++++++++++++----------------- include/linux/clk-provider.h | 9 ++++-- 2 files changed, 54 insertions(+), 31 deletions(-)
drivers/clk/clk-mux.c +47 -29
@@ -29,35 +29,24 @@#define to_clk_mux (_hw) container_of(_hw, struct clk_mux, hw) -static u8 clk_mux_get_parent (struct clk_hw *hw) +unsigned int clk_mux_get_parent (struct clk_hw *hw,unsigned int val, +unsigned int *table,unsigned long flags) { -struct clk_mux *mux =to_clk_mux (hw);int num_parents =__clk_get_num_parents (hw->clk); -u32 val; -/* -* FIXME need a mux-specific flag to determine if val is bitwise or numeric -* e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1 -* to 0x7 (index starts at one) -* OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so -* val = 0x4 really means "bit 2, index starts at bit 0" -*/ - val =clk_readl (mux->reg) >> mux->shift; - val &= mux->mask; - -if (mux->table) { +if (table) {int i;for (i =0 ; i < num_parents; i++) -if (mux->table[i] == val) +if (table[i] == val)return i;return -EINVAL ; } -if (val && (mux->flags &CLK_MUX_INDEX_BIT )) +if (val && (flags &CLK_MUX_INDEX_BIT )) val =ffs (val) -1 ; -if (val && (mux->flags &CLK_MUX_INDEX_ONE )) +if (val && (flags &CLK_MUX_INDEX_ONE )) val--;if (val >= num_parents)
@@ -65,24 +54,53 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)return val; } +EXPORT_SYMBOL_GPL (clk_mux_get_parent); -static int clk_mux_set_parent (struct clk_hw *hw,u8 index) +static u8 _clk_mux_get_parent (struct clk_hw *hw) {struct clk_mux *mux =to_clk_mux (hw);u32 val; -unsigned long flags =0 ; -if (mux->table) - index = mux->table[index]; +/* +* FIXME need a mux-specific flag to determine if val is bitwise or numeric +* e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1 +* to 0x7 (index starts at one) +* OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so +* val = 0x4 really means "bit 2, index starts at bit 0" +*/ + val =clk_readl (mux->reg) >> mux->shift; + val &= mux->mask; + +return clk_mux_get_parent (hw, val, mux->table, mux->flags); +} -else { -if (mux->flags &CLK_MUX_INDEX_BIT ) - index =1 << index; +unsigned int clk_mux_reindex (u8 index,unsigned int *table, +unsigned long flags) +{ +unsigned int val = index; -if (mux->flags &CLK_MUX_INDEX_ONE ) - index++; +if (table) { + val = table[val]; + }else { +if (flags &CLK_MUX_INDEX_BIT ) + val =1 << index; + +if (flags &CLK_MUX_INDEX_ONE ) + val++; } +return val; +} +EXPORT_SYMBOL_GPL (clk_mux_reindex); + +static int clk_mux_set_parent (struct clk_hw *hw,u8 index) +{ +struct clk_mux *mux =to_clk_mux (hw); +u32 val; +unsigned long flags =0 ; + + index =clk_mux_reindex (index, mux->table, mux->flags); +if (mux->lock)spin_lock_irqsave (mux->lock, flags);
@@ -102,21 +120,21 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index) }const struct clk_ops clk_mux_ops = { - .get_parent = clk_mux_get_parent, + .get_parent = _clk_mux_get_parent, .set_parent = clk_mux_set_parent, .determine_rate = __clk_mux_determine_rate, };EXPORT_SYMBOL_GPL (clk_mux_ops);const struct clk_ops clk_mux_ro_ops = { - .get_parent = clk_mux_get_parent, + .get_parent = _clk_mux_get_parent, };EXPORT_SYMBOL_GPL (clk_mux_ro_ops);struct clk *clk_register_mux_table (struct device *dev,const char *name,const char **parent_names,u8 num_parents,unsigned long flags,void __iomem *reg,u8 shift,u32 mask, -u8 clk_mux_flags,u32 *table,spinlock_t *lock) +u8 clk_mux_flags,unsigned int *table,spinlock_t *lock) {struct clk_mux *mux;struct clk *clk;
include/linux/clk-provider.h +7 -2
@@ -409,7 +409,7 @@ void clk_unregister_divider(struct clk *clk);struct clk_mux {struct clk_hw hw;void __iomem *reg; -u32 *table; +unsigned int *table;u32 mask;u8 shift;u8 flags;
@@ -425,6 +425,11 @@ struct clk_mux {extern const struct clk_ops clk_mux_ops;extern const struct clk_ops clk_mux_ro_ops; +unsigned int clk_mux_get_parent (struct clk_hw *hw,unsigned int val, +unsigned int *table,unsigned long flags); +unsigned int clk_mux_reindex (u8 index,unsigned int *table, +unsigned long flags); + struct clk *clk_register_mux(struct device *dev, const char *name, const char **parent_names, u8 num_parents, unsigned long flags, void __iomem *reg, u8 shift, u8 width,
@@ -433,7 +438,7 @@ struct clk *clk_register_mux(struct device *dev, const char *name,struct clk *clk_register_mux_table (struct device *dev,const char *name,const char **parent_names,u8 num_parents,unsigned long flags,void __iomem *reg,u8 shift,u32 mask, -u8 clk_mux_flags,u32 *table,spinlock_t *lock); +u8 clk_mux_flags,unsigned int *table,spinlock_t *lock);void clk_unregister_mux (struct clk *clk);
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 3/13 clk: Avoid sending high rates to downstream clocks during set_rate
In reply to Stephen BoydIf a clock is on and we call clk_set_rate() on it we may get into a situation where the clock temporarily increases in rate dramatically while we walk the tree and call .set_rate() ops. For example, consider a case where a PLL feeds into a divider. Initially the divider is set to divide by 1 and the PLL is running fairly slow (100MHz). The downstream consumer of the divider output can only handle rates =< 400 MHz, but the divider can only choose between divisors of 1 and 4.
+-----+ +----------------+ | PLL |-->| div 1 or div 4 |---> consumer device +-----+ +----------------+
To achieve a rate of 400MHz on the output of the divider, we would have to set the rate of the PLL to 1.6 GHz and then divide it by 4. The current code would set the PLL to 1.6GHz first while the divider is still set to 1, thus causing the downstream consumer of the clock to receive a few clock cycles of 1.6GHz clock (far beyond it's maximum acceptable rate). We should be changing the divider first before increasing the PLL rate to avoid this problem.
Therefore, set the rate of any child clocks that are increasing in rate from their current rate so that they can increase their dividers if necessary. We assume that there isn't such a thing as minimum rate requirements.
--- drivers/clk/clk.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-)
drivers/clk/clk.c +22 -12
@@ -1689,21 +1689,24 @@ static struct clk_core *clk_propagate_rate_change(struct clk_core *clk,* walk down a subtree and set the new rates notifying the rate * change on the way */ -static void clk_change_rate (struct clk_core *clk) +static void +clk_change_rate (struct clk_core *clk,unsigned long best_parent_rate) {struct clk_core *child;struct hlist_node *tmp;unsigned long old_rate; -unsigned long best_parent_rate =0 ;bool skip_set_rate = false;struct clk_core *old_parent; - old_rate = clk->rate; +hlist_for_each_entry (child, &clk->children, child_node) { +/* Skip children who will be reparented to another clock */ +if (child->new_parent && child->new_parent != clk) +continue ; +if (child->new_rate > child->rate) +clk_change_rate (child, clk->new_rate); + } -if (clk->new_parent) - best_parent_rate = clk->new_parent->rate; -else if (clk->parent) - best_parent_rate = clk->parent->rate; + old_rate = clk->rate;if (clk->new_parent && clk->new_parent != clk->parent) { old_parent =__clk_set_parent_before (clk, clk->new_parent);
@@ -1723,7 +1726,7 @@ static void clk_change_rate(struct clk_core *clk)if (!skip_set_rate && clk->ops->set_rate) clk->ops->set_rate (clk->hw, clk->new_rate, best_parent_rate); - clk->rate =clk_recalc (clk, best_parent_rate); + clk->rate = clk->new_rate;if (clk->notifier_count && old_rate != clk->rate)__clk_notify (clk,POST_RATE_CHANGE , old_rate, clk->rate);
@@ -1736,12 +1739,13 @@ static void clk_change_rate(struct clk_core *clk)/* Skip children who will be reparented to another clock */ if (child->new_parent && child->new_parent != clk)continue ; -clk_change_rate (child); +if (child->new_rate != child->rate) +clk_change_rate (child, clk->new_rate); }/* handle the new child who might not be in clk->children yet */ -if (clk->new_child) -clk_change_rate (clk->new_child); +if (clk->new_child && clk->new_child->new_rate != clk->new_child->rate) +clk_change_rate (clk->new_child, clk->new_rate); } static int clk_core_set_rate_nolock(struct clk_core *clk,
@@ -1750,6 +1754,7 @@ static int clk_core_set_rate_nolock(struct clk_core *clk,struct clk_core *top, *fail_clk;unsigned long rate = req_rate;int ret =0 ; +unsigned long parent_rate;if (!clk)return 0 ;
@@ -1775,8 +1780,13 @@ static int clk_core_set_rate_nolock(struct clk_core *clk,return -EBUSY ; } +if (top->parent) + parent_rate = top->parent->rate; +else + parent_rate =0 ; +/* change the rates */ -clk_change_rate (top); +clk_change_rate (top, parent_rate); clk->req_rate = req_rate;
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 4/13 clk: Add safe switch hook
In reply to Stephen BoydSometimes clocks can't accept their parent source turning off while the source is reprogrammed to a different rate. Most notably CPU clocks require a way to switch away from the current PLL they're running on, reprogram that PLL to a new rate, and then switch back to the PLL with the new rate once they're done. Add a hook that drivers can implement allowing them to return a 'safe parent' that they can switch their parent to while the upstream source is reprogrammed to support this.
---
This patch is good enough for Krait, but soon I'll need to support a "safe rate" where we ask a clock what rate it needs to be running at to be sure it's within voltage constraints. Right now safe parent handles that problem on Krait, but on other platforms it won't work.
drivers/clk/clk.c | 61 ++++++++++++++++++++++++++++++++++++++------ include/linux/clk-provider.h | 1 + 2 files changed, 54 insertions(+), 8 deletions(-)
drivers/clk/clk.c +53 -8
@@ -56,9 +56,12 @@ struct clk_core {struct clk_core **parents;u8 num_parents;u8 new_parent_index; +u8 safe_parent_index;unsigned long rate;unsigned long req_rate; +unsigned long old_rate;unsigned long new_rate; +struct clk_core *safe_parent;struct clk_core *new_parent;struct clk_core *new_child;unsigned long flags;
@@ -1550,7 +1553,8 @@ out:static void clk_calc_subtree (struct clk_core *clk,unsigned long new_rate,struct clk_core *new_parent,u8 p_index) { -struct clk_core *child; +struct clk_core *child, *parent; +struct clk_hw *parent_hw; clk->new_rate = new_rate; clk->new_parent = new_parent;
@@ -1560,6 +1564,18 @@ static void clk_calc_subtree(struct clk_core *clk, unsigned long new_rate,if (new_parent && new_parent != clk->parent) new_parent->new_child = clk; +if (clk->ops->get_safe_parent) { + parent_hw = clk->ops->get_safe_parent (clk->hw); +if (parent_hw) { + parent = parent_hw->core; + p_index =clk_fetch_parent_index (clk, parent); + clk->safe_parent_index = p_index; + clk->safe_parent = parent; + } + }else { + clk->safe_parent =NULL ; + } +hlist_for_each_entry (child, &clk->children, child_node) { child->new_rate =clk_recalc (child, new_rate);clk_calc_subtree (child, child->new_rate,NULL ,0 );
@@ -1655,14 +1671,43 @@ static struct clk_core *clk_propagate_rate_change(struct clk_core *clk, unsigned long event) {struct clk_core *child, *tmp_clk, *fail_clk =NULL ; +struct clk_core *old_parent;int ret =NOTIFY_DONE ; -if (clk->rate == clk->new_rate) +if (clk->rate == clk->new_rate && event !=POST_RATE_CHANGE )return NULL ; +switch (event) { +case PRE_RATE_CHANGE : +if (clk->safe_parent) + clk->ops->set_parent (clk->hw, clk->safe_parent_index); + clk->old_rate = clk->rate; +break ; +case POST_RATE_CHANGE : +if (clk->safe_parent) { + old_parent =__clk_set_parent_before (clk, + clk->new_parent); +if (clk->ops->set_rate_and_parent) { + clk->ops->set_rate_and_parent (clk->hw, + clk->new_rate, + clk->new_parent ? + clk->new_parent->rate :0 , + clk->new_parent_index); + }else if (clk->ops->set_parent) { + clk->ops->set_parent (clk->hw, + clk->new_parent_index); + } +__clk_set_parent_after (clk, clk->new_parent, + old_parent); + } +break ; + } +if (clk->notifier_count) { - ret =__clk_notify (clk, event, clk->rate, clk->new_rate); -if (ret &NOTIFY_STOP_MASK ) +if (event !=POST_RATE_CHANGE || clk->old_rate != clk->rate) + ret =__clk_notify (clk, event, clk->old_rate, + clk->new_rate); +if (ret &NOTIFY_STOP_MASK && event !=POST_RATE_CHANGE ) fail_clk = clk; }
@@ -1708,7 +1753,8 @@ clk_change_rate(struct clk_core *clk, unsigned long best_parent_rate) old_rate = clk->rate; -if (clk->new_parent && clk->new_parent != clk->parent) { +if (clk->new_parent && clk->new_parent != clk->parent && + !clk->safe_parent) { old_parent =__clk_set_parent_before (clk, clk->new_parent);if (clk->ops->set_rate_and_parent) {
@@ -1728,9 +1774,6 @@ clk_change_rate(struct clk_core *clk, unsigned long best_parent_rate) clk->rate = clk->new_rate; -if (clk->notifier_count && old_rate != clk->rate) -__clk_notify (clk,POST_RATE_CHANGE , old_rate, clk->rate); -/* * Use safe iteration, as change_rate can actually swap parents * for certain clock types.
@@ -1790,6 +1833,8 @@ static int clk_core_set_rate_nolock(struct clk_core *clk, clk->req_rate = req_rate; +clk_propagate_rate_change (top,POST_RATE_CHANGE ); +return ret; }
include/linux/clk-provider.h +1 -0
@@ -183,6 +183,7 @@ struct clk_ops { struct clk_hw **best_parent_hw);int (*set_parent)(struct clk_hw *hw,u8 index);u8 (*get_parent)(struct clk_hw *hw); +struct clk_hw *(*get_safe_parent)(struct clk_hw *hw);int (*set_rate)(struct clk_hw *hw,unsigned long rate,unsigned long parent_rate); int (*set_rate_and_parent)(struct clk_hw *hw,
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 5/13 clk: qcom: Add support for High-Frequency PLLs (HFPLLs)
In reply to Stephen BoydHFPLLs are the main frequency source for Krait CPU clocks. Add support for changing the rate of these PLLs.
---
I'd really like to get rid of __clk_hfpll_init_once() if possible...
drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-hfpll.c | 253 +++++++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-hfpll.h | 54 +++++++++ 3 files changed, 308 insertions(+) create mode 100644 drivers/clk/qcom/clk-hfpll.c create mode 100644 drivers/clk/qcom/clk-hfpll.h
drivers/clk/qcom/Makefile +1 -0
@@ -8,6 +8,7 @@ clk-qcom-y += clk-rcg2.o clk-qcom-y += clk-branch.o clk-qcom-y += clk-regmap-divider.o clk-qcom-y += clk-regmap-mux.o +clk-qcom-y += clk-hfpll.o clk-qcom-y += reset.o obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
drivers/clk/qcom/clk-hfpll.c new file +253 -0
253 lines not on this page · raw message
drivers/clk/qcom/clk-hfpll.h new file +54 -0
54 lines not on this page · raw message
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 6/13 clk: qcom: Add HFPLL driver
In reply to Stephen BoydOn some devices (MSM8974 for example), the HFPLLs are instantiated within the Krait processor subsystem as separate register regions. Add a driver for these PLLs so that we can provide HFPLL clocks for use by the system.
--- .../devicetree/bindings/clock/qcom,hfpll.txt | 40 ++++++++ drivers/clk/qcom/Kconfig | 8 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/hfpll.c | 109 +++++++++++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,hfpll.txt create mode 100644 drivers/clk/qcom/hfpll.c
Documentation/devicetree/bindings/clock/qcom,hfpll.txt new file +40 -0
@@ -0,0 +1,40 @@ +High-Frequency PLL (HFPLL) + +PROPERTIES + +- compatible: + Usage: required + Value type: <string> + Definition: must be "qcom,hfpll" + +- reg: + Usage: required + Value type: <prop-encoded-array> + Definition: address and size of HPLL registers. An optional second + element specifies the address and size of the alias + register region. + +- clock-output-names: + Usage: required + Value type: <string> + Definition: Name of the PLL. Typically hfpllX where X is a CPU number + starting at 0. Otherwise hfpll_Y where Y is more specific + such as "l2". + +Example: + +1) An HFPLL for the L2 cache. + + clock-controller at f9016000 { + compatible = "qcom,hfpll"; + reg = <0xf9016000 0x30>; + clock-output-names = "hfpll_l2"; + }; + +2) An HFPLL for CPU0. This HFPLL has the alias register region. + + clock-controller at f908a000 { + compatible = "qcom,hfpll"; + reg = <0xf908a000 0x30>, <0xf900a000 0x30>; + clock-output-names = "hfpll0"; + };
drivers/clk/qcom/Kconfig +8 -0
@@ -88,3 +88,11 @@ config MSM_MMCC_8974 Support for the multimedia clock controller on msm8974 devices. Say Y if you want to support multimedia devices such as display, graphics, video encode/decode, camera, etc. + +config QCOM_HFPLL + tristate "High-Frequency PLL (HFPLL) Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the high-frequency PLLs present on Qualcomm devices. + Say Y if you want to support CPU frequency scaling on devices + such as MSM8974, APQ8084, etc.
drivers/clk/qcom/Makefile +1 -0
@@ -21,3 +21,4 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o +obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
drivers/clk/qcom/hfpll.c new file +109 -0
109 lines not on this page · raw message
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 7/13 clk: qcom: Add MSM8960/APQ8064's HFPLLs
In reply to Stephen BoydDescribe the HFPLLs present on MSM8960 and APQ8064 devices.
--- drivers/clk/qcom/gcc-msm8960.c | 172 +++++++++++++++++++++++++++ include/dt-bindings/clock/qcom,gcc-msm8960.h | 2 + 2 files changed, 174 insertions(+)
drivers/clk/qcom/gcc-msm8960.c +172 -0
@@ -30,6 +30,7 @@#include "clk-pll.h" #include "clk-rcg.h" #include "clk-branch.h" +#include "clk-hfpll.h" #include "reset.h" static struct clk_pll pll3 = {
@@ -75,6 +76,164 @@ static struct clk_regmap pll8_vote = { }, }; +static struct hfpll_data hfpll0_data = { + .mode_reg =0x3200 , + .l_reg =0x3208 , + .m_reg =0x320c , + .n_reg =0x3210 , + .config_reg =0x3204 , + .status_reg =0x321c , + .config_val =0x7845c665 , + .droop_reg =0x3214 , + .droop_val =0x0108c000 , + .min_rate =600000000UL , + .max_rate =1800000000UL , +}; + +static struct clk_hfpll hfpll0 = { + .d = &hfpll0_data, + .clkr.hw.init = &(struct clk_init_data ){ + .parent_names = (const char *[]){"pxo" }, + .num_parents =1 , + .name ="hfpll0" , + .ops = &clk_ops_hfpll, + .flags =CLK_IGNORE_UNUSED , + }, + .lock =__SPIN_LOCK_UNLOCKED (hfpll0.lock), +}; + +static struct hfpll_data hfpll1_8064_data = { + .mode_reg =0x3240 , + .l_reg =0x3248 , + .m_reg =0x324c , + .n_reg =0x3250 , + .config_reg =0x3244 , + .status_reg =0x325c , + .config_val =0x7845c665 , + .droop_reg =0x3254 , + .droop_val =0x0108c000 , + .min_rate =600000000UL , + .max_rate =1800000000UL , +}; + +static struct hfpll_data hfpll1_data = { + .mode_reg =0x3300 , + .l_reg =0x3308 , + .m_reg =0x330c , + .n_reg =0x3310 , + .config_reg =0x3304 , + .status_reg =0x331c , + .config_val =0x7845c665 , + .droop_reg =0x3314 , + .droop_val =0x0108c000 , + .min_rate =600000000UL , + .max_rate =1800000000UL , +}; + +static struct clk_hfpll hfpll1 = { + .d = &hfpll1_data, + .clkr.hw.init = &(struct clk_init_data ){ + .parent_names = (const char *[]){"pxo" }, + .num_parents =1 , + .name ="hfpll1" , + .ops = &clk_ops_hfpll, + .flags =CLK_IGNORE_UNUSED , + }, + .lock =__SPIN_LOCK_UNLOCKED (hfpll1.lock), +}; + +static struct hfpll_data hfpll2_data = { + .mode_reg =0x3280 , + .l_reg =0x3288 , + .m_reg =0x328c , + .n_reg =0x3290 , + .config_reg =0x3284 , + .status_reg =0x329c , + .config_val =0x7845c665 , + .droop_reg =0x3294 , + .droop_val =0x0108c000 , + .min_rate =600000000UL , + .max_rate =1800000000UL , +}; + +static struct clk_hfpll hfpll2 = { + .d = &hfpll2_data, + .clkr.hw.init = &(struct clk_init_data ){ + .parent_names = (const char *[]){"pxo" }, + .num_parents =1 , + .name ="hfpll2" , + .ops = &clk_ops_hfpll, + .flags =CLK_IGNORE_UNUSED , + }, + .lock =__SPIN_LOCK_UNLOCKED (hfpll2.lock), +}; + +static struct hfpll_data hfpll3_data = { + .mode_reg =0x32c0 , + .l_reg =0x32c8 , + .m_reg =0x32cc , + .n_reg =0x32d0 , + .config_reg =0x32c4 , + .status_reg =0x32dc , + .config_val =0x7845c665 , + .droop_reg =0x32d4 , + .droop_val =0x0108c000 , + .min_rate =600000000UL , + .max_rate =1800000000UL , +}; + +static struct clk_hfpll hfpll3 = { + .d = &hfpll3_data, + .clkr.hw.init = &(struct clk_init_data ){ + .parent_names = (const char *[]){"pxo" }, + .num_parents =1 , + .name ="hfpll3" , + .ops = &clk_ops_hfpll, + .flags =CLK_IGNORE_UNUSED , + }, + .lock =__SPIN_LOCK_UNLOCKED (hfpll3.lock), +}; + +static struct hfpll_data hfpll_l2_8064_data = { + .mode_reg =0x3300 , + .l_reg =0x3308 , + .m_reg =0x330c , + .n_reg =0x3310 , + .config_reg =0x3304 , + .status_reg =0x331c , + .config_val =0x7845c665 , + .droop_reg =0x3314 , + .droop_val =0x0108c000 , + .min_rate =600000000UL , + .max_rate =1800000000UL , +}; + +static struct hfpll_data hfpll_l2_data = { + .mode_reg =0x3400 , + .l_reg =0x3408 , + .m_reg =0x340c , + .n_reg =0x3410 , + .config_reg =0x3404 , + .status_reg =0x341c , + .config_val =0x7845c665 , + .droop_reg =0x3414 , + .droop_val =0x0108c000 , + .min_rate =600000000UL , + .max_rate =1800000000UL , +}; + +static struct clk_hfpll hfpll_l2 = { + .d = &hfpll_l2_data, + .clkr.hw.init = &(struct clk_init_data ){ + .parent_names = (const char *[]){"pxo" }, + .num_parents =1 , + .name ="hfpll_l2" , + .ops = &clk_ops_hfpll, + .flags =CLK_IGNORE_UNUSED , + }, + .lock =__SPIN_LOCK_UNLOCKED (hfpll_l2.lock), +}; +static struct clk_pll pll14 = { .l_reg =0x31c4 , .m_reg =0x31c8 ,
@@ -3140,6 +3299,9 @@ static struct clk_regmap *gcc_msm8960_clks[] = { [PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr, [PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr, [RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr, + [PLL9] = &hfpll0.clkr, + [PLL10] = &hfpll1.clkr, + [PLL12] = &hfpll_l2.clkr, };static const struct qcom_reset_map gcc_msm8960_resets[] = {
@@ -3350,6 +3512,11 @@ static struct clk_regmap *gcc_apq8064_clks[] = { [PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr, [PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr, [RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr, + [PLL9] = &hfpll0.clkr, + [PLL10] = &hfpll1.clkr, + [PLL12] = &hfpll_l2.clkr, + [PLL16] = &hfpll2.clkr, + [PLL17] = &hfpll3.clkr, };static const struct qcom_reset_map gcc_apq8064_resets[] = {
@@ -3496,6 +3663,11 @@ static int gcc_msm8960_probe(struct platform_device *pdev)if (!match)return -EINVAL ; +if (match->data == &gcc_apq8064_desc) { + hfpll1.d = &hfpll1_8064_data; + hfpll_l2.d = &hfpll_l2_8064_data; + } +/* Temporary until RPM clocks supported */ clk =clk_register_fixed_rate (dev,"cxo" ,NULL ,CLK_IS_ROOT ,19200000 );if (IS_ERR (clk))
include/dt-bindings/clock/qcom,gcc-msm8960.h +2 -0
@@ -319,5 +319,7 @@#define CE3_SRC 303#define CE3_CORE_CLK 304#define CE3_H_CLK 305 +#define PLL16 306 +#define PLL17 307#endif
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 8/13 clk: qcom: Add IPQ806X's HFPLLs
In reply to Stephen BoydDescribe the HFPLLs present on IPQ806X devices.
--- drivers/clk/qcom/gcc-ipq806x.c | 83 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+)
drivers/clk/qcom/gcc-ipq806x.c +83 -0
@@ -30,6 +30,7 @@#include "clk-pll.h" #include "clk-rcg.h" #include "clk-branch.h" +#include "clk-hfpll.h" #include "reset.h" static struct clk_pll pll0 = {
@@ -113,6 +114,85 @@ static struct clk_regmap pll8_vote = { }, }; +static struct hfpll_data hfpll0_data = { + .mode_reg =0x3200 , + .l_reg =0x3208 , + .m_reg =0x320c , + .n_reg =0x3210 , + .config_reg =0x3204 , + .status_reg =0x321c , + .config_val =0x7845c665 , + .droop_reg =0x3214 , + .droop_val =0x0108c000 , + .min_rate =600000000UL , + .max_rate =1800000000UL , +}; + +static struct clk_hfpll hfpll0 = { + .d = &hfpll0_data, + .clkr.hw.init = &(struct clk_init_data ){ + .parent_names = (const char *[]){"pxo" }, + .num_parents =1 , + .name ="hfpll0" , + .ops = &clk_ops_hfpll, + .flags =CLK_IGNORE_UNUSED , + }, + .lock =__SPIN_LOCK_UNLOCKED (hfpll0.lock), +}; + +static struct hfpll_data hfpll1_data = { + .mode_reg =0x3240 , + .l_reg =0x3248 , + .m_reg =0x324c , + .n_reg =0x3250 , + .config_reg =0x3244 , + .status_reg =0x325c , + .config_val =0x7845c665 , + .droop_reg =0x3314 , + .droop_val =0x0108c000 , + .min_rate =600000000UL , + .max_rate =1800000000UL , +}; + +static struct clk_hfpll hfpll1 = { + .d = &hfpll1_data, + .clkr.hw.init = &(struct clk_init_data ){ + .parent_names = (const char *[]){"pxo" }, + .num_parents =1 , + .name ="hfpll1" , + .ops = &clk_ops_hfpll, + .flags =CLK_IGNORE_UNUSED , + }, + .lock =__SPIN_LOCK_UNLOCKED (hfpll1.lock), +}; + +static struct hfpll_data hfpll_l2_data = { + .mode_reg =0x3300 , + .l_reg =0x3308 , + .m_reg =0x330c , + .n_reg =0x3310 , + .config_reg =0x3304 , + .status_reg =0x331c , + .config_val =0x7845c665 , + .droop_reg =0x3314 , + .droop_val =0x0108c000 , + .min_rate =600000000UL , + .max_rate =1800000000UL , +}; + +static struct clk_hfpll hfpll_l2 = { + .d = &hfpll_l2_data, + .clkr.hw.init = &(struct clk_init_data ){ + .parent_names = (const char *[]){"pxo" }, + .num_parents =1 , + .name ="hfpll_l2" , + .ops = &clk_ops_hfpll, + .flags =CLK_IGNORE_UNUSED , + }, + .lock =__SPIN_LOCK_UNLOCKED (hfpll_l2.lock), +}; + +static struct clk_pll pll14 = { .l_reg =0x31c4 , .m_reg =0x31c8 ,
@@ -2273,6 +2353,9 @@ static struct clk_regmap *gcc_ipq806x_clks[] = { [USB_FS1_XCVR_SRC] = &usb_fs1_xcvr_clk_src.clkr, [USB_FS1_XCVR_CLK] = &usb_fs1_xcvr_clk.clkr, [USB_FS1_SYSTEM_CLK] = &usb_fs1_sys_clk.clkr, + [PLL9] = &hfpll0.clkr, + [PLL10] = &hfpll1.clkr, + [PLL12] = &hfpll_l2.clkr, };static const struct qcom_reset_map gcc_ipq806x_resets[] = {
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 9/13 clk: qcom: Add support for Krait clocks
In reply to Stephen BoydThe Krait clocks are made up of a series of muxes and a divider that choose between a fixed rate clock and dedicated HFPLLs for each CPU. Instead of using mmio accesses to remux parents, the Krait implementation exposes the remux control via cp15 registers. Support these clocks.
--- drivers/clk/qcom/Kconfig | 4 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-krait.c | 166 +++++++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-krait.h | 49 +++++++++++++ 4 files changed, 220 insertions(+) create mode 100644 drivers/clk/qcom/clk-krait.c create mode 100644 drivers/clk/qcom/clk-krait.h
drivers/clk/qcom/Kconfig +4 -0
@@ -96,3 +96,7 @@ config QCOM_HFPLL Support for the high-frequency PLLs present on Qualcomm devices. Say Y if you want to support CPU frequency scaling on devices such as MSM8974, APQ8084, etc. + +config KRAIT_CLOCKS + bool + select KRAIT_L2_ACCESSORS
drivers/clk/qcom/Makefile +1 -0
@@ -8,6 +8,7 @@ clk-qcom-y += clk-rcg2.o clk-qcom-y += clk-branch.o clk-qcom-y += clk-regmap-divider.o clk-qcom-y += clk-regmap-mux.o +clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o clk-qcom-y += clk-hfpll.o clk-qcom-y += reset.o
drivers/clk/qcom/clk-krait.c new file +166 -0
166 lines not on this page · raw message
drivers/clk/qcom/clk-krait.h new file +49 -0
49 lines not on this page · raw message
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 10/13 clk: qcom: Add KPSS ACC/GCC driver
In reply to Stephen BoydThe ACC and GCC regions present in KPSSv1 contain registers to control clocks and power to each Krait CPU and L2. For CPUfreq purposes probe these devices and expose a mux clock that chooses between PXO and PLL8.
--- .../devicetree/bindings/arm/msm/qcom,kpss-acc.txt | 7 ++ .../devicetree/bindings/arm/msm/qcom,kpss-gcc.txt | 28 +++++++ drivers/clk/qcom/Kconfig | 8 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/kpss-xcc.c | 95 ++++++++++++++++++++++ 5 files changed, 139 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt create mode 100644 drivers/clk/qcom/kpss-xcc.c
Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt +7 -0
@@ -21,10 +21,17 @@ PROPERTIES the register region. An optional second element specifies the base address and size of the alias register region. +- clock-output-names: + Usage: optional + Value type: <string> + Definition: Name of the output clock. Typically acpuX_aux where X is a + CPU number starting at 0. + Example: clock-controller at 2088000 { compatible = "qcom,kpss-acc-v2"; reg = <0x02088000 0x1000>, <0x02008000 0x1000>; + clock-output-names = "acpu0_aux"; };
Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt new file +28 -0
@@ -0,0 +1,28 @@ +Krait Processor Sub-system (KPSS) Global Clock Controller (GCC) + +PROPERTIES + +- compatible: + Usage: required + Value type: <string> + Definition: should be one of: + "qcom,kpss-gcc" + +- reg: + Usage: required + Value type: <prop-encoded-array> + Definition: base address and size of the register region + +- clock-output-names: + Usage: required + Value type: <string> + Definition: Name of the output clock. Typically acpu_l2_aux indicating + an L2 cache auxiliary clock. + +Example: + + l2cc: clock-controller at 2011000 { + compatible = "qcom,kpss-gcc"; + reg = <0x2011000 0x1000>; + clock-output-names = "acpu_l2_aux"; + };
drivers/clk/qcom/Kconfig +8 -0
@@ -97,6 +97,14 @@ config QCOM_HFPLL Say Y if you want to support CPU frequency scaling on devices such as MSM8974, APQ8084, etc. +config KPSS_XCC + tristate "KPSS Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the Krait ACC and GCC clock controllers. Say Y + if you want to support CPU frequency scaling on devices such + as MSM8960, APQ8064, etc. + config KRAIT_CLOCKS bool select KRAIT_L2_ACCESSORS
drivers/clk/qcom/Makefile +1 -0
@@ -22,4 +22,5 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o +obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
drivers/clk/qcom/kpss-xcc.c new file +95 -0
95 lines not on this page · raw message
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 11/13 clk: qcom: Add Krait clock controller driver
In reply to Stephen BoydThe Krait CPU clocks are made up of a primary mux and secondary mux for each CPU and the L2, controlled via cp15 accessors. For Kraits within KPSSv1 each secondary mux accepts a different aux source, but on KPSSv2 each secondary mux accepts the same aux source.
--- .../devicetree/bindings/clock/qcom,krait-cc.txt | 22 ++ drivers/clk/qcom/Kconfig | 8 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/krait-cc.c | 352 +++++++++++++++++++++ 4 files changed, 383 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,krait-cc.txt create mode 100644 drivers/clk/qcom/krait-cc.c
Documentation/devicetree/bindings/clock/qcom,krait-cc.txt new file +22 -0
@@ -0,0 +1,22 @@ +Krait Clock Controller + +PROPERTIES + +- compatible: + Usage: required + Value type: <string> + Definition: must be one of: + "qcom,krait-cc-v1" + "qcom,krait-cc-v2" + +- #clock-cells: + Usage: required + Value type: <u32> + Definition: must be 1 + +Example: + + kraitcc: clock-controller { + compatible = "qcom,krait-cc-v1"; + #clock-cells = <1>; + };
drivers/clk/qcom/Kconfig +8 -0
@@ -105,6 +105,14 @@ config KPSS_XCC if you want to support CPU frequency scaling on devices such as MSM8960, APQ8064, etc. +config KRAITCC + tristate "Krait Clock Controller" + depends on COMMON_CLK_QCOM && ARM + select KRAIT_CLOCKS + help + Support for the Krait CPU clocks on Qualcomm devices. + Say Y if you want to support CPU frequency scaling. + config KRAIT_CLOCKS bool select KRAIT_L2_ACCESSORS
drivers/clk/qcom/Makefile +1 -0
@@ -24,3 +24,4 @@ obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o obj-$(CONFIG_QCOM_HFPLL) += hfpll.o +obj-$(CONFIG_KRAITCC) += krait-cc.o
drivers/clk/qcom/krait-cc.c new file +352 -0
352 lines not on this page · raw message
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 12/13 cpufreq: Add module to register cpufreq on Krait CPUs
In reply to Stephen BoydRegister a cpufreq-generic device whenever we detect that a "qcom,krait" compatible CPU is present in DT.
--- .../devicetree/bindings/arm/msm/qcom,pvs.txt | 38 ++++ drivers/cpufreq/Kconfig.arm | 9 + drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq.c | 204 +++++++++++++++++++++ 4 files changed, 252 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,pvs.txt create mode 100644 drivers/cpufreq/qcom-cpufreq.c
Documentation/devicetree/bindings/arm/msm/qcom,pvs.txt new file +38 -0
@@ -0,0 +1,38 @@ +Qualcomm Process Voltage Scaling Tables + +The node name is required to be "qcom,pvs". There shall only be one +such node present in the root of the tree. + +PROPERTIES + +- qcom,pvs-format-a or qcom,pvs-format-b: + Usage: required + Value type: <empty> + Definition: Indicates the format of qcom,speedX-pvsY-bin-vZ properties. + If qcom,pvs-format-a is used the table is two columns + (frequency and voltage in that order). If qcom,pvs-format-b is used the table is three columns (frequency, voltage, + and current in that order). + +- qcom,speedX-pvsY-bin-vZ: + Usage: required + Value type: <prop-encoded-array> + Definition: The PVS table corresponding to the speed bin X, pvs bin Y, + and version Z. +Example: + + qcom,pvs { + qcom,pvs-format-a; + qcom,speed0-pvs0-bin-v0 = + < 384000000 950000 >, + < 486000000 975000 >, + < 594000000 1000000 >, + < 702000000 1025000 >, + < 810000000 1075000 >, + < 918000000 1100000 >, + < 1026000000 1125000 >, + < 1134000000 1175000 >, + < 1242000000 1200000 >, + < 1350000000 1225000 >, + < 1458000000 1237500 >, + < 1512000000 1250000 >; + };
drivers/cpufreq/Kconfig.arm +9 -0
@@ -137,6 +137,15 @@ config ARM_OMAP2PLUS_CPUFREQ depends on ARCH_OMAP2PLUS default ARCH_OMAP2PLUS +config ARM_QCOM_CPUFREQ + tristate "Qualcomm based" + depends on ARCH_QCOM + select PM_OPP + help + This adds the CPUFreq driver for Qualcomm SoC based boards. + + If in doubt, say N. + config ARM_S3C_CPUFREQ bool help
drivers/cpufreq/Makefile +1 -0
@@ -65,6 +65,7 @@ obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ) += qcom-cpufreq.o obj-$(CONFIG_ARM_S3C24XX_CPUFREQ) += s3c24xx-cpufreq.o obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
drivers/cpufreq/qcom-cpufreq.c new file +204 -0
204 lines not on this page · raw message
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 13/13 ARM: dts: qcom: Add necessary DT data for Krait cpufreq
In reply to Stephen BoydAdd the necessary DT nodes and data so we can probe the cpufreq driver on MSM devices with Krait CPUs.
--- arch/arm/boot/dts/qcom-apq8064.dtsi | 230 ++++++++++++++++++++++++++ arch/arm/boot/dts/qcom-msm8960.dtsi | 49 ++++++ arch/arm/boot/dts/qcom-msm8974.dtsi | 311 +++++++++++++++++++++++++++++++++++- 3 files changed, 586 insertions(+), 4 deletions(-)
arch/arm/boot/dts/qcom-apq8064.dtsi +230 -0
@@ -23,6 +23,9 @@ next-level-cache = <&L2>; qcom,acc = <&acc0>; qcom,saw = <&saw0>; + clocks = <&kraitcc 0>; + clock-names = "cpu"; + clock-latency = <100000>; }; cpu at 1 {
@@ -33,6 +36,9 @@ next-level-cache = <&L2>; qcom,acc = <&acc1>; qcom,saw = <&saw1>; + clocks = <&kraitcc 1>; + clock-names = "cpu"; + clock-latency = <100000>; }; cpu at 2 {
@@ -43,6 +49,9 @@ next-level-cache = <&L2>; qcom,acc = <&acc2>; qcom,saw = <&saw2>; + clocks = <&kraitcc 2>; + clock-names = "cpu"; + clock-latency = <100000>; }; cpu at 3 {
@@ -53,6 +62,9 @@ next-level-cache = <&L2>; qcom,acc = <&acc3>; qcom,saw = <&saw3>; + clocks = <&kraitcc 3>; + clock-names = "cpu"; + clock-latency = <100000>; }; L2: l2-cache {
@@ -66,6 +78,214 @@ interrupts = <1 10 0x304>; }; + qcom,pvs { + qcom,pvs-format-a; + qcom,speed0-pvs0-bin-v0 = + < 384000000 950000 >, + < 486000000 975000 >, + < 594000000 1000000 >, + < 702000000 1025000 >, + < 810000000 1075000 >, + < 918000000 1100000 >; + + qcom,speed0-pvs1-bin-v0 = + < 384000000 900000 >, + < 486000000 925000 >, + < 594000000 950000 >, + < 702000000 975000 >, + < 810000000 1025000 >, + < 918000000 1050000 >; + + qcom,speed0-pvs3-bin-v0 = + < 384000000 850000 >, + < 486000000 875000 >, + < 594000000 900000 >, + < 702000000 925000 >, + < 810000000 975000 >, + < 918000000 1000000 >; + + qcom,speed0-pvs4-bin-v0 = + < 384000000 850000 >, + < 486000000 875000 >, + < 594000000 900000 >, + < 702000000 925000 >, + < 810000000 962500 >, + < 918000000 975000 >; + + qcom,speed1-pvs0-bin-v0 = + < 384000000 950000 >, + < 486000000 950000 >, + < 594000000 950000 >, + < 702000000 962500 >, + < 810000000 1000000 >, + < 918000000 1025000 >; + + qcom,speed1-pvs1-bin-v0 = + < 384000000 950000 >, + < 486000000 950000 >, + < 594000000 950000 >, + < 702000000 962500 >, + < 810000000 975000 >, + < 918000000 1000000 >; + + qcom,speed1-pvs2-bin-v0 = + < 384000000 925000 >, + < 486000000 925000 >, + < 594000000 925000 >, + < 702000000 925000 >, + < 810000000 937500 >, + < 918000000 950000 >; + + qcom,speed1-pvs3-bin-v0 = + < 384000000 900000 >, + < 486000000 900000 >, + < 594000000 900000 >, + < 702000000 900000 >, + < 810000000 900000 >, + < 918000000 925000 >; + + qcom,speed1-pvs4-bin-v0 = + < 384000000 875000 >, + < 486000000 875000 >, + < 594000000 875000 >, + < 702000000 875000 >, + < 810000000 887500 >, + < 918000000 900000 >; + + qcom,speed1-pvs5-bin-v0 = + < 384000000 875000 >, + < 486000000 875000 >, + < 594000000 875000 >, + < 702000000 875000 >, + < 810000000 887500 >, + < 918000000 900000 >; + + qcom,speed1-pvs6-bin-v0 = + < 384000000 875000 >, + < 486000000 875000 >, + < 594000000 875000 >, + < 702000000 875000 >, + < 810000000 887500 >, + < 918000000 900000 >; + + qcom,speed2-pvs0-bin-v0 = + < 384000000 950000 >, + < 486000000 950000 >, + < 594000000 950000 >, + < 702000000 950000 >, + < 810000000 962500 >, + < 918000000 975000 >; + + qcom,speed2-pvs1-bin-v0 = + < 384000000 925000 >, + < 486000000 925000 >, + < 594000000 925000 >, + < 702000000 925000 >, + < 810000000 937500 >, + < 918000000 950000 >; + + qcom,speed2-pvs2-bin-v0 = + < 384000000 900000 >, + < 486000000 900000 >, + < 594000000 900000 >, + < 702000000 900000 >, + < 810000000 912500 >, + < 918000000 925000 >; + + qcom,speed2-pvs3-bin-v0 = + < 384000000 900000 >, + < 486000000 900000 >, + < 594000000 900000 >, + < 702000000 900000 >, + < 810000000 900000 >, + < 918000000 912500 >; + + qcom,speed2-pvs4-bin-v0 = + < 384000000 875000 >, + < 486000000 875000 >, + < 594000000 875000 >, + < 702000000 875000 >, + < 810000000 887500 >, + < 918000000 900000 >; + + qcom,speed2-pvs5-bin-v0 = + < 384000000 875000 >, + < 486000000 875000 >, + < 594000000 875000 >, + < 702000000 875000 >, + < 810000000 887500 >, + < 918000000 900000 >; + + qcom,speed2-pvs6-bin-v0 = + < 384000000 875000 >, + < 486000000 875000 >, + < 594000000 875000 >, + < 702000000 875000 >, + < 810000000 887500 >, + < 918000000 900000 >; + + qcom,speed14-pvs0-bin-v0 = + < 384000000 950000 >, + < 486000000 950000 >, + < 594000000 950000 >, + < 702000000 962500 >, + < 810000000 1000000 >, + < 918000000 1025000 >; + + qcom,speed14-pvs1-bin-v0 = + < 384000000 950000 >, + < 486000000 950000 >, + < 594000000 950000 >, + < 702000000 962500 >, + < 810000000 975000 >, + < 918000000 1000000 >; + + qcom,speed14-pvs2-bin-v0 = + < 384000000 925000 >, + < 486000000 925000 >, + < 594000000 925000 >, + < 702000000 925000 >, + < 810000000 937500 >, + < 918000000 950000 >; + + qcom,speed14-pvs3-bin-v0 = + < 384000000 900000 >, + < 486000000 900000 >, + < 594000000 900000 >, + < 702000000 900000 >, + < 810000000 900000 >, + < 918000000 925000 >; + + qcom,speed14-pvs4-bin-v0 = + < 384000000 875000 >, + < 486000000 875000 >, + < 594000000 875000 >, + < 702000000 875000 >, + < 810000000 887500 >, + < 918000000 900000 >; + + qcom,speed14-pvs5-bin-v0 = + < 384000000 875000 >, + < 486000000 875000 >, + < 594000000 875000 >, + < 702000000 875000 >, + < 810000000 887500 >, + < 918000000 900000 >; + + qcom,speed14-pvs6-bin-v0 = + < 384000000 875000 >, + < 486000000 875000 >, + < 594000000 875000 >, + < 702000000 875000 >, + < 810000000 887500 >, + < 918000000 900000 >; + }; + + kraitcc: clock-controller { + compatible = "qcom,krait-cc-v1"; + #clock-cells = <1>; + }; + soc: soc { #address-cells = <1>; #size-cells = <1>;
@@ -122,21 +342,31 @@ acc0: clock-controller at 2088000 { compatible = "qcom,kpss-acc-v1"; reg = <0x02088000 0x1000>, <0x02008000 0x1000>; + clock-output-names = "acpu0_aux"; }; acc1: clock-controller at 2098000 { compatible = "qcom,kpss-acc-v1"; reg = <0x02098000 0x1000>, <0x02008000 0x1000>; + clock-output-names = "acpu1_aux"; }; acc2: clock-controller at 20a8000 { compatible = "qcom,kpss-acc-v1"; reg = <0x020a8000 0x1000>, <0x02008000 0x1000>; + clock-output-names = "acpu2_aux"; }; acc3: clock-controller at 20b8000 { compatible = "qcom,kpss-acc-v1"; reg = <0x020b8000 0x1000>, <0x02008000 0x1000>; + clock-output-names = "acpu3_aux"; + }; + + l2cc: clock-controller at 2011000 { + compatible = "qcom,kpss-gcc"; + reg = <0x2011000 0x1000>; + clock-output-names = "acpu_l2_aux"; }; saw0: regulator at 2089000 {
arch/arm/boot/dts/qcom-msm8960.dtsi +49 -0
78 lines not on this page · raw message
arch/arm/boot/dts/qcom-msm8974.dtsi +307 -4
359 lines not on this page · raw message
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Hi!
Quoted 25 lines · Stephen Boyd
These patches provide cpufreq scaling on devices with Krait CPUs. In Krait CPU designs there's one PLL and two muxes per CPU, allowing us to switch CPU frequencies independently.
secondary +-----+ + | QSB |-------+------------|\ +-----+ | | |-+ | +-------|/ | | | + | +-----+ | | | | PLL |----+-------+ | primary +-----+ | | | + | | +-----|\ +------+ +-------+ | | | \ | | | HFPLL |----------+-----------------| |-----| CPU0 | +-------+ | | | | | | | | | | +-----+ | / +------+ | | +-| / 2 |---------|/ | | +-----+ + | | secondary | | + | +------------|\ | | |-+ +---------------|/ | primary
Quoted 8 lines
+ | + +-----|\ +------+ +-------+ v | \ | | | HFPLL |----------------------------| |-----| CPU1 | +-------+ | | | | | | +-----+ | / +------+ +-| / 2 |---------|/ +-----+ +
Nice ascii art :-). There should be "+" at place marked by "v" :-).
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Quoted 25 lines · Stephen Boyd
These patches provide cpufreq scaling on devices with Krait CPUs. In Krait CPU designs there's one PLL and two muxes per CPU, allowing us to switch CPU frequencies independently.
secondary +-----+ + | QSB |-------+------------|\ +-----+ | | |-+ | +-------|/ | | | + | +-----+ | | | | PLL |----+-------+ | primary +-----+ | | | + | | +-----|\ +------+ +-------+ | | | \ | | | HFPLL |----------+-----------------| |-----| CPU0 | +-------+ | | | | | | | | | | +-----+ | / +------+ | | +-| / 2 |---------|/ | | +-----+ + | | secondary | | + | +------------|\ | | |-+ +---------------|/ | primary
Quoted 8 lines
+ | + +-----|\ +------+ +-------+ | \ | | | HFPLL |----------------------------| |-----| CPU1 | +-------+ | | | | | | +-----+ | / +------+ +-| / 2 |---------|/ +-----+ +
And actually this picture should go to Documentation/ somewhere...
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html