1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2015 MediaTek Inc.
4  * Authors:
5  *	YT Shen <yt.shen@mediatek.com>
6  *	CK Hu <ck.hu@mediatek.com>
7  */
8 
9 #include <linux/clk.h>
10 #include <linux/of.h>
11 #include <linux/of_address.h>
12 #include <linux/of_platform.h>
13 #include <linux/platform_device.h>
14 #include <linux/soc/mediatek/mtk-cmdq.h>
15 #include <drm/drm_print.h>
16 
17 #include "mtk_disp_drv.h"
18 #include "mtk_drm_drv.h"
19 #include "mtk_drm_plane.h"
20 #include "mtk_drm_ddp_comp.h"
21 #include "mtk_drm_crtc.h"
22 
23 #define DISP_OD_EN				0x0000
24 #define DISP_OD_INTEN				0x0008
25 #define DISP_OD_INTSTA				0x000c
26 #define DISP_OD_CFG				0x0020
27 #define DISP_OD_SIZE				0x0030
28 #define DISP_DITHER_5				0x0114
29 #define DISP_DITHER_7				0x011c
30 #define DISP_DITHER_15				0x013c
31 #define DISP_DITHER_16				0x0140
32 
33 #define DISP_REG_UFO_START			0x0000
34 
35 #define DISP_DITHER_EN				0x0000
36 #define DITHER_EN				BIT(0)
37 #define DISP_DITHER_CFG				0x0020
38 #define DITHER_RELAY_MODE			BIT(0)
39 #define DITHER_ENGINE_EN			BIT(1)
40 #define DISP_DITHER_SIZE			0x0030
41 
42 #define LUT_10BIT_MASK				0x03ff
43 
44 #define OD_RELAYMODE				BIT(0)
45 
46 #define UFO_BYPASS				BIT(2)
47 
48 #define DISP_DITHERING				BIT(2)
49 #define DITHER_LSB_ERR_SHIFT_R(x)		(((x) & 0x7) << 28)
50 #define DITHER_OVFLW_BIT_R(x)			(((x) & 0x7) << 24)
51 #define DITHER_ADD_LSHIFT_R(x)			(((x) & 0x7) << 20)
52 #define DITHER_ADD_RSHIFT_R(x)			(((x) & 0x7) << 16)
53 #define DITHER_NEW_BIT_MODE			BIT(0)
54 #define DITHER_LSB_ERR_SHIFT_B(x)		(((x) & 0x7) << 28)
55 #define DITHER_OVFLW_BIT_B(x)			(((x) & 0x7) << 24)
56 #define DITHER_ADD_LSHIFT_B(x)			(((x) & 0x7) << 20)
57 #define DITHER_ADD_RSHIFT_B(x)			(((x) & 0x7) << 16)
58 #define DITHER_LSB_ERR_SHIFT_G(x)		(((x) & 0x7) << 12)
59 #define DITHER_OVFLW_BIT_G(x)			(((x) & 0x7) << 8)
60 #define DITHER_ADD_LSHIFT_G(x)			(((x) & 0x7) << 4)
61 #define DITHER_ADD_RSHIFT_G(x)			(((x) & 0x7) << 0)
62 
63 struct mtk_ddp_comp_dev {
64 	struct clk *clk;
65 	void __iomem *regs;
66 	struct cmdq_client_reg cmdq_reg;
67 };
68 
69 void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value,
70 		   struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
71 		   unsigned int offset)
72 {
73 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
74 	if (cmdq_pkt)
75 		cmdq_pkt_write(cmdq_pkt, cmdq_reg->subsys,
76 			       cmdq_reg->offset + offset, value);
77 	else
78 #endif
79 		writel(value, regs + offset);
80 }
81 
82 void mtk_ddp_write_relaxed(struct cmdq_pkt *cmdq_pkt, unsigned int value,
83 			   struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
84 			   unsigned int offset)
85 {
86 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
87 	if (cmdq_pkt)
88 		cmdq_pkt_write(cmdq_pkt, cmdq_reg->subsys,
89 			       cmdq_reg->offset + offset, value);
90 	else
91 #endif
92 		writel_relaxed(value, regs + offset);
93 }
94 
95 void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, unsigned int value,
96 			struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
97 			unsigned int offset, unsigned int mask)
98 {
99 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
100 	if (cmdq_pkt) {
101 		cmdq_pkt_write_mask(cmdq_pkt, cmdq_reg->subsys,
102 				    cmdq_reg->offset + offset, value, mask);
103 	} else {
104 #endif
105 		u32 tmp = readl(regs + offset);
106 
107 		tmp = (tmp & ~mask) | (value & mask);
108 		writel(tmp, regs + offset);
109 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
110 	}
111 #endif
112 }
113 
114 static int mtk_ddp_clk_enable(struct device *dev)
115 {
116 	struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
117 
118 	return clk_prepare_enable(priv->clk);
119 }
120 
121 static void mtk_ddp_clk_disable(struct device *dev)
122 {
123 	struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
124 
125 	clk_disable_unprepare(priv->clk);
126 }
127 
128 void mtk_dither_set_common(void __iomem *regs, struct cmdq_client_reg *cmdq_reg,
129 			   unsigned int bpc, unsigned int cfg,
130 			   unsigned int dither_en, struct cmdq_pkt *cmdq_pkt)
131 {
132 	/* If bpc equal to 0, the dithering function didn't be enabled */
133 	if (bpc == 0)
134 		return;
135 
136 	if (bpc >= MTK_MIN_BPC) {
137 		mtk_ddp_write(cmdq_pkt, 0, cmdq_reg, regs, DISP_DITHER_5);
138 		mtk_ddp_write(cmdq_pkt, 0, cmdq_reg, regs, DISP_DITHER_7);
139 		mtk_ddp_write(cmdq_pkt,
140 			      DITHER_LSB_ERR_SHIFT_R(MTK_MAX_BPC - bpc) |
141 			      DITHER_ADD_LSHIFT_R(MTK_MAX_BPC - bpc) |
142 			      DITHER_NEW_BIT_MODE,
143 			      cmdq_reg, regs, DISP_DITHER_15);
144 		mtk_ddp_write(cmdq_pkt,
145 			      DITHER_LSB_ERR_SHIFT_B(MTK_MAX_BPC - bpc) |
146 			      DITHER_ADD_LSHIFT_B(MTK_MAX_BPC - bpc) |
147 			      DITHER_LSB_ERR_SHIFT_G(MTK_MAX_BPC - bpc) |
148 			      DITHER_ADD_LSHIFT_G(MTK_MAX_BPC - bpc),
149 			      cmdq_reg, regs, DISP_DITHER_16);
150 		mtk_ddp_write(cmdq_pkt, dither_en, cmdq_reg, regs, cfg);
151 	}
152 }
153 
154 static void mtk_dither_set(struct device *dev, unsigned int bpc,
155 		    unsigned int cfg, struct cmdq_pkt *cmdq_pkt)
156 {
157 	struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
158 
159 	mtk_dither_set_common(priv->regs, &priv->cmdq_reg, bpc, cfg,
160 			      DISP_DITHERING, cmdq_pkt);
161 }
162 
163 static void mtk_od_config(struct device *dev, unsigned int w,
164 			  unsigned int h, unsigned int vrefresh,
165 			  unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
166 {
167 	struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
168 
169 	mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, DISP_OD_SIZE);
170 	mtk_ddp_write(cmdq_pkt, OD_RELAYMODE, &priv->cmdq_reg, priv->regs, DISP_OD_CFG);
171 	mtk_dither_set(dev, bpc, DISP_OD_CFG, cmdq_pkt);
172 }
173 
174 static void mtk_od_start(struct device *dev)
175 {
176 	struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
177 
178 	writel(1, priv->regs + DISP_OD_EN);
179 }
180 
181 static void mtk_ufoe_start(struct device *dev)
182 {
183 	struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
184 
185 	writel(UFO_BYPASS, priv->regs + DISP_REG_UFO_START);
186 }
187 
188 static void mtk_dither_config(struct device *dev, unsigned int w,
189 			      unsigned int h, unsigned int vrefresh,
190 			      unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
191 {
192 	struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
193 
194 	mtk_ddp_write(cmdq_pkt, h << 16 | w, &priv->cmdq_reg, priv->regs, DISP_DITHER_SIZE);
195 	mtk_ddp_write(cmdq_pkt, DITHER_RELAY_MODE, &priv->cmdq_reg, priv->regs, DISP_DITHER_CFG);
196 	mtk_dither_set_common(priv->regs, &priv->cmdq_reg, bpc, DISP_DITHER_CFG,
197 			      DITHER_ENGINE_EN, cmdq_pkt);
198 }
199 
200 static void mtk_dither_start(struct device *dev)
201 {
202 	struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
203 
204 	writel(DITHER_EN, priv->regs + DISP_DITHER_EN);
205 }
206 
207 static void mtk_dither_stop(struct device *dev)
208 {
209 	struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
210 
211 	writel_relaxed(0x0, priv->regs + DISP_DITHER_EN);
212 }
213 
214 static const struct mtk_ddp_comp_funcs ddp_aal = {
215 	.clk_enable = mtk_aal_clk_enable,
216 	.clk_disable = mtk_aal_clk_disable,
217 	.gamma_set = mtk_aal_gamma_set,
218 	.config = mtk_aal_config,
219 	.start = mtk_aal_start,
220 	.stop = mtk_aal_stop,
221 };
222 
223 static const struct mtk_ddp_comp_funcs ddp_ccorr = {
224 	.clk_enable = mtk_ccorr_clk_enable,
225 	.clk_disable = mtk_ccorr_clk_disable,
226 	.config = mtk_ccorr_config,
227 	.start = mtk_ccorr_start,
228 	.stop = mtk_ccorr_stop,
229 	.ctm_set = mtk_ccorr_ctm_set,
230 };
231 
232 static const struct mtk_ddp_comp_funcs ddp_color = {
233 	.clk_enable = mtk_color_clk_enable,
234 	.clk_disable = mtk_color_clk_disable,
235 	.config = mtk_color_config,
236 	.start = mtk_color_start,
237 };
238 
239 static const struct mtk_ddp_comp_funcs ddp_dither = {
240 	.clk_enable = mtk_ddp_clk_enable,
241 	.clk_disable = mtk_ddp_clk_disable,
242 	.config = mtk_dither_config,
243 	.start = mtk_dither_start,
244 	.stop = mtk_dither_stop,
245 };
246 
247 static const struct mtk_ddp_comp_funcs ddp_dpi = {
248 	.start = mtk_dpi_start,
249 	.stop = mtk_dpi_stop,
250 };
251 
252 static const struct mtk_ddp_comp_funcs ddp_dsi = {
253 	.start = mtk_dsi_ddp_start,
254 	.stop = mtk_dsi_ddp_stop,
255 };
256 
257 static const struct mtk_ddp_comp_funcs ddp_gamma = {
258 	.clk_enable = mtk_gamma_clk_enable,
259 	.clk_disable = mtk_gamma_clk_disable,
260 	.gamma_set = mtk_gamma_set,
261 	.config = mtk_gamma_config,
262 	.start = mtk_gamma_start,
263 	.stop = mtk_gamma_stop,
264 };
265 
266 static const struct mtk_ddp_comp_funcs ddp_od = {
267 	.clk_enable = mtk_ddp_clk_enable,
268 	.clk_disable = mtk_ddp_clk_disable,
269 	.config = mtk_od_config,
270 	.start = mtk_od_start,
271 };
272 
273 static const struct mtk_ddp_comp_funcs ddp_ovl = {
274 	.clk_enable = mtk_ovl_clk_enable,
275 	.clk_disable = mtk_ovl_clk_disable,
276 	.config = mtk_ovl_config,
277 	.start = mtk_ovl_start,
278 	.stop = mtk_ovl_stop,
279 	.enable_vblank = mtk_ovl_enable_vblank,
280 	.disable_vblank = mtk_ovl_disable_vblank,
281 	.supported_rotations = mtk_ovl_supported_rotations,
282 	.layer_nr = mtk_ovl_layer_nr,
283 	.layer_check = mtk_ovl_layer_check,
284 	.layer_config = mtk_ovl_layer_config,
285 	.bgclr_in_on = mtk_ovl_bgclr_in_on,
286 	.bgclr_in_off = mtk_ovl_bgclr_in_off,
287 };
288 
289 static const struct mtk_ddp_comp_funcs ddp_rdma = {
290 	.clk_enable = mtk_rdma_clk_enable,
291 	.clk_disable = mtk_rdma_clk_disable,
292 	.config = mtk_rdma_config,
293 	.start = mtk_rdma_start,
294 	.stop = mtk_rdma_stop,
295 	.enable_vblank = mtk_rdma_enable_vblank,
296 	.disable_vblank = mtk_rdma_disable_vblank,
297 	.layer_nr = mtk_rdma_layer_nr,
298 	.layer_config = mtk_rdma_layer_config,
299 };
300 
301 static const struct mtk_ddp_comp_funcs ddp_ufoe = {
302 	.clk_enable = mtk_ddp_clk_enable,
303 	.clk_disable = mtk_ddp_clk_disable,
304 	.start = mtk_ufoe_start,
305 };
306 
307 static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
308 	[MTK_DISP_OVL] = "ovl",
309 	[MTK_DISP_OVL_2L] = "ovl-2l",
310 	[MTK_DISP_RDMA] = "rdma",
311 	[MTK_DISP_WDMA] = "wdma",
312 	[MTK_DISP_COLOR] = "color",
313 	[MTK_DISP_CCORR] = "ccorr",
314 	[MTK_DISP_AAL] = "aal",
315 	[MTK_DISP_GAMMA] = "gamma",
316 	[MTK_DISP_DITHER] = "dither",
317 	[MTK_DISP_UFOE] = "ufoe",
318 	[MTK_DSI] = "dsi",
319 	[MTK_DPI] = "dpi",
320 	[MTK_DISP_PWM] = "pwm",
321 	[MTK_DISP_MUTEX] = "mutex",
322 	[MTK_DISP_OD] = "od",
323 	[MTK_DISP_BLS] = "bls",
324 };
325 
326 struct mtk_ddp_comp_match {
327 	enum mtk_ddp_comp_type type;
328 	int alias_id;
329 	const struct mtk_ddp_comp_funcs *funcs;
330 };
331 
332 static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
333 	[DDP_COMPONENT_AAL0]	= { MTK_DISP_AAL,	0, &ddp_aal },
334 	[DDP_COMPONENT_AAL1]	= { MTK_DISP_AAL,	1, &ddp_aal },
335 	[DDP_COMPONENT_BLS]	= { MTK_DISP_BLS,	0, NULL },
336 	[DDP_COMPONENT_CCORR]	= { MTK_DISP_CCORR,	0, &ddp_ccorr },
337 	[DDP_COMPONENT_COLOR0]	= { MTK_DISP_COLOR,	0, &ddp_color },
338 	[DDP_COMPONENT_COLOR1]	= { MTK_DISP_COLOR,	1, &ddp_color },
339 	[DDP_COMPONENT_DITHER]	= { MTK_DISP_DITHER,	0, &ddp_dither },
340 	[DDP_COMPONENT_DPI0]	= { MTK_DPI,		0, &ddp_dpi },
341 	[DDP_COMPONENT_DPI1]	= { MTK_DPI,		1, &ddp_dpi },
342 	[DDP_COMPONENT_DSI0]	= { MTK_DSI,		0, &ddp_dsi },
343 	[DDP_COMPONENT_DSI1]	= { MTK_DSI,		1, &ddp_dsi },
344 	[DDP_COMPONENT_DSI2]	= { MTK_DSI,		2, &ddp_dsi },
345 	[DDP_COMPONENT_DSI3]	= { MTK_DSI,		3, &ddp_dsi },
346 	[DDP_COMPONENT_GAMMA]	= { MTK_DISP_GAMMA,	0, &ddp_gamma },
347 	[DDP_COMPONENT_OD0]	= { MTK_DISP_OD,	0, &ddp_od },
348 	[DDP_COMPONENT_OD1]	= { MTK_DISP_OD,	1, &ddp_od },
349 	[DDP_COMPONENT_OVL0]	= { MTK_DISP_OVL,	0, &ddp_ovl },
350 	[DDP_COMPONENT_OVL1]	= { MTK_DISP_OVL,	1, &ddp_ovl },
351 	[DDP_COMPONENT_OVL_2L0]	= { MTK_DISP_OVL_2L,	0, &ddp_ovl },
352 	[DDP_COMPONENT_OVL_2L1]	= { MTK_DISP_OVL_2L,	1, &ddp_ovl },
353 	[DDP_COMPONENT_PWM0]	= { MTK_DISP_PWM,	0, NULL },
354 	[DDP_COMPONENT_PWM1]	= { MTK_DISP_PWM,	1, NULL },
355 	[DDP_COMPONENT_PWM2]	= { MTK_DISP_PWM,	2, NULL },
356 	[DDP_COMPONENT_RDMA0]	= { MTK_DISP_RDMA,	0, &ddp_rdma },
357 	[DDP_COMPONENT_RDMA1]	= { MTK_DISP_RDMA,	1, &ddp_rdma },
358 	[DDP_COMPONENT_RDMA2]	= { MTK_DISP_RDMA,	2, &ddp_rdma },
359 	[DDP_COMPONENT_UFOE]	= { MTK_DISP_UFOE,	0, &ddp_ufoe },
360 	[DDP_COMPONENT_WDMA0]	= { MTK_DISP_WDMA,	0, NULL },
361 	[DDP_COMPONENT_WDMA1]	= { MTK_DISP_WDMA,	1, NULL },
362 };
363 
364 static bool mtk_drm_find_comp_in_ddp(struct device *dev,
365 				     const enum mtk_ddp_comp_id *path,
366 				     unsigned int path_len,
367 				     struct mtk_ddp_comp *ddp_comp)
368 {
369 	unsigned int i;
370 
371 	if (path == NULL)
372 		return false;
373 
374 	for (i = 0U; i < path_len; i++)
375 		if (dev == ddp_comp[path[i]].dev)
376 			return true;
377 
378 	return false;
379 }
380 
381 int mtk_ddp_comp_get_id(struct device_node *node,
382 			enum mtk_ddp_comp_type comp_type)
383 {
384 	int id = of_alias_get_id(node, mtk_ddp_comp_stem[comp_type]);
385 	int i;
386 
387 	for (i = 0; i < ARRAY_SIZE(mtk_ddp_matches); i++) {
388 		if (comp_type == mtk_ddp_matches[i].type &&
389 		    (id < 0 || id == mtk_ddp_matches[i].alias_id))
390 			return i;
391 	}
392 
393 	return -EINVAL;
394 }
395 
396 unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm,
397 						struct device *dev)
398 {
399 	struct mtk_drm_private *private = drm->dev_private;
400 	unsigned int ret = 0;
401 
402 	if (mtk_drm_find_comp_in_ddp(dev, private->data->main_path, private->data->main_len,
403 				     private->ddp_comp))
404 		ret = BIT(0);
405 	else if (mtk_drm_find_comp_in_ddp(dev, private->data->ext_path,
406 					  private->data->ext_len, private->ddp_comp))
407 		ret = BIT(1);
408 	else if (mtk_drm_find_comp_in_ddp(dev, private->data->third_path,
409 					  private->data->third_len, private->ddp_comp))
410 		ret = BIT(2);
411 	else
412 		DRM_INFO("Failed to find comp in ddp table\n");
413 
414 	return ret;
415 }
416 
417 static int mtk_ddp_get_larb_dev(struct device_node *node, struct mtk_ddp_comp *comp,
418 				struct device *dev)
419 {
420 	struct device_node *larb_node;
421 	struct platform_device *larb_pdev;
422 
423 	larb_node = of_parse_phandle(node, "mediatek,larb", 0);
424 	if (!larb_node) {
425 		dev_err(dev, "Missing mediadek,larb phandle in %pOF node\n", node);
426 		return -EINVAL;
427 	}
428 
429 	larb_pdev = of_find_device_by_node(larb_node);
430 	if (!larb_pdev) {
431 		dev_warn(dev, "Waiting for larb device %pOF\n", larb_node);
432 		of_node_put(larb_node);
433 		return -EPROBE_DEFER;
434 	}
435 	of_node_put(larb_node);
436 	comp->larb_dev = &larb_pdev->dev;
437 
438 	return 0;
439 }
440 
441 int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp,
442 		      enum mtk_ddp_comp_id comp_id)
443 {
444 	struct platform_device *comp_pdev;
445 	enum mtk_ddp_comp_type type;
446 	struct mtk_ddp_comp_dev *priv;
447 	int ret;
448 
449 	if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX)
450 		return -EINVAL;
451 
452 	type = mtk_ddp_matches[comp_id].type;
453 
454 	comp->id = comp_id;
455 	comp->funcs = mtk_ddp_matches[comp_id].funcs;
456 	comp_pdev = of_find_device_by_node(node);
457 	if (!comp_pdev) {
458 		DRM_INFO("Waiting for device %s\n", node->full_name);
459 		return -EPROBE_DEFER;
460 	}
461 	comp->dev = &comp_pdev->dev;
462 
463 	/* Only DMA capable components need the LARB property */
464 	if (type == MTK_DISP_OVL ||
465 	    type == MTK_DISP_OVL_2L ||
466 	    type == MTK_DISP_RDMA ||
467 	    type == MTK_DISP_WDMA) {
468 		ret = mtk_ddp_get_larb_dev(node, comp, comp->dev);
469 		if (ret)
470 			return ret;
471 	}
472 
473 	if (type == MTK_DISP_AAL ||
474 	    type == MTK_DISP_BLS ||
475 	    type == MTK_DISP_CCORR ||
476 	    type == MTK_DISP_COLOR ||
477 	    type == MTK_DISP_GAMMA ||
478 	    type == MTK_DPI ||
479 	    type == MTK_DSI ||
480 	    type == MTK_DISP_OVL ||
481 	    type == MTK_DISP_OVL_2L ||
482 	    type == MTK_DISP_PWM ||
483 	    type == MTK_DISP_RDMA)
484 		return 0;
485 
486 	priv = devm_kzalloc(comp->dev, sizeof(*priv), GFP_KERNEL);
487 	if (!priv)
488 		return -ENOMEM;
489 
490 	priv->regs = of_iomap(node, 0);
491 	priv->clk = of_clk_get(node, 0);
492 	if (IS_ERR(priv->clk))
493 		return PTR_ERR(priv->clk);
494 
495 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
496 	ret = cmdq_dev_get_client_reg(comp->dev, &priv->cmdq_reg, 0);
497 	if (ret)
498 		dev_dbg(comp->dev, "get mediatek,gce-client-reg fail!\n");
499 #endif
500 
501 	platform_set_drvdata(comp_pdev, priv);
502 
503 	return 0;
504 }
505