Skip to content

Commit 3fa3620

Browse files
JackyBaiabelvesa
authored andcommitted
clk: imx: Add the pcc reset controller support on imx8ulp
On i.MX8ULP, for some of the PCCs, it has a peripheral SW RST bit resides in the same registers as the clock controller. So add this SW RST controller support alongs with the pcc clock initialization. the reset and clock shared the same register, to avoid accessing the same register by reset control and clock control concurrently, locking is necessary, so reuse the imx_ccm_lock spinlock to simplify the code. Suggested-by: Liu Ying <[email protected]> Signed-off-by: Jacky Bai <[email protected]> Reviewed-by: Abel Vesa <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Abel Vesa <[email protected]>
1 parent c43a801 commit 3fa3620

File tree

2 files changed

+123
-3
lines changed

2 files changed

+123
-3
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@
2929
static int pcc_gate_enable(struct clk_hw *hw)
3030
{
3131
struct clk_gate *gate = to_clk_gate(hw);
32+
unsigned long flags;
3233
u32 val;
3334
int ret;
3435

3536
ret = clk_gate_ops.enable(hw);
3637
if (ret)
3738
return ret;
3839

40+
spin_lock_irqsave(gate->lock, flags);
3941
/*
4042
* release the sw reset for peripherals associated with
4143
* with this pcc clock.
@@ -44,6 +46,8 @@ static int pcc_gate_enable(struct clk_hw *hw)
4446
val |= SW_RST;
4547
writel(val, gate->reg);
4648

49+
spin_unlock_irqrestore(gate->lock, flags);
50+
4751
return 0;
4852
}
4953

@@ -84,6 +88,8 @@ static struct clk_hw *imx_ulp_clk_hw_composite(const char *name,
8488
mux->reg = reg;
8589
mux->shift = PCG_PCS_SHIFT;
8690
mux->mask = PCG_PCS_MASK;
91+
if (has_swrst)
92+
mux->lock = &imx_ccm_lock;
8793
}
8894

8995
if (rate_present) {
@@ -101,6 +107,8 @@ static struct clk_hw *imx_ulp_clk_hw_composite(const char *name,
101107
fd->nwidth = PCG_PCD_WIDTH;
102108
fd->nmask = PCG_PCD_MASK;
103109
fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
110+
if (has_swrst)
111+
fd->lock = &imx_ccm_lock;
104112
}
105113

106114
if (gate_present) {
@@ -113,6 +121,8 @@ static struct clk_hw *imx_ulp_clk_hw_composite(const char *name,
113121
gate_hw = &gate->hw;
114122
gate->reg = reg;
115123
gate->bit_idx = PCG_CGC_SHIFT;
124+
if (has_swrst)
125+
gate->lock = &imx_ccm_lock;
116126
/*
117127
* make sure clock is gated during clock tree initialization,
118128
* the HW ONLY allow clock parent/rate changed with clock gated,

drivers/clk/imx/clk-imx8ulp.c

Lines changed: 113 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/module.h>
1010
#include <linux/of_device.h>
1111
#include <linux/platform_device.h>
12+
#include <linux/reset-controller.h>
1213
#include <linux/slab.h>
1314

1415
#include "clk.h"
@@ -48,6 +49,99 @@ static const char * const nic_per_divplat[] = { "nic_per_divplat" };
4849
static const char * const lpav_axi_div[] = { "lpav_axi_div" };
4950
static const char * const lpav_bus_div[] = { "lpav_bus_div" };
5051

52+
struct pcc_reset_dev {
53+
void __iomem *base;
54+
struct reset_controller_dev rcdev;
55+
const u32 *resets;
56+
/* Set to imx_ccm_lock to protect register access shared with clock control */
57+
spinlock_t *lock;
58+
};
59+
60+
#define PCC_SW_RST BIT(28)
61+
#define to_pcc_reset_dev(_rcdev) container_of(_rcdev, struct pcc_reset_dev, rcdev)
62+
63+
static const u32 pcc3_resets[] = {
64+
0xa8, 0xac, 0xc8, 0xcc, 0xd0,
65+
0xd4, 0xd8, 0xdc, 0xe0, 0xe4,
66+
0xe8, 0xec, 0xf0
67+
};
68+
69+
static const u32 pcc4_resets[] = {
70+
0x4, 0x8, 0xc, 0x10, 0x14,
71+
0x18, 0x1c, 0x20, 0x24, 0x34,
72+
0x38, 0x3c, 0x40, 0x44, 0x48,
73+
0x4c, 0x54
74+
};
75+
76+
static const u32 pcc5_resets[] = {
77+
0xa0, 0xa4, 0xa8, 0xac, 0xb0,
78+
0xb4, 0xbc, 0xc0, 0xc8, 0xcc,
79+
0xd0, 0xf0, 0xf4, 0xf8
80+
};
81+
82+
static int imx8ulp_pcc_assert(struct reset_controller_dev *rcdev, unsigned long id)
83+
{
84+
struct pcc_reset_dev *pcc_reset = to_pcc_reset_dev(rcdev);
85+
u32 offset = pcc_reset->resets[id];
86+
unsigned long flags;
87+
u32 val;
88+
89+
spin_lock_irqsave(pcc_reset->lock, flags);
90+
91+
val = readl(pcc_reset->base + offset);
92+
val &= ~PCC_SW_RST;
93+
writel(val, pcc_reset->base + offset);
94+
95+
spin_unlock_irqrestore(pcc_reset->lock, flags);
96+
97+
return 0;
98+
}
99+
100+
static int imx8ulp_pcc_deassert(struct reset_controller_dev *rcdev, unsigned long id)
101+
{
102+
struct pcc_reset_dev *pcc_reset = to_pcc_reset_dev(rcdev);
103+
u32 offset = pcc_reset->resets[id];
104+
unsigned long flags;
105+
u32 val;
106+
107+
spin_lock_irqsave(pcc_reset->lock, flags);
108+
109+
val = readl(pcc_reset->base + offset);
110+
val |= PCC_SW_RST;
111+
writel(val, pcc_reset->base + offset);
112+
113+
spin_unlock_irqrestore(pcc_reset->lock, flags);
114+
115+
return 0;
116+
}
117+
118+
static const struct reset_control_ops imx8ulp_pcc_reset_ops = {
119+
.assert = imx8ulp_pcc_assert,
120+
.deassert = imx8ulp_pcc_deassert,
121+
};
122+
123+
static int imx8ulp_pcc_reset_init(struct platform_device *pdev, void __iomem *base,
124+
const u32 *resets, unsigned int nr_resets)
125+
{
126+
struct device_node *np = pdev->dev.of_node;
127+
struct device *dev = &pdev->dev;
128+
struct pcc_reset_dev *pcc_reset;
129+
130+
pcc_reset = devm_kzalloc(dev, sizeof(*pcc_reset), GFP_KERNEL);
131+
if (!pcc_reset)
132+
return -ENOMEM;
133+
134+
pcc_reset->base = base;
135+
pcc_reset->lock = &imx_ccm_lock;
136+
pcc_reset->resets = resets;
137+
pcc_reset->rcdev.owner = THIS_MODULE;
138+
pcc_reset->rcdev.nr_resets = nr_resets;
139+
pcc_reset->rcdev.ops = &imx8ulp_pcc_reset_ops;
140+
pcc_reset->rcdev.of_node = np;
141+
142+
return devm_reset_controller_register(dev, &pcc_reset->rcdev);
143+
}
144+
51145
static int imx8ulp_clk_cgc1_init(struct platform_device *pdev)
52146
{
53147
struct device *dev = &pdev->dev;
@@ -288,10 +382,13 @@ static int imx8ulp_clk_pcc3_init(struct platform_device *pdev)
288382
imx_check_clk_hws(clks, clk_data->num);
289383

290384
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
385+
if (ret)
386+
return ret;
291387

292388
imx_register_uart_clocks(1);
293389

294-
return ret;
390+
/* register the pcc3 reset controller */
391+
return imx8ulp_pcc_reset_init(pdev, base, pcc3_resets, ARRAY_SIZE(pcc3_resets));
295392
}
296393

297394
static int imx8ulp_clk_pcc4_init(struct platform_device *pdev)
@@ -300,6 +397,7 @@ static int imx8ulp_clk_pcc4_init(struct platform_device *pdev)
300397
struct clk_hw_onecell_data *clk_data;
301398
struct clk_hw **clks;
302399
void __iomem *base;
400+
int ret;
303401

304402
clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_PCC4_END),
305403
GFP_KERNEL);
@@ -339,7 +437,13 @@ static int imx8ulp_clk_pcc4_init(struct platform_device *pdev)
339437

340438
imx_check_clk_hws(clks, clk_data->num);
341439

342-
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
440+
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
441+
if (ret)
442+
return ret;
443+
444+
/* register the pcc4 reset controller */
445+
return imx8ulp_pcc_reset_init(pdev, base, pcc4_resets, ARRAY_SIZE(pcc4_resets));
446+
343447
}
344448

345449
static int imx8ulp_clk_pcc5_init(struct platform_device *pdev)
@@ -348,6 +452,7 @@ static int imx8ulp_clk_pcc5_init(struct platform_device *pdev)
348452
struct clk_hw_onecell_data *clk_data;
349453
struct clk_hw **clks;
350454
void __iomem *base;
455+
int ret;
351456

352457
clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_PCC5_END),
353458
GFP_KERNEL);
@@ -420,7 +525,12 @@ static int imx8ulp_clk_pcc5_init(struct platform_device *pdev)
420525

421526
imx_check_clk_hws(clks, clk_data->num);
422527

423-
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
528+
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
529+
if (ret)
530+
return ret;
531+
532+
/* register the pcc5 reset controller */
533+
return imx8ulp_pcc_reset_init(pdev, base, pcc5_resets, ARRAY_SIZE(pcc5_resets));
424534
}
425535

426536
static int imx8ulp_clk_probe(struct platform_device *pdev)

0 commit comments

Comments
 (0)