[PATCH V6 8/9] clk: imx: implement new clk_hw based APIs
Clock providers are recommended to use the new struct clk_hw based API, so implement IMX clk_hw based provider helpers functions to the new approach. Signed-off-by: Dong Aisheng --- ChangeLog: v2->v4: * no changes v1->v2: new patches --- drivers/clk/imx/clk.c | 22 ++ drivers/clk/imx/clk.h | 62 +++ 2 files changed, 84 insertions(+) diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c index 9074e69..1efed86 100644 --- a/drivers/clk/imx/clk.c +++ b/drivers/clk/imx/clk.c @@ -18,6 +18,16 @@ void __init imx_check_clocks(struct clk *clks[], unsigned int count) i, PTR_ERR(clks[i])); } +void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + if (IS_ERR(clks[i])) + pr_err("i.MX clk %u: register failed with %ld\n", + i, PTR_ERR(clks[i])); +} + static struct clk * __init imx_obtain_fixed_clock_from_dt(const char *name) { struct of_phandle_args phandle; @@ -49,6 +59,18 @@ struct clk * __init imx_obtain_fixed_clock( return clk; } +struct clk_hw * __init imx_obtain_fixed_clk_hw(struct device_node *np, + const char *name) +{ + struct clk *clk; + + clk = of_clk_get_by_name(np, name); + if (IS_ERR(clk)) + return ERR_PTR(-ENOENT); + + return __clk_get_hw(clk); +} + /* * This fixups the register CCM_CSCMR1 write value. * The write/read/divider values of the aclk_podf field diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 3886979..cf0596d 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -8,6 +8,7 @@ extern spinlock_t imx_ccm_lock; void imx_check_clocks(struct clk *clks[], unsigned int count); +void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count); void imx_register_uart_clocks(struct clk ** const clks[]); extern void imx_cscmr1_fixup(u32 *val); @@ -54,6 +55,9 @@ struct clk *clk_register_gate2(struct device *dev, const char *name, struct clk * imx_obtain_fixed_clock( const char *name, unsigned long rate); +struct clk_hw *imx_obtain_fixed_clk_hw(struct device_node *np, + const char *name); + struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, void __iomem *reg, u8 shift, u32 exclusive_mask); @@ -90,6 +94,16 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) return clk_register_fixed_rate(NULL, name, NULL, 0, rate); } +static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate) +{ + return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); +} + +static inline struct clk_hw *imx_get_clk_hw_fixed(const char *name, int rate) +{ + return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); +} + static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, u8 shift, u8 width, const char * const *parents, int num_parents) @@ -113,6 +127,15 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent, reg, shift, width, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_divider(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width) +{ + return clk_hw_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT, + reg, shift, width, 0, _ccm_lock); +} + static inline struct clk *imx_clk_divider_flags(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width, unsigned long flags) @@ -121,6 +144,15 @@ static inline struct clk *imx_clk_divider_flags(const char *name, reg, shift, width, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width, unsigned long flags) +{ + return clk_hw_register_divider(NULL, name, parent, flags, + reg, shift, width, 0, _ccm_lock); +} + static inline struct clk *imx_clk_divider2(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width) { @@ -143,6 +175,13 @@ static inline struct clk *imx_clk_gate_flags(const char *name, const char *paren shift, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_gate(const char *name, const char *parent, +void
[PATCH V6 8/9] clk: imx: implement new clk_hw based APIs
Clock providers are recommended to use the new struct clk_hw based API, so implement IMX clk_hw based provider helpers functions to the new approach. Signed-off-by: Dong Aisheng --- ChangeLog: v2->v4: * no changes v1->v2: new patches --- drivers/clk/imx/clk.c | 22 ++ drivers/clk/imx/clk.h | 62 +++ 2 files changed, 84 insertions(+) diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c index 9074e69..1efed86 100644 --- a/drivers/clk/imx/clk.c +++ b/drivers/clk/imx/clk.c @@ -18,6 +18,16 @@ void __init imx_check_clocks(struct clk *clks[], unsigned int count) i, PTR_ERR(clks[i])); } +void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + if (IS_ERR(clks[i])) + pr_err("i.MX clk %u: register failed with %ld\n", + i, PTR_ERR(clks[i])); +} + static struct clk * __init imx_obtain_fixed_clock_from_dt(const char *name) { struct of_phandle_args phandle; @@ -49,6 +59,18 @@ struct clk * __init imx_obtain_fixed_clock( return clk; } +struct clk_hw * __init imx_obtain_fixed_clk_hw(struct device_node *np, + const char *name) +{ + struct clk *clk; + + clk = of_clk_get_by_name(np, name); + if (IS_ERR(clk)) + return ERR_PTR(-ENOENT); + + return __clk_get_hw(clk); +} + /* * This fixups the register CCM_CSCMR1 write value. * The write/read/divider values of the aclk_podf field diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 3886979..cf0596d 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -8,6 +8,7 @@ extern spinlock_t imx_ccm_lock; void imx_check_clocks(struct clk *clks[], unsigned int count); +void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count); void imx_register_uart_clocks(struct clk ** const clks[]); extern void imx_cscmr1_fixup(u32 *val); @@ -54,6 +55,9 @@ struct clk *clk_register_gate2(struct device *dev, const char *name, struct clk * imx_obtain_fixed_clock( const char *name, unsigned long rate); +struct clk_hw *imx_obtain_fixed_clk_hw(struct device_node *np, + const char *name); + struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, void __iomem *reg, u8 shift, u32 exclusive_mask); @@ -90,6 +94,16 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) return clk_register_fixed_rate(NULL, name, NULL, 0, rate); } +static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate) +{ + return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); +} + +static inline struct clk_hw *imx_get_clk_hw_fixed(const char *name, int rate) +{ + return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); +} + static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, u8 shift, u8 width, const char * const *parents, int num_parents) @@ -113,6 +127,15 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent, reg, shift, width, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_divider(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width) +{ + return clk_hw_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT, + reg, shift, width, 0, _ccm_lock); +} + static inline struct clk *imx_clk_divider_flags(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width, unsigned long flags) @@ -121,6 +144,15 @@ static inline struct clk *imx_clk_divider_flags(const char *name, reg, shift, width, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width, unsigned long flags) +{ + return clk_hw_register_divider(NULL, name, parent, flags, + reg, shift, width, 0, _ccm_lock); +} + static inline struct clk *imx_clk_divider2(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width) { @@ -143,6 +175,13 @@ static inline struct clk *imx_clk_gate_flags(const char *name, const char *paren shift, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_gate(const char *name, const char *parent, +void
[PATCH V6 9/9] clk: imx: add imx7ulp clk driver
i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks The clocking scheme provides clear separation between M4 domain and A7 domain. Except for a few clock sources shared between two domains, such as the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and clock management are separated and contained within each domain. M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. This driver only adds clock support in A7 domain. Note that most clocks required to be operated when gated, e.g. pll, pfd, pcc. And more special cases that scs/ddr/nic mux selecting different clock source requires that clock to be enabled first, then we need set CLK_OPS_PARENT_ENABLE flag for them properly. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v5->v6: * sosc/firc/dpll/ddr clock should use divider table as they're not 1:1 v4->v5: * clk-composite API name changed accordingly v3->v4: * update after changing scg and pcc into separete nodes according to Rob's suggestion v2->v3: * no changes v1->v2: * use of_clk_add_hw_provider instead * split the clocks register process into two parts: early part for possible timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for the left normal peripheral clocks registered by a platform driver. --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx7ulp.c | 220 ++ 2 files changed, 221 insertions(+) create mode 100644 drivers/clk/imx/clk-imx7ulp.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index a5cab3e..615b413 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -30,4 +30,5 @@ obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o +obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c new file mode 100644 index 000..3b7507f --- /dev/null +++ b/drivers/clk/imx/clk-imx7ulp.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static const char * const pll_pre_sels[] = { "sosc", "firc", }; +static const char * const spll_pfd_sels[] = { "spll_pfd0", "spll_pfd1", "spll_pfd2", "spll_pfd3", }; +static const char * const spll_sels[] = { "spll", "spll_pfd_sel", }; +static const char * const apll_pfd_sels[] = { "apll_pfd0", "apll_pfd1", "apll_pfd2", "apll_pfd3", }; +static const char * const apll_sels[] = { "apll", "apll_pfd_sel", }; +static const char * const scs_sels[] = { "dummy", "sosc", "sirc", "firc", "dummy", "apll_sel", "spll_sel", "upll", }; +static const char * const ddr_sels[] = { "apll_pfd_sel", "upll", }; +static const char * const nic_sels[] = { "firc", "ddr_clk", }; +static const char * const periph_plat_sels[] = { "dummy", "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", }; +static const char * const periph_bus_sels[]= { "dummy", "sosc_bus_clk", "mpll", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", }; + +/* used by sosc/sirc/firc/ddr/spll/apll dividers */ +static const struct clk_div_table ulp_div_table[] = { + { .val = 1, .div = 1, }, + { .val = 2, .div = 2, }, + { .val = 3, .div = 4, }, + { .val = 4, .div = 8, }, + { .val = 5, .div = 16, }, + { .val = 6, .div = 32, }, + { .val = 7, .div = 64, }, +}; + +static void __init imx7ulp_clk_scg1_init(struct device_node *np) +{ + struct clk_hw_onecell_data *clk_data; + struct clk_hw **clks; + void __iomem *base; + + clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) * + IMX7ULP_CLK_SCG1_END, GFP_KERNEL); + if (!clk_data) + return; + + clk_data->num = IMX7ULP_CLK_SCG1_END; + clks = clk_data->hws; + + clks[IMX7ULP_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0); + + clks[IMX7ULP_CLK_ROSC] = imx_obtain_fixed_clk_hw(np, "rosc"); + clks[IMX7ULP_CLK_SOSC] = imx_obtain_fixed_clk_hw(np, "sosc"); + clks[IMX7ULP_CLK_SIRC] = imx_obtain_fixed_clk_hw(np, "sirc"); + clks[IMX7ULP_CLK_FIRC] = imx_obtain_fixed_clk_hw(np, "firc"); + clks[IMX7ULP_CLK_MIPI_PLL] = imx_obtain_fixed_clk_hw(np, "mpll"); +
[PATCH V6 6/9] dt-bindings: clock: add imx7ulp clock binding doc
i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks Note IMX7ULP has two clock domains: M4 and A7. This binding doc is only for A7 clock domain. Cc: Rob Herring Cc: Mark Rutland Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v4->v5: * fix a typo that clock-name -> clock-names * one compatible string per line * add input clocks for pcc2/3 v3->v4: * make scg, pcc separate nodes according to Rob's suggestion v2->v3: * no changes v1->v2: no changes --- .../devicetree/bindings/clock/imx7ulp-clock.txt| 104 include/dt-bindings/clock/imx7ulp-clock.h | 109 + 2 files changed, 213 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt new file mode 100644 index 000..a4f8cd4 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt @@ -0,0 +1,104 @@ +* Clock bindings for Freescale i.MX7ULP + +i.MX7ULP Clock functions are under joint control of the System +Clock Generation (SCG) modules, Peripheral Clock Control (PCC) +modules, and Core Mode Controller (CMC)1 blocks + +The clocking scheme provides clear separation between M4 domain +and A7 domain. Except for a few clock sources shared between two +domains, such as the System Oscillator clock, the Slow IRC (SIRC), +and and the Fast IRC clock (FIRCLK), clock sources and clock +management are separated and contained within each domain. + +M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. +A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. + +Note: this binding doc is only for A7 clock domain. + +System Clock Generation (SCG) modules: +- +The System Clock Generation (SCG) is responsible for clock generation +and distribution across this device. Functions performed by the SCG +include: clock reference selection, generation of clock used to derive +processor, system, peripheral bus and external memory interface clocks, +source selection for peripheral clocks and control of power saving +clock gating mode. + +Required properties: + +- compatible: Should be "fsl,imx7ulp-scg1". +- reg :Should contain registers location and length. +- #clock-cells:Should be <1>. +- clocks: Should contain the fixed input clocks. +- clock-names: Should contain the following clock names: + "rosc", "sosc", "sirc", "firc", "upll", "mpll". + +Peripheral Clock Control (PCC) modules: +- +The Peripheral Clock Control (PCC) is responsible for clock selection, +optional division and clock gating mode for peripherals in their +respected power domain + +Required properties: +- compatible: Should be one of: + "fsl,imx7ulp-pcc2", + "fsl,imx7ulp-pcc3". +- reg :Should contain registers location and length. +- #clock-cells:Should be <1>. +- clocks: Should contain the fixed input clocks. +- clock-names: Should contain the following clock names: + "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", + "apll_pfd1", "apll_pfd0", "upll", "sosc_bus_clk", + "mpll", "firc_bus_clk", "rosc", "spll_bus_clk"; + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. +See include/dt-bindings/clock/imx7ulp-clock.h +for the full list of i.MX7ULP clock IDs of each module. + +Examples: + +#include + +scg1: scg1@403e { + compatible = "fsl,imx7ulp-scg1; + reg = <0x403e 0x1>; + clocks = <>, <>, <>, +<>, <>, <>; + clock-names = "rosc", "sosc", "sirc", + "firc", "upll", "mpll"; + #clock-cells = <1>; +}; + +pcc2: pcc2@403f { + compatible = "fsl,imx7ulp-pcc2"; + reg = <0x403f 0x1>; + #clock-cells = <1>; + clocks = < IMX7ULP_CLK_NIC1_BUS_DIV>, +< IMX7ULP_CLK_NIC1_DIV>, +< IMX7ULP_CLK_DDR_DIV>, +< IMX7ULP_CLK_APLL_PFD2>, +< IMX7ULP_CLK_APLL_PFD1>, +< IMX7ULP_CLK_APLL_PFD0>, +< IMX7ULP_CLK_UPLL>, +< IMX7ULP_CLK_SOSC_BUS_CLK>, +< IMX7ULP_CLK_MIPI_PLL>, +< IMX7ULP_CLK_FIRC_BUS_CLK>, +< IMX7ULP_CLK_ROSC>, +< IMX7ULP_CLK_SPLL_BUS_CLK>; + clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk", + "apll_pfd2", "apll_pfd1", "apll_pfd0", + "upll",
[PATCH V6 9/9] clk: imx: add imx7ulp clk driver
i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks The clocking scheme provides clear separation between M4 domain and A7 domain. Except for a few clock sources shared between two domains, such as the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and clock management are separated and contained within each domain. M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. This driver only adds clock support in A7 domain. Note that most clocks required to be operated when gated, e.g. pll, pfd, pcc. And more special cases that scs/ddr/nic mux selecting different clock source requires that clock to be enabled first, then we need set CLK_OPS_PARENT_ENABLE flag for them properly. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v5->v6: * sosc/firc/dpll/ddr clock should use divider table as they're not 1:1 v4->v5: * clk-composite API name changed accordingly v3->v4: * update after changing scg and pcc into separete nodes according to Rob's suggestion v2->v3: * no changes v1->v2: * use of_clk_add_hw_provider instead * split the clocks register process into two parts: early part for possible timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for the left normal peripheral clocks registered by a platform driver. --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx7ulp.c | 220 ++ 2 files changed, 221 insertions(+) create mode 100644 drivers/clk/imx/clk-imx7ulp.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index a5cab3e..615b413 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -30,4 +30,5 @@ obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o +obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c new file mode 100644 index 000..3b7507f --- /dev/null +++ b/drivers/clk/imx/clk-imx7ulp.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static const char * const pll_pre_sels[] = { "sosc", "firc", }; +static const char * const spll_pfd_sels[] = { "spll_pfd0", "spll_pfd1", "spll_pfd2", "spll_pfd3", }; +static const char * const spll_sels[] = { "spll", "spll_pfd_sel", }; +static const char * const apll_pfd_sels[] = { "apll_pfd0", "apll_pfd1", "apll_pfd2", "apll_pfd3", }; +static const char * const apll_sels[] = { "apll", "apll_pfd_sel", }; +static const char * const scs_sels[] = { "dummy", "sosc", "sirc", "firc", "dummy", "apll_sel", "spll_sel", "upll", }; +static const char * const ddr_sels[] = { "apll_pfd_sel", "upll", }; +static const char * const nic_sels[] = { "firc", "ddr_clk", }; +static const char * const periph_plat_sels[] = { "dummy", "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", }; +static const char * const periph_bus_sels[]= { "dummy", "sosc_bus_clk", "mpll", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", }; + +/* used by sosc/sirc/firc/ddr/spll/apll dividers */ +static const struct clk_div_table ulp_div_table[] = { + { .val = 1, .div = 1, }, + { .val = 2, .div = 2, }, + { .val = 3, .div = 4, }, + { .val = 4, .div = 8, }, + { .val = 5, .div = 16, }, + { .val = 6, .div = 32, }, + { .val = 7, .div = 64, }, +}; + +static void __init imx7ulp_clk_scg1_init(struct device_node *np) +{ + struct clk_hw_onecell_data *clk_data; + struct clk_hw **clks; + void __iomem *base; + + clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) * + IMX7ULP_CLK_SCG1_END, GFP_KERNEL); + if (!clk_data) + return; + + clk_data->num = IMX7ULP_CLK_SCG1_END; + clks = clk_data->hws; + + clks[IMX7ULP_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0); + + clks[IMX7ULP_CLK_ROSC] = imx_obtain_fixed_clk_hw(np, "rosc"); + clks[IMX7ULP_CLK_SOSC] = imx_obtain_fixed_clk_hw(np, "sosc"); + clks[IMX7ULP_CLK_SIRC] = imx_obtain_fixed_clk_hw(np, "sirc"); + clks[IMX7ULP_CLK_FIRC] = imx_obtain_fixed_clk_hw(np, "firc"); + clks[IMX7ULP_CLK_MIPI_PLL] = imx_obtain_fixed_clk_hw(np, "mpll"); +
[PATCH V6 6/9] dt-bindings: clock: add imx7ulp clock binding doc
i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks Note IMX7ULP has two clock domains: M4 and A7. This binding doc is only for A7 clock domain. Cc: Rob Herring Cc: Mark Rutland Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v4->v5: * fix a typo that clock-name -> clock-names * one compatible string per line * add input clocks for pcc2/3 v3->v4: * make scg, pcc separate nodes according to Rob's suggestion v2->v3: * no changes v1->v2: no changes --- .../devicetree/bindings/clock/imx7ulp-clock.txt| 104 include/dt-bindings/clock/imx7ulp-clock.h | 109 + 2 files changed, 213 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt new file mode 100644 index 000..a4f8cd4 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt @@ -0,0 +1,104 @@ +* Clock bindings for Freescale i.MX7ULP + +i.MX7ULP Clock functions are under joint control of the System +Clock Generation (SCG) modules, Peripheral Clock Control (PCC) +modules, and Core Mode Controller (CMC)1 blocks + +The clocking scheme provides clear separation between M4 domain +and A7 domain. Except for a few clock sources shared between two +domains, such as the System Oscillator clock, the Slow IRC (SIRC), +and and the Fast IRC clock (FIRCLK), clock sources and clock +management are separated and contained within each domain. + +M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. +A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. + +Note: this binding doc is only for A7 clock domain. + +System Clock Generation (SCG) modules: +- +The System Clock Generation (SCG) is responsible for clock generation +and distribution across this device. Functions performed by the SCG +include: clock reference selection, generation of clock used to derive +processor, system, peripheral bus and external memory interface clocks, +source selection for peripheral clocks and control of power saving +clock gating mode. + +Required properties: + +- compatible: Should be "fsl,imx7ulp-scg1". +- reg :Should contain registers location and length. +- #clock-cells:Should be <1>. +- clocks: Should contain the fixed input clocks. +- clock-names: Should contain the following clock names: + "rosc", "sosc", "sirc", "firc", "upll", "mpll". + +Peripheral Clock Control (PCC) modules: +- +The Peripheral Clock Control (PCC) is responsible for clock selection, +optional division and clock gating mode for peripherals in their +respected power domain + +Required properties: +- compatible: Should be one of: + "fsl,imx7ulp-pcc2", + "fsl,imx7ulp-pcc3". +- reg :Should contain registers location and length. +- #clock-cells:Should be <1>. +- clocks: Should contain the fixed input clocks. +- clock-names: Should contain the following clock names: + "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", + "apll_pfd1", "apll_pfd0", "upll", "sosc_bus_clk", + "mpll", "firc_bus_clk", "rosc", "spll_bus_clk"; + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. +See include/dt-bindings/clock/imx7ulp-clock.h +for the full list of i.MX7ULP clock IDs of each module. + +Examples: + +#include + +scg1: scg1@403e { + compatible = "fsl,imx7ulp-scg1; + reg = <0x403e 0x1>; + clocks = <>, <>, <>, +<>, <>, <>; + clock-names = "rosc", "sosc", "sirc", + "firc", "upll", "mpll"; + #clock-cells = <1>; +}; + +pcc2: pcc2@403f { + compatible = "fsl,imx7ulp-pcc2"; + reg = <0x403f 0x1>; + #clock-cells = <1>; + clocks = < IMX7ULP_CLK_NIC1_BUS_DIV>, +< IMX7ULP_CLK_NIC1_DIV>, +< IMX7ULP_CLK_DDR_DIV>, +< IMX7ULP_CLK_APLL_PFD2>, +< IMX7ULP_CLK_APLL_PFD1>, +< IMX7ULP_CLK_APLL_PFD0>, +< IMX7ULP_CLK_UPLL>, +< IMX7ULP_CLK_SOSC_BUS_CLK>, +< IMX7ULP_CLK_MIPI_PLL>, +< IMX7ULP_CLK_FIRC_BUS_CLK>, +< IMX7ULP_CLK_ROSC>, +< IMX7ULP_CLK_SPLL_BUS_CLK>; + clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk", + "apll_pfd2", "apll_pfd1", "apll_pfd0", + "upll",
[PATCH V6 3/9] clk: imx: add pllv4 support
pllv4 is designed for System Clock Generation (SCG) module observed in IMX ULP SoC series. e.g. i.MX7ULP. The SCG modules generates clock used to derive processor, system, peripheral bus and external memory interface clocks while this patch intends to support the PLL part. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * remove clk_pllv4_is_enabled() check in set_rate, instead it will be handled by core later. * use readl_poll_timeout * use clk_hw_register instead of clk_register * other minor changes --- drivers/clk/imx/Makefile| 1 + drivers/clk/imx/clk-pllv4.c | 182 drivers/clk/imx/clk.h | 3 + 3 files changed, 186 insertions(+) create mode 100644 drivers/clk/imx/clk-pllv4.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 077e732..4cac28b 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,6 +12,7 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ + clk-pllv4.o \ clk-pfd.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c new file mode 100644 index 000..67c64c7 --- /dev/null +++ b/drivers/clk/imx/clk-pllv4.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include + +/* PLL Control Status Register (xPLLCSR) */ +#define PLL_CSR_OFFSET 0x0 +#define PLL_VLDBIT(24) +#define PLL_EN BIT(0) + +/* PLL Configuration Register (xPLLCFG) */ +#define PLL_CFG_OFFSET 0x08 +#define BP_PLL_MULT16 +#define BM_PLL_MULT(0x7f << 16) + +/* PLL Numerator Register (xPLLNUM) */ +#define PLL_NUM_OFFSET 0x10 + +/* PLL Denominator Register (xPLLDENOM) */ +#define PLL_DENOM_OFFSET 0x14 + +struct clk_pllv4 { + struct clk_hw hw; + void __iomem*base; +}; + +/* Valid PLL MULT Table */ +static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16}; + +#define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw) + +#define LOCK_TIMEOUT_USUSEC_PER_MSEC + +static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll) +{ + u32 csr; + + return readl_poll_timeout(pll->base + PLL_CSR_OFFSET, + csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US); +} + +static int clk_pllv4_is_enabled(struct clk_hw *hw) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + if (readl_relaxed(pll->base) & PLL_EN) + return 1; + + return 0; +} + +static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + u32 div; + + div = readl_relaxed(pll->base + PLL_CFG_OFFSET); + div &= BM_PLL_MULT; + div >>= BP_PLL_MULT; + + return parent_rate * div; +} + +static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate, +unsigned long *prate) +{ + unsigned long parent_rate = *prate; + unsigned long round_rate, i; + + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + round_rate = parent_rate * pllv4_mult_table[i]; + if (rate >= round_rate) + return round_rate; + } + + return round_rate; +} + +static bool clk_pllv4_is_valid_mult(unsigned int mult) +{ + int i; + + /* check if mult is in valid MULT table */ + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + if (pllv4_mult_table[i] == mult) + return true; + } + + return false; +} + +static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + u32 val, mult; + + mult = rate / parent_rate; + + if (!clk_pllv4_is_valid_mult(mult)) + return -EINVAL; + + val = readl_relaxed(pll->base + PLL_CFG_OFFSET); + val &= ~BM_PLL_MULT; + val |= mult << BP_PLL_MULT; + writel_relaxed(val, pll->base + PLL_CFG_OFFSET); + + return 0; +} + +static int clk_pllv4_enable(struct clk_hw *hw) +{ + u32 val; + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + val = readl_relaxed(pll->base); + val |= PLL_EN; + writel_relaxed(val, pll->base); + + return clk_pllv4_wait_lock(pll); +} + +static void clk_pllv4_disable(struct clk_hw *hw) +{ + u32 val; + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + val = readl_relaxed(pll->base); + val &= ~PLL_EN; +
[PATCH V6 4/9] clk: imx: add pfdv2 support
The pfdv2 is designed for PLL Fractional Divide (PFD) observed in System Clock Generation (SCG) module in IMX ULP SoC series. e.g. i.MX7ULP. NOTE pfdv2 can only be operated when clk is gated. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * change to readl_poll_timeout * add pfd lock to protect share reg access between rate and enable/disable operations and multiple pfd instances. * use clk_hw_register --- drivers/clk/imx/Makefile| 3 +- drivers/clk/imx/clk-pfdv2.c | 201 drivers/clk/imx/clk.h | 3 + 3 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-pfdv2.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4cac28b..e7248de 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -13,7 +13,8 @@ obj-y += \ clk-pllv2.o \ clk-pllv3.o \ clk-pllv4.o \ - clk-pfd.o + clk-pfd.o \ + clk-pfdv2.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c new file mode 100644 index 000..afb2904 --- /dev/null +++ b/drivers/clk/imx/clk-pfdv2.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include + +/** + * struct clk_pfdv2 - IMX PFD clock + * @clk_hw:clock source + * @reg: PFD register address + * @gate_bit: Gate bit offset + * @vld_bit: Valid bit offset + * @frac_off: PLL Fractional Divider offset + */ + +struct clk_pfdv2 { + struct clk_hw hw; + void __iomem*reg; + u8 gate_bit; + u8 vld_bit; + u8 frac_off; +}; + +#define to_clk_pfdv2(_hw) container_of(_hw, struct clk_pfdv2, hw) + +#define CLK_PFDV2_FRAC_MASK 0x3f + +#define LOCK_TIMEOUT_USUSEC_PER_MSEC + +static DEFINE_SPINLOCK(pfd_lock); + +static int clk_pfdv2_wait(struct clk_pfdv2 *pfd) +{ + u32 val; + + return readl_poll_timeout(pfd->reg, val, val & pfd->vld_bit, + 0, LOCK_TIMEOUT_US); +} + +static int clk_pfdv2_enable(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val &= ~pfd->gate_bit; + writel_relaxed(val, pfd->reg); + spin_unlock_irqrestore(_lock, flags); + + return clk_pfdv2_wait(pfd); +} + +static void clk_pfdv2_disable(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val |= pfd->gate_bit; + writel_relaxed(val, pfd->reg); + spin_unlock_irqrestore(_lock, flags); +} + +static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + u64 tmp = parent_rate; + u8 frac; + + frac = (readl_relaxed(pfd->reg) >> pfd->frac_off) + & CLK_PFDV2_FRAC_MASK; + + if (!frac) { + pr_debug("clk_pfdv2: %s invalid pfd frac value 0\n", +clk_hw_get_name(hw)); + return 0; + } + + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static long clk_pfdv2_round_rate(struct clk_hw *hw, unsigned long rate, +unsigned long *prate) +{ + u64 tmp = *prate; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + tmp = *prate; + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static int clk_pfdv2_is_enabled(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + + if (readl_relaxed(pfd->reg) & pfd->gate_bit) + return 0; + + return 1; +} + +static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u64 tmp = parent_rate; + u32 val; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val &= ~(CLK_PFDV2_FRAC_MASK <<
[PATCH V6 5/9] clk: imx: add imx7ulp composite clk support
The imx composite clk is designed for Peripheral Clock Control (PCC) module observed in IMX ULP SoC series. NOTE pcc can only be operated when clk is gated. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v4->v5: * rename to clk-composite-7ulp.c as we have another clk-composite-8m.c, function name also changed accordingly v3->v4: * no changes v2->v3: * no changes v1->v2: * remove an unneeded blank line change * use clk_hw_register --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-composite-7ulp.c | 85 drivers/clk/imx/clk.h| 6 +++ 3 files changed, 92 insertions(+) create mode 100644 drivers/clk/imx/clk-composite-7ulp.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index e7248de..a5cab3e 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -4,6 +4,7 @@ obj-y += \ clk.o \ clk-busy.o \ clk-cpu.o \ + clk-composite-7ulp.o \ clk-divider-gate.o \ clk-fixup-div.o \ clk-fixup-mux.o \ diff --git a/drivers/clk/imx/clk-composite-7ulp.c b/drivers/clk/imx/clk-composite-7ulp.c new file mode 100644 index 000..22f679c --- /dev/null +++ b/drivers/clk/imx/clk-composite-7ulp.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + */ + +#include +#include +#include + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 +#define PCG_CGC_SHIFT 30 +#define PCG_FRAC_SHIFT 3 +#define PCG_FRAC_WIDTH 1 +#define PCG_FRAC_MASK BIT(3) +#define PCG_PCD_SHIFT 0 +#define PCG_PCD_WIDTH 3 +#define PCG_PCD_MASK 0x7 + +struct clk_hw *imx7ulp_clk_composite(const char *name, +const char * const *parent_names, +int num_parents, bool mux_present, +bool rate_present, bool gate_present, +void __iomem *reg) +{ + struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL; + struct clk_fractional_divider *fd = NULL; + struct clk_gate *gate = NULL; + struct clk_mux *mux = NULL; + struct clk_hw *hw; + + if (mux_present) { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + mux_hw = >hw; + mux->reg = reg; + mux->shift = PCG_PCS_SHIFT; + mux->mask = PCG_PCS_MASK; + } + + if (rate_present) { + fd = kzalloc(sizeof(*fd), GFP_KERNEL); + if (!fd) { + kfree(mux); + return ERR_PTR(-ENOMEM); + } + fd_hw = >hw; + fd->reg = reg; + fd->mshift = PCG_FRAC_SHIFT; + fd->mwidth = PCG_FRAC_WIDTH; + fd->mmask = PCG_FRAC_MASK; + fd->nshift = PCG_PCD_SHIFT; + fd->nwidth = PCG_PCD_WIDTH; + fd->nmask = PCG_PCD_MASK; + fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED; + } + + if (gate_present) { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + kfree(mux); + kfree(fd); + return ERR_PTR(-ENOMEM); + } + gate_hw = >hw; + gate->reg = reg; + gate->bit_idx = PCG_CGC_SHIFT; + } + + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux_hw, _mux_ops, fd_hw, + _fractional_divider_ops, gate_hw, + _gate_ops, CLK_SET_RATE_GATE | + CLK_SET_PARENT_GATE); + if (IS_ERR(hw)) { + kfree(mux); + kfree(fd); + kfree(gate); + } + + return hw; +} diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index ebeb754..2e3bcfa 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -71,6 +71,12 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, const char **parent_names, int num_parents); +struct clk_hw *imx7ulp_clk_composite(const char *name, +const char * const *parent_names, +int num_parents, bool mux_present, +bool rate_present, bool gate_present, +void __iomem *reg); + struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width,
[PATCH V6 3/9] clk: imx: add pllv4 support
pllv4 is designed for System Clock Generation (SCG) module observed in IMX ULP SoC series. e.g. i.MX7ULP. The SCG modules generates clock used to derive processor, system, peripheral bus and external memory interface clocks while this patch intends to support the PLL part. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * remove clk_pllv4_is_enabled() check in set_rate, instead it will be handled by core later. * use readl_poll_timeout * use clk_hw_register instead of clk_register * other minor changes --- drivers/clk/imx/Makefile| 1 + drivers/clk/imx/clk-pllv4.c | 182 drivers/clk/imx/clk.h | 3 + 3 files changed, 186 insertions(+) create mode 100644 drivers/clk/imx/clk-pllv4.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 077e732..4cac28b 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,6 +12,7 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ + clk-pllv4.o \ clk-pfd.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c new file mode 100644 index 000..67c64c7 --- /dev/null +++ b/drivers/clk/imx/clk-pllv4.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include + +/* PLL Control Status Register (xPLLCSR) */ +#define PLL_CSR_OFFSET 0x0 +#define PLL_VLDBIT(24) +#define PLL_EN BIT(0) + +/* PLL Configuration Register (xPLLCFG) */ +#define PLL_CFG_OFFSET 0x08 +#define BP_PLL_MULT16 +#define BM_PLL_MULT(0x7f << 16) + +/* PLL Numerator Register (xPLLNUM) */ +#define PLL_NUM_OFFSET 0x10 + +/* PLL Denominator Register (xPLLDENOM) */ +#define PLL_DENOM_OFFSET 0x14 + +struct clk_pllv4 { + struct clk_hw hw; + void __iomem*base; +}; + +/* Valid PLL MULT Table */ +static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16}; + +#define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw) + +#define LOCK_TIMEOUT_USUSEC_PER_MSEC + +static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll) +{ + u32 csr; + + return readl_poll_timeout(pll->base + PLL_CSR_OFFSET, + csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US); +} + +static int clk_pllv4_is_enabled(struct clk_hw *hw) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + if (readl_relaxed(pll->base) & PLL_EN) + return 1; + + return 0; +} + +static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + u32 div; + + div = readl_relaxed(pll->base + PLL_CFG_OFFSET); + div &= BM_PLL_MULT; + div >>= BP_PLL_MULT; + + return parent_rate * div; +} + +static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate, +unsigned long *prate) +{ + unsigned long parent_rate = *prate; + unsigned long round_rate, i; + + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + round_rate = parent_rate * pllv4_mult_table[i]; + if (rate >= round_rate) + return round_rate; + } + + return round_rate; +} + +static bool clk_pllv4_is_valid_mult(unsigned int mult) +{ + int i; + + /* check if mult is in valid MULT table */ + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + if (pllv4_mult_table[i] == mult) + return true; + } + + return false; +} + +static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + u32 val, mult; + + mult = rate / parent_rate; + + if (!clk_pllv4_is_valid_mult(mult)) + return -EINVAL; + + val = readl_relaxed(pll->base + PLL_CFG_OFFSET); + val &= ~BM_PLL_MULT; + val |= mult << BP_PLL_MULT; + writel_relaxed(val, pll->base + PLL_CFG_OFFSET); + + return 0; +} + +static int clk_pllv4_enable(struct clk_hw *hw) +{ + u32 val; + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + val = readl_relaxed(pll->base); + val |= PLL_EN; + writel_relaxed(val, pll->base); + + return clk_pllv4_wait_lock(pll); +} + +static void clk_pllv4_disable(struct clk_hw *hw) +{ + u32 val; + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + val = readl_relaxed(pll->base); + val &= ~PLL_EN; +
[PATCH V6 4/9] clk: imx: add pfdv2 support
The pfdv2 is designed for PLL Fractional Divide (PFD) observed in System Clock Generation (SCG) module in IMX ULP SoC series. e.g. i.MX7ULP. NOTE pfdv2 can only be operated when clk is gated. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * change to readl_poll_timeout * add pfd lock to protect share reg access between rate and enable/disable operations and multiple pfd instances. * use clk_hw_register --- drivers/clk/imx/Makefile| 3 +- drivers/clk/imx/clk-pfdv2.c | 201 drivers/clk/imx/clk.h | 3 + 3 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-pfdv2.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4cac28b..e7248de 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -13,7 +13,8 @@ obj-y += \ clk-pllv2.o \ clk-pllv3.o \ clk-pllv4.o \ - clk-pfd.o + clk-pfd.o \ + clk-pfdv2.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c new file mode 100644 index 000..afb2904 --- /dev/null +++ b/drivers/clk/imx/clk-pfdv2.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include + +/** + * struct clk_pfdv2 - IMX PFD clock + * @clk_hw:clock source + * @reg: PFD register address + * @gate_bit: Gate bit offset + * @vld_bit: Valid bit offset + * @frac_off: PLL Fractional Divider offset + */ + +struct clk_pfdv2 { + struct clk_hw hw; + void __iomem*reg; + u8 gate_bit; + u8 vld_bit; + u8 frac_off; +}; + +#define to_clk_pfdv2(_hw) container_of(_hw, struct clk_pfdv2, hw) + +#define CLK_PFDV2_FRAC_MASK 0x3f + +#define LOCK_TIMEOUT_USUSEC_PER_MSEC + +static DEFINE_SPINLOCK(pfd_lock); + +static int clk_pfdv2_wait(struct clk_pfdv2 *pfd) +{ + u32 val; + + return readl_poll_timeout(pfd->reg, val, val & pfd->vld_bit, + 0, LOCK_TIMEOUT_US); +} + +static int clk_pfdv2_enable(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val &= ~pfd->gate_bit; + writel_relaxed(val, pfd->reg); + spin_unlock_irqrestore(_lock, flags); + + return clk_pfdv2_wait(pfd); +} + +static void clk_pfdv2_disable(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val |= pfd->gate_bit; + writel_relaxed(val, pfd->reg); + spin_unlock_irqrestore(_lock, flags); +} + +static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + u64 tmp = parent_rate; + u8 frac; + + frac = (readl_relaxed(pfd->reg) >> pfd->frac_off) + & CLK_PFDV2_FRAC_MASK; + + if (!frac) { + pr_debug("clk_pfdv2: %s invalid pfd frac value 0\n", +clk_hw_get_name(hw)); + return 0; + } + + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static long clk_pfdv2_round_rate(struct clk_hw *hw, unsigned long rate, +unsigned long *prate) +{ + u64 tmp = *prate; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + tmp = *prate; + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static int clk_pfdv2_is_enabled(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + + if (readl_relaxed(pfd->reg) & pfd->gate_bit) + return 0; + + return 1; +} + +static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u64 tmp = parent_rate; + u32 val; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val &= ~(CLK_PFDV2_FRAC_MASK <<
[PATCH V6 5/9] clk: imx: add imx7ulp composite clk support
The imx composite clk is designed for Peripheral Clock Control (PCC) module observed in IMX ULP SoC series. NOTE pcc can only be operated when clk is gated. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v4->v5: * rename to clk-composite-7ulp.c as we have another clk-composite-8m.c, function name also changed accordingly v3->v4: * no changes v2->v3: * no changes v1->v2: * remove an unneeded blank line change * use clk_hw_register --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-composite-7ulp.c | 85 drivers/clk/imx/clk.h| 6 +++ 3 files changed, 92 insertions(+) create mode 100644 drivers/clk/imx/clk-composite-7ulp.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index e7248de..a5cab3e 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -4,6 +4,7 @@ obj-y += \ clk.o \ clk-busy.o \ clk-cpu.o \ + clk-composite-7ulp.o \ clk-divider-gate.o \ clk-fixup-div.o \ clk-fixup-mux.o \ diff --git a/drivers/clk/imx/clk-composite-7ulp.c b/drivers/clk/imx/clk-composite-7ulp.c new file mode 100644 index 000..22f679c --- /dev/null +++ b/drivers/clk/imx/clk-composite-7ulp.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + */ + +#include +#include +#include + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 +#define PCG_CGC_SHIFT 30 +#define PCG_FRAC_SHIFT 3 +#define PCG_FRAC_WIDTH 1 +#define PCG_FRAC_MASK BIT(3) +#define PCG_PCD_SHIFT 0 +#define PCG_PCD_WIDTH 3 +#define PCG_PCD_MASK 0x7 + +struct clk_hw *imx7ulp_clk_composite(const char *name, +const char * const *parent_names, +int num_parents, bool mux_present, +bool rate_present, bool gate_present, +void __iomem *reg) +{ + struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL; + struct clk_fractional_divider *fd = NULL; + struct clk_gate *gate = NULL; + struct clk_mux *mux = NULL; + struct clk_hw *hw; + + if (mux_present) { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + mux_hw = >hw; + mux->reg = reg; + mux->shift = PCG_PCS_SHIFT; + mux->mask = PCG_PCS_MASK; + } + + if (rate_present) { + fd = kzalloc(sizeof(*fd), GFP_KERNEL); + if (!fd) { + kfree(mux); + return ERR_PTR(-ENOMEM); + } + fd_hw = >hw; + fd->reg = reg; + fd->mshift = PCG_FRAC_SHIFT; + fd->mwidth = PCG_FRAC_WIDTH; + fd->mmask = PCG_FRAC_MASK; + fd->nshift = PCG_PCD_SHIFT; + fd->nwidth = PCG_PCD_WIDTH; + fd->nmask = PCG_PCD_MASK; + fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED; + } + + if (gate_present) { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + kfree(mux); + kfree(fd); + return ERR_PTR(-ENOMEM); + } + gate_hw = >hw; + gate->reg = reg; + gate->bit_idx = PCG_CGC_SHIFT; + } + + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux_hw, _mux_ops, fd_hw, + _fractional_divider_ops, gate_hw, + _gate_ops, CLK_SET_RATE_GATE | + CLK_SET_PARENT_GATE); + if (IS_ERR(hw)) { + kfree(mux); + kfree(fd); + kfree(gate); + } + + return hw; +} diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index ebeb754..2e3bcfa 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -71,6 +71,12 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, const char **parent_names, int num_parents); +struct clk_hw *imx7ulp_clk_composite(const char *name, +const char * const *parent_names, +int num_parents, bool mux_present, +bool rate_present, bool gate_present, +void __iomem *reg); + struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width,
[PATCH V6 0/9] clk: add imx7ulp clk support
This patch series intends to add imx7ulp clk support. i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks The clocking scheme provides clear separation between M4 domain and A7 domain. Except for a few clock sources shared between two domains, such as the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and clock management are separated and contained within each domain. M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. Note: this series only adds A7 clock domain support as M4 clock domain will be handled by M4 seperately. Change Log: v5->v6: * move gatable divider from common divider to imx specfic folder(suggested by Michael) * a small update of PATCH 9 for ddr/firc/dpll/sosc clocks to use divider table v4->v5: * rename to clk-composite-7ulp.c as we have another clk-composite-8m.c, function name also changed accordingly * binding doc updated with adding input clocks for PCC module v3->v4: * update after changing scg and pcc into separete nodes according to Rob's suggestion v2->v3: * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible racy Others no changes. v1->v2: * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers * use clk_hw apis to register clocks * use of_clk_add_hw_provider * split the clocks register process into two parts: early part for possible timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for the left normal peripheral clocks registered by a platform driver. Dong Aisheng (9): clk: imx: add gatable clock divider support clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support clk: imx: add pllv4 support clk: imx: add pfdv2 support clk: imx: add imx7ulp composite clk support dt-bindings: clock: add imx7ulp clock binding doc clk: imx: make mux parent strings const clk: imx: implement new clk_hw based APIs clk: imx: add imx7ulp clk driver .../devicetree/bindings/clock/imx7ulp-clock.txt| 104 ++ drivers/clk/clk-fractional-divider.c | 10 + drivers/clk/imx/Makefile | 7 +- drivers/clk/imx/clk-busy.c | 2 +- drivers/clk/imx/clk-composite-7ulp.c | 85 drivers/clk/imx/clk-divider-gate.c | 219 drivers/clk/imx/clk-fixup-mux.c| 2 +- drivers/clk/imx/clk-imx7ulp.c | 220 + drivers/clk/imx/clk-pfdv2.c| 201 +++ drivers/clk/imx/clk-pllv4.c| 182 + drivers/clk/imx/clk.c | 22 +++ drivers/clk/imx/clk.h | 96 - include/dt-bindings/clock/imx7ulp-clock.h | 109 ++ include/linux/clk-provider.h | 8 + 14 files changed, 1257 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt create mode 100644 drivers/clk/imx/clk-composite-7ulp.c create mode 100644 drivers/clk/imx/clk-divider-gate.c create mode 100644 drivers/clk/imx/clk-imx7ulp.c create mode 100644 drivers/clk/imx/clk-pfdv2.c create mode 100644 drivers/clk/imx/clk-pllv4.c create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h -- 2.7.4
[PATCH V6 1/9] clk: imx: add gatable clock divider support
For dividers with zero indicating clock is disabled, instead of giving a warning each time like "clkx: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set" in exist code, we'd like to introduce enable/disable function for it. e.g. 000b - Clock disabled 001b - Divide by 1 010b - Divide by 2 ... Set rate when the clk is disabled will cache the rate request and only when the clk is enabled will the driver actually program the hardware to have the requested divider value. Similarly, when the clk is disabled we'll write a 0 there, but when the clk is enabled we'll restore whatever rate (divider) was chosen last. It does mean that recalc rate will be sort of odd, because when the clk is off it will return 0, and when the clk is on it will return the right rate. So to make things work, we'll need to return the cached rate in recalc rate when the clk is off and read the hardware when the clk is on. NOTE for the default off divider, the recalc rate will still return 0 as there's still no proper preset rate. Enable such divider will give user a reminder error message. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Signed-off-by: Dong Aisheng --- ChangeLog: v5->v6: * move gatable divider code into imx specific clock folder as suggested by Michael. Patch title also updated accordingly. v4->v5: * no changes v3->v4: * no changes v2->v3: * split normal and gate ops * fix the possible racy v1->v2: * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-divider-gate.c | 219 + drivers/clk/imx/clk.h | 4 + 3 files changed, 224 insertions(+) create mode 100644 drivers/clk/imx/clk-divider-gate.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..077e732 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -4,6 +4,7 @@ obj-y += \ clk.o \ clk-busy.o \ clk-cpu.o \ + clk-divider-gate.o \ clk-fixup-div.o \ clk-fixup-mux.o \ clk-gate-exclusive.o \ diff --git a/drivers/clk/imx/clk-divider-gate.c b/drivers/clk/imx/clk-divider-gate.c new file mode 100644 index 000..b48fba2 --- /dev/null +++ b/drivers/clk/imx/clk-divider-gate.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 NXP. + * Dong Aisheng + */ + +#include +#include +#include +#include + +struct clk_divider_gate { + struct clk_divider divider; + u32 cached_val; +}; + +static inline struct clk_divider_gate *to_clk_divider_gate(struct clk_hw *hw) +{ + struct clk_divider *div = to_clk_divider(hw); + + return container_of(div, struct clk_divider_gate, divider); +} + +static unsigned long clk_divider_gate_recalc_rate_ro(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_divider *div = to_clk_divider(hw); + unsigned int val; + + val = clk_readl(div->reg) >> div->shift; + val &= clk_div_mask(div->width); + if (!val) + return 0; + + return divider_recalc_rate(hw, parent_rate, val, div->table, + div->flags, div->width); +} + +static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider_gate *div_gate = to_clk_divider_gate(hw); + struct clk_divider *div = to_clk_divider(hw); + unsigned long flags = 0; + unsigned int val; + + spin_lock_irqsave(div->lock, flags); + + if (!clk_hw_is_enabled(hw)) { + val = div_gate->cached_val; + } else { + val = clk_readl(div->reg) >> div->shift; + val &= clk_div_mask(div->width); + } + + spin_unlock_irqrestore(div->lock, flags); + + if (!val) + return 0; + + return divider_recalc_rate(hw, parent_rate, val, div->table, + div->flags, div->width); +} + +static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + return clk_divider_ops.round_rate(hw, rate, prate); +} + +static int clk_divider_gate_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider_gate *div_gate = to_clk_divider_gate(hw); + struct clk_divider *div = to_clk_divider(hw); + unsigned long flags = 0; + int value; + u32 val; + + value = divider_get_val(rate, parent_rate, div->table, + div->width, div->flags); + if (value < 0) + return value; + + spin_lock_irqsave(div->lock, flags); + + if (clk_hw_is_enabled(hw)) { + val = clk_readl(div->reg); + val &= ~(clk_div_mask(div->width) << div->shift); +
[PATCH V6 7/9] clk: imx: make mux parent strings const
As the commit 2893c379461a ("clk: make strings in parent name arrays const"), let's make the parent strings const, otherwise we may meet the following warning when compiling: drivers/clk/imx/clk-imx7ulp.c: In function 'imx7ulp_clocks_init': drivers/clk/imx/clk-imx7ulp.c:73:35: warning: passing argument 5 of 'imx_clk_mux_flags' discards 'const' qualifier from pointer target type clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); ^ In file included from drivers/clk/imx/clk-imx7ulp.c:23:0: drivers/clk/imx/clk.h:200:27: note: expected 'const char **' but argument is of type 'const char * const*' ... Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Signed-off-by: Dong Aisheng --- ChangeLog: v1->v4: no changes --- drivers/clk/imx/clk-busy.c | 2 +- drivers/clk/imx/clk-fixup-mux.c | 2 +- drivers/clk/imx/clk.h | 18 +++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/clk/imx/clk-busy.c b/drivers/clk/imx/clk-busy.c index 9903652..e695622 100644 --- a/drivers/clk/imx/clk-busy.c +++ b/drivers/clk/imx/clk-busy.c @@ -154,7 +154,7 @@ static const struct clk_ops clk_busy_mux_ops = { struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, -const char **parent_names, int num_parents) +const char * const *parent_names, int num_parents) { struct clk_busy_mux *busy; struct clk *clk; diff --git a/drivers/clk/imx/clk-fixup-mux.c b/drivers/clk/imx/clk-fixup-mux.c index c9b327e..44817c1 100644 --- a/drivers/clk/imx/clk-fixup-mux.c +++ b/drivers/clk/imx/clk-fixup-mux.c @@ -70,7 +70,7 @@ static const struct clk_ops clk_fixup_mux_ops = { }; struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, + u8 shift, u8 width, const char * const *parents, int num_parents, void (*fixup)(u32 *val)) { struct clk_fixup_mux *fixup_mux; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 2e3bcfa..3886979 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -69,7 +69,7 @@ struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, -const char **parent_names, int num_parents); +const char * const *parent_names, int num_parents); struct clk_hw *imx7ulp_clk_composite(const char *name, const char * const *parent_names, @@ -82,7 +82,7 @@ struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void (*fixup)(u32 *val)); struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, + u8 shift, u8 width, const char * const *parents, int num_parents, void (*fixup)(u32 *val)); static inline struct clk *imx_clk_fixed(const char *name, int rate) @@ -91,7 +91,8 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) } static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg, @@ -204,7 +205,8 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent, } static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT, reg, shift, @@ -212,7 +214,8 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, } static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE, @@ -220,8
[PATCH V6 2/9] clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support
Adding CLK_FRAC_DIVIDER_ZERO_BASED flag to indicate the numerator and denominator value in register are start from 0. This can be used to support frac dividers like below: Divider output clock = Divider input clock x [(frac +1) / (div +1)] where frac/div in register is: 000b - Divide by 1. 001b - Divide by 2. 010b - Divide by 3. Cc: Stephen Boyd Cc: Michael Turquette Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * improve comments suggested by Stephen --- drivers/clk/clk-fractional-divider.c | 10 ++ include/linux/clk-provider.h | 8 2 files changed, 18 insertions(+) diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index fdf625f..7ccde6b 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -40,6 +40,11 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, m = (val & fd->mmask) >> fd->mshift; n = (val & fd->nmask) >> fd->nshift; + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + m++; + n++; + } + if (!n || !m) return parent_rate; @@ -103,6 +108,11 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), , ); + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + m--; + n--; + } + if (fd->lock) spin_lock_irqsave(fd->lock, flags); else diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 08b1aa7..bee6453 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -594,6 +594,12 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw); * @lock: register lock * * Clock with adjustable fractional divider affecting its output frequency. + * + * Flags: + * CLK_FRAC_DIVIDER_ZERO_BASED - by default the numerator and denominator + * is the value read from the register. If CLK_FRAC_DIVIDER_ZERO_BASED + * is set then the numerator and denominator are both the value read + * plus one. */ struct clk_fractional_divider { struct clk_hw hw; @@ -613,6 +619,8 @@ struct clk_fractional_divider { #define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw) +#define CLK_FRAC_DIVIDER_ZERO_BASEDBIT(0) + extern const struct clk_ops clk_fractional_divider_ops; struct clk *clk_register_fractional_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, -- 2.7.4
[PATCH V6 0/9] clk: add imx7ulp clk support
This patch series intends to add imx7ulp clk support. i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks The clocking scheme provides clear separation between M4 domain and A7 domain. Except for a few clock sources shared between two domains, such as the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and clock management are separated and contained within each domain. M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. Note: this series only adds A7 clock domain support as M4 clock domain will be handled by M4 seperately. Change Log: v5->v6: * move gatable divider from common divider to imx specfic folder(suggested by Michael) * a small update of PATCH 9 for ddr/firc/dpll/sosc clocks to use divider table v4->v5: * rename to clk-composite-7ulp.c as we have another clk-composite-8m.c, function name also changed accordingly * binding doc updated with adding input clocks for PCC module v3->v4: * update after changing scg and pcc into separete nodes according to Rob's suggestion v2->v3: * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible racy Others no changes. v1->v2: * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers * use clk_hw apis to register clocks * use of_clk_add_hw_provider * split the clocks register process into two parts: early part for possible timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for the left normal peripheral clocks registered by a platform driver. Dong Aisheng (9): clk: imx: add gatable clock divider support clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support clk: imx: add pllv4 support clk: imx: add pfdv2 support clk: imx: add imx7ulp composite clk support dt-bindings: clock: add imx7ulp clock binding doc clk: imx: make mux parent strings const clk: imx: implement new clk_hw based APIs clk: imx: add imx7ulp clk driver .../devicetree/bindings/clock/imx7ulp-clock.txt| 104 ++ drivers/clk/clk-fractional-divider.c | 10 + drivers/clk/imx/Makefile | 7 +- drivers/clk/imx/clk-busy.c | 2 +- drivers/clk/imx/clk-composite-7ulp.c | 85 drivers/clk/imx/clk-divider-gate.c | 219 drivers/clk/imx/clk-fixup-mux.c| 2 +- drivers/clk/imx/clk-imx7ulp.c | 220 + drivers/clk/imx/clk-pfdv2.c| 201 +++ drivers/clk/imx/clk-pllv4.c| 182 + drivers/clk/imx/clk.c | 22 +++ drivers/clk/imx/clk.h | 96 - include/dt-bindings/clock/imx7ulp-clock.h | 109 ++ include/linux/clk-provider.h | 8 + 14 files changed, 1257 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt create mode 100644 drivers/clk/imx/clk-composite-7ulp.c create mode 100644 drivers/clk/imx/clk-divider-gate.c create mode 100644 drivers/clk/imx/clk-imx7ulp.c create mode 100644 drivers/clk/imx/clk-pfdv2.c create mode 100644 drivers/clk/imx/clk-pllv4.c create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h -- 2.7.4
[PATCH V6 1/9] clk: imx: add gatable clock divider support
For dividers with zero indicating clock is disabled, instead of giving a warning each time like "clkx: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set" in exist code, we'd like to introduce enable/disable function for it. e.g. 000b - Clock disabled 001b - Divide by 1 010b - Divide by 2 ... Set rate when the clk is disabled will cache the rate request and only when the clk is enabled will the driver actually program the hardware to have the requested divider value. Similarly, when the clk is disabled we'll write a 0 there, but when the clk is enabled we'll restore whatever rate (divider) was chosen last. It does mean that recalc rate will be sort of odd, because when the clk is off it will return 0, and when the clk is on it will return the right rate. So to make things work, we'll need to return the cached rate in recalc rate when the clk is off and read the hardware when the clk is on. NOTE for the default off divider, the recalc rate will still return 0 as there's still no proper preset rate. Enable such divider will give user a reminder error message. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Signed-off-by: Dong Aisheng --- ChangeLog: v5->v6: * move gatable divider code into imx specific clock folder as suggested by Michael. Patch title also updated accordingly. v4->v5: * no changes v3->v4: * no changes v2->v3: * split normal and gate ops * fix the possible racy v1->v2: * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-divider-gate.c | 219 + drivers/clk/imx/clk.h | 4 + 3 files changed, 224 insertions(+) create mode 100644 drivers/clk/imx/clk-divider-gate.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..077e732 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -4,6 +4,7 @@ obj-y += \ clk.o \ clk-busy.o \ clk-cpu.o \ + clk-divider-gate.o \ clk-fixup-div.o \ clk-fixup-mux.o \ clk-gate-exclusive.o \ diff --git a/drivers/clk/imx/clk-divider-gate.c b/drivers/clk/imx/clk-divider-gate.c new file mode 100644 index 000..b48fba2 --- /dev/null +++ b/drivers/clk/imx/clk-divider-gate.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 NXP. + * Dong Aisheng + */ + +#include +#include +#include +#include + +struct clk_divider_gate { + struct clk_divider divider; + u32 cached_val; +}; + +static inline struct clk_divider_gate *to_clk_divider_gate(struct clk_hw *hw) +{ + struct clk_divider *div = to_clk_divider(hw); + + return container_of(div, struct clk_divider_gate, divider); +} + +static unsigned long clk_divider_gate_recalc_rate_ro(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_divider *div = to_clk_divider(hw); + unsigned int val; + + val = clk_readl(div->reg) >> div->shift; + val &= clk_div_mask(div->width); + if (!val) + return 0; + + return divider_recalc_rate(hw, parent_rate, val, div->table, + div->flags, div->width); +} + +static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider_gate *div_gate = to_clk_divider_gate(hw); + struct clk_divider *div = to_clk_divider(hw); + unsigned long flags = 0; + unsigned int val; + + spin_lock_irqsave(div->lock, flags); + + if (!clk_hw_is_enabled(hw)) { + val = div_gate->cached_val; + } else { + val = clk_readl(div->reg) >> div->shift; + val &= clk_div_mask(div->width); + } + + spin_unlock_irqrestore(div->lock, flags); + + if (!val) + return 0; + + return divider_recalc_rate(hw, parent_rate, val, div->table, + div->flags, div->width); +} + +static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + return clk_divider_ops.round_rate(hw, rate, prate); +} + +static int clk_divider_gate_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider_gate *div_gate = to_clk_divider_gate(hw); + struct clk_divider *div = to_clk_divider(hw); + unsigned long flags = 0; + int value; + u32 val; + + value = divider_get_val(rate, parent_rate, div->table, + div->width, div->flags); + if (value < 0) + return value; + + spin_lock_irqsave(div->lock, flags); + + if (clk_hw_is_enabled(hw)) { + val = clk_readl(div->reg); + val &= ~(clk_div_mask(div->width) << div->shift); +
[PATCH V6 7/9] clk: imx: make mux parent strings const
As the commit 2893c379461a ("clk: make strings in parent name arrays const"), let's make the parent strings const, otherwise we may meet the following warning when compiling: drivers/clk/imx/clk-imx7ulp.c: In function 'imx7ulp_clocks_init': drivers/clk/imx/clk-imx7ulp.c:73:35: warning: passing argument 5 of 'imx_clk_mux_flags' discards 'const' qualifier from pointer target type clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); ^ In file included from drivers/clk/imx/clk-imx7ulp.c:23:0: drivers/clk/imx/clk.h:200:27: note: expected 'const char **' but argument is of type 'const char * const*' ... Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Signed-off-by: Dong Aisheng --- ChangeLog: v1->v4: no changes --- drivers/clk/imx/clk-busy.c | 2 +- drivers/clk/imx/clk-fixup-mux.c | 2 +- drivers/clk/imx/clk.h | 18 +++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/clk/imx/clk-busy.c b/drivers/clk/imx/clk-busy.c index 9903652..e695622 100644 --- a/drivers/clk/imx/clk-busy.c +++ b/drivers/clk/imx/clk-busy.c @@ -154,7 +154,7 @@ static const struct clk_ops clk_busy_mux_ops = { struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, -const char **parent_names, int num_parents) +const char * const *parent_names, int num_parents) { struct clk_busy_mux *busy; struct clk *clk; diff --git a/drivers/clk/imx/clk-fixup-mux.c b/drivers/clk/imx/clk-fixup-mux.c index c9b327e..44817c1 100644 --- a/drivers/clk/imx/clk-fixup-mux.c +++ b/drivers/clk/imx/clk-fixup-mux.c @@ -70,7 +70,7 @@ static const struct clk_ops clk_fixup_mux_ops = { }; struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, + u8 shift, u8 width, const char * const *parents, int num_parents, void (*fixup)(u32 *val)) { struct clk_fixup_mux *fixup_mux; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 2e3bcfa..3886979 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -69,7 +69,7 @@ struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, -const char **parent_names, int num_parents); +const char * const *parent_names, int num_parents); struct clk_hw *imx7ulp_clk_composite(const char *name, const char * const *parent_names, @@ -82,7 +82,7 @@ struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void (*fixup)(u32 *val)); struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, + u8 shift, u8 width, const char * const *parents, int num_parents, void (*fixup)(u32 *val)); static inline struct clk *imx_clk_fixed(const char *name, int rate) @@ -91,7 +91,8 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) } static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg, @@ -204,7 +205,8 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent, } static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT, reg, shift, @@ -212,7 +214,8 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, } static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE, @@ -220,8
[PATCH V6 2/9] clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support
Adding CLK_FRAC_DIVIDER_ZERO_BASED flag to indicate the numerator and denominator value in register are start from 0. This can be used to support frac dividers like below: Divider output clock = Divider input clock x [(frac +1) / (div +1)] where frac/div in register is: 000b - Divide by 1. 001b - Divide by 2. 010b - Divide by 3. Cc: Stephen Boyd Cc: Michael Turquette Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * improve comments suggested by Stephen --- drivers/clk/clk-fractional-divider.c | 10 ++ include/linux/clk-provider.h | 8 2 files changed, 18 insertions(+) diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index fdf625f..7ccde6b 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -40,6 +40,11 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, m = (val & fd->mmask) >> fd->mshift; n = (val & fd->nmask) >> fd->nshift; + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + m++; + n++; + } + if (!n || !m) return parent_rate; @@ -103,6 +108,11 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), , ); + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + m--; + n--; + } + if (fd->lock) spin_lock_irqsave(fd->lock, flags); else diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 08b1aa7..bee6453 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -594,6 +594,12 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw); * @lock: register lock * * Clock with adjustable fractional divider affecting its output frequency. + * + * Flags: + * CLK_FRAC_DIVIDER_ZERO_BASED - by default the numerator and denominator + * is the value read from the register. If CLK_FRAC_DIVIDER_ZERO_BASED + * is set then the numerator and denominator are both the value read + * plus one. */ struct clk_fractional_divider { struct clk_hw hw; @@ -613,6 +619,8 @@ struct clk_fractional_divider { #define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw) +#define CLK_FRAC_DIVIDER_ZERO_BASEDBIT(0) + extern const struct clk_ops clk_fractional_divider_ops; struct clk *clk_register_fractional_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, -- 2.7.4
RE: [PATCH RESEND V4 1/9] clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support
Hi Michael, > -Original Message- > From: Michael Turquette [mailto:mturque...@baylibre.com] [...] > Hi Dong, > > Quoting A.s. Dong (2018-10-21 06:10:48) > > For dividers with zero indicating clock is disabled, instead of giving > > a warning each time like "clkx: Zero divisor and > > CLK_DIVIDER_ALLOW_ZERO not set" in exist code, we'd like to introduce > enable/disable function for it. > > e.g. > > 000b - Clock disabled > > 001b - Divide by 1 > > 010b - Divide by 2 > > ... > > I feel bad to NAK this patch after it's been on the list for so long, Never mind, I feel better than no response about it. :-) > but this > implementation really should belong in your hardware specific clock provider > driver. > Got your point. > This patch expands clk-divider to also be a gate, which is a non-starter. > Basic > clock types were meant to remain basic. I'm already imagining how this > precedent would cause other submissions: "why should I use composite clock > when we can just add new clk_ops to the basic clock types!" :-( > > Also the implementation becomes cleaner when you don't have to make it > coexist with clk-divider.c. You can drop the flags and just implement a > machine > specific clock type that combines gates and dividers. Sound good to me. The original purpose to put it in framework is in order to save possible duplicated codes for a similar SoC as the implementation actually is HW independent. But I think we could start from putting it in machine code first. Thanks for the suggestion. Will update soon and resend. Regards Dong Aisheng > > Best regards, > Mike > > > > > Set rate when the clk is disabled will cache the rate request and only > > when the clk is enabled will the driver actually program the hardware > > to have the requested divider value. Similarly, when the clk is > > disabled we'll write a 0 there, but when the clk is enabled we'll > > restore whatever rate > > (divider) was chosen last. > > > > It does mean that recalc rate will be sort of odd, because when the > > clk is off it will return 0, and when the clk is on it will return the > > right rate. > > So to make things work, we'll need to return the cached rate in recalc > > rate when the clk is off and read the hardware when the clk is on. > > > > NOTE for the default off divider, the recalc rate will still return 0 > > as there's still no proper preset rate. Enable such divider will give > > user a reminder error message. > > > > Cc: Stephen Boyd > > Cc: Michael Turquette > > Cc: Shawn Guo > > Signed-off-by: Dong Aisheng > > > > --- > > ChangeLog: > > v3->v4: > > * no changes > > v2->v3: > > * split normal and gate ops > > * fix the possible racy > > v1->v2: > > * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers > > --- > > drivers/clk/clk-divider.c| 152 > +++ > > include/linux/clk-provider.h | 9 +++ > > 2 files changed, 161 insertions(+) > > > > diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c > > index b6234a5..b3566fd 100644 > > --- a/drivers/clk/clk-divider.c > > +++ b/drivers/clk/clk-divider.c > > @@ -122,6 +122,9 @@ unsigned long divider_recalc_rate(struct clk_hw > > *hw, unsigned long parent_rate, > > > > div = _get_div(table, val, flags, width); > > if (!div) { > > + if (flags & CLK_DIVIDER_ZERO_GATE) > > + return 0; > > + > > WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), > > "%s: Zero divisor and > CLK_DIVIDER_ALLOW_ZERO not set\n", > > clk_hw_get_name(hw)); @@ -145,6 +148,34 > @@ > > static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, > >divider->flags, divider->width); } > > > > +static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw, > > + unsigned long > > +parent_rate) { > > + struct clk_divider *divider = to_clk_divider(hw); > > + unsigned long flags = 0; > > + unsigned int val; > > + > > + if (divider->lock) > > + spin_lock_irqsave(divider->lock, flags); > > + else > > + __acquire(divider->lock); > > + > > + if (!clk_hw_is_enabled(hw)) { > > + val = divider->cached_val; > > + } else { >
RE: [PATCH RESEND V4 1/9] clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support
Hi Michael, > -Original Message- > From: Michael Turquette [mailto:mturque...@baylibre.com] [...] > Hi Dong, > > Quoting A.s. Dong (2018-10-21 06:10:48) > > For dividers with zero indicating clock is disabled, instead of giving > > a warning each time like "clkx: Zero divisor and > > CLK_DIVIDER_ALLOW_ZERO not set" in exist code, we'd like to introduce > enable/disable function for it. > > e.g. > > 000b - Clock disabled > > 001b - Divide by 1 > > 010b - Divide by 2 > > ... > > I feel bad to NAK this patch after it's been on the list for so long, Never mind, I feel better than no response about it. :-) > but this > implementation really should belong in your hardware specific clock provider > driver. > Got your point. > This patch expands clk-divider to also be a gate, which is a non-starter. > Basic > clock types were meant to remain basic. I'm already imagining how this > precedent would cause other submissions: "why should I use composite clock > when we can just add new clk_ops to the basic clock types!" :-( > > Also the implementation becomes cleaner when you don't have to make it > coexist with clk-divider.c. You can drop the flags and just implement a > machine > specific clock type that combines gates and dividers. Sound good to me. The original purpose to put it in framework is in order to save possible duplicated codes for a similar SoC as the implementation actually is HW independent. But I think we could start from putting it in machine code first. Thanks for the suggestion. Will update soon and resend. Regards Dong Aisheng > > Best regards, > Mike > > > > > Set rate when the clk is disabled will cache the rate request and only > > when the clk is enabled will the driver actually program the hardware > > to have the requested divider value. Similarly, when the clk is > > disabled we'll write a 0 there, but when the clk is enabled we'll > > restore whatever rate > > (divider) was chosen last. > > > > It does mean that recalc rate will be sort of odd, because when the > > clk is off it will return 0, and when the clk is on it will return the > > right rate. > > So to make things work, we'll need to return the cached rate in recalc > > rate when the clk is off and read the hardware when the clk is on. > > > > NOTE for the default off divider, the recalc rate will still return 0 > > as there's still no proper preset rate. Enable such divider will give > > user a reminder error message. > > > > Cc: Stephen Boyd > > Cc: Michael Turquette > > Cc: Shawn Guo > > Signed-off-by: Dong Aisheng > > > > --- > > ChangeLog: > > v3->v4: > > * no changes > > v2->v3: > > * split normal and gate ops > > * fix the possible racy > > v1->v2: > > * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers > > --- > > drivers/clk/clk-divider.c| 152 > +++ > > include/linux/clk-provider.h | 9 +++ > > 2 files changed, 161 insertions(+) > > > > diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c > > index b6234a5..b3566fd 100644 > > --- a/drivers/clk/clk-divider.c > > +++ b/drivers/clk/clk-divider.c > > @@ -122,6 +122,9 @@ unsigned long divider_recalc_rate(struct clk_hw > > *hw, unsigned long parent_rate, > > > > div = _get_div(table, val, flags, width); > > if (!div) { > > + if (flags & CLK_DIVIDER_ZERO_GATE) > > + return 0; > > + > > WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), > > "%s: Zero divisor and > CLK_DIVIDER_ALLOW_ZERO not set\n", > > clk_hw_get_name(hw)); @@ -145,6 +148,34 > @@ > > static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, > >divider->flags, divider->width); } > > > > +static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw, > > + unsigned long > > +parent_rate) { > > + struct clk_divider *divider = to_clk_divider(hw); > > + unsigned long flags = 0; > > + unsigned int val; > > + > > + if (divider->lock) > > + spin_lock_irqsave(divider->lock, flags); > > + else > > + __acquire(divider->lock); > > + > > + if (!clk_hw_is_enabled(hw)) { > > + val = divider->cached_val; > > + } else { >
RE: [PATCH] pinctrl: imx: make sure that maps are fully initialized
Hi Martin, > -Original Message- > From: Martin Kaiser [mailto:mar...@kaiser.cx] > Sent: Sunday, November 11, 2018 1:37 AM [...] > > The commit that added scu based pinctrl support introduced a regression for > the mmio case. In the for-loop where the maps are initialized, we end up > creating a partially initialized map in some cases. This causes a kernel panic > when such a map is used at a later stage. > > When scu is not used and and a pin uses the default pad configuration, the > current code sets the map's type and data.configs.group_or_pin but no configs > or num_configs are set. The previous code without scu support did not create a > new map at all in this case and did not increment the counter. > > Fix this by setting the map type and data.configs.group_or_pin only when a > configuration was set before, either by scu or by mmio using a non-default pad > config. Increment the counter only if a new map was created. > > Fixes: b96eea718bf6 ("pinctrl: fsl: add scu based pinctrl support") > Cc: A.s. Dong > Signed-off-by: Martin Kaiser Thanks for reporting this issue. The original code intended to save 3 common lines for both SCU and MMIO pads, but it did change the code logic a bit which resulted in a regression specificly for NO_PAD_CTL cases used on a few legacy boards. (NO_PAD_CTL is deprecated for new boards dts). I agree with Leonard that this fixes is not so good. A simpler and proper fix could be: diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index b704f7c..ab962f5 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -109,6 +109,15 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, new_map++; for (i = j = 0; i < grp->num_pins; i++) { pin = &((struct imx_pin *)(grp->data))[i]; + + /* +* We only create config maps for SCU pads or MMIO pads that +* are not using the default config (a.k.a NO_PAD_CTL) +*/ + if (!(info->flags & IMX_USE_SCU) && + (pin->conf.mmio.config & IMX_NO_PAD_CTL)) + continue; + new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN; new_map[j].data.configs.group_or_pin = pin_get_name(pctldev, pin->pin); @@ -121,7 +130,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, new_map[j].data.configs.configs = (unsigned long *)>conf.scu; new_map[j].data.configs.num_configs = 2; - } else if (!(pin->conf.mmio.config & IMX_NO_PAD_CTL)) { + } else { new_map[j].data.configs.configs = >conf.mmio.config; new_map[j].data.configs.num_configs = 1; @@ -550,6 +559,8 @@ static void imx_pinctrl_parse_pin_mmio(struct imx_pinctrl *ipctl, pin_mmio->config = config & ~IMX_PAD_SION; } + *list_p = list; //thanks to Leonard for pointing out this + dev_dbg(ipctl->dev, "%s: 0x%x 0x%08lx", info->pins[*pin_id].name, pin_mmio->mux_mode, pin_mmio->config); As you both had a patch, i'm not sure who i'm going to expect for a updated one, so I would send it my own with both of your tags. Thanks for the effort. Regards Dong Aisheng > --- > > A crash looks like this > > [4.028525] Unable to handle kernel NULL pointer dereference at virtual > address > [4.036667] pgd = (ptrval) > [4.039505] [] *pgd= > [4.043162] Internal error: Oops: 5 [#1] ARM > [4.047466] Modules linked in: > [4.050582] CPU: 0 PID: 1 Comm: swapper Not tainted > 4.20.0-rc1-next-20181106+ #2269 > [4.058270] Hardware name: Freescale i.MX25 (Device Tree Support) > [4.064456] PC is at strcmp+0xc/0x40 > [4.068111] LR is at create_pinctrl+0x104/0x36c > [4.072680] pc : []lr : []psr: 6013 > [4.078980] sp : d38bbce8 ip : d38bbcf8 fp : d38bbcf4 > [4.084236] r10: d3b2e0e0 r9 : d3b2e0c0 r8 : > [4.089494] r7 : d3b2e238 r6 : d3b2e1c0 r5 : r4 : > d3b0df00 > [4.096054] r3 : 85981bcd r2 : 85981bcd r1 : d3a729e0 r0 : > > [4.102615] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM > Segment none > [4.109786] Control: 0005317f Table: 80004000 DAC: 0053 > [4.115569] Process swapper (pid: 1, stack limit = 0x(ptrval)) > [4.121437] Stack: (0xd38bbce8 to 0xd38bc000) > [4.125849] bce0: d38bbd3c d38bbcf8 c0220bc8 > c05699dc d38bbd3c c06adb58 >
RE: [PATCH] pinctrl: imx: make sure that maps are fully initialized
Hi Martin, > -Original Message- > From: Martin Kaiser [mailto:mar...@kaiser.cx] > Sent: Sunday, November 11, 2018 1:37 AM [...] > > The commit that added scu based pinctrl support introduced a regression for > the mmio case. In the for-loop where the maps are initialized, we end up > creating a partially initialized map in some cases. This causes a kernel panic > when such a map is used at a later stage. > > When scu is not used and and a pin uses the default pad configuration, the > current code sets the map's type and data.configs.group_or_pin but no configs > or num_configs are set. The previous code without scu support did not create a > new map at all in this case and did not increment the counter. > > Fix this by setting the map type and data.configs.group_or_pin only when a > configuration was set before, either by scu or by mmio using a non-default pad > config. Increment the counter only if a new map was created. > > Fixes: b96eea718bf6 ("pinctrl: fsl: add scu based pinctrl support") > Cc: A.s. Dong > Signed-off-by: Martin Kaiser Thanks for reporting this issue. The original code intended to save 3 common lines for both SCU and MMIO pads, but it did change the code logic a bit which resulted in a regression specificly for NO_PAD_CTL cases used on a few legacy boards. (NO_PAD_CTL is deprecated for new boards dts). I agree with Leonard that this fixes is not so good. A simpler and proper fix could be: diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index b704f7c..ab962f5 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -109,6 +109,15 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, new_map++; for (i = j = 0; i < grp->num_pins; i++) { pin = &((struct imx_pin *)(grp->data))[i]; + + /* +* We only create config maps for SCU pads or MMIO pads that +* are not using the default config (a.k.a NO_PAD_CTL) +*/ + if (!(info->flags & IMX_USE_SCU) && + (pin->conf.mmio.config & IMX_NO_PAD_CTL)) + continue; + new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN; new_map[j].data.configs.group_or_pin = pin_get_name(pctldev, pin->pin); @@ -121,7 +130,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, new_map[j].data.configs.configs = (unsigned long *)>conf.scu; new_map[j].data.configs.num_configs = 2; - } else if (!(pin->conf.mmio.config & IMX_NO_PAD_CTL)) { + } else { new_map[j].data.configs.configs = >conf.mmio.config; new_map[j].data.configs.num_configs = 1; @@ -550,6 +559,8 @@ static void imx_pinctrl_parse_pin_mmio(struct imx_pinctrl *ipctl, pin_mmio->config = config & ~IMX_PAD_SION; } + *list_p = list; //thanks to Leonard for pointing out this + dev_dbg(ipctl->dev, "%s: 0x%x 0x%08lx", info->pins[*pin_id].name, pin_mmio->mux_mode, pin_mmio->config); As you both had a patch, i'm not sure who i'm going to expect for a updated one, so I would send it my own with both of your tags. Thanks for the effort. Regards Dong Aisheng > --- > > A crash looks like this > > [4.028525] Unable to handle kernel NULL pointer dereference at virtual > address > [4.036667] pgd = (ptrval) > [4.039505] [] *pgd= > [4.043162] Internal error: Oops: 5 [#1] ARM > [4.047466] Modules linked in: > [4.050582] CPU: 0 PID: 1 Comm: swapper Not tainted > 4.20.0-rc1-next-20181106+ #2269 > [4.058270] Hardware name: Freescale i.MX25 (Device Tree Support) > [4.064456] PC is at strcmp+0xc/0x40 > [4.068111] LR is at create_pinctrl+0x104/0x36c > [4.072680] pc : []lr : []psr: 6013 > [4.078980] sp : d38bbce8 ip : d38bbcf8 fp : d38bbcf4 > [4.084236] r10: d3b2e0e0 r9 : d3b2e0c0 r8 : > [4.089494] r7 : d3b2e238 r6 : d3b2e1c0 r5 : r4 : > d3b0df00 > [4.096054] r3 : 85981bcd r2 : 85981bcd r1 : d3a729e0 r0 : > > [4.102615] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM > Segment none > [4.109786] Control: 0005317f Table: 80004000 DAC: 0053 > [4.115569] Process swapper (pid: 1, stack limit = 0x(ptrval)) > [4.121437] Stack: (0xd38bbce8 to 0xd38bc000) > [4.125849] bce0: d38bbd3c d38bbcf8 c0220bc8 > c05699dc d38bbd3c c06adb58 >
RE: [PATCH v9 3/5] clk: imx: add SCCG PLL type
Hi Stephen, [...] > > I already sent the 12th version of this current patch series and I > > would really like to get this in ASAP so that the booting up of imx8mq will > not be delayed. > > > > Ok. Well we're in rc1 right now, and so we're not merging new drivers into > mainline. I can merge the clk driver into clk-next, but you'll have to wait > for the > stabilization period to end (approximately 6 or 7 weeks) before this can get > into the next kernel version. It will be in linux-next much sooner of course. That would be great if you can help that. We're now working with SUSE to enable i.MX8 support. Their criteria is only backporting patches which must be at least in maintainer's next tree already. So either picked up by you or Shawn would help a lot on it. BTW, one simple question is that because MX8MQ DTS patches depends on this clock driver series. How would you suggest this series to go through your tree or Shawn's tree? Regards Dong Aisheng
RE: [PATCH v9 3/5] clk: imx: add SCCG PLL type
Hi Stephen, [...] > > I already sent the 12th version of this current patch series and I > > would really like to get this in ASAP so that the booting up of imx8mq will > not be delayed. > > > > Ok. Well we're in rc1 right now, and so we're not merging new drivers into > mainline. I can merge the clk driver into clk-next, but you'll have to wait > for the > stabilization period to end (approximately 6 or 7 weeks) before this can get > into the next kernel version. It will be in linux-next much sooner of course. That would be great if you can help that. We're now working with SUSE to enable i.MX8 support. Their criteria is only backporting patches which must be at least in maintainer's next tree already. So either picked up by you or Shawn would help a lot on it. BTW, one simple question is that because MX8MQ DTS patches depends on this clock driver series. How would you suggest this series to go through your tree or Shawn's tree? Regards Dong Aisheng
[PATCH V5 3/9] clk: imx: add pllv4 support
pllv4 is designed for System Clock Generation (SCG) module observed in IMX ULP SoC series. e.g. i.MX7ULP. The SCG modules generates clock used to derive processor, system, peripheral bus and external memory interface clocks while this patch intends to support the PLL part. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * remove clk_pllv4_is_enabled() check in set_rate, instead it will be handled by core later. * use readl_poll_timeout * use clk_hw_register instead of clk_register * other minor changes --- drivers/clk/imx/Makefile| 1 + drivers/clk/imx/clk-pllv4.c | 182 drivers/clk/imx/clk.h | 3 + 3 files changed, 186 insertions(+) create mode 100644 drivers/clk/imx/clk-pllv4.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..bfe31bf 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -11,6 +11,7 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ + clk-pllv4.o \ clk-pfd.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c new file mode 100644 index 000..67c64c7 --- /dev/null +++ b/drivers/clk/imx/clk-pllv4.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include + +/* PLL Control Status Register (xPLLCSR) */ +#define PLL_CSR_OFFSET 0x0 +#define PLL_VLDBIT(24) +#define PLL_EN BIT(0) + +/* PLL Configuration Register (xPLLCFG) */ +#define PLL_CFG_OFFSET 0x08 +#define BP_PLL_MULT16 +#define BM_PLL_MULT(0x7f << 16) + +/* PLL Numerator Register (xPLLNUM) */ +#define PLL_NUM_OFFSET 0x10 + +/* PLL Denominator Register (xPLLDENOM) */ +#define PLL_DENOM_OFFSET 0x14 + +struct clk_pllv4 { + struct clk_hw hw; + void __iomem*base; +}; + +/* Valid PLL MULT Table */ +static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16}; + +#define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw) + +#define LOCK_TIMEOUT_USUSEC_PER_MSEC + +static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll) +{ + u32 csr; + + return readl_poll_timeout(pll->base + PLL_CSR_OFFSET, + csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US); +} + +static int clk_pllv4_is_enabled(struct clk_hw *hw) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + if (readl_relaxed(pll->base) & PLL_EN) + return 1; + + return 0; +} + +static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + u32 div; + + div = readl_relaxed(pll->base + PLL_CFG_OFFSET); + div &= BM_PLL_MULT; + div >>= BP_PLL_MULT; + + return parent_rate * div; +} + +static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate, +unsigned long *prate) +{ + unsigned long parent_rate = *prate; + unsigned long round_rate, i; + + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + round_rate = parent_rate * pllv4_mult_table[i]; + if (rate >= round_rate) + return round_rate; + } + + return round_rate; +} + +static bool clk_pllv4_is_valid_mult(unsigned int mult) +{ + int i; + + /* check if mult is in valid MULT table */ + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + if (pllv4_mult_table[i] == mult) + return true; + } + + return false; +} + +static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + u32 val, mult; + + mult = rate / parent_rate; + + if (!clk_pllv4_is_valid_mult(mult)) + return -EINVAL; + + val = readl_relaxed(pll->base + PLL_CFG_OFFSET); + val &= ~BM_PLL_MULT; + val |= mult << BP_PLL_MULT; + writel_relaxed(val, pll->base + PLL_CFG_OFFSET); + + return 0; +} + +static int clk_pllv4_enable(struct clk_hw *hw) +{ + u32 val; + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + val = readl_relaxed(pll->base); + val |= PLL_EN; + writel_relaxed(val, pll->base); + + return clk_pllv4_wait_lock(pll); +} + +static void clk_pllv4_disable(struct clk_hw *hw) +{ + u32 val; + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + val = readl_relaxed(pll->base); + val &= ~PLL_EN; +
[PATCH V5 8/9] clk: imx: implement new clk_hw based APIs
Clock providers are recommended to use the new struct clk_hw based API, so implement IMX clk_hw based provider helpers functions to the new approach. Signed-off-by: Dong Aisheng --- ChangeLog: v2->v4: * no changes v1->v2: new patches --- drivers/clk/imx/clk.c | 22 ++ drivers/clk/imx/clk.h | 62 +++ 2 files changed, 84 insertions(+) diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c index 9074e69..1efed86 100644 --- a/drivers/clk/imx/clk.c +++ b/drivers/clk/imx/clk.c @@ -18,6 +18,16 @@ void __init imx_check_clocks(struct clk *clks[], unsigned int count) i, PTR_ERR(clks[i])); } +void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + if (IS_ERR(clks[i])) + pr_err("i.MX clk %u: register failed with %ld\n", + i, PTR_ERR(clks[i])); +} + static struct clk * __init imx_obtain_fixed_clock_from_dt(const char *name) { struct of_phandle_args phandle; @@ -49,6 +59,18 @@ struct clk * __init imx_obtain_fixed_clock( return clk; } +struct clk_hw * __init imx_obtain_fixed_clk_hw(struct device_node *np, + const char *name) +{ + struct clk *clk; + + clk = of_clk_get_by_name(np, name); + if (IS_ERR(clk)) + return ERR_PTR(-ENOENT); + + return __clk_get_hw(clk); +} + /* * This fixups the register CCM_CSCMR1 write value. * The write/read/divider values of the aclk_podf field diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 290d4b2..75ad05b 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -8,6 +8,7 @@ extern spinlock_t imx_ccm_lock; void imx_check_clocks(struct clk *clks[], unsigned int count); +void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count); void imx_register_uart_clocks(struct clk ** const clks[]); extern void imx_cscmr1_fixup(u32 *val); @@ -54,6 +55,9 @@ struct clk *clk_register_gate2(struct device *dev, const char *name, struct clk * imx_obtain_fixed_clock( const char *name, unsigned long rate); +struct clk_hw *imx_obtain_fixed_clk_hw(struct device_node *np, + const char *name); + struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, void __iomem *reg, u8 shift, u32 exclusive_mask); @@ -90,6 +94,16 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) return clk_register_fixed_rate(NULL, name, NULL, 0, rate); } +static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate) +{ + return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); +} + +static inline struct clk_hw *imx_get_clk_hw_fixed(const char *name, int rate) +{ + return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); +} + static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, u8 shift, u8 width, const char * const *parents, int num_parents) @@ -113,6 +127,15 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent, reg, shift, width, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_divider(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width) +{ + return clk_hw_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT, + reg, shift, width, 0, _ccm_lock); +} + static inline struct clk *imx_clk_divider_flags(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width, unsigned long flags) @@ -121,6 +144,15 @@ static inline struct clk *imx_clk_divider_flags(const char *name, reg, shift, width, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width, unsigned long flags) +{ + return clk_hw_register_divider(NULL, name, parent, flags, + reg, shift, width, 0, _ccm_lock); +} + static inline struct clk *imx_clk_divider2(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width) { @@ -143,6 +175,13 @@ static inline struct clk *imx_clk_gate_flags(const char *name, const char *paren shift, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_gate(const char *name, const char *parent, +void
[PATCH V5 2/9] clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support
Adding CLK_FRAC_DIVIDER_ZERO_BASED flag to indicate the numerator and denominator value in register are start from 0. This can be used to support frac dividers like below: Divider output clock = Divider input clock x [(frac +1) / (div +1)] where frac/div in register is: 000b - Divide by 1. 001b - Divide by 2. 010b - Divide by 3. Cc: Stephen Boyd Cc: Michael Turquette Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * improve comments suggested by Stephen --- drivers/clk/clk-fractional-divider.c | 10 ++ include/linux/clk-provider.h | 8 2 files changed, 18 insertions(+) diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index fdf625f..7ccde6b 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -40,6 +40,11 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, m = (val & fd->mmask) >> fd->mshift; n = (val & fd->nmask) >> fd->nshift; + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + m++; + n++; + } + if (!n || !m) return parent_rate; @@ -103,6 +108,11 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), , ); + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + m--; + n--; + } + if (fd->lock) spin_lock_irqsave(fd->lock, flags); else diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 08f135a..90d7c26 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -603,6 +603,12 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw); * @lock: register lock * * Clock with adjustable fractional divider affecting its output frequency. + * + * Flags: + * CLK_FRAC_DIVIDER_ZERO_BASED - by default the numerator and denominator + * is the value read from the register. If CLK_FRAC_DIVIDER_ZERO_BASED + * is set then the numerator and denominator are both the value read + * plus one. */ struct clk_fractional_divider { struct clk_hw hw; @@ -622,6 +628,8 @@ struct clk_fractional_divider { #define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw) +#define CLK_FRAC_DIVIDER_ZERO_BASEDBIT(0) + extern const struct clk_ops clk_fractional_divider_ops; struct clk *clk_register_fractional_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, -- 2.7.4
[PATCH V5 4/9] clk: imx: add pfdv2 support
The pfdv2 is designed for PLL Fractional Divide (PFD) observed in System Clock Generation (SCG) module in IMX ULP SoC series. e.g. i.MX7ULP. NOTE pfdv2 can only be operated when clk is gated. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * change to readl_poll_timeout * add pfd lock to protect share reg access between rate and enable/disable operations and multiple pfd instances. * use clk_hw_register --- drivers/clk/imx/Makefile| 3 +- drivers/clk/imx/clk-pfdv2.c | 201 drivers/clk/imx/clk.h | 3 + 3 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-pfdv2.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index bfe31bf..e5b0d42 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,7 +12,8 @@ obj-y += \ clk-pllv2.o \ clk-pllv3.o \ clk-pllv4.o \ - clk-pfd.o + clk-pfd.o \ + clk-pfdv2.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c new file mode 100644 index 000..afb2904 --- /dev/null +++ b/drivers/clk/imx/clk-pfdv2.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include + +/** + * struct clk_pfdv2 - IMX PFD clock + * @clk_hw:clock source + * @reg: PFD register address + * @gate_bit: Gate bit offset + * @vld_bit: Valid bit offset + * @frac_off: PLL Fractional Divider offset + */ + +struct clk_pfdv2 { + struct clk_hw hw; + void __iomem*reg; + u8 gate_bit; + u8 vld_bit; + u8 frac_off; +}; + +#define to_clk_pfdv2(_hw) container_of(_hw, struct clk_pfdv2, hw) + +#define CLK_PFDV2_FRAC_MASK 0x3f + +#define LOCK_TIMEOUT_USUSEC_PER_MSEC + +static DEFINE_SPINLOCK(pfd_lock); + +static int clk_pfdv2_wait(struct clk_pfdv2 *pfd) +{ + u32 val; + + return readl_poll_timeout(pfd->reg, val, val & pfd->vld_bit, + 0, LOCK_TIMEOUT_US); +} + +static int clk_pfdv2_enable(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val &= ~pfd->gate_bit; + writel_relaxed(val, pfd->reg); + spin_unlock_irqrestore(_lock, flags); + + return clk_pfdv2_wait(pfd); +} + +static void clk_pfdv2_disable(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val |= pfd->gate_bit; + writel_relaxed(val, pfd->reg); + spin_unlock_irqrestore(_lock, flags); +} + +static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + u64 tmp = parent_rate; + u8 frac; + + frac = (readl_relaxed(pfd->reg) >> pfd->frac_off) + & CLK_PFDV2_FRAC_MASK; + + if (!frac) { + pr_debug("clk_pfdv2: %s invalid pfd frac value 0\n", +clk_hw_get_name(hw)); + return 0; + } + + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static long clk_pfdv2_round_rate(struct clk_hw *hw, unsigned long rate, +unsigned long *prate) +{ + u64 tmp = *prate; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + tmp = *prate; + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static int clk_pfdv2_is_enabled(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + + if (readl_relaxed(pfd->reg) & pfd->gate_bit) + return 0; + + return 1; +} + +static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u64 tmp = parent_rate; + u32 val; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val &= ~(CLK_PFDV2_FRAC_MASK <<
[PATCH V5 3/9] clk: imx: add pllv4 support
pllv4 is designed for System Clock Generation (SCG) module observed in IMX ULP SoC series. e.g. i.MX7ULP. The SCG modules generates clock used to derive processor, system, peripheral bus and external memory interface clocks while this patch intends to support the PLL part. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * remove clk_pllv4_is_enabled() check in set_rate, instead it will be handled by core later. * use readl_poll_timeout * use clk_hw_register instead of clk_register * other minor changes --- drivers/clk/imx/Makefile| 1 + drivers/clk/imx/clk-pllv4.c | 182 drivers/clk/imx/clk.h | 3 + 3 files changed, 186 insertions(+) create mode 100644 drivers/clk/imx/clk-pllv4.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..bfe31bf 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -11,6 +11,7 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ + clk-pllv4.o \ clk-pfd.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c new file mode 100644 index 000..67c64c7 --- /dev/null +++ b/drivers/clk/imx/clk-pllv4.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include + +/* PLL Control Status Register (xPLLCSR) */ +#define PLL_CSR_OFFSET 0x0 +#define PLL_VLDBIT(24) +#define PLL_EN BIT(0) + +/* PLL Configuration Register (xPLLCFG) */ +#define PLL_CFG_OFFSET 0x08 +#define BP_PLL_MULT16 +#define BM_PLL_MULT(0x7f << 16) + +/* PLL Numerator Register (xPLLNUM) */ +#define PLL_NUM_OFFSET 0x10 + +/* PLL Denominator Register (xPLLDENOM) */ +#define PLL_DENOM_OFFSET 0x14 + +struct clk_pllv4 { + struct clk_hw hw; + void __iomem*base; +}; + +/* Valid PLL MULT Table */ +static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16}; + +#define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw) + +#define LOCK_TIMEOUT_USUSEC_PER_MSEC + +static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll) +{ + u32 csr; + + return readl_poll_timeout(pll->base + PLL_CSR_OFFSET, + csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US); +} + +static int clk_pllv4_is_enabled(struct clk_hw *hw) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + if (readl_relaxed(pll->base) & PLL_EN) + return 1; + + return 0; +} + +static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + u32 div; + + div = readl_relaxed(pll->base + PLL_CFG_OFFSET); + div &= BM_PLL_MULT; + div >>= BP_PLL_MULT; + + return parent_rate * div; +} + +static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate, +unsigned long *prate) +{ + unsigned long parent_rate = *prate; + unsigned long round_rate, i; + + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + round_rate = parent_rate * pllv4_mult_table[i]; + if (rate >= round_rate) + return round_rate; + } + + return round_rate; +} + +static bool clk_pllv4_is_valid_mult(unsigned int mult) +{ + int i; + + /* check if mult is in valid MULT table */ + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + if (pllv4_mult_table[i] == mult) + return true; + } + + return false; +} + +static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + u32 val, mult; + + mult = rate / parent_rate; + + if (!clk_pllv4_is_valid_mult(mult)) + return -EINVAL; + + val = readl_relaxed(pll->base + PLL_CFG_OFFSET); + val &= ~BM_PLL_MULT; + val |= mult << BP_PLL_MULT; + writel_relaxed(val, pll->base + PLL_CFG_OFFSET); + + return 0; +} + +static int clk_pllv4_enable(struct clk_hw *hw) +{ + u32 val; + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + val = readl_relaxed(pll->base); + val |= PLL_EN; + writel_relaxed(val, pll->base); + + return clk_pllv4_wait_lock(pll); +} + +static void clk_pllv4_disable(struct clk_hw *hw) +{ + u32 val; + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + val = readl_relaxed(pll->base); + val &= ~PLL_EN; +
[PATCH V5 8/9] clk: imx: implement new clk_hw based APIs
Clock providers are recommended to use the new struct clk_hw based API, so implement IMX clk_hw based provider helpers functions to the new approach. Signed-off-by: Dong Aisheng --- ChangeLog: v2->v4: * no changes v1->v2: new patches --- drivers/clk/imx/clk.c | 22 ++ drivers/clk/imx/clk.h | 62 +++ 2 files changed, 84 insertions(+) diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c index 9074e69..1efed86 100644 --- a/drivers/clk/imx/clk.c +++ b/drivers/clk/imx/clk.c @@ -18,6 +18,16 @@ void __init imx_check_clocks(struct clk *clks[], unsigned int count) i, PTR_ERR(clks[i])); } +void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + if (IS_ERR(clks[i])) + pr_err("i.MX clk %u: register failed with %ld\n", + i, PTR_ERR(clks[i])); +} + static struct clk * __init imx_obtain_fixed_clock_from_dt(const char *name) { struct of_phandle_args phandle; @@ -49,6 +59,18 @@ struct clk * __init imx_obtain_fixed_clock( return clk; } +struct clk_hw * __init imx_obtain_fixed_clk_hw(struct device_node *np, + const char *name) +{ + struct clk *clk; + + clk = of_clk_get_by_name(np, name); + if (IS_ERR(clk)) + return ERR_PTR(-ENOENT); + + return __clk_get_hw(clk); +} + /* * This fixups the register CCM_CSCMR1 write value. * The write/read/divider values of the aclk_podf field diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 290d4b2..75ad05b 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -8,6 +8,7 @@ extern spinlock_t imx_ccm_lock; void imx_check_clocks(struct clk *clks[], unsigned int count); +void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count); void imx_register_uart_clocks(struct clk ** const clks[]); extern void imx_cscmr1_fixup(u32 *val); @@ -54,6 +55,9 @@ struct clk *clk_register_gate2(struct device *dev, const char *name, struct clk * imx_obtain_fixed_clock( const char *name, unsigned long rate); +struct clk_hw *imx_obtain_fixed_clk_hw(struct device_node *np, + const char *name); + struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, void __iomem *reg, u8 shift, u32 exclusive_mask); @@ -90,6 +94,16 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) return clk_register_fixed_rate(NULL, name, NULL, 0, rate); } +static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate) +{ + return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); +} + +static inline struct clk_hw *imx_get_clk_hw_fixed(const char *name, int rate) +{ + return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); +} + static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, u8 shift, u8 width, const char * const *parents, int num_parents) @@ -113,6 +127,15 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent, reg, shift, width, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_divider(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width) +{ + return clk_hw_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT, + reg, shift, width, 0, _ccm_lock); +} + static inline struct clk *imx_clk_divider_flags(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width, unsigned long flags) @@ -121,6 +144,15 @@ static inline struct clk *imx_clk_divider_flags(const char *name, reg, shift, width, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width, unsigned long flags) +{ + return clk_hw_register_divider(NULL, name, parent, flags, + reg, shift, width, 0, _ccm_lock); +} + static inline struct clk *imx_clk_divider2(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width) { @@ -143,6 +175,13 @@ static inline struct clk *imx_clk_gate_flags(const char *name, const char *paren shift, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_gate(const char *name, const char *parent, +void
[PATCH V5 2/9] clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support
Adding CLK_FRAC_DIVIDER_ZERO_BASED flag to indicate the numerator and denominator value in register are start from 0. This can be used to support frac dividers like below: Divider output clock = Divider input clock x [(frac +1) / (div +1)] where frac/div in register is: 000b - Divide by 1. 001b - Divide by 2. 010b - Divide by 3. Cc: Stephen Boyd Cc: Michael Turquette Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * improve comments suggested by Stephen --- drivers/clk/clk-fractional-divider.c | 10 ++ include/linux/clk-provider.h | 8 2 files changed, 18 insertions(+) diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index fdf625f..7ccde6b 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -40,6 +40,11 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, m = (val & fd->mmask) >> fd->mshift; n = (val & fd->nmask) >> fd->nshift; + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + m++; + n++; + } + if (!n || !m) return parent_rate; @@ -103,6 +108,11 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), , ); + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + m--; + n--; + } + if (fd->lock) spin_lock_irqsave(fd->lock, flags); else diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 08f135a..90d7c26 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -603,6 +603,12 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw); * @lock: register lock * * Clock with adjustable fractional divider affecting its output frequency. + * + * Flags: + * CLK_FRAC_DIVIDER_ZERO_BASED - by default the numerator and denominator + * is the value read from the register. If CLK_FRAC_DIVIDER_ZERO_BASED + * is set then the numerator and denominator are both the value read + * plus one. */ struct clk_fractional_divider { struct clk_hw hw; @@ -622,6 +628,8 @@ struct clk_fractional_divider { #define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw) +#define CLK_FRAC_DIVIDER_ZERO_BASEDBIT(0) + extern const struct clk_ops clk_fractional_divider_ops; struct clk *clk_register_fractional_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, -- 2.7.4
[PATCH V5 4/9] clk: imx: add pfdv2 support
The pfdv2 is designed for PLL Fractional Divide (PFD) observed in System Clock Generation (SCG) module in IMX ULP SoC series. e.g. i.MX7ULP. NOTE pfdv2 can only be operated when clk is gated. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * change to readl_poll_timeout * add pfd lock to protect share reg access between rate and enable/disable operations and multiple pfd instances. * use clk_hw_register --- drivers/clk/imx/Makefile| 3 +- drivers/clk/imx/clk-pfdv2.c | 201 drivers/clk/imx/clk.h | 3 + 3 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-pfdv2.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index bfe31bf..e5b0d42 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,7 +12,8 @@ obj-y += \ clk-pllv2.o \ clk-pllv3.o \ clk-pllv4.o \ - clk-pfd.o + clk-pfd.o \ + clk-pfdv2.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c new file mode 100644 index 000..afb2904 --- /dev/null +++ b/drivers/clk/imx/clk-pfdv2.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include + +/** + * struct clk_pfdv2 - IMX PFD clock + * @clk_hw:clock source + * @reg: PFD register address + * @gate_bit: Gate bit offset + * @vld_bit: Valid bit offset + * @frac_off: PLL Fractional Divider offset + */ + +struct clk_pfdv2 { + struct clk_hw hw; + void __iomem*reg; + u8 gate_bit; + u8 vld_bit; + u8 frac_off; +}; + +#define to_clk_pfdv2(_hw) container_of(_hw, struct clk_pfdv2, hw) + +#define CLK_PFDV2_FRAC_MASK 0x3f + +#define LOCK_TIMEOUT_USUSEC_PER_MSEC + +static DEFINE_SPINLOCK(pfd_lock); + +static int clk_pfdv2_wait(struct clk_pfdv2 *pfd) +{ + u32 val; + + return readl_poll_timeout(pfd->reg, val, val & pfd->vld_bit, + 0, LOCK_TIMEOUT_US); +} + +static int clk_pfdv2_enable(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val &= ~pfd->gate_bit; + writel_relaxed(val, pfd->reg); + spin_unlock_irqrestore(_lock, flags); + + return clk_pfdv2_wait(pfd); +} + +static void clk_pfdv2_disable(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val |= pfd->gate_bit; + writel_relaxed(val, pfd->reg); + spin_unlock_irqrestore(_lock, flags); +} + +static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + u64 tmp = parent_rate; + u8 frac; + + frac = (readl_relaxed(pfd->reg) >> pfd->frac_off) + & CLK_PFDV2_FRAC_MASK; + + if (!frac) { + pr_debug("clk_pfdv2: %s invalid pfd frac value 0\n", +clk_hw_get_name(hw)); + return 0; + } + + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static long clk_pfdv2_round_rate(struct clk_hw *hw, unsigned long rate, +unsigned long *prate) +{ + u64 tmp = *prate; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + tmp = *prate; + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static int clk_pfdv2_is_enabled(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + + if (readl_relaxed(pfd->reg) & pfd->gate_bit) + return 0; + + return 1; +} + +static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u64 tmp = parent_rate; + u32 val; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val &= ~(CLK_PFDV2_FRAC_MASK <<
[PATCH V5 7/9] clk: imx: make mux parent strings const
As the commit 2893c379461a ("clk: make strings in parent name arrays const"), let's make the parent strings const, otherwise we may meet the following warning when compiling: drivers/clk/imx/clk-imx7ulp.c: In function 'imx7ulp_clocks_init': drivers/clk/imx/clk-imx7ulp.c:73:35: warning: passing argument 5 of 'imx_clk_mux_flags' discards 'const' qualifier from pointer target type clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); ^ In file included from drivers/clk/imx/clk-imx7ulp.c:23:0: drivers/clk/imx/clk.h:200:27: note: expected 'const char **' but argument is of type 'const char * const*' ... Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Signed-off-by: Dong Aisheng --- ChangeLog: v1->v4: no changes --- drivers/clk/imx/clk-busy.c | 2 +- drivers/clk/imx/clk-fixup-mux.c | 2 +- drivers/clk/imx/clk.h | 18 +++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/clk/imx/clk-busy.c b/drivers/clk/imx/clk-busy.c index 9903652..e695622 100644 --- a/drivers/clk/imx/clk-busy.c +++ b/drivers/clk/imx/clk-busy.c @@ -154,7 +154,7 @@ static const struct clk_ops clk_busy_mux_ops = { struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, -const char **parent_names, int num_parents) +const char * const *parent_names, int num_parents) { struct clk_busy_mux *busy; struct clk *clk; diff --git a/drivers/clk/imx/clk-fixup-mux.c b/drivers/clk/imx/clk-fixup-mux.c index c9b327e..44817c1 100644 --- a/drivers/clk/imx/clk-fixup-mux.c +++ b/drivers/clk/imx/clk-fixup-mux.c @@ -70,7 +70,7 @@ static const struct clk_ops clk_fixup_mux_ops = { }; struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, + u8 shift, u8 width, const char * const *parents, int num_parents, void (*fixup)(u32 *val)) { struct clk_fixup_mux *fixup_mux; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 55a6434..290d4b2 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -69,7 +69,7 @@ struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, -const char **parent_names, int num_parents); +const char * const *parent_names, int num_parents); struct clk_hw *imx7ulp_clk_composite(const char *name, const char * const *parent_names, @@ -82,7 +82,7 @@ struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void (*fixup)(u32 *val)); struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, + u8 shift, u8 width, const char * const *parents, int num_parents, void (*fixup)(u32 *val)); static inline struct clk *imx_clk_fixed(const char *name, int rate) @@ -91,7 +91,8 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) } static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg, @@ -204,7 +205,8 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent, } static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT, reg, shift, @@ -212,7 +214,8 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, } static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE, @@ -220,8
[PATCH V5 6/9] dt-bindings: clock: add imx7ulp clock binding doc
i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks Note IMX7ULP has two clock domains: M4 and A7. This binding doc is only for A7 clock domain. Cc: Rob Herring Cc: Mark Rutland Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v4->v5: * fix a typo that clock-name -> clock-names * one compatible string per line * add input clocks for pcc2/3 v3->v4: * make scg, pcc separate nodes according to Rob's suggestion v2->v3: * no changes v1->v2: no changes --- .../devicetree/bindings/clock/imx7ulp-clock.txt| 104 include/dt-bindings/clock/imx7ulp-clock.h | 109 + 2 files changed, 213 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt new file mode 100644 index 000..a4f8cd4 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt @@ -0,0 +1,104 @@ +* Clock bindings for Freescale i.MX7ULP + +i.MX7ULP Clock functions are under joint control of the System +Clock Generation (SCG) modules, Peripheral Clock Control (PCC) +modules, and Core Mode Controller (CMC)1 blocks + +The clocking scheme provides clear separation between M4 domain +and A7 domain. Except for a few clock sources shared between two +domains, such as the System Oscillator clock, the Slow IRC (SIRC), +and and the Fast IRC clock (FIRCLK), clock sources and clock +management are separated and contained within each domain. + +M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. +A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. + +Note: this binding doc is only for A7 clock domain. + +System Clock Generation (SCG) modules: +- +The System Clock Generation (SCG) is responsible for clock generation +and distribution across this device. Functions performed by the SCG +include: clock reference selection, generation of clock used to derive +processor, system, peripheral bus and external memory interface clocks, +source selection for peripheral clocks and control of power saving +clock gating mode. + +Required properties: + +- compatible: Should be "fsl,imx7ulp-scg1". +- reg :Should contain registers location and length. +- #clock-cells:Should be <1>. +- clocks: Should contain the fixed input clocks. +- clock-names: Should contain the following clock names: + "rosc", "sosc", "sirc", "firc", "upll", "mpll". + +Peripheral Clock Control (PCC) modules: +- +The Peripheral Clock Control (PCC) is responsible for clock selection, +optional division and clock gating mode for peripherals in their +respected power domain + +Required properties: +- compatible: Should be one of: + "fsl,imx7ulp-pcc2", + "fsl,imx7ulp-pcc3". +- reg :Should contain registers location and length. +- #clock-cells:Should be <1>. +- clocks: Should contain the fixed input clocks. +- clock-names: Should contain the following clock names: + "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", + "apll_pfd1", "apll_pfd0", "upll", "sosc_bus_clk", + "mpll", "firc_bus_clk", "rosc", "spll_bus_clk"; + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. +See include/dt-bindings/clock/imx7ulp-clock.h +for the full list of i.MX7ULP clock IDs of each module. + +Examples: + +#include + +scg1: scg1@403e { + compatible = "fsl,imx7ulp-scg1; + reg = <0x403e 0x1>; + clocks = <>, <>, <>, +<>, <>, <>; + clock-names = "rosc", "sosc", "sirc", + "firc", "upll", "mpll"; + #clock-cells = <1>; +}; + +pcc2: pcc2@403f { + compatible = "fsl,imx7ulp-pcc2"; + reg = <0x403f 0x1>; + #clock-cells = <1>; + clocks = < IMX7ULP_CLK_NIC1_BUS_DIV>, +< IMX7ULP_CLK_NIC1_DIV>, +< IMX7ULP_CLK_DDR_DIV>, +< IMX7ULP_CLK_APLL_PFD2>, +< IMX7ULP_CLK_APLL_PFD1>, +< IMX7ULP_CLK_APLL_PFD0>, +< IMX7ULP_CLK_UPLL>, +< IMX7ULP_CLK_SOSC_BUS_CLK>, +< IMX7ULP_CLK_MIPI_PLL>, +< IMX7ULP_CLK_FIRC_BUS_CLK>, +< IMX7ULP_CLK_ROSC>, +< IMX7ULP_CLK_SPLL_BUS_CLK>; + clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk", + "apll_pfd2", "apll_pfd1", "apll_pfd0", + "upll",
[PATCH V5 9/9] clk: imx: add imx7ulp clk driver
i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks The clocking scheme provides clear separation between M4 domain and A7 domain. Except for a few clock sources shared between two domains, such as the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and clock management are separated and contained within each domain. M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. This driver only adds clock support in A7 domain. Note that most clocks required to be operated when gated, e.g. pll, pfd, pcc. And more special cases that scs/ddr/nic mux selecting different clock source requires that clock to be enabled first, then we need set CLK_OPS_PARENT_ENABLE flag for them properly. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v4->v5: * clk-composite API name changed accordingly v3->v4: * update after changing scg and pcc into separete nodes according to Rob's suggestion v2->v3: * no changes v1->v2: * use of_clk_add_hw_provider instead * split the clocks register process into two parts: early part for possible timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for the left normal peripheral clocks registered by a platform driver. --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx7ulp.c | 209 ++ 2 files changed, 210 insertions(+) create mode 100644 drivers/clk/imx/clk-imx7ulp.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index c44d3d4..98ec8ed 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -29,4 +29,5 @@ obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o +obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c new file mode 100644 index 000..6d2e3ef --- /dev/null +++ b/drivers/clk/imx/clk-imx7ulp.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static const char * const pll_pre_sels[] = { "sosc", "firc", }; +static const char * const spll_pfd_sels[] = { "spll_pfd0", "spll_pfd1", "spll_pfd2", "spll_pfd3", }; +static const char * const spll_sels[] = { "spll", "spll_pfd_sel", }; +static const char * const apll_pfd_sels[] = { "apll_pfd0", "apll_pfd1", "apll_pfd2", "apll_pfd3", }; +static const char * const apll_sels[] = { "apll", "apll_pfd_sel", }; +static const char * const scs_sels[] = { "dummy", "sosc", "sirc", "firc", "dummy", "apll_sel", "spll_sel", "upll", }; +static const char * const ddr_sels[] = { "apll_pfd_sel", "upll", }; +static const char * const nic_sels[] = { "firc", "ddr_clk", }; +static const char * const periph_plat_sels[] = { "dummy", "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", }; +static const char * const periph_bus_sels[]= { "dummy", "sosc_bus_clk", "mpll", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", }; + +static void __init imx7ulp_clk_scg1_init(struct device_node *np) +{ + struct clk_hw_onecell_data *clk_data; + struct clk_hw **clks; + void __iomem *base; + + clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) * + IMX7ULP_CLK_SCG1_END, GFP_KERNEL); + if (!clk_data) + return; + + clk_data->num = IMX7ULP_CLK_SCG1_END; + clks = clk_data->hws; + + clks[IMX7ULP_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0); + + clks[IMX7ULP_CLK_ROSC] = imx_obtain_fixed_clk_hw(np, "rosc"); + clks[IMX7ULP_CLK_SOSC] = imx_obtain_fixed_clk_hw(np, "sosc"); + clks[IMX7ULP_CLK_SIRC] = imx_obtain_fixed_clk_hw(np, "sirc"); + clks[IMX7ULP_CLK_FIRC] = imx_obtain_fixed_clk_hw(np, "firc"); + clks[IMX7ULP_CLK_MIPI_PLL] = imx_obtain_fixed_clk_hw(np, "mpll"); + clks[IMX7ULP_CLK_UPLL] = imx_obtain_fixed_clk_hw(np, "upll"); + + /* SCG1 */ + base = of_iomap(np, 0); + WARN_ON(!base); + + /* NOTE: xPLL config can't be changed when xPLL is enabled */ + clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_hw_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); + clks[IMX7ULP_CLK_SPLL_PRE_SEL]
[PATCH V5 5/9] clk: imx: add imx7ulp composite clk support
The imx composite clk is designed for Peripheral Clock Control (PCC) module observed in IMX ULP SoC series. NOTE pcc can only be operated when clk is gated. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v4->v5: * rename to clk-composite-7ulp.c as we have another clk-composite-8m.c, function name also changed accordingly v3->v4: * no changes v2->v3: * no changes v1->v2: * remove an unneeded blank line change * use clk_hw_register --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-composite-7ulp.c | 85 drivers/clk/imx/clk.h| 6 +++ 3 files changed, 92 insertions(+) create mode 100644 drivers/clk/imx/clk-composite-7ulp.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index e5b0d42..c44d3d4 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -4,6 +4,7 @@ obj-y += \ clk.o \ clk-busy.o \ clk-cpu.o \ + clk-composite-7ulp.o \ clk-fixup-div.o \ clk-fixup-mux.o \ clk-gate-exclusive.o \ diff --git a/drivers/clk/imx/clk-composite-7ulp.c b/drivers/clk/imx/clk-composite-7ulp.c new file mode 100644 index 000..22f679c --- /dev/null +++ b/drivers/clk/imx/clk-composite-7ulp.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + */ + +#include +#include +#include + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 +#define PCG_CGC_SHIFT 30 +#define PCG_FRAC_SHIFT 3 +#define PCG_FRAC_WIDTH 1 +#define PCG_FRAC_MASK BIT(3) +#define PCG_PCD_SHIFT 0 +#define PCG_PCD_WIDTH 3 +#define PCG_PCD_MASK 0x7 + +struct clk_hw *imx7ulp_clk_composite(const char *name, +const char * const *parent_names, +int num_parents, bool mux_present, +bool rate_present, bool gate_present, +void __iomem *reg) +{ + struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL; + struct clk_fractional_divider *fd = NULL; + struct clk_gate *gate = NULL; + struct clk_mux *mux = NULL; + struct clk_hw *hw; + + if (mux_present) { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + mux_hw = >hw; + mux->reg = reg; + mux->shift = PCG_PCS_SHIFT; + mux->mask = PCG_PCS_MASK; + } + + if (rate_present) { + fd = kzalloc(sizeof(*fd), GFP_KERNEL); + if (!fd) { + kfree(mux); + return ERR_PTR(-ENOMEM); + } + fd_hw = >hw; + fd->reg = reg; + fd->mshift = PCG_FRAC_SHIFT; + fd->mwidth = PCG_FRAC_WIDTH; + fd->mmask = PCG_FRAC_MASK; + fd->nshift = PCG_PCD_SHIFT; + fd->nwidth = PCG_PCD_WIDTH; + fd->nmask = PCG_PCD_MASK; + fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED; + } + + if (gate_present) { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + kfree(mux); + kfree(fd); + return ERR_PTR(-ENOMEM); + } + gate_hw = >hw; + gate->reg = reg; + gate->bit_idx = PCG_CGC_SHIFT; + } + + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux_hw, _mux_ops, fd_hw, + _fractional_divider_ops, gate_hw, + _gate_ops, CLK_SET_RATE_GATE | + CLK_SET_PARENT_GATE); + if (IS_ERR(hw)) { + kfree(mux); + kfree(fd); + kfree(gate); + } + + return hw; +} diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index a5a9374..55a6434 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -71,6 +71,12 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, const char **parent_names, int num_parents); +struct clk_hw *imx7ulp_clk_composite(const char *name, +const char * const *parent_names, +int num_parents, bool mux_present, +bool rate_present, bool gate_present, +void __iomem *reg); + struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width,
[PATCH V5 9/9] clk: imx: add imx7ulp clk driver
i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks The clocking scheme provides clear separation between M4 domain and A7 domain. Except for a few clock sources shared between two domains, such as the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and clock management are separated and contained within each domain. M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. This driver only adds clock support in A7 domain. Note that most clocks required to be operated when gated, e.g. pll, pfd, pcc. And more special cases that scs/ddr/nic mux selecting different clock source requires that clock to be enabled first, then we need set CLK_OPS_PARENT_ENABLE flag for them properly. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v4->v5: * clk-composite API name changed accordingly v3->v4: * update after changing scg and pcc into separete nodes according to Rob's suggestion v2->v3: * no changes v1->v2: * use of_clk_add_hw_provider instead * split the clocks register process into two parts: early part for possible timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for the left normal peripheral clocks registered by a platform driver. --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx7ulp.c | 209 ++ 2 files changed, 210 insertions(+) create mode 100644 drivers/clk/imx/clk-imx7ulp.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index c44d3d4..98ec8ed 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -29,4 +29,5 @@ obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o +obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c new file mode 100644 index 000..6d2e3ef --- /dev/null +++ b/drivers/clk/imx/clk-imx7ulp.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static const char * const pll_pre_sels[] = { "sosc", "firc", }; +static const char * const spll_pfd_sels[] = { "spll_pfd0", "spll_pfd1", "spll_pfd2", "spll_pfd3", }; +static const char * const spll_sels[] = { "spll", "spll_pfd_sel", }; +static const char * const apll_pfd_sels[] = { "apll_pfd0", "apll_pfd1", "apll_pfd2", "apll_pfd3", }; +static const char * const apll_sels[] = { "apll", "apll_pfd_sel", }; +static const char * const scs_sels[] = { "dummy", "sosc", "sirc", "firc", "dummy", "apll_sel", "spll_sel", "upll", }; +static const char * const ddr_sels[] = { "apll_pfd_sel", "upll", }; +static const char * const nic_sels[] = { "firc", "ddr_clk", }; +static const char * const periph_plat_sels[] = { "dummy", "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", }; +static const char * const periph_bus_sels[]= { "dummy", "sosc_bus_clk", "mpll", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", }; + +static void __init imx7ulp_clk_scg1_init(struct device_node *np) +{ + struct clk_hw_onecell_data *clk_data; + struct clk_hw **clks; + void __iomem *base; + + clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) * + IMX7ULP_CLK_SCG1_END, GFP_KERNEL); + if (!clk_data) + return; + + clk_data->num = IMX7ULP_CLK_SCG1_END; + clks = clk_data->hws; + + clks[IMX7ULP_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0); + + clks[IMX7ULP_CLK_ROSC] = imx_obtain_fixed_clk_hw(np, "rosc"); + clks[IMX7ULP_CLK_SOSC] = imx_obtain_fixed_clk_hw(np, "sosc"); + clks[IMX7ULP_CLK_SIRC] = imx_obtain_fixed_clk_hw(np, "sirc"); + clks[IMX7ULP_CLK_FIRC] = imx_obtain_fixed_clk_hw(np, "firc"); + clks[IMX7ULP_CLK_MIPI_PLL] = imx_obtain_fixed_clk_hw(np, "mpll"); + clks[IMX7ULP_CLK_UPLL] = imx_obtain_fixed_clk_hw(np, "upll"); + + /* SCG1 */ + base = of_iomap(np, 0); + WARN_ON(!base); + + /* NOTE: xPLL config can't be changed when xPLL is enabled */ + clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_hw_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); + clks[IMX7ULP_CLK_SPLL_PRE_SEL]
[PATCH V5 5/9] clk: imx: add imx7ulp composite clk support
The imx composite clk is designed for Peripheral Clock Control (PCC) module observed in IMX ULP SoC series. NOTE pcc can only be operated when clk is gated. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v4->v5: * rename to clk-composite-7ulp.c as we have another clk-composite-8m.c, function name also changed accordingly v3->v4: * no changes v2->v3: * no changes v1->v2: * remove an unneeded blank line change * use clk_hw_register --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-composite-7ulp.c | 85 drivers/clk/imx/clk.h| 6 +++ 3 files changed, 92 insertions(+) create mode 100644 drivers/clk/imx/clk-composite-7ulp.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index e5b0d42..c44d3d4 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -4,6 +4,7 @@ obj-y += \ clk.o \ clk-busy.o \ clk-cpu.o \ + clk-composite-7ulp.o \ clk-fixup-div.o \ clk-fixup-mux.o \ clk-gate-exclusive.o \ diff --git a/drivers/clk/imx/clk-composite-7ulp.c b/drivers/clk/imx/clk-composite-7ulp.c new file mode 100644 index 000..22f679c --- /dev/null +++ b/drivers/clk/imx/clk-composite-7ulp.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + */ + +#include +#include +#include + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 +#define PCG_CGC_SHIFT 30 +#define PCG_FRAC_SHIFT 3 +#define PCG_FRAC_WIDTH 1 +#define PCG_FRAC_MASK BIT(3) +#define PCG_PCD_SHIFT 0 +#define PCG_PCD_WIDTH 3 +#define PCG_PCD_MASK 0x7 + +struct clk_hw *imx7ulp_clk_composite(const char *name, +const char * const *parent_names, +int num_parents, bool mux_present, +bool rate_present, bool gate_present, +void __iomem *reg) +{ + struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL; + struct clk_fractional_divider *fd = NULL; + struct clk_gate *gate = NULL; + struct clk_mux *mux = NULL; + struct clk_hw *hw; + + if (mux_present) { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + mux_hw = >hw; + mux->reg = reg; + mux->shift = PCG_PCS_SHIFT; + mux->mask = PCG_PCS_MASK; + } + + if (rate_present) { + fd = kzalloc(sizeof(*fd), GFP_KERNEL); + if (!fd) { + kfree(mux); + return ERR_PTR(-ENOMEM); + } + fd_hw = >hw; + fd->reg = reg; + fd->mshift = PCG_FRAC_SHIFT; + fd->mwidth = PCG_FRAC_WIDTH; + fd->mmask = PCG_FRAC_MASK; + fd->nshift = PCG_PCD_SHIFT; + fd->nwidth = PCG_PCD_WIDTH; + fd->nmask = PCG_PCD_MASK; + fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED; + } + + if (gate_present) { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + kfree(mux); + kfree(fd); + return ERR_PTR(-ENOMEM); + } + gate_hw = >hw; + gate->reg = reg; + gate->bit_idx = PCG_CGC_SHIFT; + } + + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux_hw, _mux_ops, fd_hw, + _fractional_divider_ops, gate_hw, + _gate_ops, CLK_SET_RATE_GATE | + CLK_SET_PARENT_GATE); + if (IS_ERR(hw)) { + kfree(mux); + kfree(fd); + kfree(gate); + } + + return hw; +} diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index a5a9374..55a6434 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -71,6 +71,12 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, const char **parent_names, int num_parents); +struct clk_hw *imx7ulp_clk_composite(const char *name, +const char * const *parent_names, +int num_parents, bool mux_present, +bool rate_present, bool gate_present, +void __iomem *reg); + struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width,
[PATCH V5 7/9] clk: imx: make mux parent strings const
As the commit 2893c379461a ("clk: make strings in parent name arrays const"), let's make the parent strings const, otherwise we may meet the following warning when compiling: drivers/clk/imx/clk-imx7ulp.c: In function 'imx7ulp_clocks_init': drivers/clk/imx/clk-imx7ulp.c:73:35: warning: passing argument 5 of 'imx_clk_mux_flags' discards 'const' qualifier from pointer target type clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); ^ In file included from drivers/clk/imx/clk-imx7ulp.c:23:0: drivers/clk/imx/clk.h:200:27: note: expected 'const char **' but argument is of type 'const char * const*' ... Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Signed-off-by: Dong Aisheng --- ChangeLog: v1->v4: no changes --- drivers/clk/imx/clk-busy.c | 2 +- drivers/clk/imx/clk-fixup-mux.c | 2 +- drivers/clk/imx/clk.h | 18 +++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/clk/imx/clk-busy.c b/drivers/clk/imx/clk-busy.c index 9903652..e695622 100644 --- a/drivers/clk/imx/clk-busy.c +++ b/drivers/clk/imx/clk-busy.c @@ -154,7 +154,7 @@ static const struct clk_ops clk_busy_mux_ops = { struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, -const char **parent_names, int num_parents) +const char * const *parent_names, int num_parents) { struct clk_busy_mux *busy; struct clk *clk; diff --git a/drivers/clk/imx/clk-fixup-mux.c b/drivers/clk/imx/clk-fixup-mux.c index c9b327e..44817c1 100644 --- a/drivers/clk/imx/clk-fixup-mux.c +++ b/drivers/clk/imx/clk-fixup-mux.c @@ -70,7 +70,7 @@ static const struct clk_ops clk_fixup_mux_ops = { }; struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, + u8 shift, u8 width, const char * const *parents, int num_parents, void (*fixup)(u32 *val)) { struct clk_fixup_mux *fixup_mux; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 55a6434..290d4b2 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -69,7 +69,7 @@ struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, -const char **parent_names, int num_parents); +const char * const *parent_names, int num_parents); struct clk_hw *imx7ulp_clk_composite(const char *name, const char * const *parent_names, @@ -82,7 +82,7 @@ struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void (*fixup)(u32 *val)); struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, + u8 shift, u8 width, const char * const *parents, int num_parents, void (*fixup)(u32 *val)); static inline struct clk *imx_clk_fixed(const char *name, int rate) @@ -91,7 +91,8 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) } static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg, @@ -204,7 +205,8 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent, } static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT, reg, shift, @@ -212,7 +214,8 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, } static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE, @@ -220,8
[PATCH V5 6/9] dt-bindings: clock: add imx7ulp clock binding doc
i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks Note IMX7ULP has two clock domains: M4 and A7. This binding doc is only for A7 clock domain. Cc: Rob Herring Cc: Mark Rutland Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v4->v5: * fix a typo that clock-name -> clock-names * one compatible string per line * add input clocks for pcc2/3 v3->v4: * make scg, pcc separate nodes according to Rob's suggestion v2->v3: * no changes v1->v2: no changes --- .../devicetree/bindings/clock/imx7ulp-clock.txt| 104 include/dt-bindings/clock/imx7ulp-clock.h | 109 + 2 files changed, 213 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt new file mode 100644 index 000..a4f8cd4 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt @@ -0,0 +1,104 @@ +* Clock bindings for Freescale i.MX7ULP + +i.MX7ULP Clock functions are under joint control of the System +Clock Generation (SCG) modules, Peripheral Clock Control (PCC) +modules, and Core Mode Controller (CMC)1 blocks + +The clocking scheme provides clear separation between M4 domain +and A7 domain. Except for a few clock sources shared between two +domains, such as the System Oscillator clock, the Slow IRC (SIRC), +and and the Fast IRC clock (FIRCLK), clock sources and clock +management are separated and contained within each domain. + +M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. +A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. + +Note: this binding doc is only for A7 clock domain. + +System Clock Generation (SCG) modules: +- +The System Clock Generation (SCG) is responsible for clock generation +and distribution across this device. Functions performed by the SCG +include: clock reference selection, generation of clock used to derive +processor, system, peripheral bus and external memory interface clocks, +source selection for peripheral clocks and control of power saving +clock gating mode. + +Required properties: + +- compatible: Should be "fsl,imx7ulp-scg1". +- reg :Should contain registers location and length. +- #clock-cells:Should be <1>. +- clocks: Should contain the fixed input clocks. +- clock-names: Should contain the following clock names: + "rosc", "sosc", "sirc", "firc", "upll", "mpll". + +Peripheral Clock Control (PCC) modules: +- +The Peripheral Clock Control (PCC) is responsible for clock selection, +optional division and clock gating mode for peripherals in their +respected power domain + +Required properties: +- compatible: Should be one of: + "fsl,imx7ulp-pcc2", + "fsl,imx7ulp-pcc3". +- reg :Should contain registers location and length. +- #clock-cells:Should be <1>. +- clocks: Should contain the fixed input clocks. +- clock-names: Should contain the following clock names: + "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", + "apll_pfd1", "apll_pfd0", "upll", "sosc_bus_clk", + "mpll", "firc_bus_clk", "rosc", "spll_bus_clk"; + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. +See include/dt-bindings/clock/imx7ulp-clock.h +for the full list of i.MX7ULP clock IDs of each module. + +Examples: + +#include + +scg1: scg1@403e { + compatible = "fsl,imx7ulp-scg1; + reg = <0x403e 0x1>; + clocks = <>, <>, <>, +<>, <>, <>; + clock-names = "rosc", "sosc", "sirc", + "firc", "upll", "mpll"; + #clock-cells = <1>; +}; + +pcc2: pcc2@403f { + compatible = "fsl,imx7ulp-pcc2"; + reg = <0x403f 0x1>; + #clock-cells = <1>; + clocks = < IMX7ULP_CLK_NIC1_BUS_DIV>, +< IMX7ULP_CLK_NIC1_DIV>, +< IMX7ULP_CLK_DDR_DIV>, +< IMX7ULP_CLK_APLL_PFD2>, +< IMX7ULP_CLK_APLL_PFD1>, +< IMX7ULP_CLK_APLL_PFD0>, +< IMX7ULP_CLK_UPLL>, +< IMX7ULP_CLK_SOSC_BUS_CLK>, +< IMX7ULP_CLK_MIPI_PLL>, +< IMX7ULP_CLK_FIRC_BUS_CLK>, +< IMX7ULP_CLK_ROSC>, +< IMX7ULP_CLK_SPLL_BUS_CLK>; + clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk", + "apll_pfd2", "apll_pfd1", "apll_pfd0", + "upll",
[PATCH V5 1/9] clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support
For dividers with zero indicating clock is disabled, instead of giving a warning each time like "clkx: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set" in exist code, we'd like to introduce enable/disable function for it. e.g. 000b - Clock disabled 001b - Divide by 1 010b - Divide by 2 ... Set rate when the clk is disabled will cache the rate request and only when the clk is enabled will the driver actually program the hardware to have the requested divider value. Similarly, when the clk is disabled we'll write a 0 there, but when the clk is enabled we'll restore whatever rate (divider) was chosen last. It does mean that recalc rate will be sort of odd, because when the clk is off it will return 0, and when the clk is on it will return the right rate. So to make things work, we'll need to return the cached rate in recalc rate when the clk is off and read the hardware when the clk is on. NOTE for the default off divider, the recalc rate will still return 0 as there's still no proper preset rate. Enable such divider will give user a reminder error message. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * split normal and gate ops * fix the possible racy v1->v2: * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers --- drivers/clk/clk-divider.c| 152 +++ include/linux/clk-provider.h | 9 +++ 2 files changed, 161 insertions(+) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index b6234a5..b3566fd 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -122,6 +122,9 @@ unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, div = _get_div(table, val, flags, width); if (!div) { + if (flags & CLK_DIVIDER_ZERO_GATE) + return 0; + WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", clk_hw_get_name(hw)); @@ -145,6 +148,34 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, divider->flags, divider->width); } +static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + unsigned int val; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + if (!clk_hw_is_enabled(hw)) { + val = divider->cached_val; + } else { + val = clk_readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + } + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + + return divider_recalc_rate(hw, parent_rate, val, divider->table, + divider->flags, divider->width); +} + static bool _is_valid_table_div(const struct clk_div_table *table, unsigned int div) { @@ -437,6 +468,108 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +static int clk_divider_gate_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + int value; + u32 val; + + value = divider_get_val(rate, parent_rate, divider->table, + divider->width, divider->flags); + if (value < 0) + return value; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + if (clk_hw_is_enabled(hw)) { + if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { + val = clk_div_mask(divider->width) << (divider->shift + 16); + } else { + val = clk_readl(divider->reg); + val &= ~(clk_div_mask(divider->width) << divider->shift); + } + val |= (u32)value << divider->shift; + clk_writel(val, divider->reg); + } else { + divider->cached_val = value; + } + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + + return 0; +} + +static int clk_divider_enable(struct clk_hw *hw) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + u32 val; + + if (!divider->cached_val) { + pr_err("%s: no valid
[PATCH V5 0/9] clk: add imx7ulp clk support
This patch series intends to add imx7ulp clk support. i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks The clocking scheme provides clear separation between M4 domain and A7 domain. Except for a few clock sources shared between two domains, such as the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and clock management are separated and contained within each domain. M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. Note: this series only adds A7 clock domain support as M4 clock domain will be handled by M4 seperately. Change Log: v4->v5: * rename to clk-composite-7ulp.c as we have another clk-composite-8m.c, function name also changed accordingly * binding doc updated with adding input clocks for PCC module v3->v4: * update after changing scg and pcc into separete nodes according to Rob's suggestion v2->v3: * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible racy Others no changes. v1->v2: * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers * use clk_hw apis to register clocks * use of_clk_add_hw_provider * split the clocks register process into two parts: early part for possible timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for the left normal peripheral clocks registered by a platform driver. Dong Aisheng (9): clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support clk: imx: add pllv4 support clk: imx: add pfdv2 support clk: imx: add imx7ulp composite clk support dt-bindings: clock: add imx7ulp clock binding doc clk: imx: make mux parent strings const clk: imx: implement new clk_hw based APIs clk: imx: add imx7ulp clk driver .../devicetree/bindings/clock/imx7ulp-clock.txt| 104 ++ drivers/clk/clk-divider.c | 152 +++ drivers/clk/clk-fractional-divider.c | 10 + drivers/clk/imx/Makefile | 6 +- drivers/clk/imx/clk-busy.c | 2 +- drivers/clk/imx/clk-composite-7ulp.c | 85 + drivers/clk/imx/clk-fixup-mux.c| 2 +- drivers/clk/imx/clk-imx7ulp.c | 209 + drivers/clk/imx/clk-pfdv2.c| 201 drivers/clk/imx/clk-pllv4.c| 182 ++ drivers/clk/imx/clk.c | 22 +++ drivers/clk/imx/clk.h | 92 - include/dt-bindings/clock/imx7ulp-clock.h | 109 +++ include/linux/clk-provider.h | 17 ++ 14 files changed, 1183 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt create mode 100644 drivers/clk/imx/clk-composite-7ulp.c create mode 100644 drivers/clk/imx/clk-imx7ulp.c create mode 100644 drivers/clk/imx/clk-pfdv2.c create mode 100644 drivers/clk/imx/clk-pllv4.c create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h -- 2.7.4
[PATCH V5 1/9] clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support
For dividers with zero indicating clock is disabled, instead of giving a warning each time like "clkx: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set" in exist code, we'd like to introduce enable/disable function for it. e.g. 000b - Clock disabled 001b - Divide by 1 010b - Divide by 2 ... Set rate when the clk is disabled will cache the rate request and only when the clk is enabled will the driver actually program the hardware to have the requested divider value. Similarly, when the clk is disabled we'll write a 0 there, but when the clk is enabled we'll restore whatever rate (divider) was chosen last. It does mean that recalc rate will be sort of odd, because when the clk is off it will return 0, and when the clk is on it will return the right rate. So to make things work, we'll need to return the cached rate in recalc rate when the clk is off and read the hardware when the clk is on. NOTE for the default off divider, the recalc rate will still return 0 as there's still no proper preset rate. Enable such divider will give user a reminder error message. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * split normal and gate ops * fix the possible racy v1->v2: * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers --- drivers/clk/clk-divider.c| 152 +++ include/linux/clk-provider.h | 9 +++ 2 files changed, 161 insertions(+) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index b6234a5..b3566fd 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -122,6 +122,9 @@ unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, div = _get_div(table, val, flags, width); if (!div) { + if (flags & CLK_DIVIDER_ZERO_GATE) + return 0; + WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", clk_hw_get_name(hw)); @@ -145,6 +148,34 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, divider->flags, divider->width); } +static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + unsigned int val; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + if (!clk_hw_is_enabled(hw)) { + val = divider->cached_val; + } else { + val = clk_readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + } + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + + return divider_recalc_rate(hw, parent_rate, val, divider->table, + divider->flags, divider->width); +} + static bool _is_valid_table_div(const struct clk_div_table *table, unsigned int div) { @@ -437,6 +468,108 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +static int clk_divider_gate_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + int value; + u32 val; + + value = divider_get_val(rate, parent_rate, divider->table, + divider->width, divider->flags); + if (value < 0) + return value; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + if (clk_hw_is_enabled(hw)) { + if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { + val = clk_div_mask(divider->width) << (divider->shift + 16); + } else { + val = clk_readl(divider->reg); + val &= ~(clk_div_mask(divider->width) << divider->shift); + } + val |= (u32)value << divider->shift; + clk_writel(val, divider->reg); + } else { + divider->cached_val = value; + } + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + + return 0; +} + +static int clk_divider_enable(struct clk_hw *hw) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + u32 val; + + if (!divider->cached_val) { + pr_err("%s: no valid
[PATCH V5 0/9] clk: add imx7ulp clk support
This patch series intends to add imx7ulp clk support. i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks The clocking scheme provides clear separation between M4 domain and A7 domain. Except for a few clock sources shared between two domains, such as the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and clock management are separated and contained within each domain. M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. Note: this series only adds A7 clock domain support as M4 clock domain will be handled by M4 seperately. Change Log: v4->v5: * rename to clk-composite-7ulp.c as we have another clk-composite-8m.c, function name also changed accordingly * binding doc updated with adding input clocks for PCC module v3->v4: * update after changing scg and pcc into separete nodes according to Rob's suggestion v2->v3: * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible racy Others no changes. v1->v2: * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers * use clk_hw apis to register clocks * use of_clk_add_hw_provider * split the clocks register process into two parts: early part for possible timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for the left normal peripheral clocks registered by a platform driver. Dong Aisheng (9): clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support clk: imx: add pllv4 support clk: imx: add pfdv2 support clk: imx: add imx7ulp composite clk support dt-bindings: clock: add imx7ulp clock binding doc clk: imx: make mux parent strings const clk: imx: implement new clk_hw based APIs clk: imx: add imx7ulp clk driver .../devicetree/bindings/clock/imx7ulp-clock.txt| 104 ++ drivers/clk/clk-divider.c | 152 +++ drivers/clk/clk-fractional-divider.c | 10 + drivers/clk/imx/Makefile | 6 +- drivers/clk/imx/clk-busy.c | 2 +- drivers/clk/imx/clk-composite-7ulp.c | 85 + drivers/clk/imx/clk-fixup-mux.c| 2 +- drivers/clk/imx/clk-imx7ulp.c | 209 + drivers/clk/imx/clk-pfdv2.c| 201 drivers/clk/imx/clk-pllv4.c| 182 ++ drivers/clk/imx/clk.c | 22 +++ drivers/clk/imx/clk.h | 92 - include/dt-bindings/clock/imx7ulp-clock.h | 109 +++ include/linux/clk-provider.h | 17 ++ 14 files changed, 1183 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt create mode 100644 drivers/clk/imx/clk-composite-7ulp.c create mode 100644 drivers/clk/imx/clk-imx7ulp.c create mode 100644 drivers/clk/imx/clk-pfdv2.c create mode 100644 drivers/clk/imx/clk-pllv4.c create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h -- 2.7.4
RE: [PATCH RESEND V4 0/9] clk: add imx7ulp clk support
> -Original Message- > From: Leonard Crestez > Sent: Tuesday, November 6, 2018 11:34 PM [...] > > On Tue, 2018-11-06 at 15:30 +, A.s. Dong wrote: > > Gently Ping... > > > drivers/clk/imx/clk-composite.c| 85 + > > During review for 8m clocks a separate but different composite clk was added. > In order to avoid confusion that was named "clk-composite-8m.c", it would > make sense to move the 7ulp code to clk-composite-7ulp.c. > I guess we can do it, thanks. Regards Dong Aisheng > -- > Regards, > Leonard
RE: [PATCH RESEND V4 0/9] clk: add imx7ulp clk support
> -Original Message- > From: Leonard Crestez > Sent: Tuesday, November 6, 2018 11:34 PM [...] > > On Tue, 2018-11-06 at 15:30 +, A.s. Dong wrote: > > Gently Ping... > > > drivers/clk/imx/clk-composite.c| 85 + > > During review for 8m clocks a separate but different composite clk was added. > In order to avoid confusion that was named "clk-composite-8m.c", it would > make sense to move the 7ulp code to clk-composite-7ulp.c. > I guess we can do it, thanks. Regards Dong Aisheng > -- > Regards, > Leonard
RE: [PATCH RESEND V4 0/9] clk: add imx7ulp clk support
Gently Ping... > -Original Message- > From: A.s. Dong > Sent: Sunday, October 21, 2018 9:15 PM > To: sb...@kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > mturque...@baylibre.com; shawn...@kernel.org; Anson Huang > ; Jacky Bai ; dl-linux-imx > ; linux-...@vger.kernel.org > Subject: RE: [PATCH RESEND V4 0/9] clk: add imx7ulp clk support > > Hi Stephen, > > In case you might miss to queue this series into your review list, so I > resend this > series again. > This series actually has been pending for a couple of months without > comments. > Hopefully you could help find some time to handle it when you're free. > > Thanks > > Regards > Dong Aisheng > > > -Original Message- > > From: A.s. Dong > > Sent: Sunday, October 21, 2018 9:11 PM > > To: linux-...@vger.kernel.org > > Cc: linux-kernel@vger.kernel.org; > > linux-arm-ker...@lists.infradead.org; > > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > Anson > > Huang ; Jacky Bai ; > > dl-linux-imx ; A.s. Dong > > Subject: [PATCH RESEND V4 0/9] clk: add imx7ulp clk support > > > > This is a rebased version of below patch series against latest clk tree. > > [PATCH RESEND V3 0/9] clk: add imx7ulp clk support > > https://lkml.org/lkml/2018/3/16/310 > > > > It only updates the license to SPDX format as well as a minor fix of pllv4. > > > > This patch series intends to add imx7ulp clk support. > > > > i.MX7ULP Clock functions are under joint control of the System Clock > > Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and > > Core Mode Controller (CMC)1 blocks > > > > The clocking scheme provides clear separation between M4 domain and A7 > > domain. Except for a few clock sources shared between two domains, > > such as the System Oscillator clock, the Slow IRC (SIRC), and and the > > Fast IRC clock (FIRCLK), clock sources and clock management are > > separated and contained within each domain. > > > > M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. > > A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. > > > > Note: this series only adds A7 clock domain support as M4 clock domain > > will be handled by M4 seperately. > > > > Change Log: > > v3->v4: > > * update after changing scg and pcc into separete nodes according to > >Rob's suggestion > > v2->v3: > > * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible racy > >Others no changes. > > > > v1->v2: > > * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers > > * use clk_hw apis to register clocks > > * use of_clk_add_hw_provider > > * split the clocks register process into two parts: early part for possible > >timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part > for > >the left normal peripheral clocks registered by a platform driver. > > > > Dong Aisheng (9): > > clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support > > clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support > > clk: imx: add pllv4 support > > clk: imx: add pfdv2 support > > clk: imx: add composite clk support > > dt-bindings: clock: add imx7ulp clock binding doc > > clk: imx: make mux parent strings const > > clk: imx: implement new clk_hw based APIs > > clk: imx: add imx7ulp clk driver > > > > .../devicetree/bindings/clock/imx7ulp-clock.txt| 87 + > > drivers/clk/clk-divider.c | 152 > > +++ > > drivers/clk/clk-fractional-divider.c | 10 + > > drivers/clk/imx/Makefile | 6 +- > > drivers/clk/imx/clk-busy.c | 2 +- > > drivers/clk/imx/clk-composite.c| 85 + > > drivers/clk/imx/clk-fixup-mux.c| 2 +- > > drivers/clk/imx/clk-imx7ulp.c | 209 > > + > > drivers/clk/imx/clk-pfdv2.c| 201 > > > > drivers/clk/imx/clk-pllv4.c| 182 > > ++ > > drivers/clk/imx/clk.c | 22 +++ > > drivers/clk/imx/clk.h | 92 - > > include/dt-bindings/clock/imx7ulp-clock.h | 109 +++ > > include/linux/clk-provider.h | 17 ++ > > 14 files changed, 1166 insertions(+), 10 deletions(-) create mode > > 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt > > create mode 100644 drivers/clk/imx/clk-composite.c create mode > > 100644 drivers/clk/imx/clk-imx7ulp.c create mode 100644 > > drivers/clk/imx/clk-pfdv2.c create mode 100644 > > drivers/clk/imx/clk-pllv4.c create mode 100644 > > include/dt-bindings/clock/imx7ulp-clock.h > > > > -- > > 2.7.4
RE: [PATCH RESEND V4 0/9] clk: add imx7ulp clk support
Gently Ping... > -Original Message- > From: A.s. Dong > Sent: Sunday, October 21, 2018 9:15 PM > To: sb...@kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > mturque...@baylibre.com; shawn...@kernel.org; Anson Huang > ; Jacky Bai ; dl-linux-imx > ; linux-...@vger.kernel.org > Subject: RE: [PATCH RESEND V4 0/9] clk: add imx7ulp clk support > > Hi Stephen, > > In case you might miss to queue this series into your review list, so I > resend this > series again. > This series actually has been pending for a couple of months without > comments. > Hopefully you could help find some time to handle it when you're free. > > Thanks > > Regards > Dong Aisheng > > > -Original Message- > > From: A.s. Dong > > Sent: Sunday, October 21, 2018 9:11 PM > > To: linux-...@vger.kernel.org > > Cc: linux-kernel@vger.kernel.org; > > linux-arm-ker...@lists.infradead.org; > > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > Anson > > Huang ; Jacky Bai ; > > dl-linux-imx ; A.s. Dong > > Subject: [PATCH RESEND V4 0/9] clk: add imx7ulp clk support > > > > This is a rebased version of below patch series against latest clk tree. > > [PATCH RESEND V3 0/9] clk: add imx7ulp clk support > > https://lkml.org/lkml/2018/3/16/310 > > > > It only updates the license to SPDX format as well as a minor fix of pllv4. > > > > This patch series intends to add imx7ulp clk support. > > > > i.MX7ULP Clock functions are under joint control of the System Clock > > Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and > > Core Mode Controller (CMC)1 blocks > > > > The clocking scheme provides clear separation between M4 domain and A7 > > domain. Except for a few clock sources shared between two domains, > > such as the System Oscillator clock, the Slow IRC (SIRC), and and the > > Fast IRC clock (FIRCLK), clock sources and clock management are > > separated and contained within each domain. > > > > M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. > > A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. > > > > Note: this series only adds A7 clock domain support as M4 clock domain > > will be handled by M4 seperately. > > > > Change Log: > > v3->v4: > > * update after changing scg and pcc into separete nodes according to > >Rob's suggestion > > v2->v3: > > * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible racy > >Others no changes. > > > > v1->v2: > > * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers > > * use clk_hw apis to register clocks > > * use of_clk_add_hw_provider > > * split the clocks register process into two parts: early part for possible > >timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part > for > >the left normal peripheral clocks registered by a platform driver. > > > > Dong Aisheng (9): > > clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support > > clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support > > clk: imx: add pllv4 support > > clk: imx: add pfdv2 support > > clk: imx: add composite clk support > > dt-bindings: clock: add imx7ulp clock binding doc > > clk: imx: make mux parent strings const > > clk: imx: implement new clk_hw based APIs > > clk: imx: add imx7ulp clk driver > > > > .../devicetree/bindings/clock/imx7ulp-clock.txt| 87 + > > drivers/clk/clk-divider.c | 152 > > +++ > > drivers/clk/clk-fractional-divider.c | 10 + > > drivers/clk/imx/Makefile | 6 +- > > drivers/clk/imx/clk-busy.c | 2 +- > > drivers/clk/imx/clk-composite.c| 85 + > > drivers/clk/imx/clk-fixup-mux.c| 2 +- > > drivers/clk/imx/clk-imx7ulp.c | 209 > > + > > drivers/clk/imx/clk-pfdv2.c| 201 > > > > drivers/clk/imx/clk-pllv4.c| 182 > > ++ > > drivers/clk/imx/clk.c | 22 +++ > > drivers/clk/imx/clk.h | 92 - > > include/dt-bindings/clock/imx7ulp-clock.h | 109 +++ > > include/linux/clk-provider.h | 17 ++ > > 14 files changed, 1166 insertions(+), 10 deletions(-) create mode > > 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt > > create mode 100644 drivers/clk/imx/clk-composite.c create mode > > 100644 drivers/clk/imx/clk-imx7ulp.c create mode 100644 > > drivers/clk/imx/clk-pfdv2.c create mode 100644 > > drivers/clk/imx/clk-pllv4.c create mode 100644 > > include/dt-bindings/clock/imx7ulp-clock.h > > > > -- > > 2.7.4
RE: [PATCH RESEND V4 6/9] dt-bindings: clock: add imx7ulp clock binding doc
> -Original Message- > From: Rob Herring [mailto:r...@kernel.org] > Sent: Tuesday, October 23, 2018 6:17 AM [...] > > On Sun, Oct 21, 2018 at 01:11:09PM +, A.s. Dong wrote: > > i.MX7ULP Clock functions are under joint control of the System Clock > > Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and > > Core Mode Controller (CMC)1 blocks > > > > Note IMX7ULP has two clock domains: M4 and A7. This binding doc is > > only for A7 clock domain. > > > > Cc: Rob Herring > > Cc: Mark Rutland > > Cc: Stephen Boyd > > Cc: Michael Turquette > > Cc: devicet...@vger.kernel.org > > Cc: Shawn Guo > > Cc: Anson Huang > > Cc: Bai Ping > > Signed-off-by: Dong Aisheng > > > > --- > > ChangeLog: > > v3->v4: > > * make scg, pcc separate nodes according to Rob's suggestion > > v2->v3: > > * no changes > > v1->v2: no changes > > --- > > .../devicetree/bindings/clock/imx7ulp-clock.txt| 87 > > > include/dt-bindings/clock/imx7ulp-clock.h | 109 > + > > 2 files changed, 196 insertions(+) > > create mode 100644 > > Documentation/devicetree/bindings/clock/imx7ulp-clock.txt > > create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h > > > > diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt > > b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt > > new file mode 100644 > > index 000..2239383 > > --- /dev/null > > +++ b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt > > @@ -0,0 +1,87 @@ > > +* Clock bindings for Freescale i.MX7ULP > > + > > +i.MX7ULP Clock functions are under joint control of the System Clock > > +Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and > > +Core Mode Controller (CMC)1 blocks > > + > > +The clocking scheme provides clear separation between M4 domain and > > +A7 domain. Except for a few clock sources shared between two domains, > > +such as the System Oscillator clock, the Slow IRC (SIRC), and and the > > +Fast IRC clock (FIRCLK), clock sources and clock management are > > +separated and contained within each domain. > > + > > +M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. > > +A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. > > Where's the CMC1 binding? > CMC module is more related to low power control, so did not put in clock series. But yes, it's missed in early series, will add it in next Arch patch series. > > + > > +Note: this binding doc is only for A7 clock domain. > > + > > +System Clock Generation (SCG) modules: > > +- > > +The System Clock Generation (SCG) is responsible for clock generation > > +and distribution across this device. Functions performed by the SCG > > +include: clock reference selection, generation of clock used to > > +derive processor, system, peripheral bus and external memory > > +interface clocks, source selection for peripheral clocks and control > > +of power saving clock gating mode. > > + > > +Required properties: > > + > > +- compatible: Should be "fsl,imx7ulp-scg1". > > +- reg :Should contain registers location and length. > > +- #clock-cells:Should be <1>. > > +- clocks: Should contain the fixed input clocks. > > +- clock-name: Should contain the following clock names:"rosc", "sosc", > > clock-names > Got it > > + "sirc", "firc", "upll", "mpll". > > + > > +Peripheral Clock Control (PCC) modules: > > +- > > +The Peripheral Clock Control (PCC) is responsible for clock > > +selection, optional division and clock gating mode for peripherals in > > +their respected power domain > > + > > +Required properties: > > +- compatible: Should be "fsl,imx7ulp-pcc2" or "fsl,imx7ulp-pcc3". > > Please format one per line. > Got it > There's some register layout difference between PCC2 and PCC3? > Yes, they're for different clocks and the layout may be slightly different. For example, some clocks support rate setting (with dividers) while some of them not. > > +- reg :Should contain registers location and length. > > +- #clock-cells:Should be <1>. > > No input clocks to list? > Sorry for missing them, should add it. Appreciate fo
RE: [PATCH RESEND V4 6/9] dt-bindings: clock: add imx7ulp clock binding doc
> -Original Message- > From: Rob Herring [mailto:r...@kernel.org] > Sent: Tuesday, October 23, 2018 6:17 AM [...] > > On Sun, Oct 21, 2018 at 01:11:09PM +, A.s. Dong wrote: > > i.MX7ULP Clock functions are under joint control of the System Clock > > Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and > > Core Mode Controller (CMC)1 blocks > > > > Note IMX7ULP has two clock domains: M4 and A7. This binding doc is > > only for A7 clock domain. > > > > Cc: Rob Herring > > Cc: Mark Rutland > > Cc: Stephen Boyd > > Cc: Michael Turquette > > Cc: devicet...@vger.kernel.org > > Cc: Shawn Guo > > Cc: Anson Huang > > Cc: Bai Ping > > Signed-off-by: Dong Aisheng > > > > --- > > ChangeLog: > > v3->v4: > > * make scg, pcc separate nodes according to Rob's suggestion > > v2->v3: > > * no changes > > v1->v2: no changes > > --- > > .../devicetree/bindings/clock/imx7ulp-clock.txt| 87 > > > include/dt-bindings/clock/imx7ulp-clock.h | 109 > + > > 2 files changed, 196 insertions(+) > > create mode 100644 > > Documentation/devicetree/bindings/clock/imx7ulp-clock.txt > > create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h > > > > diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt > > b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt > > new file mode 100644 > > index 000..2239383 > > --- /dev/null > > +++ b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt > > @@ -0,0 +1,87 @@ > > +* Clock bindings for Freescale i.MX7ULP > > + > > +i.MX7ULP Clock functions are under joint control of the System Clock > > +Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and > > +Core Mode Controller (CMC)1 blocks > > + > > +The clocking scheme provides clear separation between M4 domain and > > +A7 domain. Except for a few clock sources shared between two domains, > > +such as the System Oscillator clock, the Slow IRC (SIRC), and and the > > +Fast IRC clock (FIRCLK), clock sources and clock management are > > +separated and contained within each domain. > > + > > +M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. > > +A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. > > Where's the CMC1 binding? > CMC module is more related to low power control, so did not put in clock series. But yes, it's missed in early series, will add it in next Arch patch series. > > + > > +Note: this binding doc is only for A7 clock domain. > > + > > +System Clock Generation (SCG) modules: > > +- > > +The System Clock Generation (SCG) is responsible for clock generation > > +and distribution across this device. Functions performed by the SCG > > +include: clock reference selection, generation of clock used to > > +derive processor, system, peripheral bus and external memory > > +interface clocks, source selection for peripheral clocks and control > > +of power saving clock gating mode. > > + > > +Required properties: > > + > > +- compatible: Should be "fsl,imx7ulp-scg1". > > +- reg :Should contain registers location and length. > > +- #clock-cells:Should be <1>. > > +- clocks: Should contain the fixed input clocks. > > +- clock-name: Should contain the following clock names:"rosc", "sosc", > > clock-names > Got it > > + "sirc", "firc", "upll", "mpll". > > + > > +Peripheral Clock Control (PCC) modules: > > +- > > +The Peripheral Clock Control (PCC) is responsible for clock > > +selection, optional division and clock gating mode for peripherals in > > +their respected power domain > > + > > +Required properties: > > +- compatible: Should be "fsl,imx7ulp-pcc2" or "fsl,imx7ulp-pcc3". > > Please format one per line. > Got it > There's some register layout difference between PCC2 and PCC3? > Yes, they're for different clocks and the layout may be slightly different. For example, some clocks support rate setting (with dividers) while some of them not. > > +- reg :Should contain registers location and length. > > +- #clock-cells:Should be <1>. > > No input clocks to list? > Sorry for missing them, should add it. Appreciate fo
RE: [PATCH RESEND V4 0/9] clk: add imx7ulp clk support
Hi Stephen, In case you might miss to queue this series into your review list, so I resend this series again. This series actually has been pending for a couple of months without comments. Hopefully you could help find some time to handle it when you're free. Thanks Regards Dong Aisheng > -Original Message- > From: A.s. Dong > Sent: Sunday, October 21, 2018 9:11 PM > To: linux-...@vger.kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; Anson > Huang ; Jacky Bai ; dl-linux-imx > ; A.s. Dong > Subject: [PATCH RESEND V4 0/9] clk: add imx7ulp clk support > > This is a rebased version of below patch series against latest clk tree. > [PATCH RESEND V3 0/9] clk: add imx7ulp clk support > https://lkml.org/lkml/2018/3/16/310 > > It only updates the license to SPDX format as well as a minor fix of pllv4. > > This patch series intends to add imx7ulp clk support. > > i.MX7ULP Clock functions are under joint control of the System Clock > Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core > Mode Controller (CMC)1 blocks > > The clocking scheme provides clear separation between M4 domain and A7 > domain. Except for a few clock sources shared between two domains, such as > the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock > (FIRCLK), clock sources and clock management are separated and contained > within each domain. > > M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. > A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. > > Note: this series only adds A7 clock domain support as M4 clock domain will > be handled by M4 seperately. > > Change Log: > v3->v4: > * update after changing scg and pcc into separete nodes according to >Rob's suggestion > v2->v3: > * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible racy >Others no changes. > > v1->v2: > * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers > * use clk_hw apis to register clocks > * use of_clk_add_hw_provider > * split the clocks register process into two parts: early part for possible >timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for >the left normal peripheral clocks registered by a platform driver. > > Dong Aisheng (9): > clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support > clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support > clk: imx: add pllv4 support > clk: imx: add pfdv2 support > clk: imx: add composite clk support > dt-bindings: clock: add imx7ulp clock binding doc > clk: imx: make mux parent strings const > clk: imx: implement new clk_hw based APIs > clk: imx: add imx7ulp clk driver > > .../devicetree/bindings/clock/imx7ulp-clock.txt| 87 + > drivers/clk/clk-divider.c | 152 > +++ > drivers/clk/clk-fractional-divider.c | 10 + > drivers/clk/imx/Makefile | 6 +- > drivers/clk/imx/clk-busy.c | 2 +- > drivers/clk/imx/clk-composite.c| 85 + > drivers/clk/imx/clk-fixup-mux.c| 2 +- > drivers/clk/imx/clk-imx7ulp.c | 209 > + > drivers/clk/imx/clk-pfdv2.c| 201 > > drivers/clk/imx/clk-pllv4.c| 182 > ++ > drivers/clk/imx/clk.c | 22 +++ > drivers/clk/imx/clk.h | 92 - > include/dt-bindings/clock/imx7ulp-clock.h | 109 +++ > include/linux/clk-provider.h | 17 ++ > 14 files changed, 1166 insertions(+), 10 deletions(-) create mode 100644 > Documentation/devicetree/bindings/clock/imx7ulp-clock.txt > create mode 100644 drivers/clk/imx/clk-composite.c create mode 100644 > drivers/clk/imx/clk-imx7ulp.c create mode 100644 > drivers/clk/imx/clk-pfdv2.c create mode 100644 drivers/clk/imx/clk-pllv4.c > create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h > > -- > 2.7.4
RE: [PATCH RESEND V4 0/9] clk: add imx7ulp clk support
Hi Stephen, In case you might miss to queue this series into your review list, so I resend this series again. This series actually has been pending for a couple of months without comments. Hopefully you could help find some time to handle it when you're free. Thanks Regards Dong Aisheng > -Original Message- > From: A.s. Dong > Sent: Sunday, October 21, 2018 9:11 PM > To: linux-...@vger.kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; Anson > Huang ; Jacky Bai ; dl-linux-imx > ; A.s. Dong > Subject: [PATCH RESEND V4 0/9] clk: add imx7ulp clk support > > This is a rebased version of below patch series against latest clk tree. > [PATCH RESEND V3 0/9] clk: add imx7ulp clk support > https://lkml.org/lkml/2018/3/16/310 > > It only updates the license to SPDX format as well as a minor fix of pllv4. > > This patch series intends to add imx7ulp clk support. > > i.MX7ULP Clock functions are under joint control of the System Clock > Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core > Mode Controller (CMC)1 blocks > > The clocking scheme provides clear separation between M4 domain and A7 > domain. Except for a few clock sources shared between two domains, such as > the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock > (FIRCLK), clock sources and clock management are separated and contained > within each domain. > > M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. > A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. > > Note: this series only adds A7 clock domain support as M4 clock domain will > be handled by M4 seperately. > > Change Log: > v3->v4: > * update after changing scg and pcc into separete nodes according to >Rob's suggestion > v2->v3: > * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible racy >Others no changes. > > v1->v2: > * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers > * use clk_hw apis to register clocks > * use of_clk_add_hw_provider > * split the clocks register process into two parts: early part for possible >timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for >the left normal peripheral clocks registered by a platform driver. > > Dong Aisheng (9): > clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support > clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support > clk: imx: add pllv4 support > clk: imx: add pfdv2 support > clk: imx: add composite clk support > dt-bindings: clock: add imx7ulp clock binding doc > clk: imx: make mux parent strings const > clk: imx: implement new clk_hw based APIs > clk: imx: add imx7ulp clk driver > > .../devicetree/bindings/clock/imx7ulp-clock.txt| 87 + > drivers/clk/clk-divider.c | 152 > +++ > drivers/clk/clk-fractional-divider.c | 10 + > drivers/clk/imx/Makefile | 6 +- > drivers/clk/imx/clk-busy.c | 2 +- > drivers/clk/imx/clk-composite.c| 85 + > drivers/clk/imx/clk-fixup-mux.c| 2 +- > drivers/clk/imx/clk-imx7ulp.c | 209 > + > drivers/clk/imx/clk-pfdv2.c| 201 > > drivers/clk/imx/clk-pllv4.c| 182 > ++ > drivers/clk/imx/clk.c | 22 +++ > drivers/clk/imx/clk.h | 92 - > include/dt-bindings/clock/imx7ulp-clock.h | 109 +++ > include/linux/clk-provider.h | 17 ++ > 14 files changed, 1166 insertions(+), 10 deletions(-) create mode 100644 > Documentation/devicetree/bindings/clock/imx7ulp-clock.txt > create mode 100644 drivers/clk/imx/clk-composite.c create mode 100644 > drivers/clk/imx/clk-imx7ulp.c create mode 100644 > drivers/clk/imx/clk-pfdv2.c create mode 100644 drivers/clk/imx/clk-pllv4.c > create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h > > -- > 2.7.4
[PATCH RESEND V4 6/9] dt-bindings: clock: add imx7ulp clock binding doc
i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks Note IMX7ULP has two clock domains: M4 and A7. This binding doc is only for A7 clock domain. Cc: Rob Herring Cc: Mark Rutland Cc: Stephen Boyd Cc: Michael Turquette Cc: devicet...@vger.kernel.org Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * make scg, pcc separate nodes according to Rob's suggestion v2->v3: * no changes v1->v2: no changes --- .../devicetree/bindings/clock/imx7ulp-clock.txt| 87 include/dt-bindings/clock/imx7ulp-clock.h | 109 + 2 files changed, 196 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt new file mode 100644 index 000..2239383 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt @@ -0,0 +1,87 @@ +* Clock bindings for Freescale i.MX7ULP + +i.MX7ULP Clock functions are under joint control of the System +Clock Generation (SCG) modules, Peripheral Clock Control (PCC) +modules, and Core Mode Controller (CMC)1 blocks + +The clocking scheme provides clear separation between M4 domain +and A7 domain. Except for a few clock sources shared between two +domains, such as the System Oscillator clock, the Slow IRC (SIRC), +and and the Fast IRC clock (FIRCLK), clock sources and clock +management are separated and contained within each domain. + +M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. +A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. + +Note: this binding doc is only for A7 clock domain. + +System Clock Generation (SCG) modules: +- +The System Clock Generation (SCG) is responsible for clock generation +and distribution across this device. Functions performed by the SCG +include: clock reference selection, generation of clock used to derive +processor, system, peripheral bus and external memory interface clocks, +source selection for peripheral clocks and control of power saving +clock gating mode. + +Required properties: + +- compatible: Should be "fsl,imx7ulp-scg1". +- reg :Should contain registers location and length. +- #clock-cells:Should be <1>. +- clocks: Should contain the fixed input clocks. +- clock-name: Should contain the following clock names:"rosc", "sosc", + "sirc", "firc", "upll", "mpll". + +Peripheral Clock Control (PCC) modules: +- +The Peripheral Clock Control (PCC) is responsible for clock selection, +optional division and clock gating mode for peripherals in their +respected power domain + +Required properties: +- compatible: Should be "fsl,imx7ulp-pcc2" or "fsl,imx7ulp-pcc3". +- reg :Should contain registers location and length. +- #clock-cells:Should be <1>. + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. +See include/dt-bindings/clock/imx7ulp-clock.h +for the full list of i.MX7ULP clock IDs of each module. + +Examples: + +#include + +scg1: scg1@403e { + compatible = "fsl,imx7ulp-scg1; + reg = <0x403e 0x1>; + clocks = <>, <>, <>, +<>, <>, <>; + clock-names = "rosc", "sosc", "sirc", + "firc", "upll", "mpll"; + #clock-cells = <1>; +}; + +pcc2: pcc2@403f { + compatible = "fsl,imx7ulp-pcc2"; + reg = <0x403f 0x1>; + #clock-cells = <1>; +}; + +pcc3: pcc3@40b3 { + compatible = "fsl,imx7ulp-pcc3"; + reg = <0x40b3 0x1>; + #clock-cells = <1>; +}; + +usdhc1: usdhc@4038 { + compatible = "fsl,imx7ulp-usdhc"; + reg = <0x4038 0x1>; + interrupts = ; + clocks = < IMX7ULP_CLK_NIC1_BUS_DIV>, +< IMX7ULP_CLK_NIC1_DIV>, +< IMX7ULP_CLK_USDHC1>; + clock-names ="ipg", "ahb", "per"; + bus-width = <4>; +}; diff --git a/include/dt-bindings/clock/imx7ulp-clock.h b/include/dt-bindings/clock/imx7ulp-clock.h new file mode 100644 index 000..008c5ee --- /dev/null +++ b/include/dt-bindings/clock/imx7ulp-clock.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + */ + +#ifndef __DT_BINDINGS_CLOCK_IMX7ULP_H +#define __DT_BINDINGS_CLOCK_IMX7ULP_H + +/* SCG1 */ + +#define IMX7ULP_CLK_DUMMY 0 +#define IMX7ULP_CLK_ROSC 1 +#define IMX7ULP_CLK_SOSC 2 +#define IMX7ULP_CLK_FIRC 3 +#define
[PATCH RESEND V4 3/9] clk: imx: add pllv4 support
pllv4 is designed for System Clock Generation (SCG) module observed in IMX ULP SoC series. e.g. i.MX7ULP. The SCG modules generates clock used to derive processor, system, peripheral bus and external memory interface clocks while this patch intends to support the PLL part. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * remove clk_pllv4_is_enabled() check in set_rate, instead it will be handled by core later. * use readl_poll_timeout * use clk_hw_register instead of clk_register * other minor changes --- drivers/clk/imx/Makefile| 1 + drivers/clk/imx/clk-pllv4.c | 182 drivers/clk/imx/clk.h | 3 + 3 files changed, 186 insertions(+) create mode 100644 drivers/clk/imx/clk-pllv4.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..bfe31bf 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -11,6 +11,7 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ + clk-pllv4.o \ clk-pfd.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c new file mode 100644 index 000..67c64c7 --- /dev/null +++ b/drivers/clk/imx/clk-pllv4.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include + +/* PLL Control Status Register (xPLLCSR) */ +#define PLL_CSR_OFFSET 0x0 +#define PLL_VLDBIT(24) +#define PLL_EN BIT(0) + +/* PLL Configuration Register (xPLLCFG) */ +#define PLL_CFG_OFFSET 0x08 +#define BP_PLL_MULT16 +#define BM_PLL_MULT(0x7f << 16) + +/* PLL Numerator Register (xPLLNUM) */ +#define PLL_NUM_OFFSET 0x10 + +/* PLL Denominator Register (xPLLDENOM) */ +#define PLL_DENOM_OFFSET 0x14 + +struct clk_pllv4 { + struct clk_hw hw; + void __iomem*base; +}; + +/* Valid PLL MULT Table */ +static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16}; + +#define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw) + +#define LOCK_TIMEOUT_USUSEC_PER_MSEC + +static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll) +{ + u32 csr; + + return readl_poll_timeout(pll->base + PLL_CSR_OFFSET, + csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US); +} + +static int clk_pllv4_is_enabled(struct clk_hw *hw) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + if (readl_relaxed(pll->base) & PLL_EN) + return 1; + + return 0; +} + +static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + u32 div; + + div = readl_relaxed(pll->base + PLL_CFG_OFFSET); + div &= BM_PLL_MULT; + div >>= BP_PLL_MULT; + + return parent_rate * div; +} + +static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate, +unsigned long *prate) +{ + unsigned long parent_rate = *prate; + unsigned long round_rate, i; + + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + round_rate = parent_rate * pllv4_mult_table[i]; + if (rate >= round_rate) + return round_rate; + } + + return round_rate; +} + +static bool clk_pllv4_is_valid_mult(unsigned int mult) +{ + int i; + + /* check if mult is in valid MULT table */ + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + if (pllv4_mult_table[i] == mult) + return true; + } + + return false; +} + +static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + u32 val, mult; + + mult = rate / parent_rate; + + if (!clk_pllv4_is_valid_mult(mult)) + return -EINVAL; + + val = readl_relaxed(pll->base + PLL_CFG_OFFSET); + val &= ~BM_PLL_MULT; + val |= mult << BP_PLL_MULT; + writel_relaxed(val, pll->base + PLL_CFG_OFFSET); + + return 0; +} + +static int clk_pllv4_enable(struct clk_hw *hw) +{ + u32 val; + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + val = readl_relaxed(pll->base); + val |= PLL_EN; + writel_relaxed(val, pll->base); + + return clk_pllv4_wait_lock(pll); +} + +static void clk_pllv4_disable(struct clk_hw *hw) +{ + u32 val; + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + val = readl_relaxed(pll->base); + val &= ~PLL_EN; +
[PATCH RESEND V4 2/9] clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support
Adding CLK_FRAC_DIVIDER_ZERO_BASED flag to indicate the numerator and denominator value in register are start from 0. This can be used to support frac dividers like below: Divider output clock = Divider input clock x [(frac +1) / (div +1)] where frac/div in register is: 000b - Divide by 1. 001b - Divide by 2. 010b - Divide by 3. Cc: Stephen Boyd Cc: Michael Turquette Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * improve comments suggested by Stephen --- drivers/clk/clk-fractional-divider.c | 10 ++ include/linux/clk-provider.h | 8 2 files changed, 18 insertions(+) diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index fdf625f..7ccde6b 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -40,6 +40,11 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, m = (val & fd->mmask) >> fd->mshift; n = (val & fd->nmask) >> fd->nshift; + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + m++; + n++; + } + if (!n || !m) return parent_rate; @@ -103,6 +108,11 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), , ); + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + m--; + n--; + } + if (fd->lock) spin_lock_irqsave(fd->lock, flags); else diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 08f135a..90d7c26 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -603,6 +603,12 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw); * @lock: register lock * * Clock with adjustable fractional divider affecting its output frequency. + * + * Flags: + * CLK_FRAC_DIVIDER_ZERO_BASED - by default the numerator and denominator + * is the value read from the register. If CLK_FRAC_DIVIDER_ZERO_BASED + * is set then the numerator and denominator are both the value read + * plus one. */ struct clk_fractional_divider { struct clk_hw hw; @@ -622,6 +628,8 @@ struct clk_fractional_divider { #define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw) +#define CLK_FRAC_DIVIDER_ZERO_BASEDBIT(0) + extern const struct clk_ops clk_fractional_divider_ops; struct clk *clk_register_fractional_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, -- 2.7.4
[PATCH RESEND V4 3/9] clk: imx: add pllv4 support
pllv4 is designed for System Clock Generation (SCG) module observed in IMX ULP SoC series. e.g. i.MX7ULP. The SCG modules generates clock used to derive processor, system, peripheral bus and external memory interface clocks while this patch intends to support the PLL part. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * remove clk_pllv4_is_enabled() check in set_rate, instead it will be handled by core later. * use readl_poll_timeout * use clk_hw_register instead of clk_register * other minor changes --- drivers/clk/imx/Makefile| 1 + drivers/clk/imx/clk-pllv4.c | 182 drivers/clk/imx/clk.h | 3 + 3 files changed, 186 insertions(+) create mode 100644 drivers/clk/imx/clk-pllv4.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..bfe31bf 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -11,6 +11,7 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ + clk-pllv4.o \ clk-pfd.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c new file mode 100644 index 000..67c64c7 --- /dev/null +++ b/drivers/clk/imx/clk-pllv4.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include + +/* PLL Control Status Register (xPLLCSR) */ +#define PLL_CSR_OFFSET 0x0 +#define PLL_VLDBIT(24) +#define PLL_EN BIT(0) + +/* PLL Configuration Register (xPLLCFG) */ +#define PLL_CFG_OFFSET 0x08 +#define BP_PLL_MULT16 +#define BM_PLL_MULT(0x7f << 16) + +/* PLL Numerator Register (xPLLNUM) */ +#define PLL_NUM_OFFSET 0x10 + +/* PLL Denominator Register (xPLLDENOM) */ +#define PLL_DENOM_OFFSET 0x14 + +struct clk_pllv4 { + struct clk_hw hw; + void __iomem*base; +}; + +/* Valid PLL MULT Table */ +static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16}; + +#define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw) + +#define LOCK_TIMEOUT_USUSEC_PER_MSEC + +static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll) +{ + u32 csr; + + return readl_poll_timeout(pll->base + PLL_CSR_OFFSET, + csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US); +} + +static int clk_pllv4_is_enabled(struct clk_hw *hw) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + if (readl_relaxed(pll->base) & PLL_EN) + return 1; + + return 0; +} + +static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + u32 div; + + div = readl_relaxed(pll->base + PLL_CFG_OFFSET); + div &= BM_PLL_MULT; + div >>= BP_PLL_MULT; + + return parent_rate * div; +} + +static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate, +unsigned long *prate) +{ + unsigned long parent_rate = *prate; + unsigned long round_rate, i; + + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + round_rate = parent_rate * pllv4_mult_table[i]; + if (rate >= round_rate) + return round_rate; + } + + return round_rate; +} + +static bool clk_pllv4_is_valid_mult(unsigned int mult) +{ + int i; + + /* check if mult is in valid MULT table */ + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + if (pllv4_mult_table[i] == mult) + return true; + } + + return false; +} + +static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv4 *pll = to_clk_pllv4(hw); + u32 val, mult; + + mult = rate / parent_rate; + + if (!clk_pllv4_is_valid_mult(mult)) + return -EINVAL; + + val = readl_relaxed(pll->base + PLL_CFG_OFFSET); + val &= ~BM_PLL_MULT; + val |= mult << BP_PLL_MULT; + writel_relaxed(val, pll->base + PLL_CFG_OFFSET); + + return 0; +} + +static int clk_pllv4_enable(struct clk_hw *hw) +{ + u32 val; + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + val = readl_relaxed(pll->base); + val |= PLL_EN; + writel_relaxed(val, pll->base); + + return clk_pllv4_wait_lock(pll); +} + +static void clk_pllv4_disable(struct clk_hw *hw) +{ + u32 val; + struct clk_pllv4 *pll = to_clk_pllv4(hw); + + val = readl_relaxed(pll->base); + val &= ~PLL_EN; +
[PATCH RESEND V4 2/9] clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support
Adding CLK_FRAC_DIVIDER_ZERO_BASED flag to indicate the numerator and denominator value in register are start from 0. This can be used to support frac dividers like below: Divider output clock = Divider input clock x [(frac +1) / (div +1)] where frac/div in register is: 000b - Divide by 1. 001b - Divide by 2. 010b - Divide by 3. Cc: Stephen Boyd Cc: Michael Turquette Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * improve comments suggested by Stephen --- drivers/clk/clk-fractional-divider.c | 10 ++ include/linux/clk-provider.h | 8 2 files changed, 18 insertions(+) diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index fdf625f..7ccde6b 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -40,6 +40,11 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, m = (val & fd->mmask) >> fd->mshift; n = (val & fd->nmask) >> fd->nshift; + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + m++; + n++; + } + if (!n || !m) return parent_rate; @@ -103,6 +108,11 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), , ); + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + m--; + n--; + } + if (fd->lock) spin_lock_irqsave(fd->lock, flags); else diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 08f135a..90d7c26 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -603,6 +603,12 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw); * @lock: register lock * * Clock with adjustable fractional divider affecting its output frequency. + * + * Flags: + * CLK_FRAC_DIVIDER_ZERO_BASED - by default the numerator and denominator + * is the value read from the register. If CLK_FRAC_DIVIDER_ZERO_BASED + * is set then the numerator and denominator are both the value read + * plus one. */ struct clk_fractional_divider { struct clk_hw hw; @@ -622,6 +628,8 @@ struct clk_fractional_divider { #define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw) +#define CLK_FRAC_DIVIDER_ZERO_BASEDBIT(0) + extern const struct clk_ops clk_fractional_divider_ops; struct clk *clk_register_fractional_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, -- 2.7.4
[PATCH RESEND V4 6/9] dt-bindings: clock: add imx7ulp clock binding doc
i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks Note IMX7ULP has two clock domains: M4 and A7. This binding doc is only for A7 clock domain. Cc: Rob Herring Cc: Mark Rutland Cc: Stephen Boyd Cc: Michael Turquette Cc: devicet...@vger.kernel.org Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * make scg, pcc separate nodes according to Rob's suggestion v2->v3: * no changes v1->v2: no changes --- .../devicetree/bindings/clock/imx7ulp-clock.txt| 87 include/dt-bindings/clock/imx7ulp-clock.h | 109 + 2 files changed, 196 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt new file mode 100644 index 000..2239383 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx7ulp-clock.txt @@ -0,0 +1,87 @@ +* Clock bindings for Freescale i.MX7ULP + +i.MX7ULP Clock functions are under joint control of the System +Clock Generation (SCG) modules, Peripheral Clock Control (PCC) +modules, and Core Mode Controller (CMC)1 blocks + +The clocking scheme provides clear separation between M4 domain +and A7 domain. Except for a few clock sources shared between two +domains, such as the System Oscillator clock, the Slow IRC (SIRC), +and and the Fast IRC clock (FIRCLK), clock sources and clock +management are separated and contained within each domain. + +M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. +A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. + +Note: this binding doc is only for A7 clock domain. + +System Clock Generation (SCG) modules: +- +The System Clock Generation (SCG) is responsible for clock generation +and distribution across this device. Functions performed by the SCG +include: clock reference selection, generation of clock used to derive +processor, system, peripheral bus and external memory interface clocks, +source selection for peripheral clocks and control of power saving +clock gating mode. + +Required properties: + +- compatible: Should be "fsl,imx7ulp-scg1". +- reg :Should contain registers location and length. +- #clock-cells:Should be <1>. +- clocks: Should contain the fixed input clocks. +- clock-name: Should contain the following clock names:"rosc", "sosc", + "sirc", "firc", "upll", "mpll". + +Peripheral Clock Control (PCC) modules: +- +The Peripheral Clock Control (PCC) is responsible for clock selection, +optional division and clock gating mode for peripherals in their +respected power domain + +Required properties: +- compatible: Should be "fsl,imx7ulp-pcc2" or "fsl,imx7ulp-pcc3". +- reg :Should contain registers location and length. +- #clock-cells:Should be <1>. + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. +See include/dt-bindings/clock/imx7ulp-clock.h +for the full list of i.MX7ULP clock IDs of each module. + +Examples: + +#include + +scg1: scg1@403e { + compatible = "fsl,imx7ulp-scg1; + reg = <0x403e 0x1>; + clocks = <>, <>, <>, +<>, <>, <>; + clock-names = "rosc", "sosc", "sirc", + "firc", "upll", "mpll"; + #clock-cells = <1>; +}; + +pcc2: pcc2@403f { + compatible = "fsl,imx7ulp-pcc2"; + reg = <0x403f 0x1>; + #clock-cells = <1>; +}; + +pcc3: pcc3@40b3 { + compatible = "fsl,imx7ulp-pcc3"; + reg = <0x40b3 0x1>; + #clock-cells = <1>; +}; + +usdhc1: usdhc@4038 { + compatible = "fsl,imx7ulp-usdhc"; + reg = <0x4038 0x1>; + interrupts = ; + clocks = < IMX7ULP_CLK_NIC1_BUS_DIV>, +< IMX7ULP_CLK_NIC1_DIV>, +< IMX7ULP_CLK_USDHC1>; + clock-names ="ipg", "ahb", "per"; + bus-width = <4>; +}; diff --git a/include/dt-bindings/clock/imx7ulp-clock.h b/include/dt-bindings/clock/imx7ulp-clock.h new file mode 100644 index 000..008c5ee --- /dev/null +++ b/include/dt-bindings/clock/imx7ulp-clock.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + */ + +#ifndef __DT_BINDINGS_CLOCK_IMX7ULP_H +#define __DT_BINDINGS_CLOCK_IMX7ULP_H + +/* SCG1 */ + +#define IMX7ULP_CLK_DUMMY 0 +#define IMX7ULP_CLK_ROSC 1 +#define IMX7ULP_CLK_SOSC 2 +#define IMX7ULP_CLK_FIRC 3 +#define
[PATCH RESEND V4 5/9] clk: imx: add composite clk support
The imx composite clk is designed for Peripheral Clock Control (PCC) module observed in IMX ULP SoC series. e.g. i.MX7ULP. NOTE pcc can only be operated when clk is gated. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * remove an unneeded blank line change * use clk_hw_register --- drivers/clk/imx/Makefile| 1 + drivers/clk/imx/clk-composite.c | 85 + drivers/clk/imx/clk.h | 6 +++ 3 files changed, 92 insertions(+) create mode 100644 drivers/clk/imx/clk-composite.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index e5b0d42..f4da12c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -4,6 +4,7 @@ obj-y += \ clk.o \ clk-busy.o \ clk-cpu.o \ + clk-composite.o \ clk-fixup-div.o \ clk-fixup-mux.o \ clk-gate-exclusive.o \ diff --git a/drivers/clk/imx/clk-composite.c b/drivers/clk/imx/clk-composite.c new file mode 100644 index 000..297974b --- /dev/null +++ b/drivers/clk/imx/clk-composite.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + */ + +#include +#include +#include + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 +#define PCG_CGC_SHIFT 30 +#define PCG_FRAC_SHIFT 3 +#define PCG_FRAC_WIDTH 1 +#define PCG_FRAC_MASK BIT(3) +#define PCG_PCD_SHIFT 0 +#define PCG_PCD_WIDTH 3 +#define PCG_PCD_MASK 0x7 + +struct clk_hw *imx_clk_composite(const char *name, + const char * const *parent_names, + int num_parents, bool mux_present, + bool rate_present, bool gate_present, + void __iomem *reg) +{ + struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL; + struct clk_fractional_divider *fd = NULL; + struct clk_gate *gate = NULL; + struct clk_mux *mux = NULL; + struct clk_hw *hw; + + if (mux_present) { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + mux_hw = >hw; + mux->reg = reg; + mux->shift = PCG_PCS_SHIFT; + mux->mask = PCG_PCS_MASK; + } + + if (rate_present) { + fd = kzalloc(sizeof(*fd), GFP_KERNEL); + if (!fd) { + kfree(mux); + return ERR_PTR(-ENOMEM); + } + fd_hw = >hw; + fd->reg = reg; + fd->mshift = PCG_FRAC_SHIFT; + fd->mwidth = PCG_FRAC_WIDTH; + fd->mmask = PCG_FRAC_MASK; + fd->nshift = PCG_PCD_SHIFT; + fd->nwidth = PCG_PCD_WIDTH; + fd->nmask = PCG_PCD_MASK; + fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED; + } + + if (gate_present) { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + kfree(mux); + kfree(fd); + return ERR_PTR(-ENOMEM); + } + gate_hw = >hw; + gate->reg = reg; + gate->bit_idx = PCG_CGC_SHIFT; + } + + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux_hw, _mux_ops, fd_hw, + _fractional_divider_ops, gate_hw, + _gate_ops, CLK_SET_RATE_GATE | + CLK_SET_PARENT_GATE); + if (IS_ERR(hw)) { + kfree(mux); + kfree(fd); + kfree(gate); + } + + return hw; +} diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index a5a9374..bc43f68 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -71,6 +71,12 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, const char **parent_names, int num_parents); +struct clk_hw *imx_clk_composite(const char *name, +const char * const *parent_names, +int num_parents, bool mux_present, +bool rate_present, bool gate_present, +void __iomem *reg); + struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width, void (*fixup)(u32 *val)); -- 2.7.4
[PATCH RESEND V4 4/9] clk: imx: add pfdv2 support
The pfdv2 is designed for PLL Fractional Divide (PFD) observed in System Clock Generation (SCG) module in IMX ULP SoC series. e.g. i.MX7ULP. NOTE pfdv2 can only be operated when clk is gated. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * change to readl_poll_timeout * add pfd lock to protect share reg access between rate and enable/disable operations and multiple pfd instances. * use clk_hw_register --- drivers/clk/imx/Makefile| 3 +- drivers/clk/imx/clk-pfdv2.c | 201 drivers/clk/imx/clk.h | 3 + 3 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-pfdv2.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index bfe31bf..e5b0d42 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,7 +12,8 @@ obj-y += \ clk-pllv2.o \ clk-pllv3.o \ clk-pllv4.o \ - clk-pfd.o + clk-pfd.o \ + clk-pfdv2.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c new file mode 100644 index 000..afb2904 --- /dev/null +++ b/drivers/clk/imx/clk-pfdv2.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include + +/** + * struct clk_pfdv2 - IMX PFD clock + * @clk_hw:clock source + * @reg: PFD register address + * @gate_bit: Gate bit offset + * @vld_bit: Valid bit offset + * @frac_off: PLL Fractional Divider offset + */ + +struct clk_pfdv2 { + struct clk_hw hw; + void __iomem*reg; + u8 gate_bit; + u8 vld_bit; + u8 frac_off; +}; + +#define to_clk_pfdv2(_hw) container_of(_hw, struct clk_pfdv2, hw) + +#define CLK_PFDV2_FRAC_MASK 0x3f + +#define LOCK_TIMEOUT_USUSEC_PER_MSEC + +static DEFINE_SPINLOCK(pfd_lock); + +static int clk_pfdv2_wait(struct clk_pfdv2 *pfd) +{ + u32 val; + + return readl_poll_timeout(pfd->reg, val, val & pfd->vld_bit, + 0, LOCK_TIMEOUT_US); +} + +static int clk_pfdv2_enable(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val &= ~pfd->gate_bit; + writel_relaxed(val, pfd->reg); + spin_unlock_irqrestore(_lock, flags); + + return clk_pfdv2_wait(pfd); +} + +static void clk_pfdv2_disable(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val |= pfd->gate_bit; + writel_relaxed(val, pfd->reg); + spin_unlock_irqrestore(_lock, flags); +} + +static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + u64 tmp = parent_rate; + u8 frac; + + frac = (readl_relaxed(pfd->reg) >> pfd->frac_off) + & CLK_PFDV2_FRAC_MASK; + + if (!frac) { + pr_debug("clk_pfdv2: %s invalid pfd frac value 0\n", +clk_hw_get_name(hw)); + return 0; + } + + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static long clk_pfdv2_round_rate(struct clk_hw *hw, unsigned long rate, +unsigned long *prate) +{ + u64 tmp = *prate; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + tmp = *prate; + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static int clk_pfdv2_is_enabled(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + + if (readl_relaxed(pfd->reg) & pfd->gate_bit) + return 0; + + return 1; +} + +static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u64 tmp = parent_rate; + u32 val; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val &= ~(CLK_PFDV2_FRAC_MASK <<
[PATCH RESEND V4 7/9] clk: imx: make mux parent strings const
As the commit 2893c379461a ("clk: make strings in parent name arrays const"), let's make the parent strings const, otherwise we may meet the following warning when compiling: drivers/clk/imx/clk-imx7ulp.c: In function 'imx7ulp_clocks_init': drivers/clk/imx/clk-imx7ulp.c:73:35: warning: passing argument 5 of 'imx_clk_mux_flags' discards 'const' qualifier from pointer target type clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); ^ In file included from drivers/clk/imx/clk-imx7ulp.c:23:0: drivers/clk/imx/clk.h:200:27: note: expected 'const char **' but argument is of type 'const char * const*' ... Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Signed-off-by: Dong Aisheng --- ChangeLog: v1->v4: no changes --- drivers/clk/imx/clk-busy.c | 2 +- drivers/clk/imx/clk-fixup-mux.c | 2 +- drivers/clk/imx/clk.h | 18 +++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/clk/imx/clk-busy.c b/drivers/clk/imx/clk-busy.c index 9903652..e695622 100644 --- a/drivers/clk/imx/clk-busy.c +++ b/drivers/clk/imx/clk-busy.c @@ -154,7 +154,7 @@ static const struct clk_ops clk_busy_mux_ops = { struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, -const char **parent_names, int num_parents) +const char * const *parent_names, int num_parents) { struct clk_busy_mux *busy; struct clk *clk; diff --git a/drivers/clk/imx/clk-fixup-mux.c b/drivers/clk/imx/clk-fixup-mux.c index c9b327e..44817c1 100644 --- a/drivers/clk/imx/clk-fixup-mux.c +++ b/drivers/clk/imx/clk-fixup-mux.c @@ -70,7 +70,7 @@ static const struct clk_ops clk_fixup_mux_ops = { }; struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, + u8 shift, u8 width, const char * const *parents, int num_parents, void (*fixup)(u32 *val)) { struct clk_fixup_mux *fixup_mux; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index bc43f68..7fca912 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -69,7 +69,7 @@ struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, -const char **parent_names, int num_parents); +const char * const *parent_names, int num_parents); struct clk_hw *imx_clk_composite(const char *name, const char * const *parent_names, @@ -82,7 +82,7 @@ struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void (*fixup)(u32 *val)); struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, + u8 shift, u8 width, const char * const *parents, int num_parents, void (*fixup)(u32 *val)); static inline struct clk *imx_clk_fixed(const char *name, int rate) @@ -91,7 +91,8 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) } static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg, @@ -204,7 +205,8 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent, } static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT, reg, shift, @@ -212,7 +214,8 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, } static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE, @@ -220,8 +223,9
[PATCH RESEND V4 4/9] clk: imx: add pfdv2 support
The pfdv2 is designed for PLL Fractional Divide (PFD) observed in System Clock Generation (SCG) module in IMX ULP SoC series. e.g. i.MX7ULP. NOTE pfdv2 can only be operated when clk is gated. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * change to readl_poll_timeout * add pfd lock to protect share reg access between rate and enable/disable operations and multiple pfd instances. * use clk_hw_register --- drivers/clk/imx/Makefile| 3 +- drivers/clk/imx/clk-pfdv2.c | 201 drivers/clk/imx/clk.h | 3 + 3 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-pfdv2.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index bfe31bf..e5b0d42 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,7 +12,8 @@ obj-y += \ clk-pllv2.o \ clk-pllv3.o \ clk-pllv4.o \ - clk-pfd.o + clk-pfd.o \ + clk-pfdv2.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c new file mode 100644 index 000..afb2904 --- /dev/null +++ b/drivers/clk/imx/clk-pfdv2.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include + +/** + * struct clk_pfdv2 - IMX PFD clock + * @clk_hw:clock source + * @reg: PFD register address + * @gate_bit: Gate bit offset + * @vld_bit: Valid bit offset + * @frac_off: PLL Fractional Divider offset + */ + +struct clk_pfdv2 { + struct clk_hw hw; + void __iomem*reg; + u8 gate_bit; + u8 vld_bit; + u8 frac_off; +}; + +#define to_clk_pfdv2(_hw) container_of(_hw, struct clk_pfdv2, hw) + +#define CLK_PFDV2_FRAC_MASK 0x3f + +#define LOCK_TIMEOUT_USUSEC_PER_MSEC + +static DEFINE_SPINLOCK(pfd_lock); + +static int clk_pfdv2_wait(struct clk_pfdv2 *pfd) +{ + u32 val; + + return readl_poll_timeout(pfd->reg, val, val & pfd->vld_bit, + 0, LOCK_TIMEOUT_US); +} + +static int clk_pfdv2_enable(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val &= ~pfd->gate_bit; + writel_relaxed(val, pfd->reg); + spin_unlock_irqrestore(_lock, flags); + + return clk_pfdv2_wait(pfd); +} + +static void clk_pfdv2_disable(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val |= pfd->gate_bit; + writel_relaxed(val, pfd->reg); + spin_unlock_irqrestore(_lock, flags); +} + +static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + u64 tmp = parent_rate; + u8 frac; + + frac = (readl_relaxed(pfd->reg) >> pfd->frac_off) + & CLK_PFDV2_FRAC_MASK; + + if (!frac) { + pr_debug("clk_pfdv2: %s invalid pfd frac value 0\n", +clk_hw_get_name(hw)); + return 0; + } + + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static long clk_pfdv2_round_rate(struct clk_hw *hw, unsigned long rate, +unsigned long *prate) +{ + u64 tmp = *prate; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + tmp = *prate; + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static int clk_pfdv2_is_enabled(struct clk_hw *hw) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + + if (readl_relaxed(pfd->reg) & pfd->gate_bit) + return 0; + + return 1; +} + +static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pfdv2 *pfd = to_clk_pfdv2(hw); + unsigned long flags; + u64 tmp = parent_rate; + u32 val; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + spin_lock_irqsave(_lock, flags); + val = readl_relaxed(pfd->reg); + val &= ~(CLK_PFDV2_FRAC_MASK <<
[PATCH RESEND V4 7/9] clk: imx: make mux parent strings const
As the commit 2893c379461a ("clk: make strings in parent name arrays const"), let's make the parent strings const, otherwise we may meet the following warning when compiling: drivers/clk/imx/clk-imx7ulp.c: In function 'imx7ulp_clocks_init': drivers/clk/imx/clk-imx7ulp.c:73:35: warning: passing argument 5 of 'imx_clk_mux_flags' discards 'const' qualifier from pointer target type clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); ^ In file included from drivers/clk/imx/clk-imx7ulp.c:23:0: drivers/clk/imx/clk.h:200:27: note: expected 'const char **' but argument is of type 'const char * const*' ... Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Signed-off-by: Dong Aisheng --- ChangeLog: v1->v4: no changes --- drivers/clk/imx/clk-busy.c | 2 +- drivers/clk/imx/clk-fixup-mux.c | 2 +- drivers/clk/imx/clk.h | 18 +++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/clk/imx/clk-busy.c b/drivers/clk/imx/clk-busy.c index 9903652..e695622 100644 --- a/drivers/clk/imx/clk-busy.c +++ b/drivers/clk/imx/clk-busy.c @@ -154,7 +154,7 @@ static const struct clk_ops clk_busy_mux_ops = { struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, -const char **parent_names, int num_parents) +const char * const *parent_names, int num_parents) { struct clk_busy_mux *busy; struct clk *clk; diff --git a/drivers/clk/imx/clk-fixup-mux.c b/drivers/clk/imx/clk-fixup-mux.c index c9b327e..44817c1 100644 --- a/drivers/clk/imx/clk-fixup-mux.c +++ b/drivers/clk/imx/clk-fixup-mux.c @@ -70,7 +70,7 @@ static const struct clk_ops clk_fixup_mux_ops = { }; struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, + u8 shift, u8 width, const char * const *parents, int num_parents, void (*fixup)(u32 *val)) { struct clk_fixup_mux *fixup_mux; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index bc43f68..7fca912 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -69,7 +69,7 @@ struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, -const char **parent_names, int num_parents); +const char * const *parent_names, int num_parents); struct clk_hw *imx_clk_composite(const char *name, const char * const *parent_names, @@ -82,7 +82,7 @@ struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void (*fixup)(u32 *val)); struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, + u8 shift, u8 width, const char * const *parents, int num_parents, void (*fixup)(u32 *val)); static inline struct clk *imx_clk_fixed(const char *name, int rate) @@ -91,7 +91,8 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) } static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg, @@ -204,7 +205,8 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent, } static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT, reg, shift, @@ -212,7 +214,8 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, } static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, int num_parents) + u8 shift, u8 width, const char * const *parents, + int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE, @@ -220,8 +223,9
[PATCH RESEND V4 5/9] clk: imx: add composite clk support
The imx composite clk is designed for Peripheral Clock Control (PCC) module observed in IMX ULP SoC series. e.g. i.MX7ULP. NOTE pcc can only be operated when clk is gated. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * no changes v1->v2: * remove an unneeded blank line change * use clk_hw_register --- drivers/clk/imx/Makefile| 1 + drivers/clk/imx/clk-composite.c | 85 + drivers/clk/imx/clk.h | 6 +++ 3 files changed, 92 insertions(+) create mode 100644 drivers/clk/imx/clk-composite.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index e5b0d42..f4da12c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -4,6 +4,7 @@ obj-y += \ clk.o \ clk-busy.o \ clk-cpu.o \ + clk-composite.o \ clk-fixup-div.o \ clk-fixup-mux.o \ clk-gate-exclusive.o \ diff --git a/drivers/clk/imx/clk-composite.c b/drivers/clk/imx/clk-composite.c new file mode 100644 index 000..297974b --- /dev/null +++ b/drivers/clk/imx/clk-composite.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + */ + +#include +#include +#include + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 +#define PCG_CGC_SHIFT 30 +#define PCG_FRAC_SHIFT 3 +#define PCG_FRAC_WIDTH 1 +#define PCG_FRAC_MASK BIT(3) +#define PCG_PCD_SHIFT 0 +#define PCG_PCD_WIDTH 3 +#define PCG_PCD_MASK 0x7 + +struct clk_hw *imx_clk_composite(const char *name, + const char * const *parent_names, + int num_parents, bool mux_present, + bool rate_present, bool gate_present, + void __iomem *reg) +{ + struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL; + struct clk_fractional_divider *fd = NULL; + struct clk_gate *gate = NULL; + struct clk_mux *mux = NULL; + struct clk_hw *hw; + + if (mux_present) { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + mux_hw = >hw; + mux->reg = reg; + mux->shift = PCG_PCS_SHIFT; + mux->mask = PCG_PCS_MASK; + } + + if (rate_present) { + fd = kzalloc(sizeof(*fd), GFP_KERNEL); + if (!fd) { + kfree(mux); + return ERR_PTR(-ENOMEM); + } + fd_hw = >hw; + fd->reg = reg; + fd->mshift = PCG_FRAC_SHIFT; + fd->mwidth = PCG_FRAC_WIDTH; + fd->mmask = PCG_FRAC_MASK; + fd->nshift = PCG_PCD_SHIFT; + fd->nwidth = PCG_PCD_WIDTH; + fd->nmask = PCG_PCD_MASK; + fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED; + } + + if (gate_present) { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + kfree(mux); + kfree(fd); + return ERR_PTR(-ENOMEM); + } + gate_hw = >hw; + gate->reg = reg; + gate->bit_idx = PCG_CGC_SHIFT; + } + + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux_hw, _mux_ops, fd_hw, + _fractional_divider_ops, gate_hw, + _gate_ops, CLK_SET_RATE_GATE | + CLK_SET_PARENT_GATE); + if (IS_ERR(hw)) { + kfree(mux); + kfree(fd); + kfree(gate); + } + + return hw; +} diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index a5a9374..bc43f68 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -71,6 +71,12 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, const char **parent_names, int num_parents); +struct clk_hw *imx_clk_composite(const char *name, +const char * const *parent_names, +int num_parents, bool mux_present, +bool rate_present, bool gate_present, +void __iomem *reg); + struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width, void (*fixup)(u32 *val)); -- 2.7.4
[PATCH RESEND V4 0/9] clk: add imx7ulp clk support
This is a rebased version of below patch series against latest clk tree. [PATCH RESEND V3 0/9] clk: add imx7ulp clk support https://lkml.org/lkml/2018/3/16/310 It only updates the license to SPDX format as well as a minor fix of pllv4. This patch series intends to add imx7ulp clk support. i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks The clocking scheme provides clear separation between M4 domain and A7 domain. Except for a few clock sources shared between two domains, such as the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and clock management are separated and contained within each domain. M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. Note: this series only adds A7 clock domain support as M4 clock domain will be handled by M4 seperately. Change Log: v3->v4: * update after changing scg and pcc into separete nodes according to Rob's suggestion v2->v3: * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible racy Others no changes. v1->v2: * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers * use clk_hw apis to register clocks * use of_clk_add_hw_provider * split the clocks register process into two parts: early part for possible timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for the left normal peripheral clocks registered by a platform driver. Dong Aisheng (9): clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support clk: imx: add pllv4 support clk: imx: add pfdv2 support clk: imx: add composite clk support dt-bindings: clock: add imx7ulp clock binding doc clk: imx: make mux parent strings const clk: imx: implement new clk_hw based APIs clk: imx: add imx7ulp clk driver .../devicetree/bindings/clock/imx7ulp-clock.txt| 87 + drivers/clk/clk-divider.c | 152 +++ drivers/clk/clk-fractional-divider.c | 10 + drivers/clk/imx/Makefile | 6 +- drivers/clk/imx/clk-busy.c | 2 +- drivers/clk/imx/clk-composite.c| 85 + drivers/clk/imx/clk-fixup-mux.c| 2 +- drivers/clk/imx/clk-imx7ulp.c | 209 + drivers/clk/imx/clk-pfdv2.c| 201 drivers/clk/imx/clk-pllv4.c| 182 ++ drivers/clk/imx/clk.c | 22 +++ drivers/clk/imx/clk.h | 92 - include/dt-bindings/clock/imx7ulp-clock.h | 109 +++ include/linux/clk-provider.h | 17 ++ 14 files changed, 1166 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt create mode 100644 drivers/clk/imx/clk-composite.c create mode 100644 drivers/clk/imx/clk-imx7ulp.c create mode 100644 drivers/clk/imx/clk-pfdv2.c create mode 100644 drivers/clk/imx/clk-pllv4.c create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h -- 2.7.4
[PATCH RESEND V4 1/9] clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support
For dividers with zero indicating clock is disabled, instead of giving a warning each time like "clkx: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set" in exist code, we'd like to introduce enable/disable function for it. e.g. 000b - Clock disabled 001b - Divide by 1 010b - Divide by 2 ... Set rate when the clk is disabled will cache the rate request and only when the clk is enabled will the driver actually program the hardware to have the requested divider value. Similarly, when the clk is disabled we'll write a 0 there, but when the clk is enabled we'll restore whatever rate (divider) was chosen last. It does mean that recalc rate will be sort of odd, because when the clk is off it will return 0, and when the clk is on it will return the right rate. So to make things work, we'll need to return the cached rate in recalc rate when the clk is off and read the hardware when the clk is on. NOTE for the default off divider, the recalc rate will still return 0 as there's still no proper preset rate. Enable such divider will give user a reminder error message. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * split normal and gate ops * fix the possible racy v1->v2: * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers --- drivers/clk/clk-divider.c| 152 +++ include/linux/clk-provider.h | 9 +++ 2 files changed, 161 insertions(+) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index b6234a5..b3566fd 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -122,6 +122,9 @@ unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, div = _get_div(table, val, flags, width); if (!div) { + if (flags & CLK_DIVIDER_ZERO_GATE) + return 0; + WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", clk_hw_get_name(hw)); @@ -145,6 +148,34 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, divider->flags, divider->width); } +static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + unsigned int val; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + if (!clk_hw_is_enabled(hw)) { + val = divider->cached_val; + } else { + val = clk_readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + } + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + + return divider_recalc_rate(hw, parent_rate, val, divider->table, + divider->flags, divider->width); +} + static bool _is_valid_table_div(const struct clk_div_table *table, unsigned int div) { @@ -437,6 +468,108 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +static int clk_divider_gate_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + int value; + u32 val; + + value = divider_get_val(rate, parent_rate, divider->table, + divider->width, divider->flags); + if (value < 0) + return value; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + if (clk_hw_is_enabled(hw)) { + if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { + val = clk_div_mask(divider->width) << (divider->shift + 16); + } else { + val = clk_readl(divider->reg); + val &= ~(clk_div_mask(divider->width) << divider->shift); + } + val |= (u32)value << divider->shift; + clk_writel(val, divider->reg); + } else { + divider->cached_val = value; + } + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + + return 0; +} + +static int clk_divider_enable(struct clk_hw *hw) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + u32 val; + + if (!divider->cached_val) { + pr_err("%s: no valid
[PATCH RESEND V4 9/9] clk: imx: add imx7ulp clk driver
i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks The clocking scheme provides clear separation between M4 domain and A7 domain. Except for a few clock sources shared between two domains, such as the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and clock management are separated and contained within each domain. M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. This driver only adds clock support in A7 domain. Note that most clocks required to be operated when gated, e.g. pll, pfd, pcc. And more special cases that scs/ddr/nic mux selecting different clock source requires that clock to be enabled first, then we need set CLK_OPS_PARENT_ENABLE flag for them properly. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * update after changing scg and pcc into separete nodes according to Rob's suggestion v2->v3: * no changes v1->v2: * use of_clk_add_hw_provider instead * split the clocks register process into two parts: early part for possible timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for the left normal peripheral clocks registered by a platform driver. --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx7ulp.c | 209 ++ 2 files changed, 210 insertions(+) create mode 100644 drivers/clk/imx/clk-imx7ulp.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index f4da12c..983c0a5 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -29,4 +29,5 @@ obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o +obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c new file mode 100644 index 000..33dedca --- /dev/null +++ b/drivers/clk/imx/clk-imx7ulp.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static const char * const pll_pre_sels[] = { "sosc", "firc", }; +static const char * const spll_pfd_sels[] = { "spll_pfd0", "spll_pfd1", "spll_pfd2", "spll_pfd3", }; +static const char * const spll_sels[] = { "spll", "spll_pfd_sel", }; +static const char * const apll_pfd_sels[] = { "apll_pfd0", "apll_pfd1", "apll_pfd2", "apll_pfd3", }; +static const char * const apll_sels[] = { "apll", "apll_pfd_sel", }; +static const char * const scs_sels[] = { "dummy", "sosc", "sirc", "firc", "dummy", "apll_sel", "spll_sel", "upll", }; +static const char * const ddr_sels[] = { "apll_pfd_sel", "upll", }; +static const char * const nic_sels[] = { "firc", "ddr_clk", }; +static const char * const periph_plat_sels[] = { "dummy", "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", }; +static const char * const periph_bus_sels[]= { "dummy", "sosc_bus_clk", "mpll", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", }; + +static void __init imx7ulp_clk_scg1_init(struct device_node *np) +{ + struct clk_hw_onecell_data *clk_data; + struct clk_hw **clks; + void __iomem *base; + + clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) * + IMX7ULP_CLK_SCG1_END, GFP_KERNEL); + if (!clk_data) + return; + + clk_data->num = IMX7ULP_CLK_SCG1_END; + clks = clk_data->hws; + + clks[IMX7ULP_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0); + + clks[IMX7ULP_CLK_ROSC] = imx_obtain_fixed_clk_hw(np, "rosc"); + clks[IMX7ULP_CLK_SOSC] = imx_obtain_fixed_clk_hw(np, "sosc"); + clks[IMX7ULP_CLK_SIRC] = imx_obtain_fixed_clk_hw(np, "sirc"); + clks[IMX7ULP_CLK_FIRC] = imx_obtain_fixed_clk_hw(np, "firc"); + clks[IMX7ULP_CLK_MIPI_PLL] = imx_obtain_fixed_clk_hw(np, "mpll"); + clks[IMX7ULP_CLK_UPLL] = imx_obtain_fixed_clk_hw(np, "upll"); + + /* SCG1 */ + base = of_iomap(np, 0); + WARN_ON(!base); + + /* NOTE: xPLL config can't be changed when xPLL is enabled */ + clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_hw_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); + clks[IMX7ULP_CLK_SPLL_PRE_SEL] = imx_clk_hw_mux_flags("spll_pre_sel", base + 0x608,
[PATCH RESEND V4 8/9] clk: imx: implement new clk_hw based APIs
Clock providers are recommended to use the new struct clk_hw based API, so implement IMX clk_hw based provider helpers functions to the new approach. Signed-off-by: Dong Aisheng --- ChangeLog: v2->v4: * no changes v1->v2: new patches --- drivers/clk/imx/clk.c | 22 ++ drivers/clk/imx/clk.h | 62 +++ 2 files changed, 84 insertions(+) diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c index 9074e69..1efed86 100644 --- a/drivers/clk/imx/clk.c +++ b/drivers/clk/imx/clk.c @@ -18,6 +18,16 @@ void __init imx_check_clocks(struct clk *clks[], unsigned int count) i, PTR_ERR(clks[i])); } +void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + if (IS_ERR(clks[i])) + pr_err("i.MX clk %u: register failed with %ld\n", + i, PTR_ERR(clks[i])); +} + static struct clk * __init imx_obtain_fixed_clock_from_dt(const char *name) { struct of_phandle_args phandle; @@ -49,6 +59,18 @@ struct clk * __init imx_obtain_fixed_clock( return clk; } +struct clk_hw * __init imx_obtain_fixed_clk_hw(struct device_node *np, + const char *name) +{ + struct clk *clk; + + clk = of_clk_get_by_name(np, name); + if (IS_ERR(clk)) + return ERR_PTR(-ENOENT); + + return __clk_get_hw(clk); +} + /* * This fixups the register CCM_CSCMR1 write value. * The write/read/divider values of the aclk_podf field diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 7fca912..d3fcaa5 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -8,6 +8,7 @@ extern spinlock_t imx_ccm_lock; void imx_check_clocks(struct clk *clks[], unsigned int count); +void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count); void imx_register_uart_clocks(struct clk ** const clks[]); extern void imx_cscmr1_fixup(u32 *val); @@ -54,6 +55,9 @@ struct clk *clk_register_gate2(struct device *dev, const char *name, struct clk * imx_obtain_fixed_clock( const char *name, unsigned long rate); +struct clk_hw *imx_obtain_fixed_clk_hw(struct device_node *np, + const char *name); + struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, void __iomem *reg, u8 shift, u32 exclusive_mask); @@ -90,6 +94,16 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) return clk_register_fixed_rate(NULL, name, NULL, 0, rate); } +static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate) +{ + return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); +} + +static inline struct clk_hw *imx_get_clk_hw_fixed(const char *name, int rate) +{ + return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); +} + static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, u8 shift, u8 width, const char * const *parents, int num_parents) @@ -113,6 +127,15 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent, reg, shift, width, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_divider(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width) +{ + return clk_hw_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT, + reg, shift, width, 0, _ccm_lock); +} + static inline struct clk *imx_clk_divider_flags(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width, unsigned long flags) @@ -121,6 +144,15 @@ static inline struct clk *imx_clk_divider_flags(const char *name, reg, shift, width, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width, unsigned long flags) +{ + return clk_hw_register_divider(NULL, name, parent, flags, + reg, shift, width, 0, _ccm_lock); +} + static inline struct clk *imx_clk_divider2(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width) { @@ -143,6 +175,13 @@ static inline struct clk *imx_clk_gate_flags(const char *name, const char *paren shift, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_gate(const char *name, const char *parent, +void
[PATCH RESEND V4 0/9] clk: add imx7ulp clk support
This is a rebased version of below patch series against latest clk tree. [PATCH RESEND V3 0/9] clk: add imx7ulp clk support https://lkml.org/lkml/2018/3/16/310 It only updates the license to SPDX format as well as a minor fix of pllv4. This patch series intends to add imx7ulp clk support. i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks The clocking scheme provides clear separation between M4 domain and A7 domain. Except for a few clock sources shared between two domains, such as the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and clock management are separated and contained within each domain. M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. Note: this series only adds A7 clock domain support as M4 clock domain will be handled by M4 seperately. Change Log: v3->v4: * update after changing scg and pcc into separete nodes according to Rob's suggestion v2->v3: * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible racy Others no changes. v1->v2: * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers * use clk_hw apis to register clocks * use of_clk_add_hw_provider * split the clocks register process into two parts: early part for possible timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for the left normal peripheral clocks registered by a platform driver. Dong Aisheng (9): clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support clk: imx: add pllv4 support clk: imx: add pfdv2 support clk: imx: add composite clk support dt-bindings: clock: add imx7ulp clock binding doc clk: imx: make mux parent strings const clk: imx: implement new clk_hw based APIs clk: imx: add imx7ulp clk driver .../devicetree/bindings/clock/imx7ulp-clock.txt| 87 + drivers/clk/clk-divider.c | 152 +++ drivers/clk/clk-fractional-divider.c | 10 + drivers/clk/imx/Makefile | 6 +- drivers/clk/imx/clk-busy.c | 2 +- drivers/clk/imx/clk-composite.c| 85 + drivers/clk/imx/clk-fixup-mux.c| 2 +- drivers/clk/imx/clk-imx7ulp.c | 209 + drivers/clk/imx/clk-pfdv2.c| 201 drivers/clk/imx/clk-pllv4.c| 182 ++ drivers/clk/imx/clk.c | 22 +++ drivers/clk/imx/clk.h | 92 - include/dt-bindings/clock/imx7ulp-clock.h | 109 +++ include/linux/clk-provider.h | 17 ++ 14 files changed, 1166 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/imx7ulp-clock.txt create mode 100644 drivers/clk/imx/clk-composite.c create mode 100644 drivers/clk/imx/clk-imx7ulp.c create mode 100644 drivers/clk/imx/clk-pfdv2.c create mode 100644 drivers/clk/imx/clk-pllv4.c create mode 100644 include/dt-bindings/clock/imx7ulp-clock.h -- 2.7.4
[PATCH RESEND V4 1/9] clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support
For dividers with zero indicating clock is disabled, instead of giving a warning each time like "clkx: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set" in exist code, we'd like to introduce enable/disable function for it. e.g. 000b - Clock disabled 001b - Divide by 1 010b - Divide by 2 ... Set rate when the clk is disabled will cache the rate request and only when the clk is enabled will the driver actually program the hardware to have the requested divider value. Similarly, when the clk is disabled we'll write a 0 there, but when the clk is enabled we'll restore whatever rate (divider) was chosen last. It does mean that recalc rate will be sort of odd, because when the clk is off it will return 0, and when the clk is on it will return the right rate. So to make things work, we'll need to return the cached rate in recalc rate when the clk is off and read the hardware when the clk is on. NOTE for the default off divider, the recalc rate will still return 0 as there's still no proper preset rate. Enable such divider will give user a reminder error message. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * no changes v2->v3: * split normal and gate ops * fix the possible racy v1->v2: * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers --- drivers/clk/clk-divider.c| 152 +++ include/linux/clk-provider.h | 9 +++ 2 files changed, 161 insertions(+) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index b6234a5..b3566fd 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -122,6 +122,9 @@ unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, div = _get_div(table, val, flags, width); if (!div) { + if (flags & CLK_DIVIDER_ZERO_GATE) + return 0; + WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", clk_hw_get_name(hw)); @@ -145,6 +148,34 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, divider->flags, divider->width); } +static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + unsigned int val; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + if (!clk_hw_is_enabled(hw)) { + val = divider->cached_val; + } else { + val = clk_readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + } + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + + return divider_recalc_rate(hw, parent_rate, val, divider->table, + divider->flags, divider->width); +} + static bool _is_valid_table_div(const struct clk_div_table *table, unsigned int div) { @@ -437,6 +468,108 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +static int clk_divider_gate_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + int value; + u32 val; + + value = divider_get_val(rate, parent_rate, divider->table, + divider->width, divider->flags); + if (value < 0) + return value; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + if (clk_hw_is_enabled(hw)) { + if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { + val = clk_div_mask(divider->width) << (divider->shift + 16); + } else { + val = clk_readl(divider->reg); + val &= ~(clk_div_mask(divider->width) << divider->shift); + } + val |= (u32)value << divider->shift; + clk_writel(val, divider->reg); + } else { + divider->cached_val = value; + } + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + + return 0; +} + +static int clk_divider_enable(struct clk_hw *hw) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + u32 val; + + if (!divider->cached_val) { + pr_err("%s: no valid
[PATCH RESEND V4 9/9] clk: imx: add imx7ulp clk driver
i.MX7ULP Clock functions are under joint control of the System Clock Generation (SCG) modules, Peripheral Clock Control (PCC) modules, and Core Mode Controller (CMC)1 blocks The clocking scheme provides clear separation between M4 domain and A7 domain. Except for a few clock sources shared between two domains, such as the System Oscillator clock, the Slow IRC (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and clock management are separated and contained within each domain. M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. This driver only adds clock support in A7 domain. Note that most clocks required to be operated when gated, e.g. pll, pfd, pcc. And more special cases that scs/ddr/nic mux selecting different clock source requires that clock to be enabled first, then we need set CLK_OPS_PARENT_ENABLE flag for them properly. Cc: Stephen Boyd Cc: Michael Turquette Cc: Shawn Guo Cc: Anson Huang Cc: Bai Ping Signed-off-by: Dong Aisheng --- ChangeLog: v3->v4: * update after changing scg and pcc into separete nodes according to Rob's suggestion v2->v3: * no changes v1->v2: * use of_clk_add_hw_provider instead * split the clocks register process into two parts: early part for possible timers clocks registered by CLK_OF_DECLARE_DRIVER and the later part for the left normal peripheral clocks registered by a platform driver. --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx7ulp.c | 209 ++ 2 files changed, 210 insertions(+) create mode 100644 drivers/clk/imx/clk-imx7ulp.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index f4da12c..983c0a5 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -29,4 +29,5 @@ obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o +obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c new file mode 100644 index 000..33dedca --- /dev/null +++ b/drivers/clk/imx/clk-imx7ulp.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017~2018 NXP + * + * Author: Dong Aisheng + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static const char * const pll_pre_sels[] = { "sosc", "firc", }; +static const char * const spll_pfd_sels[] = { "spll_pfd0", "spll_pfd1", "spll_pfd2", "spll_pfd3", }; +static const char * const spll_sels[] = { "spll", "spll_pfd_sel", }; +static const char * const apll_pfd_sels[] = { "apll_pfd0", "apll_pfd1", "apll_pfd2", "apll_pfd3", }; +static const char * const apll_sels[] = { "apll", "apll_pfd_sel", }; +static const char * const scs_sels[] = { "dummy", "sosc", "sirc", "firc", "dummy", "apll_sel", "spll_sel", "upll", }; +static const char * const ddr_sels[] = { "apll_pfd_sel", "upll", }; +static const char * const nic_sels[] = { "firc", "ddr_clk", }; +static const char * const periph_plat_sels[] = { "dummy", "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", }; +static const char * const periph_bus_sels[]= { "dummy", "sosc_bus_clk", "mpll", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", }; + +static void __init imx7ulp_clk_scg1_init(struct device_node *np) +{ + struct clk_hw_onecell_data *clk_data; + struct clk_hw **clks; + void __iomem *base; + + clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) * + IMX7ULP_CLK_SCG1_END, GFP_KERNEL); + if (!clk_data) + return; + + clk_data->num = IMX7ULP_CLK_SCG1_END; + clks = clk_data->hws; + + clks[IMX7ULP_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0); + + clks[IMX7ULP_CLK_ROSC] = imx_obtain_fixed_clk_hw(np, "rosc"); + clks[IMX7ULP_CLK_SOSC] = imx_obtain_fixed_clk_hw(np, "sosc"); + clks[IMX7ULP_CLK_SIRC] = imx_obtain_fixed_clk_hw(np, "sirc"); + clks[IMX7ULP_CLK_FIRC] = imx_obtain_fixed_clk_hw(np, "firc"); + clks[IMX7ULP_CLK_MIPI_PLL] = imx_obtain_fixed_clk_hw(np, "mpll"); + clks[IMX7ULP_CLK_UPLL] = imx_obtain_fixed_clk_hw(np, "upll"); + + /* SCG1 */ + base = of_iomap(np, 0); + WARN_ON(!base); + + /* NOTE: xPLL config can't be changed when xPLL is enabled */ + clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_hw_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); + clks[IMX7ULP_CLK_SPLL_PRE_SEL] = imx_clk_hw_mux_flags("spll_pre_sel", base + 0x608,
[PATCH RESEND V4 8/9] clk: imx: implement new clk_hw based APIs
Clock providers are recommended to use the new struct clk_hw based API, so implement IMX clk_hw based provider helpers functions to the new approach. Signed-off-by: Dong Aisheng --- ChangeLog: v2->v4: * no changes v1->v2: new patches --- drivers/clk/imx/clk.c | 22 ++ drivers/clk/imx/clk.h | 62 +++ 2 files changed, 84 insertions(+) diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c index 9074e69..1efed86 100644 --- a/drivers/clk/imx/clk.c +++ b/drivers/clk/imx/clk.c @@ -18,6 +18,16 @@ void __init imx_check_clocks(struct clk *clks[], unsigned int count) i, PTR_ERR(clks[i])); } +void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + if (IS_ERR(clks[i])) + pr_err("i.MX clk %u: register failed with %ld\n", + i, PTR_ERR(clks[i])); +} + static struct clk * __init imx_obtain_fixed_clock_from_dt(const char *name) { struct of_phandle_args phandle; @@ -49,6 +59,18 @@ struct clk * __init imx_obtain_fixed_clock( return clk; } +struct clk_hw * __init imx_obtain_fixed_clk_hw(struct device_node *np, + const char *name) +{ + struct clk *clk; + + clk = of_clk_get_by_name(np, name); + if (IS_ERR(clk)) + return ERR_PTR(-ENOENT); + + return __clk_get_hw(clk); +} + /* * This fixups the register CCM_CSCMR1 write value. * The write/read/divider values of the aclk_podf field diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 7fca912..d3fcaa5 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -8,6 +8,7 @@ extern spinlock_t imx_ccm_lock; void imx_check_clocks(struct clk *clks[], unsigned int count); +void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count); void imx_register_uart_clocks(struct clk ** const clks[]); extern void imx_cscmr1_fixup(u32 *val); @@ -54,6 +55,9 @@ struct clk *clk_register_gate2(struct device *dev, const char *name, struct clk * imx_obtain_fixed_clock( const char *name, unsigned long rate); +struct clk_hw *imx_obtain_fixed_clk_hw(struct device_node *np, + const char *name); + struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, void __iomem *reg, u8 shift, u32 exclusive_mask); @@ -90,6 +94,16 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) return clk_register_fixed_rate(NULL, name, NULL, 0, rate); } +static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate) +{ + return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); +} + +static inline struct clk_hw *imx_get_clk_hw_fixed(const char *name, int rate) +{ + return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); +} + static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, u8 shift, u8 width, const char * const *parents, int num_parents) @@ -113,6 +127,15 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent, reg, shift, width, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_divider(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width) +{ + return clk_hw_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT, + reg, shift, width, 0, _ccm_lock); +} + static inline struct clk *imx_clk_divider_flags(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width, unsigned long flags) @@ -121,6 +144,15 @@ static inline struct clk *imx_clk_divider_flags(const char *name, reg, shift, width, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width, unsigned long flags) +{ + return clk_hw_register_divider(NULL, name, parent, flags, + reg, shift, width, 0, _ccm_lock); +} + static inline struct clk *imx_clk_divider2(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width) { @@ -143,6 +175,13 @@ static inline struct clk *imx_clk_gate_flags(const char *name, const char *paren shift, 0, _ccm_lock); } +static inline struct clk_hw *imx_clk_hw_gate(const char *name, const char *parent, +void
RE: [PATCH v2 0/4] Port mxs-dcp to imx6ull and imx6sll
Hi Leonard, > -Original Message- > From: Leonard Crestez > Sent: Monday, October 15, 2018 9:28 PM [...] > Subject: [PATCH v2 0/4] Port mxs-dcp to imx6ull and imx6sll > > The DCP block is present on 6sll and 6ull but not enabled. The hardware is > mostly compatible with 6sl, the only important difference is that explicit > clock > enabling is required. > > There were several issues with the functionality of this driver (it didn't > even > probe properly) but they are fixed in cryptodev/master by this series: > https://lore.kernel.org/patchwork/cover/994874/ > Thanks for the work. I will be glad to help the test if you provide some test guides. :-) Regards Dong Aisheng > --- > Changes since v1: > * Add devicetree maintainers for dt-bindings > * Add a patch enabling in imx_v6_v7_defconfig. Since tcrypt now passes this > shouldn't cause any issues > * Link to v1: https://lore.kernel.org/patchwork/cover/994893/ > > Leonard Crestez (4): > dt-bindings: crypto: Mention clocks for mxs-dcp > crypto: mxs-dcp - Add support for dcp clk > ARM: dts: imx6ull: Add dcp node > ARM: imx_v6_v7_defconfig: Enable CRYPTO_DEV_MXS_DCP > > .../devicetree/bindings/crypto/fsl-dcp.txt | 2 ++ > arch/arm/boot/dts/imx6ull.dtsi | 10 ++ > arch/arm/configs/imx_v6_v7_defconfig | 1 + > drivers/crypto/mxs-dcp.c | 18 > ++ > 4 files changed, 31 insertions(+) > > -- > 2.17.1
RE: [PATCH v2 0/4] Port mxs-dcp to imx6ull and imx6sll
Hi Leonard, > -Original Message- > From: Leonard Crestez > Sent: Monday, October 15, 2018 9:28 PM [...] > Subject: [PATCH v2 0/4] Port mxs-dcp to imx6ull and imx6sll > > The DCP block is present on 6sll and 6ull but not enabled. The hardware is > mostly compatible with 6sl, the only important difference is that explicit > clock > enabling is required. > > There were several issues with the functionality of this driver (it didn't > even > probe properly) but they are fixed in cryptodev/master by this series: > https://lore.kernel.org/patchwork/cover/994874/ > Thanks for the work. I will be glad to help the test if you provide some test guides. :-) Regards Dong Aisheng > --- > Changes since v1: > * Add devicetree maintainers for dt-bindings > * Add a patch enabling in imx_v6_v7_defconfig. Since tcrypt now passes this > shouldn't cause any issues > * Link to v1: https://lore.kernel.org/patchwork/cover/994893/ > > Leonard Crestez (4): > dt-bindings: crypto: Mention clocks for mxs-dcp > crypto: mxs-dcp - Add support for dcp clk > ARM: dts: imx6ull: Add dcp node > ARM: imx_v6_v7_defconfig: Enable CRYPTO_DEV_MXS_DCP > > .../devicetree/bindings/crypto/fsl-dcp.txt | 2 ++ > arch/arm/boot/dts/imx6ull.dtsi | 10 ++ > arch/arm/configs/imx_v6_v7_defconfig | 1 + > drivers/crypto/mxs-dcp.c | 18 > ++ > 4 files changed, 31 insertions(+) > > -- > 2.17.1
RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks
Ping > -Original Message- > From: A.s. Dong > Sent: Monday, October 8, 2018 6:43 PM > To: thor.tha...@linux.intel.com; linux-...@vger.kernel.org; sb...@kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > mturque...@baylibre.com; shawn...@kernel.org; dl-linux-imx > ; hdego...@redhat.com > Subject: RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks > > Hi Stephen, > > Gently ping again.. > > > > > > > > Just checking on the status of this patch. The clock routines > > > (patches > > > 1-3) are useful for one of my drivers but if they aren't accepted or > > > will take a long time to be accepted, I'll need to refactor my driver. > > > > > > > Thanks for this information. > > > > Stephen, > > Would you help to proceed this? > > > > Regards > Dong Aisheng
RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks
Ping > -Original Message- > From: A.s. Dong > Sent: Monday, October 8, 2018 6:43 PM > To: thor.tha...@linux.intel.com; linux-...@vger.kernel.org; sb...@kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > mturque...@baylibre.com; shawn...@kernel.org; dl-linux-imx > ; hdego...@redhat.com > Subject: RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks > > Hi Stephen, > > Gently ping again.. > > > > > > > > Just checking on the status of this patch. The clock routines > > > (patches > > > 1-3) are useful for one of my drivers but if they aren't accepted or > > > will take a long time to be accepted, I'll need to refactor my driver. > > > > > > > Thanks for this information. > > > > Stephen, > > Would you help to proceed this? > > > > Regards > Dong Aisheng
RE: [PATCH V4 0/9] clk: add imx7ulp clk support
Ping > -Original Message- > From: A.s. Dong > Sent: Tuesday, September 25, 2018 5:11 PM > To: sb...@kernel.org; shawn...@kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > mturque...@baylibre.com; Anson Huang ; Jacky Bai > ; dl-linux-imx ; > linux-...@vger.kernel.org > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > It's been a few months without comments. > > Shawn & Stephen, > Would you provide some suggestions on how to handle this? > > Regards > Dong Aisheng > > > -Original Message- > > From: A.s. Dong > > Sent: Thursday, September 6, 2018 11:25 AM > > To: linux-...@vger.kernel.org; sb...@kernel.org; shawn...@kernel.org > > Cc: linux-kernel@vger.kernel.org; > > linux-arm-ker...@lists.infradead.org; > > mturque...@baylibre.com; Anson Huang ; Jacky > Bai > > ; dl-linux-imx > > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > Hi Stephen, > > > > Would you shine some lights on how to proceed? > > > > Regards > > Dong Aisheng > > > > > -Original Message- > > > From: A.s. Dong > > > Sent: Monday, August 27, 2018 11:46 AM > > > To: linux-...@vger.kernel.org; sb...@kernel.org; shawn...@kernel.org > > > Cc: linux-kernel@vger.kernel.org; > > > linux-arm-ker...@lists.infradead.org; > > > mturque...@baylibre.com; Anson Huang ; Jacky > > Bai > > > ; dl-linux-imx > > > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > > > Kindly ping again... This is really pending too long... > > > > > > Stephen & Shawn, > > > Any suggestion on how to proceed this patch set? > > > > > > Regards > > > Dong Aisheng > > > > > > > -Original Message- > > > > From: A.s. Dong > > > > Sent: Thursday, July 26, 2018 9:51 AM > > > > To: linux-...@vger.kernel.org; sb...@kernel.org > > > > Cc: linux-kernel@vger.kernel.org; > > > > linux-arm-ker...@lists.infradead.org; > > > > mturque...@baylibre.com; shawn...@kernel.org; Anson Huang > > > > ; Jacky Bai ; dl-linux-imx > > > > > > > > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > > > > > Hi Stephen, > > > > > > > > Do you have a chance to look at it? > > > > This patch series has been pending for quite a long time without > > > > much comments. > > > > > > > > Regards > > > > Dong Aisheng > > > > > > > > > -Original Message- > > > > > From: A.s. Dong > > > > > Sent: Wednesday, July 18, 2018 9:37 PM > > > > > To: linux-...@vger.kernel.org > > > > > Cc: linux-kernel@vger.kernel.org; > > > > > linux-arm-ker...@lists.infradead.org; > > > > > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > > > > Anson > > > > > Huang ; Jacky Bai ; dl- > > > > > linux-imx ; A.s. Dong > > > > > Subject: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > > > > > > > This is a rebased version of below patch series against latest clk > > > > > tree. > > > > > [PATCH RESEND V3 0/9] clk: add imx7ulp clk support > > > > > https://lkml.org/lkml/2018/3/16/310 > > > > > > > > > > This patch series intends to add imx7ulp clk support. > > > > > > > > > > i.MX7ULP Clock functions are under joint control of the System > > > > > Clock Generation (SCG) modules, Peripheral Clock Control (PCC) > > > > > modules, and Core Mode Controller (CMC)1 blocks > > > > > > > > > > The clocking scheme provides clear separation between M4 domain > > > > > and > > > > > A7 domain. Except for a few clock sources shared between two > > > > > domains, such as the System Oscillator clock, the Slow IRC > > > > > (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and > > > > > clock management are separated and contained within each domain. > > > > > > > > > > M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 > > modules. > > > > > A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 > modules. > > > > > > > > > > Note: this series only adds A7 clock domain support as M4 clock > > > &
RE: [PATCH V4 0/9] clk: add imx7ulp clk support
Ping > -Original Message- > From: A.s. Dong > Sent: Tuesday, September 25, 2018 5:11 PM > To: sb...@kernel.org; shawn...@kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > mturque...@baylibre.com; Anson Huang ; Jacky Bai > ; dl-linux-imx ; > linux-...@vger.kernel.org > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > It's been a few months without comments. > > Shawn & Stephen, > Would you provide some suggestions on how to handle this? > > Regards > Dong Aisheng > > > -Original Message- > > From: A.s. Dong > > Sent: Thursday, September 6, 2018 11:25 AM > > To: linux-...@vger.kernel.org; sb...@kernel.org; shawn...@kernel.org > > Cc: linux-kernel@vger.kernel.org; > > linux-arm-ker...@lists.infradead.org; > > mturque...@baylibre.com; Anson Huang ; Jacky > Bai > > ; dl-linux-imx > > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > Hi Stephen, > > > > Would you shine some lights on how to proceed? > > > > Regards > > Dong Aisheng > > > > > -Original Message- > > > From: A.s. Dong > > > Sent: Monday, August 27, 2018 11:46 AM > > > To: linux-...@vger.kernel.org; sb...@kernel.org; shawn...@kernel.org > > > Cc: linux-kernel@vger.kernel.org; > > > linux-arm-ker...@lists.infradead.org; > > > mturque...@baylibre.com; Anson Huang ; Jacky > > Bai > > > ; dl-linux-imx > > > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > > > Kindly ping again... This is really pending too long... > > > > > > Stephen & Shawn, > > > Any suggestion on how to proceed this patch set? > > > > > > Regards > > > Dong Aisheng > > > > > > > -Original Message- > > > > From: A.s. Dong > > > > Sent: Thursday, July 26, 2018 9:51 AM > > > > To: linux-...@vger.kernel.org; sb...@kernel.org > > > > Cc: linux-kernel@vger.kernel.org; > > > > linux-arm-ker...@lists.infradead.org; > > > > mturque...@baylibre.com; shawn...@kernel.org; Anson Huang > > > > ; Jacky Bai ; dl-linux-imx > > > > > > > > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > > > > > Hi Stephen, > > > > > > > > Do you have a chance to look at it? > > > > This patch series has been pending for quite a long time without > > > > much comments. > > > > > > > > Regards > > > > Dong Aisheng > > > > > > > > > -Original Message- > > > > > From: A.s. Dong > > > > > Sent: Wednesday, July 18, 2018 9:37 PM > > > > > To: linux-...@vger.kernel.org > > > > > Cc: linux-kernel@vger.kernel.org; > > > > > linux-arm-ker...@lists.infradead.org; > > > > > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > > > > Anson > > > > > Huang ; Jacky Bai ; dl- > > > > > linux-imx ; A.s. Dong > > > > > Subject: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > > > > > > > This is a rebased version of below patch series against latest clk > > > > > tree. > > > > > [PATCH RESEND V3 0/9] clk: add imx7ulp clk support > > > > > https://lkml.org/lkml/2018/3/16/310 > > > > > > > > > > This patch series intends to add imx7ulp clk support. > > > > > > > > > > i.MX7ULP Clock functions are under joint control of the System > > > > > Clock Generation (SCG) modules, Peripheral Clock Control (PCC) > > > > > modules, and Core Mode Controller (CMC)1 blocks > > > > > > > > > > The clocking scheme provides clear separation between M4 domain > > > > > and > > > > > A7 domain. Except for a few clock sources shared between two > > > > > domains, such as the System Oscillator clock, the Slow IRC > > > > > (SIRC), and and the Fast IRC clock (FIRCLK), clock sources and > > > > > clock management are separated and contained within each domain. > > > > > > > > > > M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 > > modules. > > > > > A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 > modules. > > > > > > > > > > Note: this series only adds A7 clock domain support as M4 clock > > > &
RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks
Hi Stephen, Gently ping again.. > > > > > Just checking on the status of this patch. The clock routines (patches > > 1-3) are useful for one of my drivers but if they aren't accepted or > > will take a long time to be accepted, I'll need to refactor my driver. > > > > Thanks for this information. > > Stephen, > Would you help to proceed this? > Regards Dong Aisheng
RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks
Hi Stephen, Gently ping again.. > > > > > Just checking on the status of this patch. The clock routines (patches > > 1-3) are useful for one of my drivers but if they aren't accepted or > > will take a long time to be accepted, I'll need to refactor my driver. > > > > Thanks for this information. > > Stephen, > Would you help to proceed this? > Regards Dong Aisheng
RE: [PATCH 1/1] MAINTAINERS: imx: include drivers/firmware/imx path
> > diff --git a/MAINTAINERS b/MAINTAINERS index 9ad052a..d1fb824 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -1462,6 +1462,7 @@ F:arch/arm/mach-mxs/ > > F: arch/arm/boot/dts/imx* > > F: arch/arm/configs/imx*_defconfig > > F: drivers/clk/imx/ > > +F: drivers/firmware/imx/ > > Please add include/linux/firmware/imx/ too. > Sorry for missing it. Will update now. Regards Dong Aisheng > Shawn > > > F: drivers/soc/imx/ > > F: include/soc/imx/ > > > > -- > > 2.7.4 > >
RE: [PATCH 1/1] MAINTAINERS: imx: include drivers/firmware/imx path
> > diff --git a/MAINTAINERS b/MAINTAINERS index 9ad052a..d1fb824 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -1462,6 +1462,7 @@ F:arch/arm/mach-mxs/ > > F: arch/arm/boot/dts/imx* > > F: arch/arm/configs/imx*_defconfig > > F: drivers/clk/imx/ > > +F: drivers/firmware/imx/ > > Please add include/linux/firmware/imx/ too. > Sorry for missing it. Will update now. Regards Dong Aisheng > Shawn > > > F: drivers/soc/imx/ > > F: include/soc/imx/ > > > > -- > > 2.7.4 > >
RE: [PATCH V4 0/9] clk: add imx7ulp clk support
It's been a few months without comments. Shawn & Stephen, Would you provide some suggestions on how to handle this? Regards Dong Aisheng > -Original Message- > From: A.s. Dong > Sent: Thursday, September 6, 2018 11:25 AM > To: linux-...@vger.kernel.org; sb...@kernel.org; shawn...@kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > mturque...@baylibre.com; Anson Huang ; Jacky Bai > ; dl-linux-imx > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > Hi Stephen, > > Would you shine some lights on how to proceed? > > Regards > Dong Aisheng > > > -Original Message- > > From: A.s. Dong > > Sent: Monday, August 27, 2018 11:46 AM > > To: linux-...@vger.kernel.org; sb...@kernel.org; shawn...@kernel.org > > Cc: linux-kernel@vger.kernel.org; > > linux-arm-ker...@lists.infradead.org; > > mturque...@baylibre.com; Anson Huang ; Jacky > Bai > > ; dl-linux-imx > > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > Kindly ping again... This is really pending too long... > > > > Stephen & Shawn, > > Any suggestion on how to proceed this patch set? > > > > Regards > > Dong Aisheng > > > > > -Original Message- > > > From: A.s. Dong > > > Sent: Thursday, July 26, 2018 9:51 AM > > > To: linux-...@vger.kernel.org; sb...@kernel.org > > > Cc: linux-kernel@vger.kernel.org; > > > linux-arm-ker...@lists.infradead.org; > > > mturque...@baylibre.com; shawn...@kernel.org; Anson Huang > > > ; Jacky Bai ; dl-linux-imx > > > > > > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > > > Hi Stephen, > > > > > > Do you have a chance to look at it? > > > This patch series has been pending for quite a long time without > > > much comments. > > > > > > Regards > > > Dong Aisheng > > > > > > > -----Original Message- > > > > From: A.s. Dong > > > > Sent: Wednesday, July 18, 2018 9:37 PM > > > > To: linux-...@vger.kernel.org > > > > Cc: linux-kernel@vger.kernel.org; > > > > linux-arm-ker...@lists.infradead.org; > > > > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > > > Anson > > > > Huang ; Jacky Bai ; dl- > > > > linux-imx ; A.s. Dong > > > > Subject: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > > > > > This is a rebased version of below patch series against latest clk tree. > > > > [PATCH RESEND V3 0/9] clk: add imx7ulp clk support > > > > https://lkml.org/lkml/2018/3/16/310 > > > > > > > > This patch series intends to add imx7ulp clk support. > > > > > > > > i.MX7ULP Clock functions are under joint control of the System > > > > Clock Generation (SCG) modules, Peripheral Clock Control (PCC) > > > > modules, and Core Mode Controller (CMC)1 blocks > > > > > > > > The clocking scheme provides clear separation between M4 domain > > > > and > > > > A7 domain. Except for a few clock sources shared between two > > > > domains, such as the System Oscillator clock, the Slow IRC (SIRC), > > > > and and the Fast IRC clock (FIRCLK), clock sources and clock > > > > management are separated and contained within each domain. > > > > > > > > M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 > modules. > > > > A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. > > > > > > > > Note: this series only adds A7 clock domain support as M4 clock > > > > domain will be handled by M4 seperately. > > > > > > > > Change Log: > > > > v3->v4: > > > > * rebased to latest kernel > > > > * make scg and pcc separate nodes according to Rob's suggestion > > > > > > > > v2->v3: > > > > * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible > racy > > > >Others no changes. > > > > > > > > v1->v2: > > > > * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE > > > > dividers > > > > * use clk_hw apis to register clocks > > > > * use of_clk_add_hw_provider > > > > * split the clocks register process into two parts: early part for > > > > possible > > > >timers clocks registered by CLK_OF_DECLARE_DRIVER and the later >
RE: [PATCH V4 0/9] clk: add imx7ulp clk support
It's been a few months without comments. Shawn & Stephen, Would you provide some suggestions on how to handle this? Regards Dong Aisheng > -Original Message- > From: A.s. Dong > Sent: Thursday, September 6, 2018 11:25 AM > To: linux-...@vger.kernel.org; sb...@kernel.org; shawn...@kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > mturque...@baylibre.com; Anson Huang ; Jacky Bai > ; dl-linux-imx > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > Hi Stephen, > > Would you shine some lights on how to proceed? > > Regards > Dong Aisheng > > > -Original Message- > > From: A.s. Dong > > Sent: Monday, August 27, 2018 11:46 AM > > To: linux-...@vger.kernel.org; sb...@kernel.org; shawn...@kernel.org > > Cc: linux-kernel@vger.kernel.org; > > linux-arm-ker...@lists.infradead.org; > > mturque...@baylibre.com; Anson Huang ; Jacky > Bai > > ; dl-linux-imx > > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > Kindly ping again... This is really pending too long... > > > > Stephen & Shawn, > > Any suggestion on how to proceed this patch set? > > > > Regards > > Dong Aisheng > > > > > -Original Message- > > > From: A.s. Dong > > > Sent: Thursday, July 26, 2018 9:51 AM > > > To: linux-...@vger.kernel.org; sb...@kernel.org > > > Cc: linux-kernel@vger.kernel.org; > > > linux-arm-ker...@lists.infradead.org; > > > mturque...@baylibre.com; shawn...@kernel.org; Anson Huang > > > ; Jacky Bai ; dl-linux-imx > > > > > > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > > > Hi Stephen, > > > > > > Do you have a chance to look at it? > > > This patch series has been pending for quite a long time without > > > much comments. > > > > > > Regards > > > Dong Aisheng > > > > > > > -----Original Message- > > > > From: A.s. Dong > > > > Sent: Wednesday, July 18, 2018 9:37 PM > > > > To: linux-...@vger.kernel.org > > > > Cc: linux-kernel@vger.kernel.org; > > > > linux-arm-ker...@lists.infradead.org; > > > > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > > > Anson > > > > Huang ; Jacky Bai ; dl- > > > > linux-imx ; A.s. Dong > > > > Subject: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > > > > > This is a rebased version of below patch series against latest clk tree. > > > > [PATCH RESEND V3 0/9] clk: add imx7ulp clk support > > > > https://lkml.org/lkml/2018/3/16/310 > > > > > > > > This patch series intends to add imx7ulp clk support. > > > > > > > > i.MX7ULP Clock functions are under joint control of the System > > > > Clock Generation (SCG) modules, Peripheral Clock Control (PCC) > > > > modules, and Core Mode Controller (CMC)1 blocks > > > > > > > > The clocking scheme provides clear separation between M4 domain > > > > and > > > > A7 domain. Except for a few clock sources shared between two > > > > domains, such as the System Oscillator clock, the Slow IRC (SIRC), > > > > and and the Fast IRC clock (FIRCLK), clock sources and clock > > > > management are separated and contained within each domain. > > > > > > > > M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 > modules. > > > > A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. > > > > > > > > Note: this series only adds A7 clock domain support as M4 clock > > > > domain will be handled by M4 seperately. > > > > > > > > Change Log: > > > > v3->v4: > > > > * rebased to latest kernel > > > > * make scg and pcc separate nodes according to Rob's suggestion > > > > > > > > v2->v3: > > > > * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible > racy > > > >Others no changes. > > > > > > > > v1->v2: > > > > * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE > > > > dividers > > > > * use clk_hw apis to register clocks > > > > * use of_clk_add_hw_provider > > > > * split the clocks register process into two parts: early part for > > > > possible > > > >timers clocks registered by CLK_OF_DECLARE_DRIVER and the later >
RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks
> -Original Message- > From: Thor Thayer [mailto:thor.tha...@linux.intel.com] > Sent: Wednesday, September 19, 2018 10:47 PM > To: A.s. Dong ; linux-...@vger.kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > dl-linux-imx ; hdego...@redhat.com > Subject: Re: [PATCH V6 0/4] clk: new APIs to handle all available clocks > > Hi, > > On 09/16/2018 08:24 AM, A.s. Dong wrote: > > Ping again > > > >> -Original Message- > >> From: A.s. Dong > >> Sent: Thursday, September 6, 2018 11:23 AM > >> To: linux-...@vger.kernel.org > >> Cc: linux-kernel@vger.kernel.org; > >> linux-arm-ker...@lists.infradead.org; > >> sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > >> thor.tha...@linux.intel.com; dl-linux-imx ; > >> hdego...@redhat.com > >> Subject: RE: [PATCH V6 0/4] clk: new APIs to handle all available > >> clocks > >> > >> Gently ping... > >> > >>> -Original Message- > >>> From: A.s. Dong > >>> Sent: Friday, August 31, 2018 12:46 PM > >>> To: linux-...@vger.kernel.org > >>> Cc: linux-kernel@vger.kernel.org; > >>> linux-arm-ker...@lists.infradead.org; > >>> sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > >>> thor.tha...@linux.intel.com; dl-linux-imx ; > >>> hdego...@redhat.com; A.s. Dong > >>> Subject: [PATCH V6 0/4] clk: new APIs to handle all available clocks > >>> > >>> This patch series is a continue of discussion from here, > >>> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fp > >>> > atchwork.kernel.org%2Fpatch%2F9986293%2Fdata=02%7C01%7Caishe > ng. > >>> > dong%40nxp.com%7Cb79f0aa8c74c4f935adb08d61e3e7944%7C686ea1d3bc > 2b4c6f > >>> > a92cd99c5c301635%7C0%7C0%7C636729651014549633sdata=zh0RP > Vt4pqyM > >>> 84SUFRpDcbIH583JNONlBhTQeLYwDFo%3Dreserved=0 > >>> that some users may want to handle all available clocks from device > >>> tree without need to know the detailed clock information likes clock > >>> numbers and names. This is useful in writing some generic drivers to > >>> handle > >> clock part. > >>> > >>> Note: > >>> This patch series is tested on MX6Q SDB cpufreq driver with a minor > >>> change to switch to use clk_bulk_get_all. > >>> But patch 4 only test compiling. Hopefully someone could help test > >>> the function. > >>> > >>> v3->v4: > >>> * improve 'devres->clks = *clks' according to Stephen's suggestion > >>> v2->v3: > >>> * address all comments from Stephen > >>> * fix build warnings on other architectures. > >>> v1->v2: > >>> * add clk_bulk_{get|put}_all() which only supports DT platform > >>> currently > >>> * remove _all variants and the wrapper struct clk_bulk > >>> * make of_clk_bulk_get and of_clk_bulk_get_all private until someone > >>> proves they need it because they don't have a struct device pointer. > >>> > >>> Dong Aisheng (4): > >>>clk: bulk: add of_clk_bulk_get() > >>>clk: add new APIs to operate on all available clocks > >>>clk: add managed version of clk_bulk_get_all > >>>video: simplefb: switch to use clk_bulk API to simplify clock > >>> operations > >>> > >>> drivers/clk/clk-bulk.c | 80 > >>> ++ > >>> drivers/clk/clk-devres.c | 24 + > >>> drivers/video/fbdev/simplefb.c | 72 > >>> ++--- > >>> include/linux/clk.h| 65 > >>> +- > >>> 4 files changed, 186 insertions(+), 55 deletions(-) > >>> > >>> -- > >>> 2.7.4 > > > Just checking on the status of this patch. The clock routines (patches > 1-3) are useful for one of my drivers but if they aren't accepted or will > take a > long time to be accepted, I'll need to refactor my driver. > Thanks for this information. Stephen, Would you help to proceed this? Regards Dong Aisheng
RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks
> -Original Message- > From: Thor Thayer [mailto:thor.tha...@linux.intel.com] > Sent: Wednesday, September 19, 2018 10:47 PM > To: A.s. Dong ; linux-...@vger.kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > dl-linux-imx ; hdego...@redhat.com > Subject: Re: [PATCH V6 0/4] clk: new APIs to handle all available clocks > > Hi, > > On 09/16/2018 08:24 AM, A.s. Dong wrote: > > Ping again > > > >> -Original Message- > >> From: A.s. Dong > >> Sent: Thursday, September 6, 2018 11:23 AM > >> To: linux-...@vger.kernel.org > >> Cc: linux-kernel@vger.kernel.org; > >> linux-arm-ker...@lists.infradead.org; > >> sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > >> thor.tha...@linux.intel.com; dl-linux-imx ; > >> hdego...@redhat.com > >> Subject: RE: [PATCH V6 0/4] clk: new APIs to handle all available > >> clocks > >> > >> Gently ping... > >> > >>> -Original Message- > >>> From: A.s. Dong > >>> Sent: Friday, August 31, 2018 12:46 PM > >>> To: linux-...@vger.kernel.org > >>> Cc: linux-kernel@vger.kernel.org; > >>> linux-arm-ker...@lists.infradead.org; > >>> sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > >>> thor.tha...@linux.intel.com; dl-linux-imx ; > >>> hdego...@redhat.com; A.s. Dong > >>> Subject: [PATCH V6 0/4] clk: new APIs to handle all available clocks > >>> > >>> This patch series is a continue of discussion from here, > >>> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fp > >>> > atchwork.kernel.org%2Fpatch%2F9986293%2Fdata=02%7C01%7Caishe > ng. > >>> > dong%40nxp.com%7Cb79f0aa8c74c4f935adb08d61e3e7944%7C686ea1d3bc > 2b4c6f > >>> > a92cd99c5c301635%7C0%7C0%7C636729651014549633sdata=zh0RP > Vt4pqyM > >>> 84SUFRpDcbIH583JNONlBhTQeLYwDFo%3Dreserved=0 > >>> that some users may want to handle all available clocks from device > >>> tree without need to know the detailed clock information likes clock > >>> numbers and names. This is useful in writing some generic drivers to > >>> handle > >> clock part. > >>> > >>> Note: > >>> This patch series is tested on MX6Q SDB cpufreq driver with a minor > >>> change to switch to use clk_bulk_get_all. > >>> But patch 4 only test compiling. Hopefully someone could help test > >>> the function. > >>> > >>> v3->v4: > >>> * improve 'devres->clks = *clks' according to Stephen's suggestion > >>> v2->v3: > >>> * address all comments from Stephen > >>> * fix build warnings on other architectures. > >>> v1->v2: > >>> * add clk_bulk_{get|put}_all() which only supports DT platform > >>> currently > >>> * remove _all variants and the wrapper struct clk_bulk > >>> * make of_clk_bulk_get and of_clk_bulk_get_all private until someone > >>> proves they need it because they don't have a struct device pointer. > >>> > >>> Dong Aisheng (4): > >>>clk: bulk: add of_clk_bulk_get() > >>>clk: add new APIs to operate on all available clocks > >>>clk: add managed version of clk_bulk_get_all > >>>video: simplefb: switch to use clk_bulk API to simplify clock > >>> operations > >>> > >>> drivers/clk/clk-bulk.c | 80 > >>> ++ > >>> drivers/clk/clk-devres.c | 24 + > >>> drivers/video/fbdev/simplefb.c | 72 > >>> ++--- > >>> include/linux/clk.h| 65 > >>> +- > >>> 4 files changed, 186 insertions(+), 55 deletions(-) > >>> > >>> -- > >>> 2.7.4 > > > Just checking on the status of this patch. The clock routines (patches > 1-3) are useful for one of my drivers but if they aren't accepted or will > take a > long time to be accepted, I'll need to refactor my driver. > Thanks for this information. Stephen, Would you help to proceed this? Regards Dong Aisheng
RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks
Ping again > -Original Message- > From: A.s. Dong > Sent: Thursday, September 6, 2018 11:23 AM > To: linux-...@vger.kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > thor.tha...@linux.intel.com; dl-linux-imx ; > hdego...@redhat.com > Subject: RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks > > Gently ping... > > > -Original Message- > > From: A.s. Dong > > Sent: Friday, August 31, 2018 12:46 PM > > To: linux-...@vger.kernel.org > > Cc: linux-kernel@vger.kernel.org; > > linux-arm-ker...@lists.infradead.org; > > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > > thor.tha...@linux.intel.com; dl-linux-imx ; > > hdego...@redhat.com; A.s. Dong > > Subject: [PATCH V6 0/4] clk: new APIs to handle all available clocks > > > > This patch series is a continue of discussion from here, > > https://patchwork.kernel.org/patch/9986293/ > > that some users may want to handle all available clocks from device > > tree without need to know the detailed clock information likes clock > > numbers and names. This is useful in writing some generic drivers to handle > clock part. > > > > Note: > > This patch series is tested on MX6Q SDB cpufreq driver with a minor > > change to switch to use clk_bulk_get_all. > > But patch 4 only test compiling. Hopefully someone could help test the > > function. > > > > v3->v4: > > * improve 'devres->clks = *clks' according to Stephen's suggestion > > v2->v3: > > * address all comments from Stephen > > * fix build warnings on other architectures. > > v1->v2: > > * add clk_bulk_{get|put}_all() which only supports DT platform > > currently > > * remove _all variants and the wrapper struct clk_bulk > > * make of_clk_bulk_get and of_clk_bulk_get_all private until someone > >proves they need it because they don't have a struct device pointer. > > > > Dong Aisheng (4): > > clk: bulk: add of_clk_bulk_get() > > clk: add new APIs to operate on all available clocks > > clk: add managed version of clk_bulk_get_all > > video: simplefb: switch to use clk_bulk API to simplify clock > > operations > > > > drivers/clk/clk-bulk.c | 80 > > ++ > > drivers/clk/clk-devres.c | 24 + > > drivers/video/fbdev/simplefb.c | 72 ++--- > > include/linux/clk.h| 65 > > +- > > 4 files changed, 186 insertions(+), 55 deletions(-) > > > > -- > > 2.7.4
RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks
Ping again > -Original Message- > From: A.s. Dong > Sent: Thursday, September 6, 2018 11:23 AM > To: linux-...@vger.kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > thor.tha...@linux.intel.com; dl-linux-imx ; > hdego...@redhat.com > Subject: RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks > > Gently ping... > > > -Original Message- > > From: A.s. Dong > > Sent: Friday, August 31, 2018 12:46 PM > > To: linux-...@vger.kernel.org > > Cc: linux-kernel@vger.kernel.org; > > linux-arm-ker...@lists.infradead.org; > > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > > thor.tha...@linux.intel.com; dl-linux-imx ; > > hdego...@redhat.com; A.s. Dong > > Subject: [PATCH V6 0/4] clk: new APIs to handle all available clocks > > > > This patch series is a continue of discussion from here, > > https://patchwork.kernel.org/patch/9986293/ > > that some users may want to handle all available clocks from device > > tree without need to know the detailed clock information likes clock > > numbers and names. This is useful in writing some generic drivers to handle > clock part. > > > > Note: > > This patch series is tested on MX6Q SDB cpufreq driver with a minor > > change to switch to use clk_bulk_get_all. > > But patch 4 only test compiling. Hopefully someone could help test the > > function. > > > > v3->v4: > > * improve 'devres->clks = *clks' according to Stephen's suggestion > > v2->v3: > > * address all comments from Stephen > > * fix build warnings on other architectures. > > v1->v2: > > * add clk_bulk_{get|put}_all() which only supports DT platform > > currently > > * remove _all variants and the wrapper struct clk_bulk > > * make of_clk_bulk_get and of_clk_bulk_get_all private until someone > >proves they need it because they don't have a struct device pointer. > > > > Dong Aisheng (4): > > clk: bulk: add of_clk_bulk_get() > > clk: add new APIs to operate on all available clocks > > clk: add managed version of clk_bulk_get_all > > video: simplefb: switch to use clk_bulk API to simplify clock > > operations > > > > drivers/clk/clk-bulk.c | 80 > > ++ > > drivers/clk/clk-devres.c | 24 + > > drivers/video/fbdev/simplefb.c | 72 ++--- > > include/linux/clk.h| 65 > > +- > > 4 files changed, 186 insertions(+), 55 deletions(-) > > > > -- > > 2.7.4
RE: [PATCH V4 0/9] clk: add imx7ulp clk support
Hi Stephen, Would you shine some lights on how to proceed? Regards Dong Aisheng > -Original Message- > From: A.s. Dong > Sent: Monday, August 27, 2018 11:46 AM > To: linux-...@vger.kernel.org; sb...@kernel.org; shawn...@kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > mturque...@baylibre.com; Anson Huang ; Jacky Bai > ; dl-linux-imx > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > Kindly ping again... This is really pending too long... > > Stephen & Shawn, > Any suggestion on how to proceed this patch set? > > Regards > Dong Aisheng > > > -Original Message- > > From: A.s. Dong > > Sent: Thursday, July 26, 2018 9:51 AM > > To: linux-...@vger.kernel.org; sb...@kernel.org > > Cc: linux-kernel@vger.kernel.org; > > linux-arm-ker...@lists.infradead.org; > > mturque...@baylibre.com; shawn...@kernel.org; Anson Huang > > ; Jacky Bai ; dl-linux-imx > > > > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > Hi Stephen, > > > > Do you have a chance to look at it? > > This patch series has been pending for quite a long time without much > > comments. > > > > Regards > > Dong Aisheng > > > > > -Original Message- > > > From: A.s. Dong > > > Sent: Wednesday, July 18, 2018 9:37 PM > > > To: linux-...@vger.kernel.org > > > Cc: linux-kernel@vger.kernel.org; > > > linux-arm-ker...@lists.infradead.org; > > > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > > Anson > > > Huang ; Jacky Bai ; dl- > > > linux-imx ; A.s. Dong > > > Subject: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > > > This is a rebased version of below patch series against latest clk tree. > > > [PATCH RESEND V3 0/9] clk: add imx7ulp clk support > > > https://lkml.org/lkml/2018/3/16/310 > > > > > > This patch series intends to add imx7ulp clk support. > > > > > > i.MX7ULP Clock functions are under joint control of the System Clock > > > Generation (SCG) modules, Peripheral Clock Control (PCC) modules, > > > and Core Mode Controller (CMC)1 blocks > > > > > > The clocking scheme provides clear separation between M4 domain and > > > A7 domain. Except for a few clock sources shared between two > > > domains, such as the System Oscillator clock, the Slow IRC (SIRC), > > > and and the Fast IRC clock (FIRCLK), clock sources and clock > > > management are separated and contained within each domain. > > > > > > M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. > > > A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. > > > > > > Note: this series only adds A7 clock domain support as M4 clock > > > domain will be handled by M4 seperately. > > > > > > Change Log: > > > v3->v4: > > > * rebased to latest kernel > > > * make scg and pcc separate nodes according to Rob's suggestion > > > > > > v2->v3: > > > * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible > > > racy > > >Others no changes. > > > > > > v1->v2: > > > * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers > > > * use clk_hw apis to register clocks > > > * use of_clk_add_hw_provider > > > * split the clocks register process into two parts: early part for > > > possible > > >timers clocks registered by CLK_OF_DECLARE_DRIVER and the later > > > part > > for > > >the left normal peripheral clocks registered by a platform driver. > > > > > > Dong Aisheng (9): > > > clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support > > > clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag > support > > > clk: imx: add pllv4 support > > > clk: imx: add pfdv2 support > > > clk: imx: add composite clk support > > > dt-bindings: clock: add imx7ulp clock binding doc > > > clk: imx: make mux parent strings const > > > clk: imx: implement new clk_hw based APIs > > > clk: imx: add imx7ulp clk driver > > > > > > .../devicetree/bindings/clock/imx7ulp-clock.txt| 87 + > > > drivers/clk/clk-divider.c | 152 > > +++ > > > drivers/clk/clk-fractional-divider.c | 10 + > > > drivers/clk/imx/Makefile | 6 +- &
RE: [PATCH V4 0/9] clk: add imx7ulp clk support
Hi Stephen, Would you shine some lights on how to proceed? Regards Dong Aisheng > -Original Message- > From: A.s. Dong > Sent: Monday, August 27, 2018 11:46 AM > To: linux-...@vger.kernel.org; sb...@kernel.org; shawn...@kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > mturque...@baylibre.com; Anson Huang ; Jacky Bai > ; dl-linux-imx > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > Kindly ping again... This is really pending too long... > > Stephen & Shawn, > Any suggestion on how to proceed this patch set? > > Regards > Dong Aisheng > > > -Original Message- > > From: A.s. Dong > > Sent: Thursday, July 26, 2018 9:51 AM > > To: linux-...@vger.kernel.org; sb...@kernel.org > > Cc: linux-kernel@vger.kernel.org; > > linux-arm-ker...@lists.infradead.org; > > mturque...@baylibre.com; shawn...@kernel.org; Anson Huang > > ; Jacky Bai ; dl-linux-imx > > > > Subject: RE: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > Hi Stephen, > > > > Do you have a chance to look at it? > > This patch series has been pending for quite a long time without much > > comments. > > > > Regards > > Dong Aisheng > > > > > -Original Message- > > > From: A.s. Dong > > > Sent: Wednesday, July 18, 2018 9:37 PM > > > To: linux-...@vger.kernel.org > > > Cc: linux-kernel@vger.kernel.org; > > > linux-arm-ker...@lists.infradead.org; > > > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > > Anson > > > Huang ; Jacky Bai ; dl- > > > linux-imx ; A.s. Dong > > > Subject: [PATCH V4 0/9] clk: add imx7ulp clk support > > > > > > This is a rebased version of below patch series against latest clk tree. > > > [PATCH RESEND V3 0/9] clk: add imx7ulp clk support > > > https://lkml.org/lkml/2018/3/16/310 > > > > > > This patch series intends to add imx7ulp clk support. > > > > > > i.MX7ULP Clock functions are under joint control of the System Clock > > > Generation (SCG) modules, Peripheral Clock Control (PCC) modules, > > > and Core Mode Controller (CMC)1 blocks > > > > > > The clocking scheme provides clear separation between M4 domain and > > > A7 domain. Except for a few clock sources shared between two > > > domains, such as the System Oscillator clock, the Slow IRC (SIRC), > > > and and the Fast IRC clock (FIRCLK), clock sources and clock > > > management are separated and contained within each domain. > > > > > > M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules. > > > A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules. > > > > > > Note: this series only adds A7 clock domain support as M4 clock > > > domain will be handled by M4 seperately. > > > > > > Change Log: > > > v3->v4: > > > * rebased to latest kernel > > > * make scg and pcc separate nodes according to Rob's suggestion > > > > > > v2->v3: > > > * Patch 1 changed on: 1) split normal and gate ops 2) fix the possible > > > racy > > >Others no changes. > > > > > > v1->v2: > > > * add enable/disable for the type of CLK_DIVIDER_ZERO_GATE dividers > > > * use clk_hw apis to register clocks > > > * use of_clk_add_hw_provider > > > * split the clocks register process into two parts: early part for > > > possible > > >timers clocks registered by CLK_OF_DECLARE_DRIVER and the later > > > part > > for > > >the left normal peripheral clocks registered by a platform driver. > > > > > > Dong Aisheng (9): > > > clk: clk-divider: add CLK_DIVIDER_ZERO_GATE clk support > > > clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag > support > > > clk: imx: add pllv4 support > > > clk: imx: add pfdv2 support > > > clk: imx: add composite clk support > > > dt-bindings: clock: add imx7ulp clock binding doc > > > clk: imx: make mux parent strings const > > > clk: imx: implement new clk_hw based APIs > > > clk: imx: add imx7ulp clk driver > > > > > > .../devicetree/bindings/clock/imx7ulp-clock.txt| 87 + > > > drivers/clk/clk-divider.c | 152 > > +++ > > > drivers/clk/clk-fractional-divider.c | 10 + > > > drivers/clk/imx/Makefile | 6 +- &
RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks
Gently ping... > -Original Message- > From: A.s. Dong > Sent: Friday, August 31, 2018 12:46 PM > To: linux-...@vger.kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > thor.tha...@linux.intel.com; dl-linux-imx ; > hdego...@redhat.com; A.s. Dong > Subject: [PATCH V6 0/4] clk: new APIs to handle all available clocks > > This patch series is a continue of discussion from here, > https://patchwork.kernel.org/patch/9986293/ > that some users may want to handle all available clocks from device tree > without need to know the detailed clock information likes clock numbers and > names. This is useful in writing some generic drivers to handle clock part. > > Note: > This patch series is tested on MX6Q SDB cpufreq driver with a minor change to > switch to use clk_bulk_get_all. > But patch 4 only test compiling. Hopefully someone could help test the > function. > > v3->v4: > * improve 'devres->clks = *clks' according to Stephen's suggestion > v2->v3: > * address all comments from Stephen > * fix build warnings on other architectures. > v1->v2: > * add clk_bulk_{get|put}_all() which only supports DT platform currently > * remove _all variants and the wrapper struct clk_bulk > * make of_clk_bulk_get and of_clk_bulk_get_all private until someone >proves they need it because they don't have a struct device pointer. > > Dong Aisheng (4): > clk: bulk: add of_clk_bulk_get() > clk: add new APIs to operate on all available clocks > clk: add managed version of clk_bulk_get_all > video: simplefb: switch to use clk_bulk API to simplify clock > operations > > drivers/clk/clk-bulk.c | 80 > ++ > drivers/clk/clk-devres.c | 24 + > drivers/video/fbdev/simplefb.c | 72 ++--- > include/linux/clk.h| 65 > +- > 4 files changed, 186 insertions(+), 55 deletions(-) > > -- > 2.7.4
RE: [PATCH V6 0/4] clk: new APIs to handle all available clocks
Gently ping... > -Original Message- > From: A.s. Dong > Sent: Friday, August 31, 2018 12:46 PM > To: linux-...@vger.kernel.org > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > sb...@kernel.org; mturque...@baylibre.com; shawn...@kernel.org; > thor.tha...@linux.intel.com; dl-linux-imx ; > hdego...@redhat.com; A.s. Dong > Subject: [PATCH V6 0/4] clk: new APIs to handle all available clocks > > This patch series is a continue of discussion from here, > https://patchwork.kernel.org/patch/9986293/ > that some users may want to handle all available clocks from device tree > without need to know the detailed clock information likes clock numbers and > names. This is useful in writing some generic drivers to handle clock part. > > Note: > This patch series is tested on MX6Q SDB cpufreq driver with a minor change to > switch to use clk_bulk_get_all. > But patch 4 only test compiling. Hopefully someone could help test the > function. > > v3->v4: > * improve 'devres->clks = *clks' according to Stephen's suggestion > v2->v3: > * address all comments from Stephen > * fix build warnings on other architectures. > v1->v2: > * add clk_bulk_{get|put}_all() which only supports DT platform currently > * remove _all variants and the wrapper struct clk_bulk > * make of_clk_bulk_get and of_clk_bulk_get_all private until someone >proves they need it because they don't have a struct device pointer. > > Dong Aisheng (4): > clk: bulk: add of_clk_bulk_get() > clk: add new APIs to operate on all available clocks > clk: add managed version of clk_bulk_get_all > video: simplefb: switch to use clk_bulk API to simplify clock > operations > > drivers/clk/clk-bulk.c | 80 > ++ > drivers/clk/clk-devres.c | 24 + > drivers/video/fbdev/simplefb.c | 72 ++--- > include/linux/clk.h| 65 > +- > 4 files changed, 186 insertions(+), 55 deletions(-) > > -- > 2.7.4
RE: [PATCH V4 4/4] video: simplefb: switch to use clk_bulk API to simplify clock operations
> -Original Message- > From: Hans de Goede [mailto:hdego...@redhat.com] > Sent: Wednesday, August 29, 2018 9:01 PM [...] > > @@ -252,39 +228,21 @@ static int simplefb_clocks_get(struct simplefb_par > *par, > > static void simplefb_clocks_enable(struct simplefb_par *par, > >struct platform_device *pdev) > > { > > - int i, ret; > > + int ret; > > + > > + ret = clk_bulk_prepare_enable(par->clk_count, par->clks); > > + if (ret) > > + dev_warn(>dev, "failed to enable clocks\n"); > > If clk_bulk_prepare_enable() fails, it leaves all clocks disabled, so you > should > not set par->clks_enabled = true; then. > Thanks for spotting this. The original code wanted to keep the behavior as before. But a bit more thinking that unlike the exist code, clk_bulk_prepare_enable will automatically do reverse clean up once it fails. So no need to set par->clks_enabled = true anymore. Will fix it and resend. Regards Dong Aisheng > Otherwise this patch looks good. > > Regards, > > Hans
RE: [PATCH V4 4/4] video: simplefb: switch to use clk_bulk API to simplify clock operations
> -Original Message- > From: Hans de Goede [mailto:hdego...@redhat.com] > Sent: Wednesday, August 29, 2018 9:01 PM [...] > > @@ -252,39 +228,21 @@ static int simplefb_clocks_get(struct simplefb_par > *par, > > static void simplefb_clocks_enable(struct simplefb_par *par, > >struct platform_device *pdev) > > { > > - int i, ret; > > + int ret; > > + > > + ret = clk_bulk_prepare_enable(par->clk_count, par->clks); > > + if (ret) > > + dev_warn(>dev, "failed to enable clocks\n"); > > If clk_bulk_prepare_enable() fails, it leaves all clocks disabled, so you > should > not set par->clks_enabled = true; then. > Thanks for spotting this. The original code wanted to keep the behavior as before. But a bit more thinking that unlike the exist code, clk_bulk_prepare_enable will automatically do reverse clean up once it fails. So no need to set par->clks_enabled = true anymore. Will fix it and resend. Regards Dong Aisheng > Otherwise this patch looks good. > > Regards, > > Hans
RE: [PATCH V3 0/4] clk: new APIs to handle all available clocks
> -Original Message- > From: Stephen Boyd [mailto:sb...@kernel.org] > Sent: Wednesday, August 29, 2018 11:09 AM > To: A.s. Dong > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > mturque...@baylibre.com; shawn...@kernel.org; dl-linux-imx > ; thor.tha...@linux.intel.com; linux-...@vger.kernel.org > Subject: RE: [PATCH V3 0/4] clk: new APIs to handle all available clocks > > Quoting A.s. Dong (2018-08-16 19:33:52) > > Hi Stephen, > > > > Do you want me to resend this series for review? > > It seems have been pending for quite a long time. > > > > Thor just pinged me for its status as he wants to use it. > > > > I was waiting for someone to try them out or review them. Good that it > happened! > > I've taken a look at the patches and I'm slightly annoyed with the API that > passes in a double pointer to clk_bulk_data and returns a count of the number > of clks found. I guess it's ok though. It's really just this > line: > > devres->clks = *clks; > > which makes my brain all confused and go think about what's being assigned > and if it's a struct copy or not. > > Maybe this on top would make it easier to take? I'll think about it tonight. > Looks like a good idea to me. Will update and resend. Thanks for the suggestion. Regards Dong Aisheng > ---8<--- > diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index > 6d3ca5ec5de8..12c87457eca1 100644 > --- a/drivers/clk/clk-devres.c > +++ b/drivers/clk/clk-devres.c > @@ -81,9 +81,9 @@ int __must_check devm_clk_bulk_get_all(struct device > *dev, > if (!devres) > return -ENOMEM; > > - ret = clk_bulk_get_all(dev, clks); > + ret = clk_bulk_get_all(dev, >clks); > if (ret > 0) { > - devres->clks = *clks; > + *clks = devres->clks; > devres->num_clks = ret; > devres_add(dev, devres); > } else {
RE: [PATCH V3 0/4] clk: new APIs to handle all available clocks
> -Original Message- > From: Stephen Boyd [mailto:sb...@kernel.org] > Sent: Wednesday, August 29, 2018 11:09 AM > To: A.s. Dong > Cc: linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; > mturque...@baylibre.com; shawn...@kernel.org; dl-linux-imx > ; thor.tha...@linux.intel.com; linux-...@vger.kernel.org > Subject: RE: [PATCH V3 0/4] clk: new APIs to handle all available clocks > > Quoting A.s. Dong (2018-08-16 19:33:52) > > Hi Stephen, > > > > Do you want me to resend this series for review? > > It seems have been pending for quite a long time. > > > > Thor just pinged me for its status as he wants to use it. > > > > I was waiting for someone to try them out or review them. Good that it > happened! > > I've taken a look at the patches and I'm slightly annoyed with the API that > passes in a double pointer to clk_bulk_data and returns a count of the number > of clks found. I guess it's ok though. It's really just this > line: > > devres->clks = *clks; > > which makes my brain all confused and go think about what's being assigned > and if it's a struct copy or not. > > Maybe this on top would make it easier to take? I'll think about it tonight. > Looks like a good idea to me. Will update and resend. Thanks for the suggestion. Regards Dong Aisheng > ---8<--- > diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index > 6d3ca5ec5de8..12c87457eca1 100644 > --- a/drivers/clk/clk-devres.c > +++ b/drivers/clk/clk-devres.c > @@ -81,9 +81,9 @@ int __must_check devm_clk_bulk_get_all(struct device > *dev, > if (!devres) > return -ENOMEM; > > - ret = clk_bulk_get_all(dev, clks); > + ret = clk_bulk_get_all(dev, >clks); > if (ret > 0) { > - devres->clks = *clks; > + *clks = devres->clks; > devres->num_clks = ret; > devres_add(dev, devres); > } else {
RE: [PATCH] pinctrl: Convert to using %pOFn instead of device_node.name
> -Original Message- > From: Rob Herring [mailto:r...@kernel.org] > Sent: Tuesday, August 28, 2018 9:53 AM > To: linux-kernel@vger.kernel.org > Cc: Linus Walleij ; A.s. Dong > ; Fabio Estevam ; Shawn > Guo ; Stefan Agner ; Pengutronix > Kernel Team ; Sean Wang > ; Matthias Brugger ; > Carlo Caione ; Kevin Hilman ; > Jason Cooper ; Andrew Lunn ; > Gregory Clement ; Sebastian Hesselbarth > ; Jean-Christophe Plagniol-Villard > ; Nicolas Ferre ; > Alexandre Belloni ; Heiko Stuebner > ; Tony Lindgren ; Haojian Zhuang > ; Patrice Chotard ; > Barry Song ; Maxime Coquelin > ; Alexandre Torgue > ; Maxime Ripard ; > Chen-Yu Tsai ; linux-g...@vger.kernel.org; > linux-media...@lists.infradead.org; linux-arm-ker...@lists.infradead.org; > linux-amlo...@lists.infradead.org; linux-rockc...@lists.infradead.org; > linux-o...@vger.kernel.org > Subject: [PATCH] pinctrl: Convert to using %pOFn instead of device_node.name > > In preparation to remove the node name pointer from struct device_node, > convert printf users to use the %pOFn format specifier. > > Cc: Linus Walleij > Cc: Dong Aisheng > Cc: Fabio Estevam > Cc: Shawn Guo > Cc: Stefan Agner > Cc: Pengutronix Kernel Team > Cc: Sean Wang > Cc: Matthias Brugger > Cc: Carlo Caione > Cc: Kevin Hilman > Cc: Jason Cooper > Cc: Andrew Lunn > Cc: Gregory Clement > Cc: Sebastian Hesselbarth > Cc: Jean-Christophe Plagniol-Villard > Cc: Nicolas Ferre > Cc: Alexandre Belloni > Cc: Heiko Stuebner > Cc: Tony Lindgren > Cc: Haojian Zhuang > Cc: Patrice Chotard > Cc: Barry Song > Cc: Maxime Coquelin > Cc: Alexandre Torgue > Cc: Maxime Ripard > Cc: Chen-Yu Tsai > Cc: linux-g...@vger.kernel.org > Cc: linux-media...@lists.infradead.org > Cc: linux-arm-ker...@lists.infradead.org > Cc: linux-amlo...@lists.infradead.org > Cc: linux-rockc...@lists.infradead.org > Cc: linux-o...@vger.kernel.org > Signed-off-by: Rob Herring > --- > drivers/pinctrl/berlin/berlin.c | 6 ++-- > drivers/pinctrl/freescale/pinctrl-imx.c | 7 ++-- > drivers/pinctrl/freescale/pinctrl-imx1-core.c | 12 +++ For i.MX, Acked-by: Dong Aisheng Regards Dong Aisheng
RE: [PATCH] pinctrl: Convert to using %pOFn instead of device_node.name
> -Original Message- > From: Rob Herring [mailto:r...@kernel.org] > Sent: Tuesday, August 28, 2018 9:53 AM > To: linux-kernel@vger.kernel.org > Cc: Linus Walleij ; A.s. Dong > ; Fabio Estevam ; Shawn > Guo ; Stefan Agner ; Pengutronix > Kernel Team ; Sean Wang > ; Matthias Brugger ; > Carlo Caione ; Kevin Hilman ; > Jason Cooper ; Andrew Lunn ; > Gregory Clement ; Sebastian Hesselbarth > ; Jean-Christophe Plagniol-Villard > ; Nicolas Ferre ; > Alexandre Belloni ; Heiko Stuebner > ; Tony Lindgren ; Haojian Zhuang > ; Patrice Chotard ; > Barry Song ; Maxime Coquelin > ; Alexandre Torgue > ; Maxime Ripard ; > Chen-Yu Tsai ; linux-g...@vger.kernel.org; > linux-media...@lists.infradead.org; linux-arm-ker...@lists.infradead.org; > linux-amlo...@lists.infradead.org; linux-rockc...@lists.infradead.org; > linux-o...@vger.kernel.org > Subject: [PATCH] pinctrl: Convert to using %pOFn instead of device_node.name > > In preparation to remove the node name pointer from struct device_node, > convert printf users to use the %pOFn format specifier. > > Cc: Linus Walleij > Cc: Dong Aisheng > Cc: Fabio Estevam > Cc: Shawn Guo > Cc: Stefan Agner > Cc: Pengutronix Kernel Team > Cc: Sean Wang > Cc: Matthias Brugger > Cc: Carlo Caione > Cc: Kevin Hilman > Cc: Jason Cooper > Cc: Andrew Lunn > Cc: Gregory Clement > Cc: Sebastian Hesselbarth > Cc: Jean-Christophe Plagniol-Villard > Cc: Nicolas Ferre > Cc: Alexandre Belloni > Cc: Heiko Stuebner > Cc: Tony Lindgren > Cc: Haojian Zhuang > Cc: Patrice Chotard > Cc: Barry Song > Cc: Maxime Coquelin > Cc: Alexandre Torgue > Cc: Maxime Ripard > Cc: Chen-Yu Tsai > Cc: linux-g...@vger.kernel.org > Cc: linux-media...@lists.infradead.org > Cc: linux-arm-ker...@lists.infradead.org > Cc: linux-amlo...@lists.infradead.org > Cc: linux-rockc...@lists.infradead.org > Cc: linux-o...@vger.kernel.org > Signed-off-by: Rob Herring > --- > drivers/pinctrl/berlin/berlin.c | 6 ++-- > drivers/pinctrl/freescale/pinctrl-imx.c | 7 ++-- > drivers/pinctrl/freescale/pinctrl-imx1-core.c | 12 +++ For i.MX, Acked-by: Dong Aisheng Regards Dong Aisheng