xref: /linux/drivers/gpu/drm/mcde/mcde_clk_div.c (revision f6e8dc9edf963dbc99085e54f6ced6da9daa6100)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/clk-provider.h>
3 #include <linux/io.h>
4 #include <linux/regulator/consumer.h>
5 
6 #include "mcde_drm.h"
7 #include "mcde_display_regs.h"
8 
9 /* The MCDE internal clock dividers for FIFO A and B */
10 struct mcde_clk_div {
11 	struct clk_hw hw;
12 	struct mcde *mcde;
13 	u32 cr;
14 	u32 cr_div;
15 };
16 
17 static int mcde_clk_div_enable(struct clk_hw *hw)
18 {
19 	struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw);
20 	struct mcde *mcde = cdiv->mcde;
21 	u32 val;
22 
23 	spin_lock(&mcde->fifo_crx1_lock);
24 	val = readl(mcde->regs + cdiv->cr);
25 	/*
26 	 * Select the PLL72 (LCD) clock as parent
27 	 * FIXME: implement other parents.
28 	 */
29 	val &= ~MCDE_CRX1_CLKSEL_MASK;
30 	val |= MCDE_CRX1_CLKSEL_CLKPLL72 << MCDE_CRX1_CLKSEL_SHIFT;
31 	/* Internal clock */
32 	val |= MCDE_CRA1_CLKTYPE_TVXCLKSEL1;
33 
34 	/* Clear then set the divider */
35 	val &= ~(MCDE_CRX1_BCD | MCDE_CRX1_PCD_MASK);
36 	val |= cdiv->cr_div;
37 
38 	writel(val, mcde->regs + cdiv->cr);
39 	spin_unlock(&mcde->fifo_crx1_lock);
40 
41 	return 0;
42 }
43 
44 static int mcde_clk_div_choose_div(struct clk_hw *hw, unsigned long rate,
45 				   unsigned long *prate, bool set_parent)
46 {
47 	int best_div = 1, div;
48 	struct clk_hw *parent = clk_hw_get_parent(hw);
49 	unsigned long best_prate = 0;
50 	unsigned long best_diff = ~0ul;
51 	int max_div = (1 << MCDE_CRX1_PCD_BITS) - 1;
52 
53 	for (div = 1; div < max_div; div++) {
54 		unsigned long this_prate, div_rate, diff;
55 
56 		if (set_parent)
57 			this_prate = clk_hw_round_rate(parent, rate * div);
58 		else
59 			this_prate = *prate;
60 		div_rate = DIV_ROUND_UP_ULL(this_prate, div);
61 		diff = abs(rate - div_rate);
62 
63 		if (diff < best_diff) {
64 			best_div = div;
65 			best_diff = diff;
66 			best_prate = this_prate;
67 		}
68 	}
69 
70 	*prate = best_prate;
71 	return best_div;
72 }
73 
74 static int mcde_clk_div_determine_rate(struct clk_hw *hw,
75 				       struct clk_rate_request *req)
76 {
77 	int div = mcde_clk_div_choose_div(hw, req->rate,
78 					  &req->best_parent_rate, true);
79 
80 	req->rate = DIV_ROUND_UP_ULL(req->best_parent_rate, div);
81 
82 	return 0;
83 }
84 
85 static unsigned long mcde_clk_div_recalc_rate(struct clk_hw *hw,
86 					       unsigned long prate)
87 {
88 	struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw);
89 	struct mcde *mcde = cdiv->mcde;
90 	u32 cr;
91 	int div;
92 
93 	/*
94 	 * If the MCDE is not powered we can't access registers.
95 	 * It will come up with 0 in the divider register bits, which
96 	 * means "divide by 2".
97 	 */
98 	if (!regulator_is_enabled(mcde->epod))
99 		return DIV_ROUND_UP_ULL(prate, 2);
100 
101 	cr = readl(mcde->regs + cdiv->cr);
102 	if (cr & MCDE_CRX1_BCD)
103 		return prate;
104 
105 	/* 0 in the PCD means "divide by 2", 1 means "divide by 3" etc */
106 	div = cr & MCDE_CRX1_PCD_MASK;
107 	div += 2;
108 
109 	return DIV_ROUND_UP_ULL(prate, div);
110 }
111 
112 static int mcde_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
113 				  unsigned long prate)
114 {
115 	struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw);
116 	int div = mcde_clk_div_choose_div(hw, rate, &prate, false);
117 	u32 cr = 0;
118 
119 	/*
120 	 * We cache the CR bits to set the divide in the state so that
121 	 * we can call this before we can even write to the hardware.
122 	 */
123 	if (div == 1) {
124 		/* Bypass clock divider */
125 		cr |= MCDE_CRX1_BCD;
126 	} else {
127 		div -= 2;
128 		cr |= div & MCDE_CRX1_PCD_MASK;
129 	}
130 	cdiv->cr_div = cr;
131 
132 	return 0;
133 }
134 
135 static const struct clk_ops mcde_clk_div_ops = {
136 	.enable = mcde_clk_div_enable,
137 	.recalc_rate = mcde_clk_div_recalc_rate,
138 	.determine_rate = mcde_clk_div_determine_rate,
139 	.set_rate = mcde_clk_div_set_rate,
140 };
141 
142 int mcde_init_clock_divider(struct mcde *mcde)
143 {
144 	struct device *dev = mcde->dev;
145 	struct mcde_clk_div *fifoa;
146 	struct mcde_clk_div *fifob;
147 	const char *parent_name;
148 	struct clk_init_data fifoa_init = {
149 		.name = "fifoa",
150 		.ops = &mcde_clk_div_ops,
151 		.parent_names = &parent_name,
152 		.num_parents = 1,
153 		.flags = CLK_SET_RATE_PARENT,
154 	};
155 	struct clk_init_data fifob_init = {
156 		.name = "fifob",
157 		.ops = &mcde_clk_div_ops,
158 		.parent_names = &parent_name,
159 		.num_parents = 1,
160 		.flags = CLK_SET_RATE_PARENT,
161 	};
162 	int ret;
163 
164 	spin_lock_init(&mcde->fifo_crx1_lock);
165 	parent_name = __clk_get_name(mcde->lcd_clk);
166 
167 	/* Allocate 2 clocks */
168 	fifoa = devm_kzalloc(dev, sizeof(*fifoa), GFP_KERNEL);
169 	if (!fifoa)
170 		return -ENOMEM;
171 	fifob = devm_kzalloc(dev, sizeof(*fifob), GFP_KERNEL);
172 	if (!fifob)
173 		return -ENOMEM;
174 
175 	fifoa->mcde = mcde;
176 	fifoa->cr = MCDE_CRA1;
177 	fifoa->hw.init = &fifoa_init;
178 	ret = devm_clk_hw_register(dev, &fifoa->hw);
179 	if (ret) {
180 		dev_err(dev, "error registering FIFO A clock divider\n");
181 		return ret;
182 	}
183 	mcde->fifoa_clk = fifoa->hw.clk;
184 
185 	fifob->mcde = mcde;
186 	fifob->cr = MCDE_CRB1;
187 	fifob->hw.init = &fifob_init;
188 	ret = devm_clk_hw_register(dev, &fifob->hw);
189 	if (ret) {
190 		dev_err(dev, "error registering FIFO B clock divider\n");
191 		return ret;
192 	}
193 	mcde->fifob_clk = fifob->hw.clk;
194 
195 	return 0;
196 }
197