1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2021 NXP
*
* Peng Fan <peng.fan@nxp.com>
*/
#include <log.h>
#include <asm/io.h>
#include <malloc.h>
#include <clk-uclass.h>
#include <dm/device.h>
#include <dm/devres.h>
#include <linux/iopoll.h>
#include <linux/clk-provider.h>
#include <clk.h>
#include "clk.h"
#include <linux/err.h>
#define TIMEOUT_US 500U
#define CCM_DIV_SHIFT 0
#define CCM_DIV_WIDTH 8
#define CCM_MUX_SHIFT 8
#define CCM_MUX_MASK 3
#define CCM_OFF_SHIFT 24
#define CCM_BUSY_SHIFT 28
#define STAT_OFFSET 0x4
#define AUTHEN_OFFSET 0x30
#define TZ_NS_SHIFT 9
#define TZ_NS_MASK BIT(9)
#define WHITE_LIST_SHIFT 16
#define readl_poll_timeout_atomic readl_poll_timeout
static int imx93_clk_composite_wait_ready(struct clk *clk, void __iomem *reg)
{
int ret;
u32 val;
ret = readl_poll_timeout_atomic(reg + STAT_OFFSET, val, !(val & BIT(CCM_BUSY_SHIFT)),
TIMEOUT_US);
if (ret)
pr_err("Slice[%s] busy timeout\n", "TODO");
return ret;
}
static void imx93_clk_composite_gate_endisable(struct clk *clk, int enable)
{
struct clk_gate *gate = to_clk_gate(clk);
u32 reg;
reg = readl(gate->reg);
if (enable)
reg &= ~BIT(gate->bit_idx);
else
reg |= BIT(gate->bit_idx);
writel(reg, gate->reg);
imx93_clk_composite_wait_ready(clk, gate->reg);
}
static int imx93_clk_composite_gate_enable(struct clk *clk)
{
imx93_clk_composite_gate_endisable(clk, 1);
return 0;
}
static int imx93_clk_composite_gate_disable(struct clk *clk)
{
imx93_clk_composite_gate_endisable(clk, 0);
return 0;
}
static const struct clk_ops imx93_clk_composite_gate_ops = {
.enable = imx93_clk_composite_gate_enable,
.disable = imx93_clk_composite_gate_disable,
};
struct clk *imx93_clk_composite_flags(const char *name,
const char * const *parent_names,
int num_parents, void __iomem *reg, u32 domain_id,
unsigned long flags)
{
struct clk *clk = ERR_PTR(-ENOMEM);
struct clk_divider *div = NULL;
struct clk_gate *gate = NULL;
struct clk_mux *mux = NULL;
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux)
goto fail;
mux->reg = reg;
mux->shift = CCM_MUX_SHIFT;
mux->mask = CCM_MUX_MASK;
mux->num_parents = num_parents;
mux->parent_names = parent_names;
mux->flags = flags;
div = kzalloc(sizeof(*div), GFP_KERNEL);
if (!div)
goto fail;
div->reg = reg;
div->shift = CCM_DIV_SHIFT;
div->width = CCM_DIV_WIDTH;
div->flags = CLK_DIVIDER_ROUND_CLOSEST | flags;
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate)
goto fail;
gate->reg = reg;
gate->bit_idx = CCM_OFF_SHIFT;
gate->flags = flags;
clk = clk_register_composite(NULL, name,
parent_names, num_parents,
&mux->clk, &clk_mux_ops,
&div->clk, &clk_divider_ops,
&gate->clk, &imx93_clk_composite_gate_ops,
flags);
if (IS_ERR(clk))
goto fail;
return clk;
fail:
kfree(gate);
kfree(div);
kfree(mux);
return ERR_CAST(clk);
}
|