1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2017 Rockchip Electronics Co. Ltd.
4 *
5 * Author: Wyon Bi <bivvy.bi@rock-chips.com>
6 */
7
8 #include <linux/clk.h>
9 #include <linux/delay.h>
10 #include <linux/err.h>
11 #include <linux/mfd/rk618.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/module.h>
14 #include <linux/of_device.h>
15 #include <linux/regmap.h>
16
17 #include <drm/drm_of.h>
18 #include <drm/drm_encoder.h>
19 #include <drm/drm_print.h>
20 #include <video/videomode.h>
21
22 #define RK618_SCALER_REG0 0x0030
23 #define SCL_VER_DOWN_MODE(x) HIWORD_UPDATE(x, 8, 8)
24 #define SCL_HOR_DOWN_MODE(x) HIWORD_UPDATE(x, 7, 7)
25 #define SCL_BIC_COE_SEL(x) HIWORD_UPDATE(x, 6, 5)
26 #define SCL_VER_MODE(x) HIWORD_UPDATE(x, 4, 3)
27 #define SCL_HOR_MODE(x) HIWORD_UPDATE(x, 2, 1)
28 #define SCL_ENABLE HIWORD_UPDATE(1, 0, 0)
29 #define SCL_DISABLE HIWORD_UPDATE(0, 0, 0)
30 #define RK618_SCALER_REG1 0x0034
31 #define SCL_V_FACTOR(x) UPDATE(x, 31, 16)
32 #define SCL_H_FACTOR(x) UPDATE(x, 15, 0)
33 #define RK618_SCALER_REG2 0x0038
34 #define DSP_FRAME_VST(x) UPDATE(x, 27, 16)
35 #define DSP_FRAME_HST(x) UPDATE(x, 11, 0)
36 #define RK618_SCALER_REG3 0x003c
37 #define DSP_HS_END(x) UPDATE(x, 23, 16)
38 #define DSP_HTOTAL(x) UPDATE(x, 11, 0)
39 #define RK618_SCALER_REG4 0x0040
40 #define DSP_HACT_END(x) UPDATE(x, 27, 16)
41 #define DSP_HACT_ST(x) UPDATE(x, 11, 0)
42 #define RK618_SCALER_REG5 0x0044
43 #define DSP_VS_END(x) UPDATE(x, 23, 16)
44 #define DSP_VTOTAL(x) UPDATE(x, 11, 0)
45 #define RK618_SCALER_REG6 0x0048
46 #define DSP_VACT_END(x) UPDATE(x, 27, 16)
47 #define DSP_VACT_ST(x) UPDATE(x, 11, 0)
48 #define RK618_SCALER_REG7 0x004c
49 #define DSP_HBOR_END(x) UPDATE(x, 27, 16)
50 #define DSP_HBOR_ST(x) UPDATE(x, 11, 0)
51 #define RK618_SCALER_REG8 0x0050
52 #define DSP_VBOR_END(x) UPDATE(x, 27, 16)
53 #define DSP_VBOR_ST(x) UPDATE(x, 11, 0)
54
55 struct rk618_scaler {
56 struct drm_bridge base;
57 struct drm_bridge *bridge;
58 struct drm_display_mode src;
59 struct drm_display_mode dst;
60 struct device *dev;
61 struct regmap *regmap;
62 struct clk *vif_clk;
63 struct clk *dither_clk;
64 struct clk *scaler_clk;
65 };
66
bridge_to_scaler(struct drm_bridge * bridge)67 static inline struct rk618_scaler *bridge_to_scaler(struct drm_bridge *bridge)
68 {
69 return container_of(bridge, struct rk618_scaler, base);
70 }
71
rk618_scaler_enable(struct rk618_scaler * scl)72 static void rk618_scaler_enable(struct rk618_scaler *scl)
73 {
74 regmap_write(scl->regmap, RK618_SCALER_REG0, SCL_ENABLE);
75 }
76
rk618_scaler_disable(struct rk618_scaler * scl)77 static void rk618_scaler_disable(struct rk618_scaler *scl)
78 {
79 regmap_write(scl->regmap, RK618_SCALER_REG0, SCL_DISABLE);
80 }
81
calc_dsp_frm_hst_vst(const struct videomode * src,const struct videomode * dst,u32 * dsp_frame_hst,u32 * dsp_frame_vst)82 static void calc_dsp_frm_hst_vst(const struct videomode *src,
83 const struct videomode *dst,
84 u32 *dsp_frame_hst, u32 *dsp_frame_vst)
85 {
86 u32 bp_in, bp_out;
87 u32 v_scale_ratio;
88 u64 t_frm_st;
89 u64 t_bp_in, t_bp_out, t_delta, tin;
90 u32 src_pixclock, dst_pixclock;
91 u32 dsp_htotal, src_htotal, src_vtotal;
92
93 src_pixclock = div_u64(1000000000000llu, src->pixelclock);
94 dst_pixclock = div_u64(1000000000000llu, dst->pixelclock);
95
96 src_htotal = src->hsync_len + src->hback_porch + src->hactive +
97 src->hfront_porch;
98 src_vtotal = src->vsync_len + src->vback_porch + src->vactive +
99 src->vfront_porch;
100 dsp_htotal = dst->hsync_len + dst->hback_porch + dst->hactive +
101 dst->hfront_porch;
102
103 bp_in = (src->vback_porch + src->vsync_len) * src_htotal +
104 src->hsync_len + src->hback_porch;
105 bp_out = (dst->vback_porch + dst->vsync_len) * dsp_htotal +
106 dst->hsync_len + dst->hback_porch;
107
108 t_bp_in = bp_in * src_pixclock;
109 t_bp_out = bp_out * dst_pixclock;
110 tin = src_vtotal * src_htotal * src_pixclock;
111
112 v_scale_ratio = src->vactive / dst->vactive;
113 if (v_scale_ratio <= 2)
114 t_delta = 5 * src_htotal * src_pixclock;
115 else
116 t_delta = 12 * src_htotal * src_pixclock;
117
118 if (t_bp_in + t_delta > t_bp_out)
119 t_frm_st = (t_bp_in + t_delta - t_bp_out);
120 else
121 t_frm_st = tin - (t_bp_out - (t_bp_in + t_delta));
122
123 do_div(t_frm_st, src_pixclock);
124 *dsp_frame_hst = do_div(t_frm_st, src_htotal);
125 *dsp_frame_vst = t_frm_st;
126 }
127
rk618_scaler_init(struct rk618_scaler * scl,const struct drm_display_mode * s,const struct drm_display_mode * d)128 static void rk618_scaler_init(struct rk618_scaler *scl,
129 const struct drm_display_mode *s,
130 const struct drm_display_mode *d)
131 {
132 struct videomode src, dst;
133 u32 dsp_frame_hst, dsp_frame_vst;
134 u32 scl_hor_mode, scl_ver_mode;
135 u32 scl_v_factor, scl_h_factor;
136 u32 dsp_htotal, dsp_hs_end, dsp_hact_st, dsp_hact_end;
137 u32 dsp_vtotal, dsp_vs_end, dsp_vact_st, dsp_vact_end;
138 u32 dsp_hbor_end, dsp_hbor_st, dsp_vbor_end, dsp_vbor_st;
139 u16 bor_right = 0, bor_left = 0, bor_up = 0, bor_down = 0;
140 u8 hor_down_mode = 0, ver_down_mode = 0;
141
142 drm_display_mode_to_videomode(s, &src);
143 drm_display_mode_to_videomode(d, &dst);
144
145 dsp_htotal = dst.hsync_len + dst.hback_porch + dst.hactive +
146 dst.hfront_porch;
147 dsp_vtotal = dst.vsync_len + dst.vback_porch + dst.vactive +
148 dst.vfront_porch;
149 dsp_hs_end = dst.hsync_len;
150 dsp_vs_end = dst.vsync_len;
151 dsp_hbor_end = dst.hsync_len + dst.hback_porch + dst.hactive;
152 dsp_hbor_st = dst.hsync_len + dst.hback_porch;
153 dsp_vbor_end = dst.vsync_len + dst.vback_porch + dst.vactive;
154 dsp_vbor_st = dst.vsync_len + dst.vback_porch;
155 dsp_hact_st = dsp_hbor_st + bor_left;
156 dsp_hact_end = dsp_hbor_end - bor_right;
157 dsp_vact_st = dsp_vbor_st + bor_up;
158 dsp_vact_end = dsp_vbor_end - bor_down;
159
160 calc_dsp_frm_hst_vst(&src, &dst, &dsp_frame_hst, &dsp_frame_vst);
161 dev_dbg(scl->dev, "dsp_frame_vst=%d, dsp_frame_hst=%d\n",
162 dsp_frame_vst, dsp_frame_hst);
163
164 if (src.hactive > dst.hactive) {
165 scl_hor_mode = 2;
166
167 if (hor_down_mode == 0) {
168 if ((src.hactive - 1) / (dst.hactive - 1) > 2)
169 scl_h_factor = ((src.hactive - 1) << 14) /
170 (dst.hactive - 1);
171 else
172 scl_h_factor = ((src.hactive - 2) << 14) /
173 (dst.hactive - 1);
174 } else {
175 scl_h_factor = (dst.hactive << 16) /
176 (src.hactive - 1);
177 }
178
179 dev_dbg(scl->dev, "horizontal scale down\n");
180 } else if (src.hactive == dst.hactive) {
181 scl_hor_mode = 0;
182 scl_h_factor = 0;
183
184 dev_dbg(scl->dev, "horizontal no scale\n");
185 } else {
186 scl_hor_mode = 1;
187 scl_h_factor = ((src.hactive - 1) << 16) / (dst.hactive - 1);
188
189 dev_dbg(scl->dev, "horizontal scale up\n");
190 }
191
192 if (src.vactive > dst.vactive) {
193 scl_ver_mode = 2;
194
195 if (ver_down_mode == 0) {
196 if ((src.vactive - 1) / (dst.vactive - 1) > 2)
197 scl_v_factor = ((src.vactive - 1) << 14) /
198 (dst.vactive - 1);
199 else
200 scl_v_factor = ((src.vactive - 2) << 14) /
201 (dst.vactive - 1);
202 } else {
203 scl_v_factor = (dst.vactive << 16) /
204 (src.vactive - 1);
205 }
206
207 dev_dbg(scl->dev, "vertical scale down\n");
208 } else if (src.vactive == dst.vactive) {
209 scl_ver_mode = 0;
210 scl_v_factor = 0;
211
212 dev_dbg(scl->dev, "vertical no scale\n");
213 } else {
214 scl_ver_mode = 1;
215 scl_v_factor = ((src.vactive - 1) << 16) / (dst.vactive - 1);
216
217 dev_dbg(scl->dev, "vertical scale up\n");
218 }
219
220 regmap_write(scl->regmap, RK618_SCALER_REG0,
221 SCL_VER_MODE(scl_ver_mode) | SCL_HOR_MODE(scl_hor_mode));
222 regmap_write(scl->regmap, RK618_SCALER_REG1,
223 SCL_V_FACTOR(scl_v_factor) | SCL_H_FACTOR(scl_h_factor));
224 regmap_write(scl->regmap, RK618_SCALER_REG2,
225 DSP_FRAME_VST(dsp_frame_vst) |
226 DSP_FRAME_HST(dsp_frame_hst));
227 regmap_write(scl->regmap, RK618_SCALER_REG3,
228 DSP_HS_END(dsp_hs_end) | DSP_HTOTAL(dsp_htotal));
229 regmap_write(scl->regmap, RK618_SCALER_REG4,
230 DSP_HACT_END(dsp_hact_end) | DSP_HACT_ST(dsp_hact_st));
231 regmap_write(scl->regmap, RK618_SCALER_REG5,
232 DSP_VS_END(dsp_vs_end) | DSP_VTOTAL(dsp_vtotal));
233 regmap_write(scl->regmap, RK618_SCALER_REG6,
234 DSP_VACT_END(dsp_vact_end) | DSP_VACT_ST(dsp_vact_st));
235 regmap_write(scl->regmap, RK618_SCALER_REG7,
236 DSP_HBOR_END(dsp_hbor_end) | DSP_HBOR_ST(dsp_hbor_st));
237 regmap_write(scl->regmap, RK618_SCALER_REG8,
238 DSP_VBOR_END(dsp_vbor_end) | DSP_VBOR_ST(dsp_vbor_st));
239 }
240
rk618_scaler_bridge_enable(struct drm_bridge * bridge)241 static void rk618_scaler_bridge_enable(struct drm_bridge *bridge)
242 {
243 struct rk618_scaler *scl = bridge_to_scaler(bridge);
244 struct drm_display_mode *src = &scl->src;
245 struct drm_display_mode *dst = &scl->dst;
246 long rate;
247
248 clk_set_parent(scl->dither_clk, scl->scaler_clk);
249
250 rate = clk_round_rate(scl->scaler_clk, dst->clock * 1000);
251 clk_set_rate(scl->scaler_clk, rate);
252 clk_prepare_enable(scl->scaler_clk);
253
254 rk618_scaler_init(scl, src, dst);
255 rk618_scaler_enable(scl);
256 }
257
rk618_scaler_bridge_disable(struct drm_bridge * bridge)258 static void rk618_scaler_bridge_disable(struct drm_bridge *bridge)
259 {
260 struct rk618_scaler *scl = bridge_to_scaler(bridge);
261
262 rk618_scaler_disable(scl);
263 clk_disable_unprepare(scl->scaler_clk);
264 clk_set_parent(scl->dither_clk, scl->vif_clk);
265 }
266
rk618_scaler_bridge_mode_set(struct drm_bridge * bridge,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted)267 static void rk618_scaler_bridge_mode_set(struct drm_bridge *bridge,
268 const struct drm_display_mode *mode,
269 const struct drm_display_mode *adjusted)
270 {
271 struct rk618_scaler *scl = bridge_to_scaler(bridge);
272 struct drm_connector *connector;
273 struct drm_display_mode *src = &scl->src;
274 struct drm_display_mode *dst = &scl->dst;
275 unsigned long dclk_rate;
276 u64 sclk_rate;
277 struct drm_connector_list_iter conn_iter;
278
279 drm_mode_copy(&scl->src, adjusted);
280
281 drm_connector_list_iter_begin(bridge->dev, &conn_iter);
282 drm_for_each_connector_iter(connector, &conn_iter) {
283 const struct drm_display_mode *mode;
284
285 if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)
286 continue;
287
288 if (!drm_connector_has_possible_encoder(connector, bridge->encoder))
289 continue;
290
291 list_for_each_entry(mode, &connector->modes, head) {
292 if (mode->type & DRM_MODE_TYPE_PREFERRED) {
293 drm_mode_copy(&scl->dst, mode);
294 break;
295 }
296 }
297 }
298 drm_connector_list_iter_end(&conn_iter);
299
300 dclk_rate = src->clock * 1000;
301 sclk_rate = (u64)dclk_rate * dst->vdisplay * dst->htotal;
302 do_div(sclk_rate, src->vdisplay * src->htotal);
303 sclk_rate = div_u64(sclk_rate, 1000);
304 dst->clock = sclk_rate;
305 sclk_rate = sclk_rate * 1000;
306 scl->bridge->driver_private = dst;
307
308 DRM_DEV_INFO(scl->dev, "src=%s, dst=%s\n", src->name, dst->name);
309 DRM_DEV_INFO(scl->dev, "dclk rate: %ld, sclk rate: %lld\n",
310 dclk_rate, sclk_rate);
311 }
312
rk618_scaler_bridge_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)313 static int rk618_scaler_bridge_attach(struct drm_bridge *bridge,
314 enum drm_bridge_attach_flags flags)
315 {
316 struct rk618_scaler *scl = bridge_to_scaler(bridge);
317 struct device *dev = scl->dev;
318 struct device_node *endpoint;
319 int ret;
320
321 endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1);
322 if (endpoint && of_device_is_available(endpoint)) {
323 struct device_node *remote;
324
325 remote = of_graph_get_remote_port_parent(endpoint);
326 of_node_put(endpoint);
327 if (!remote || !of_device_is_available(remote))
328 return -ENODEV;
329
330 scl->bridge = of_drm_find_bridge(remote);
331 of_node_put(remote);
332 if (!scl->bridge)
333 return -EPROBE_DEFER;
334
335 ret = drm_bridge_attach(bridge->encoder, scl->bridge, bridge, 0);
336 if (ret) {
337 dev_err(dev, "failed to attach bridge\n");
338 return ret;
339 }
340 }
341
342 return 0;
343 }
344
345 static const struct drm_bridge_funcs rk618_scaler_bridge_funcs = {
346 .enable = rk618_scaler_bridge_enable,
347 .disable = rk618_scaler_bridge_disable,
348 .mode_set = rk618_scaler_bridge_mode_set,
349 .attach = rk618_scaler_bridge_attach,
350 };
351
rk618_scaler_probe(struct platform_device * pdev)352 static int rk618_scaler_probe(struct platform_device *pdev)
353 {
354 struct rk618 *rk618 = dev_get_drvdata(pdev->dev.parent);
355 struct device *dev = &pdev->dev;
356 struct rk618_scaler *scl;
357 int ret;
358
359 if (!of_device_is_available(dev->of_node))
360 return -ENODEV;
361
362 scl = devm_kzalloc(dev, sizeof(*scl), GFP_KERNEL);
363 if (!scl)
364 return -ENOMEM;
365
366 scl->dev = dev;
367 scl->regmap = rk618->regmap;
368 platform_set_drvdata(pdev, scl);
369
370 scl->vif_clk = devm_clk_get(dev, "vif");
371 if (IS_ERR(scl->vif_clk)) {
372 ret = PTR_ERR(scl->vif_clk);
373 dev_err(dev, "failed to get vif clock: %d\n", ret);
374 return ret;
375 }
376
377 scl->dither_clk = devm_clk_get(dev, "dither");
378 if (IS_ERR(scl->dither_clk)) {
379 ret = PTR_ERR(scl->dither_clk);
380 dev_err(dev, "failed to get dither clock: %d\n", ret);
381 return ret;
382 }
383
384 scl->scaler_clk = devm_clk_get(dev, "scaler");
385 if (IS_ERR(scl->scaler_clk)) {
386 ret = PTR_ERR(scl->scaler_clk);
387 dev_err(dev, "failed to get scaler clock: %d\n", ret);
388 return ret;
389 }
390
391 scl->base.funcs = &rk618_scaler_bridge_funcs;
392 scl->base.of_node = dev->of_node;
393 drm_bridge_add(&scl->base);
394
395 return 0;
396 }
397
rk618_scaler_remove(struct platform_device * pdev)398 static int rk618_scaler_remove(struct platform_device *pdev)
399 {
400 struct rk618_scaler *scl = platform_get_drvdata(pdev);
401
402 drm_bridge_remove(&scl->base);
403
404 return 0;
405 }
406
407 static const struct of_device_id rk618_scaler_of_match[] = {
408 { .compatible = "rockchip,rk618-scaler", },
409 {},
410 };
411 MODULE_DEVICE_TABLE(of, rk618_scaler_of_match);
412
413 static struct platform_driver rk618_scaler_driver = {
414 .driver = {
415 .name = "rk618-scaler",
416 .of_match_table = of_match_ptr(rk618_scaler_of_match),
417 },
418 .probe = rk618_scaler_probe,
419 .remove = rk618_scaler_remove,
420 };
421 module_platform_driver(rk618_scaler_driver);
422
423 MODULE_AUTHOR("Wyon Bi <bivvy.bi@rock-chips.com>");
424 MODULE_DESCRIPTION("Rockchip RK618 SCALER driver");
425 MODULE_LICENSE("GPL v2");
426