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
|
From 126560c909f38f00c08dd5f35f50c981d5e25e1f Mon Sep 17 00:00:00 2001
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Date: Fri, 10 May 2024 15:30:44 +0100
Subject: [PATCH 1177/1215] clk: clk-rp1: Add "varsrc" clocks to represent MIPI
byte clocks
Add a new class of clocks to RP1 to represent clock sources whose
frequency changes at run-time as a side-effect of some other driver.
Specifically this is for the two MIPI DSI byte-clock sources.
Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
---
drivers/clk/clk-rp1.c | 73 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
--- a/drivers/clk/clk-rp1.c
+++ b/drivers/clk/clk-rp1.c
@@ -394,6 +394,11 @@ struct rp1_clock {
unsigned long cached_rate;
};
+struct rp1_varsrc {
+ struct clk_hw hw;
+ struct rp1_clockman *clockman;
+ unsigned long rate;
+};
struct rp1_clk_change {
struct clk_hw *hw;
@@ -1414,6 +1419,34 @@ static void rp1_clk_debug_init(struct cl
rp1_debugfs_regset(clockman, 0, regs, i, dentry);
}
+static int rp1_varsrc_set_rate(struct clk_hw *hw,
+ unsigned long rate, unsigned long parent_rate)
+{
+ struct rp1_varsrc *varsrc = container_of(hw, struct rp1_varsrc, hw);
+
+ /*
+ * "varsrc" exists purely to let clock dividers know the frequency
+ * of an externally-managed clock source (such as MIPI DSI byte-clock)
+ * which may change at run-time as a side-effect of some other driver.
+ */
+ varsrc->rate = rate;
+ return 0;
+}
+
+static unsigned long rp1_varsrc_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct rp1_varsrc *varsrc = container_of(hw, struct rp1_varsrc, hw);
+
+ return varsrc->rate;
+}
+
+static long rp1_varsrc_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ return rate;
+}
+
static const struct clk_ops rp1_pll_core_ops = {
.is_prepared = rp1_pll_core_is_on,
.prepare = rp1_pll_core_on,
@@ -1464,6 +1497,12 @@ static const struct clk_ops rp1_clk_ops
.debug_init = rp1_clk_debug_init,
};
+static const struct clk_ops rp1_varsrc_ops = {
+ .set_rate = rp1_varsrc_set_rate,
+ .recalc_rate = rp1_varsrc_recalc_rate,
+ .round_rate = rp1_varsrc_round_rate,
+};
+
static bool rp1_clk_is_claimed(const char *name);
static struct clk_hw *rp1_register_pll_core(struct rp1_clockman *clockman,
@@ -1647,6 +1686,35 @@ static struct clk_hw *rp1_register_clock
return &clock->hw;
}
+static struct clk_hw *rp1_register_varsrc(struct rp1_clockman *clockman,
+ const void *data)
+{
+ const char *name = *(char const * const *)data;
+ struct rp1_varsrc *clock;
+ struct clk_init_data init;
+ int ret;
+
+ memset(&init, 0, sizeof(init));
+ init.parent_names = &ref_clock;
+ init.num_parents = 1;
+ init.name = name;
+ init.flags = CLK_IGNORE_UNUSED;
+ init.ops = &rp1_varsrc_ops;
+
+ clock = devm_kzalloc(clockman->dev, sizeof(*clock), GFP_KERNEL);
+ if (!clock)
+ return NULL;
+
+ clock->clockman = clockman;
+ clock->hw.init = &init;
+
+ ret = devm_clk_hw_register(clockman->dev, &clock->hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return &clock->hw;
+}
+
struct rp1_clk_desc {
struct clk_hw *(*clk_register)(struct rp1_clockman *clockman,
const void *data);
@@ -1676,6 +1744,8 @@ struct rp1_clk_desc {
&(struct rp1_clock_data) \
{__VA_ARGS__})
+#define REGISTER_VARSRC(n) _REGISTER(&rp1_register_varsrc, &(const char *){n})
+
static const struct rp1_clk_desc clk_desc_array[] = {
[RP1_PLL_SYS_CORE] = REGISTER_PLL_CORE(
.name = "pll_sys_core",
@@ -2318,6 +2388,9 @@ static const struct rp1_clk_desc clk_des
.max_freq = 200 * MHz,
.fc0_src = FC_NUM(3, 6),
),
+
+ [RP1_CLK_MIPI0_DSI_BYTECLOCK] = REGISTER_VARSRC("clksrc_mipi0_dsi_byteclk"),
+ [RP1_CLK_MIPI1_DSI_BYTECLOCK] = REGISTER_VARSRC("clksrc_mipi1_dsi_byteclk"),
};
static bool rp1_clk_claimed[ARRAY_SIZE(clk_desc_array)];
|