Skip to content

Commit 897a54f

Browse files
committed
Merge tag 'clk-imx-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux into clk-imx
Pull i.MX clk driver changes from Abel Vesa: - Remove unused helpers from i.MX specific clock header - Rework all clk based helpers to use clk_hw based ones - Rework gate/mux/divider wrappers - Rework imx_clk_hw_composite and imx_clk_hw_pll14xx wrappers - Add i.MX8ULP clock driver and related bindings - Update i.MX pllv4 and composite clocks to support i.MX8ULP - Disable i.MX7ULP composite clock during initialization - Add CLK_SET_RATE_NO_REPARENT flag to the i.MX7ULP composite - Disable the pfd when set pfdv2 clock rate - Add support for i.MX8ULP in pfdv2 - Add the pcc reset controller support on i.MX8ULP - Fix the build break when clk-imx8ulp is built as module - Move csi_sel mux to correct base register in i.MX6UL clock drivr - Fix csi clk gate register in i.MX6UL clock driver - Fix build bug making CLK_IMX8ULP select MXC_CLK * tag 'clk-imx-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux: (21 commits) clk: imx: Make CLK_IMX8ULP select MXC_CLK clk: imx: imx6ul: Fix csi clk gate register clk: imx: imx6ul: Move csi_sel mux to correct base register clk: imx: Fix the build break when clk-imx8ulp build as module clk: imx: Add the pcc reset controller support on imx8ulp clk: imx: Add clock driver for imx8ulp clk: imx: Update the pfdv2 for 8ulp specific support clk: imx: disable the pfd when set pfdv2 clock rate clk: imx: Add 'CLK_SET_RATE_NO_REPARENT' for composite-7ulp clk: imx: disable i.mx7ulp composite clock during initialization clk: imx: Update the compsite driver to support imx8ulp clk: imx: Update the pllv4 to support imx8ulp dt-bindings: clock: Add imx8ulp clock support clk: imx: Rework imx_clk_hw_pll14xx wrapper clk: imx: Rework all imx_clk_hw_composite wrappers clk: imx: Rework all clk_hw_register_divider wrappers clk: imx: Rework all clk_hw_register_mux wrappers clk: imx: Rework all clk_hw_register_gate2 wrappers clk: imx: Rework all clk_hw_register_gate wrappers clk: imx: Make mux/mux2 clk based helpers use clk_hw based ones ...
2 parents 6880fa6 + e8271ef commit 897a54f

File tree

14 files changed

+1276
-348
lines changed

14 files changed

+1276
-348
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/clock/imx8ulp-cgc-clock.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: NXP i.MX8ULP Clock Generation & Control(CGC) Module Binding
8+
9+
maintainers:
10+
- Jacky Bai <[email protected]>
11+
12+
description: |
13+
On i.MX8ULP, The clock sources generation, distribution and management is
14+
under the control of several CGCs & PCCs modules. The CGC modules generate
15+
and distribute clocks on the device.
16+
17+
properties:
18+
compatible:
19+
enum:
20+
- fsl,imx8ulp-cgc1
21+
- fsl,imx8ulp-cgc2
22+
23+
reg:
24+
maxItems: 1
25+
26+
'#clock-cells':
27+
const: 1
28+
29+
required:
30+
- compatible
31+
- reg
32+
- '#clock-cells'
33+
34+
additionalProperties: false
35+
36+
examples:
37+
# Clock Generation & Control Module node:
38+
- |
39+
clock-controller@292c0000 {
40+
compatible = "fsl,imx8ulp-cgc1";
41+
reg = <0x292c0000 0x10000>;
42+
#clock-cells = <1>;
43+
};
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/clock/imx8ulp-pcc-clock.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: NXP i.MX8ULP Peripheral Clock Controller(PCC) Module Binding
8+
9+
maintainers:
10+
- Jacky Bai <[email protected]>
11+
12+
description: |
13+
On i.MX8ULP, The clock sources generation, distribution and management is
14+
under the control of several CGCs & PCCs modules. The PCC modules control
15+
software reset, clock selection, optional division and clock gating mode
16+
for peripherals.
17+
18+
properties:
19+
compatible:
20+
enum:
21+
- fsl,imx8ulp-pcc3
22+
- fsl,imx8ulp-pcc4
23+
- fsl,imx8ulp-pcc5
24+
25+
reg:
26+
maxItems: 1
27+
28+
'#clock-cells':
29+
const: 1
30+
31+
'#reset-cells':
32+
const: 1
33+
34+
required:
35+
- compatible
36+
- reg
37+
- '#clock-cells'
38+
- '#reset-cells'
39+
40+
additionalProperties: false
41+
42+
examples:
43+
# Peripheral Clock Control Module node:
44+
- |
45+
clock-controller@292d0000 {
46+
compatible = "fsl,imx8ulp-pcc3";
47+
reg = <0x292d0000 0x10000>;
48+
#clock-cells = <1>;
49+
#reset-cells = <1>;
50+
};

drivers/clk/imx/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,10 @@ config CLK_IMX8QXP
9898
select MXC_CLK_SCU
9999
help
100100
Build the driver for IMX8QXP SCU based clocks.
101+
102+
config CLK_IMX8ULP
103+
tristate "IMX8ULP CCM Clock Driver"
104+
depends on ARCH_MXC || COMPILE_TEST
105+
select MXC_CLK
106+
help
107+
Build the driver for i.MX8ULP CCM Clock Driver

drivers/clk/imx/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ clk-imx-scu-$(CONFIG_CLK_IMX8QXP) += clk-scu.o clk-imx8qxp.o \
3131
clk-imx8qxp-rsrc.o clk-imx8qm-rsrc.o
3232
clk-imx-lpcg-scu-$(CONFIG_CLK_IMX8QXP) += clk-lpcg-scu.o clk-imx8qxp-lpcg.o
3333

34+
obj-$(CONFIG_CLK_IMX8ULP) += clk-imx8ulp.o
35+
3436
obj-$(CONFIG_CLK_IMX1) += clk-imx1.o
3537
obj-$(CONFIG_CLK_IMX25) += clk-imx25.o
3638
obj-$(CONFIG_CLK_IMX27) += clk-imx27.o

drivers/clk/imx/clk-composite-7ulp.c

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/bits.h>
99
#include <linux/clk-provider.h>
1010
#include <linux/err.h>
11+
#include <linux/io.h>
1112
#include <linux/slab.h>
1213

1314
#include "../clk-fractional-divider.h"
@@ -23,17 +24,61 @@
2324
#define PCG_PCD_WIDTH 3
2425
#define PCG_PCD_MASK 0x7
2526

26-
struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
27+
#define SW_RST BIT(28)
28+
29+
static int pcc_gate_enable(struct clk_hw *hw)
30+
{
31+
struct clk_gate *gate = to_clk_gate(hw);
32+
unsigned long flags;
33+
u32 val;
34+
int ret;
35+
36+
ret = clk_gate_ops.enable(hw);
37+
if (ret)
38+
return ret;
39+
40+
spin_lock_irqsave(gate->lock, flags);
41+
/*
42+
* release the sw reset for peripherals associated with
43+
* with this pcc clock.
44+
*/
45+
val = readl(gate->reg);
46+
val |= SW_RST;
47+
writel(val, gate->reg);
48+
49+
spin_unlock_irqrestore(gate->lock, flags);
50+
51+
return 0;
52+
}
53+
54+
static void pcc_gate_disable(struct clk_hw *hw)
55+
{
56+
clk_gate_ops.disable(hw);
57+
}
58+
59+
static int pcc_gate_is_enabled(struct clk_hw *hw)
60+
{
61+
return clk_gate_ops.is_enabled(hw);
62+
}
63+
64+
static const struct clk_ops pcc_gate_ops = {
65+
.enable = pcc_gate_enable,
66+
.disable = pcc_gate_disable,
67+
.is_enabled = pcc_gate_is_enabled,
68+
};
69+
70+
static struct clk_hw *imx_ulp_clk_hw_composite(const char *name,
2771
const char * const *parent_names,
2872
int num_parents, bool mux_present,
2973
bool rate_present, bool gate_present,
30-
void __iomem *reg)
74+
void __iomem *reg, bool has_swrst)
3175
{
3276
struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL;
3377
struct clk_fractional_divider *fd = NULL;
3478
struct clk_gate *gate = NULL;
3579
struct clk_mux *mux = NULL;
3680
struct clk_hw *hw;
81+
u32 val;
3782

3883
if (mux_present) {
3984
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
@@ -43,6 +88,8 @@ struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
4388
mux->reg = reg;
4489
mux->shift = PCG_PCS_SHIFT;
4590
mux->mask = PCG_PCS_MASK;
91+
if (has_swrst)
92+
mux->lock = &imx_ccm_lock;
4693
}
4794

4895
if (rate_present) {
@@ -60,6 +107,8 @@ struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
60107
fd->nwidth = PCG_PCD_WIDTH;
61108
fd->nmask = PCG_PCD_MASK;
62109
fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
110+
if (has_swrst)
111+
fd->lock = &imx_ccm_lock;
63112
}
64113

65114
if (gate_present) {
@@ -72,13 +121,27 @@ struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
72121
gate_hw = &gate->hw;
73122
gate->reg = reg;
74123
gate->bit_idx = PCG_CGC_SHIFT;
124+
if (has_swrst)
125+
gate->lock = &imx_ccm_lock;
126+
/*
127+
* make sure clock is gated during clock tree initialization,
128+
* the HW ONLY allow clock parent/rate changed with clock gated,
129+
* during clock tree initialization, clocks could be enabled
130+
* by bootloader, so the HW status will mismatch with clock tree
131+
* prepare count, then clock core driver will allow parent/rate
132+
* change since the prepare count is zero, but HW actually
133+
* prevent the parent/rate change due to the clock is enabled.
134+
*/
135+
val = readl_relaxed(reg);
136+
val &= ~(1 << PCG_CGC_SHIFT);
137+
writel_relaxed(val, reg);
75138
}
76139

77140
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
78141
mux_hw, &clk_mux_ops, fd_hw,
79142
&clk_fractional_divider_ops, gate_hw,
80-
&clk_gate_ops, CLK_SET_RATE_GATE |
81-
CLK_SET_PARENT_GATE);
143+
has_swrst ? &pcc_gate_ops : &clk_gate_ops, CLK_SET_RATE_GATE |
144+
CLK_SET_PARENT_GATE | CLK_SET_RATE_NO_REPARENT);
82145
if (IS_ERR(hw)) {
83146
kfree(mux);
84147
kfree(fd);
@@ -87,3 +150,20 @@ struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
87150

88151
return hw;
89152
}
153+
154+
struct clk_hw *imx7ulp_clk_hw_composite(const char *name, const char * const *parent_names,
155+
int num_parents, bool mux_present, bool rate_present,
156+
bool gate_present, void __iomem *reg)
157+
{
158+
return imx_ulp_clk_hw_composite(name, parent_names, num_parents, mux_present, rate_present,
159+
gate_present, reg, false);
160+
}
161+
162+
struct clk_hw *imx8ulp_clk_hw_composite(const char *name, const char * const *parent_names,
163+
int num_parents, bool mux_present, bool rate_present,
164+
bool gate_present, void __iomem *reg, bool has_swrst)
165+
{
166+
return imx_ulp_clk_hw_composite(name, parent_names, num_parents, mux_present, rate_present,
167+
gate_present, reg, has_swrst);
168+
}
169+
EXPORT_SYMBOL_GPL(imx8ulp_clk_hw_composite);

drivers/clk/imx/clk-composite-8m.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ static const struct clk_ops imx8m_clk_composite_mux_ops = {
171171
.determine_rate = imx8m_clk_composite_mux_determine_rate,
172172
};
173173

174-
struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
174+
struct clk_hw *__imx8m_clk_hw_composite(const char *name,
175175
const char * const *parent_names,
176176
int num_parents, void __iomem *reg,
177177
u32 composite_flags,
@@ -246,4 +246,4 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
246246
kfree(mux);
247247
return ERR_CAST(hw);
248248
}
249-
EXPORT_SYMBOL_GPL(imx8m_clk_hw_composite_flags);
249+
EXPORT_SYMBOL_GPL(__imx8m_clk_hw_composite);

drivers/clk/imx/clk-imx6ul.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
161161
hws[IMX6UL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
162162
hws[IMX6UL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
163163
hws[IMX6UL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
164-
hws[IMX6UL_CLK_CSI_SEL] = imx_clk_hw_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT);
165164

166165
/* Do not bypass PLLs initially */
167166
clk_set_parent(hws[IMX6UL_PLL1_BYPASS]->clk, hws[IMX6UL_CLK_PLL1]->clk);
@@ -270,6 +269,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
270269
hws[IMX6UL_CLK_ECSPI_SEL] = imx_clk_hw_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
271270
hws[IMX6UL_CLK_LCDIF_PRE_SEL] = imx_clk_hw_mux_flags("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels), CLK_SET_RATE_PARENT);
272271
hws[IMX6UL_CLK_LCDIF_SEL] = imx_clk_hw_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
272+
hws[IMX6UL_CLK_CSI_SEL] = imx_clk_hw_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels));
273273

274274
hws[IMX6UL_CLK_LDB_DI0_DIV_SEL] = imx_clk_hw_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
275275
hws[IMX6UL_CLK_LDB_DI1_DIV_SEL] = imx_clk_hw_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
@@ -380,7 +380,6 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
380380
hws[IMX6ULL_CLK_ESAI_IPG] = imx_clk_hw_gate2_shared("esai_ipg", "ahb", base + 0x70, 0, &share_count_esai);
381381
hws[IMX6ULL_CLK_ESAI_MEM] = imx_clk_hw_gate2_shared("esai_mem", "ahb", base + 0x70, 0, &share_count_esai);
382382
}
383-
hws[IMX6UL_CLK_CSI] = imx_clk_hw_gate2("csi", "csi_podf", base + 0x70, 2);
384383
hws[IMX6UL_CLK_I2C1] = imx_clk_hw_gate2("i2c1", "perclk", base + 0x70, 6);
385384
hws[IMX6UL_CLK_I2C2] = imx_clk_hw_gate2("i2c2", "perclk", base + 0x70, 8);
386385
hws[IMX6UL_CLK_I2C3] = imx_clk_hw_gate2("i2c3", "perclk", base + 0x70, 10);
@@ -391,6 +390,12 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
391390
hws[IMX6UL_CLK_PXP] = imx_clk_hw_gate2("pxp", "axi", base + 0x70, 30);
392391

393392
/* CCGR3 */
393+
/*
394+
* Although the imx6ull reference manual lists CCGR2 as the csi clk
395+
* gate register, tests have shown that it is actually the CCGR3
396+
* register bit 0/1, same as for the imx6ul.
397+
*/
398+
hws[IMX6UL_CLK_CSI] = imx_clk_hw_gate2("csi", "csi_podf", base + 0x74, 0);
394399
hws[IMX6UL_CLK_UART5_IPG] = imx_clk_hw_gate2("uart5_ipg", "ipg", base + 0x74, 2);
395400
hws[IMX6UL_CLK_UART5_SERIAL] = imx_clk_hw_gate2("uart5_serial", "uart_podf", base + 0x74, 2);
396401
if (clk_on_imx6ul()) {

drivers/clk/imx/clk-imx7ulp.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,20 +78,20 @@ static void __init imx7ulp_clk_scg1_init(struct device_node *np)
7878
hws[IMX7ULP_CLK_SPLL_PRE_DIV] = imx_clk_hw_divider_flags("spll_pre_div", "spll_pre_sel", base + 0x608, 8, 3, CLK_SET_RATE_GATE);
7979

8080
/* name parent_name base */
81-
hws[IMX7ULP_CLK_APLL] = imx_clk_hw_pllv4("apll", "apll_pre_div", base + 0x500);
82-
hws[IMX7ULP_CLK_SPLL] = imx_clk_hw_pllv4("spll", "spll_pre_div", base + 0x600);
81+
hws[IMX7ULP_CLK_APLL] = imx_clk_hw_pllv4(IMX_PLLV4_IMX7ULP, "apll", "apll_pre_div", base + 0x500);
82+
hws[IMX7ULP_CLK_SPLL] = imx_clk_hw_pllv4(IMX_PLLV4_IMX7ULP, "spll", "spll_pre_div", base + 0x600);
8383

8484
/* APLL PFDs */
85-
hws[IMX7ULP_CLK_APLL_PFD0] = imx_clk_hw_pfdv2("apll_pfd0", "apll", base + 0x50c, 0);
86-
hws[IMX7ULP_CLK_APLL_PFD1] = imx_clk_hw_pfdv2("apll_pfd1", "apll", base + 0x50c, 1);
87-
hws[IMX7ULP_CLK_APLL_PFD2] = imx_clk_hw_pfdv2("apll_pfd2", "apll", base + 0x50c, 2);
88-
hws[IMX7ULP_CLK_APLL_PFD3] = imx_clk_hw_pfdv2("apll_pfd3", "apll", base + 0x50c, 3);
85+
hws[IMX7ULP_CLK_APLL_PFD0] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "apll_pfd0", "apll", base + 0x50c, 0);
86+
hws[IMX7ULP_CLK_APLL_PFD1] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "apll_pfd1", "apll", base + 0x50c, 1);
87+
hws[IMX7ULP_CLK_APLL_PFD2] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "apll_pfd2", "apll", base + 0x50c, 2);
88+
hws[IMX7ULP_CLK_APLL_PFD3] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "apll_pfd3", "apll", base + 0x50c, 3);
8989

9090
/* SPLL PFDs */
91-
hws[IMX7ULP_CLK_SPLL_PFD0] = imx_clk_hw_pfdv2("spll_pfd0", "spll", base + 0x60C, 0);
92-
hws[IMX7ULP_CLK_SPLL_PFD1] = imx_clk_hw_pfdv2("spll_pfd1", "spll", base + 0x60C, 1);
93-
hws[IMX7ULP_CLK_SPLL_PFD2] = imx_clk_hw_pfdv2("spll_pfd2", "spll", base + 0x60C, 2);
94-
hws[IMX7ULP_CLK_SPLL_PFD3] = imx_clk_hw_pfdv2("spll_pfd3", "spll", base + 0x60C, 3);
91+
hws[IMX7ULP_CLK_SPLL_PFD0] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "spll_pfd0", "spll", base + 0x60C, 0);
92+
hws[IMX7ULP_CLK_SPLL_PFD1] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "spll_pfd1", "spll", base + 0x60C, 1);
93+
hws[IMX7ULP_CLK_SPLL_PFD2] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "spll_pfd2", "spll", base + 0x60C, 2);
94+
hws[IMX7ULP_CLK_SPLL_PFD3] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX7ULP, "spll_pfd3", "spll", base + 0x60C, 3);
9595

9696
/* PLL Mux */
9797
hws[IMX7ULP_CLK_APLL_PFD_SEL] = imx_clk_hw_mux_flags("apll_pfd_sel", base + 0x508, 14, 2, apll_pfd_sels, ARRAY_SIZE(apll_pfd_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);

0 commit comments

Comments
 (0)