1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/clk-provider.h>
3 #include <linux/regulator/consumer.h>
6 #include "mcde_display_regs.h"
8 /* The MCDE internal clock dividers for FIFO A and B */
16 static int mcde_clk_div_enable(struct clk_hw
*hw
)
18 struct mcde_clk_div
*cdiv
= container_of(hw
, struct mcde_clk_div
, hw
);
19 struct mcde
*mcde
= cdiv
->mcde
;
22 spin_lock(&mcde
->fifo_crx1_lock
);
23 val
= readl(mcde
->regs
+ cdiv
->cr
);
25 * Select the PLL72 (LCD) clock as parent
26 * FIXME: implement other parents.
28 val
&= ~MCDE_CRX1_CLKSEL_MASK
;
29 val
|= MCDE_CRX1_CLKSEL_CLKPLL72
<< MCDE_CRX1_CLKSEL_SHIFT
;
31 val
|= MCDE_CRA1_CLKTYPE_TVXCLKSEL1
;
33 /* Clear then set the divider */
34 val
&= ~(MCDE_CRX1_BCD
| MCDE_CRX1_PCD_MASK
);
37 writel(val
, mcde
->regs
+ cdiv
->cr
);
38 spin_unlock(&mcde
->fifo_crx1_lock
);
43 static int mcde_clk_div_choose_div(struct clk_hw
*hw
, unsigned long rate
,
44 unsigned long *prate
, bool set_parent
)
46 int best_div
= 1, div
;
47 struct clk_hw
*parent
= clk_hw_get_parent(hw
);
48 unsigned long best_prate
= 0;
49 unsigned long best_diff
= ~0ul;
50 int max_div
= (1 << MCDE_CRX1_PCD_BITS
) - 1;
52 for (div
= 1; div
< max_div
; div
++) {
53 unsigned long this_prate
, div_rate
, diff
;
56 this_prate
= clk_hw_round_rate(parent
, rate
* div
);
59 div_rate
= DIV_ROUND_UP_ULL(this_prate
, div
);
60 diff
= abs(rate
- div_rate
);
62 if (diff
< best_diff
) {
65 best_prate
= this_prate
;
73 static long mcde_clk_div_round_rate(struct clk_hw
*hw
, unsigned long rate
,
76 int div
= mcde_clk_div_choose_div(hw
, rate
, prate
, true);
78 return DIV_ROUND_UP_ULL(*prate
, div
);
81 static unsigned long mcde_clk_div_recalc_rate(struct clk_hw
*hw
,
84 struct mcde_clk_div
*cdiv
= container_of(hw
, struct mcde_clk_div
, hw
);
85 struct mcde
*mcde
= cdiv
->mcde
;
90 * If the MCDE is not powered we can't access registers.
91 * It will come up with 0 in the divider register bits, which
92 * means "divide by 2".
94 if (!regulator_is_enabled(mcde
->epod
))
95 return DIV_ROUND_UP_ULL(prate
, 2);
97 cr
= readl(mcde
->regs
+ cdiv
->cr
);
98 if (cr
& MCDE_CRX1_BCD
)
101 /* 0 in the PCD means "divide by 2", 1 means "divide by 3" etc */
102 div
= cr
& MCDE_CRX1_PCD_MASK
;
105 return DIV_ROUND_UP_ULL(prate
, div
);
108 static int mcde_clk_div_set_rate(struct clk_hw
*hw
, unsigned long rate
,
111 struct mcde_clk_div
*cdiv
= container_of(hw
, struct mcde_clk_div
, hw
);
112 int div
= mcde_clk_div_choose_div(hw
, rate
, &prate
, false);
116 * We cache the CR bits to set the divide in the state so that
117 * we can call this before we can even write to the hardware.
120 /* Bypass clock divider */
124 cr
|= div
& MCDE_CRX1_PCD_MASK
;
131 static const struct clk_ops mcde_clk_div_ops
= {
132 .enable
= mcde_clk_div_enable
,
133 .recalc_rate
= mcde_clk_div_recalc_rate
,
134 .round_rate
= mcde_clk_div_round_rate
,
135 .set_rate
= mcde_clk_div_set_rate
,
138 int mcde_init_clock_divider(struct mcde
*mcde
)
140 struct device
*dev
= mcde
->dev
;
141 struct mcde_clk_div
*fifoa
;
142 struct mcde_clk_div
*fifob
;
143 const char *parent_name
;
144 struct clk_init_data fifoa_init
= {
146 .ops
= &mcde_clk_div_ops
,
147 .parent_names
= &parent_name
,
149 .flags
= CLK_SET_RATE_PARENT
,
151 struct clk_init_data fifob_init
= {
153 .ops
= &mcde_clk_div_ops
,
154 .parent_names
= &parent_name
,
156 .flags
= CLK_SET_RATE_PARENT
,
160 spin_lock_init(&mcde
->fifo_crx1_lock
);
161 parent_name
= __clk_get_name(mcde
->lcd_clk
);
163 /* Allocate 2 clocks */
164 fifoa
= devm_kzalloc(dev
, sizeof(*fifoa
), GFP_KERNEL
);
167 fifob
= devm_kzalloc(dev
, sizeof(*fifob
), GFP_KERNEL
);
172 fifoa
->cr
= MCDE_CRA1
;
173 fifoa
->hw
.init
= &fifoa_init
;
174 ret
= devm_clk_hw_register(dev
, &fifoa
->hw
);
176 dev_err(dev
, "error registering FIFO A clock divider\n");
179 mcde
->fifoa_clk
= fifoa
->hw
.clk
;
182 fifob
->cr
= MCDE_CRB1
;
183 fifob
->hw
.init
= &fifob_init
;
184 ret
= devm_clk_hw_register(dev
, &fifob
->hw
);
186 dev_err(dev
, "error registering FIFO B clock divider\n");
189 mcde
->fifob_clk
= fifob
->hw
.clk
;