xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/mediatek/mtk_disp_ovl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2015 MediaTek Inc.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <drm/drm_fourcc.h>
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/clk.h>
9*4882a593Smuzhiyun #include <linux/component.h>
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/of_device.h>
12*4882a593Smuzhiyun #include <linux/of_irq.h>
13*4882a593Smuzhiyun #include <linux/platform_device.h>
14*4882a593Smuzhiyun #include <linux/soc/mediatek/mtk-cmdq.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include "mtk_drm_crtc.h"
17*4882a593Smuzhiyun #include "mtk_drm_ddp_comp.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define DISP_REG_OVL_INTEN			0x0004
20*4882a593Smuzhiyun #define OVL_FME_CPL_INT					BIT(1)
21*4882a593Smuzhiyun #define DISP_REG_OVL_INTSTA			0x0008
22*4882a593Smuzhiyun #define DISP_REG_OVL_EN				0x000c
23*4882a593Smuzhiyun #define DISP_REG_OVL_RST			0x0014
24*4882a593Smuzhiyun #define DISP_REG_OVL_ROI_SIZE			0x0020
25*4882a593Smuzhiyun #define DISP_REG_OVL_DATAPATH_CON		0x0024
26*4882a593Smuzhiyun #define OVL_BGCLR_SEL_IN				BIT(2)
27*4882a593Smuzhiyun #define DISP_REG_OVL_ROI_BGCLR			0x0028
28*4882a593Smuzhiyun #define DISP_REG_OVL_SRC_CON			0x002c
29*4882a593Smuzhiyun #define DISP_REG_OVL_CON(n)			(0x0030 + 0x20 * (n))
30*4882a593Smuzhiyun #define DISP_REG_OVL_SRC_SIZE(n)		(0x0038 + 0x20 * (n))
31*4882a593Smuzhiyun #define DISP_REG_OVL_OFFSET(n)			(0x003c + 0x20 * (n))
32*4882a593Smuzhiyun #define DISP_REG_OVL_PITCH(n)			(0x0044 + 0x20 * (n))
33*4882a593Smuzhiyun #define DISP_REG_OVL_RDMA_CTRL(n)		(0x00c0 + 0x20 * (n))
34*4882a593Smuzhiyun #define DISP_REG_OVL_RDMA_GMC(n)		(0x00c8 + 0x20 * (n))
35*4882a593Smuzhiyun #define DISP_REG_OVL_ADDR_MT2701		0x0040
36*4882a593Smuzhiyun #define DISP_REG_OVL_ADDR_MT8173		0x0f40
37*4882a593Smuzhiyun #define DISP_REG_OVL_ADDR(ovl, n)		((ovl)->data->addr + 0x20 * (n))
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define GMC_THRESHOLD_BITS	16
40*4882a593Smuzhiyun #define GMC_THRESHOLD_HIGH	((1 << GMC_THRESHOLD_BITS) / 4)
41*4882a593Smuzhiyun #define GMC_THRESHOLD_LOW	((1 << GMC_THRESHOLD_BITS) / 8)
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define OVL_CON_BYTE_SWAP	BIT(24)
44*4882a593Smuzhiyun #define OVL_CON_MTX_YUV_TO_RGB	(6 << 16)
45*4882a593Smuzhiyun #define OVL_CON_CLRFMT_RGB	(1 << 12)
46*4882a593Smuzhiyun #define OVL_CON_CLRFMT_RGBA8888	(2 << 12)
47*4882a593Smuzhiyun #define OVL_CON_CLRFMT_ARGB8888	(3 << 12)
48*4882a593Smuzhiyun #define OVL_CON_CLRFMT_UYVY	(4 << 12)
49*4882a593Smuzhiyun #define OVL_CON_CLRFMT_YUYV	(5 << 12)
50*4882a593Smuzhiyun #define OVL_CON_CLRFMT_RGB565(ovl)	((ovl)->data->fmt_rgb565_is_0 ? \
51*4882a593Smuzhiyun 					0 : OVL_CON_CLRFMT_RGB)
52*4882a593Smuzhiyun #define OVL_CON_CLRFMT_RGB888(ovl)	((ovl)->data->fmt_rgb565_is_0 ? \
53*4882a593Smuzhiyun 					OVL_CON_CLRFMT_RGB : 0)
54*4882a593Smuzhiyun #define	OVL_CON_AEN		BIT(8)
55*4882a593Smuzhiyun #define	OVL_CON_ALPHA		0xff
56*4882a593Smuzhiyun #define	OVL_CON_VIRT_FLIP	BIT(9)
57*4882a593Smuzhiyun #define	OVL_CON_HORZ_FLIP	BIT(10)
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun struct mtk_disp_ovl_data {
60*4882a593Smuzhiyun 	unsigned int addr;
61*4882a593Smuzhiyun 	unsigned int gmc_bits;
62*4882a593Smuzhiyun 	unsigned int layer_nr;
63*4882a593Smuzhiyun 	bool fmt_rgb565_is_0;
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun /**
67*4882a593Smuzhiyun  * struct mtk_disp_ovl - DISP_OVL driver structure
68*4882a593Smuzhiyun  * @ddp_comp - structure containing type enum and hardware resources
69*4882a593Smuzhiyun  * @crtc - associated crtc to report vblank events to
70*4882a593Smuzhiyun  */
71*4882a593Smuzhiyun struct mtk_disp_ovl {
72*4882a593Smuzhiyun 	struct mtk_ddp_comp		ddp_comp;
73*4882a593Smuzhiyun 	struct drm_crtc			*crtc;
74*4882a593Smuzhiyun 	const struct mtk_disp_ovl_data	*data;
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun 
comp_to_ovl(struct mtk_ddp_comp * comp)77*4882a593Smuzhiyun static inline struct mtk_disp_ovl *comp_to_ovl(struct mtk_ddp_comp *comp)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	return container_of(comp, struct mtk_disp_ovl, ddp_comp);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
mtk_disp_ovl_irq_handler(int irq,void * dev_id)82*4882a593Smuzhiyun static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	struct mtk_disp_ovl *priv = dev_id;
85*4882a593Smuzhiyun 	struct mtk_ddp_comp *ovl = &priv->ddp_comp;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	/* Clear frame completion interrupt */
88*4882a593Smuzhiyun 	writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	if (!priv->crtc)
91*4882a593Smuzhiyun 		return IRQ_NONE;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	mtk_crtc_ddp_irq(priv->crtc, ovl);
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	return IRQ_HANDLED;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
mtk_ovl_enable_vblank(struct mtk_ddp_comp * comp,struct drm_crtc * crtc)98*4882a593Smuzhiyun static void mtk_ovl_enable_vblank(struct mtk_ddp_comp *comp,
99*4882a593Smuzhiyun 				  struct drm_crtc *crtc)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	ovl->crtc = crtc;
104*4882a593Smuzhiyun 	writel(0x0, comp->regs + DISP_REG_OVL_INTSTA);
105*4882a593Smuzhiyun 	writel_relaxed(OVL_FME_CPL_INT, comp->regs + DISP_REG_OVL_INTEN);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
mtk_ovl_disable_vblank(struct mtk_ddp_comp * comp)108*4882a593Smuzhiyun static void mtk_ovl_disable_vblank(struct mtk_ddp_comp *comp)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	ovl->crtc = NULL;
113*4882a593Smuzhiyun 	writel_relaxed(0x0, comp->regs + DISP_REG_OVL_INTEN);
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
mtk_ovl_start(struct mtk_ddp_comp * comp)116*4882a593Smuzhiyun static void mtk_ovl_start(struct mtk_ddp_comp *comp)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	writel_relaxed(0x1, comp->regs + DISP_REG_OVL_EN);
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
mtk_ovl_stop(struct mtk_ddp_comp * comp)121*4882a593Smuzhiyun static void mtk_ovl_stop(struct mtk_ddp_comp *comp)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	writel_relaxed(0x0, comp->regs + DISP_REG_OVL_EN);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
mtk_ovl_config(struct mtk_ddp_comp * comp,unsigned int w,unsigned int h,unsigned int vrefresh,unsigned int bpc,struct cmdq_pkt * cmdq_pkt)126*4882a593Smuzhiyun static void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w,
127*4882a593Smuzhiyun 			   unsigned int h, unsigned int vrefresh,
128*4882a593Smuzhiyun 			   unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	if (w != 0 && h != 0)
131*4882a593Smuzhiyun 		mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, comp,
132*4882a593Smuzhiyun 				      DISP_REG_OVL_ROI_SIZE);
133*4882a593Smuzhiyun 	mtk_ddp_write_relaxed(cmdq_pkt, 0x0, comp, DISP_REG_OVL_ROI_BGCLR);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	mtk_ddp_write(cmdq_pkt, 0x1, comp, DISP_REG_OVL_RST);
136*4882a593Smuzhiyun 	mtk_ddp_write(cmdq_pkt, 0x0, comp, DISP_REG_OVL_RST);
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
mtk_ovl_layer_nr(struct mtk_ddp_comp * comp)139*4882a593Smuzhiyun static unsigned int mtk_ovl_layer_nr(struct mtk_ddp_comp *comp)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	return ovl->data->layer_nr;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
mtk_ovl_supported_rotations(struct mtk_ddp_comp * comp)146*4882a593Smuzhiyun static unsigned int mtk_ovl_supported_rotations(struct mtk_ddp_comp *comp)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	return DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
149*4882a593Smuzhiyun 	       DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
mtk_ovl_layer_check(struct mtk_ddp_comp * comp,unsigned int idx,struct mtk_plane_state * mtk_state)152*4882a593Smuzhiyun static int mtk_ovl_layer_check(struct mtk_ddp_comp *comp, unsigned int idx,
153*4882a593Smuzhiyun 			       struct mtk_plane_state *mtk_state)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	struct drm_plane_state *state = &mtk_state->base;
156*4882a593Smuzhiyun 	unsigned int rotation = 0;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	rotation = drm_rotation_simplify(state->rotation,
159*4882a593Smuzhiyun 					 DRM_MODE_ROTATE_0 |
160*4882a593Smuzhiyun 					 DRM_MODE_REFLECT_X |
161*4882a593Smuzhiyun 					 DRM_MODE_REFLECT_Y);
162*4882a593Smuzhiyun 	rotation &= ~DRM_MODE_ROTATE_0;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	/* We can only do reflection, not rotation */
165*4882a593Smuzhiyun 	if ((rotation & DRM_MODE_ROTATE_MASK) != 0)
166*4882a593Smuzhiyun 		return -EINVAL;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	/*
169*4882a593Smuzhiyun 	 * TODO: Rotating/reflecting YUV buffers is not supported at this time.
170*4882a593Smuzhiyun 	 *	 Only RGB[AX] variants are supported.
171*4882a593Smuzhiyun 	 */
172*4882a593Smuzhiyun 	if (state->fb->format->is_yuv && rotation != 0)
173*4882a593Smuzhiyun 		return -EINVAL;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	state->rotation = rotation;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	return 0;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
mtk_ovl_layer_on(struct mtk_ddp_comp * comp,unsigned int idx,struct cmdq_pkt * cmdq_pkt)180*4882a593Smuzhiyun static void mtk_ovl_layer_on(struct mtk_ddp_comp *comp, unsigned int idx,
181*4882a593Smuzhiyun 			     struct cmdq_pkt *cmdq_pkt)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	unsigned int gmc_thrshd_l;
184*4882a593Smuzhiyun 	unsigned int gmc_thrshd_h;
185*4882a593Smuzhiyun 	unsigned int gmc_value;
186*4882a593Smuzhiyun 	struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	mtk_ddp_write(cmdq_pkt, 0x1, comp,
189*4882a593Smuzhiyun 		      DISP_REG_OVL_RDMA_CTRL(idx));
190*4882a593Smuzhiyun 	gmc_thrshd_l = GMC_THRESHOLD_LOW >>
191*4882a593Smuzhiyun 		      (GMC_THRESHOLD_BITS - ovl->data->gmc_bits);
192*4882a593Smuzhiyun 	gmc_thrshd_h = GMC_THRESHOLD_HIGH >>
193*4882a593Smuzhiyun 		      (GMC_THRESHOLD_BITS - ovl->data->gmc_bits);
194*4882a593Smuzhiyun 	if (ovl->data->gmc_bits == 10)
195*4882a593Smuzhiyun 		gmc_value = gmc_thrshd_h | gmc_thrshd_h << 16;
196*4882a593Smuzhiyun 	else
197*4882a593Smuzhiyun 		gmc_value = gmc_thrshd_l | gmc_thrshd_l << 8 |
198*4882a593Smuzhiyun 			    gmc_thrshd_h << 16 | gmc_thrshd_h << 24;
199*4882a593Smuzhiyun 	mtk_ddp_write(cmdq_pkt, gmc_value,
200*4882a593Smuzhiyun 		      comp, DISP_REG_OVL_RDMA_GMC(idx));
201*4882a593Smuzhiyun 	mtk_ddp_write_mask(cmdq_pkt, BIT(idx), comp,
202*4882a593Smuzhiyun 			   DISP_REG_OVL_SRC_CON, BIT(idx));
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
mtk_ovl_layer_off(struct mtk_ddp_comp * comp,unsigned int idx,struct cmdq_pkt * cmdq_pkt)205*4882a593Smuzhiyun static void mtk_ovl_layer_off(struct mtk_ddp_comp *comp, unsigned int idx,
206*4882a593Smuzhiyun 			      struct cmdq_pkt *cmdq_pkt)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	mtk_ddp_write_mask(cmdq_pkt, 0, comp,
209*4882a593Smuzhiyun 			   DISP_REG_OVL_SRC_CON, BIT(idx));
210*4882a593Smuzhiyun 	mtk_ddp_write(cmdq_pkt, 0, comp,
211*4882a593Smuzhiyun 		      DISP_REG_OVL_RDMA_CTRL(idx));
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
ovl_fmt_convert(struct mtk_disp_ovl * ovl,unsigned int fmt)214*4882a593Smuzhiyun static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	/* The return value in switch "MEM_MODE_INPUT_FORMAT_XXX"
217*4882a593Smuzhiyun 	 * is defined in mediatek HW data sheet.
218*4882a593Smuzhiyun 	 * The alphabet order in XXX is no relation to data
219*4882a593Smuzhiyun 	 * arrangement in memory.
220*4882a593Smuzhiyun 	 */
221*4882a593Smuzhiyun 	switch (fmt) {
222*4882a593Smuzhiyun 	default:
223*4882a593Smuzhiyun 	case DRM_FORMAT_RGB565:
224*4882a593Smuzhiyun 		return OVL_CON_CLRFMT_RGB565(ovl);
225*4882a593Smuzhiyun 	case DRM_FORMAT_BGR565:
226*4882a593Smuzhiyun 		return OVL_CON_CLRFMT_RGB565(ovl) | OVL_CON_BYTE_SWAP;
227*4882a593Smuzhiyun 	case DRM_FORMAT_RGB888:
228*4882a593Smuzhiyun 		return OVL_CON_CLRFMT_RGB888(ovl);
229*4882a593Smuzhiyun 	case DRM_FORMAT_BGR888:
230*4882a593Smuzhiyun 		return OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP;
231*4882a593Smuzhiyun 	case DRM_FORMAT_RGBX8888:
232*4882a593Smuzhiyun 	case DRM_FORMAT_RGBA8888:
233*4882a593Smuzhiyun 		return OVL_CON_CLRFMT_ARGB8888;
234*4882a593Smuzhiyun 	case DRM_FORMAT_BGRX8888:
235*4882a593Smuzhiyun 	case DRM_FORMAT_BGRA8888:
236*4882a593Smuzhiyun 		return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP;
237*4882a593Smuzhiyun 	case DRM_FORMAT_XRGB8888:
238*4882a593Smuzhiyun 	case DRM_FORMAT_ARGB8888:
239*4882a593Smuzhiyun 		return OVL_CON_CLRFMT_RGBA8888;
240*4882a593Smuzhiyun 	case DRM_FORMAT_XBGR8888:
241*4882a593Smuzhiyun 	case DRM_FORMAT_ABGR8888:
242*4882a593Smuzhiyun 		return OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP;
243*4882a593Smuzhiyun 	case DRM_FORMAT_UYVY:
244*4882a593Smuzhiyun 		return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB;
245*4882a593Smuzhiyun 	case DRM_FORMAT_YUYV:
246*4882a593Smuzhiyun 		return OVL_CON_CLRFMT_YUYV | OVL_CON_MTX_YUV_TO_RGB;
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun 
mtk_ovl_layer_config(struct mtk_ddp_comp * comp,unsigned int idx,struct mtk_plane_state * state,struct cmdq_pkt * cmdq_pkt)250*4882a593Smuzhiyun static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
251*4882a593Smuzhiyun 				 struct mtk_plane_state *state,
252*4882a593Smuzhiyun 				 struct cmdq_pkt *cmdq_pkt)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 	struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
255*4882a593Smuzhiyun 	struct mtk_plane_pending_state *pending = &state->pending;
256*4882a593Smuzhiyun 	unsigned int addr = pending->addr;
257*4882a593Smuzhiyun 	unsigned int pitch = pending->pitch & 0xffff;
258*4882a593Smuzhiyun 	unsigned int fmt = pending->format;
259*4882a593Smuzhiyun 	unsigned int offset = (pending->y << 16) | pending->x;
260*4882a593Smuzhiyun 	unsigned int src_size = (pending->height << 16) | pending->width;
261*4882a593Smuzhiyun 	unsigned int con;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	if (!pending->enable) {
264*4882a593Smuzhiyun 		mtk_ovl_layer_off(comp, idx, cmdq_pkt);
265*4882a593Smuzhiyun 		return;
266*4882a593Smuzhiyun 	}
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	con = ovl_fmt_convert(ovl, fmt);
269*4882a593Smuzhiyun 	if (state->base.fb && state->base.fb->format->has_alpha)
270*4882a593Smuzhiyun 		con |= OVL_CON_AEN | OVL_CON_ALPHA;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	if (pending->rotation & DRM_MODE_REFLECT_Y) {
273*4882a593Smuzhiyun 		con |= OVL_CON_VIRT_FLIP;
274*4882a593Smuzhiyun 		addr += (pending->height - 1) * pending->pitch;
275*4882a593Smuzhiyun 	}
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	if (pending->rotation & DRM_MODE_REFLECT_X) {
278*4882a593Smuzhiyun 		con |= OVL_CON_HORZ_FLIP;
279*4882a593Smuzhiyun 		addr += pending->pitch - 1;
280*4882a593Smuzhiyun 	}
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	mtk_ddp_write_relaxed(cmdq_pkt, con, comp,
283*4882a593Smuzhiyun 			      DISP_REG_OVL_CON(idx));
284*4882a593Smuzhiyun 	mtk_ddp_write_relaxed(cmdq_pkt, pitch, comp,
285*4882a593Smuzhiyun 			      DISP_REG_OVL_PITCH(idx));
286*4882a593Smuzhiyun 	mtk_ddp_write_relaxed(cmdq_pkt, src_size, comp,
287*4882a593Smuzhiyun 			      DISP_REG_OVL_SRC_SIZE(idx));
288*4882a593Smuzhiyun 	mtk_ddp_write_relaxed(cmdq_pkt, offset, comp,
289*4882a593Smuzhiyun 			      DISP_REG_OVL_OFFSET(idx));
290*4882a593Smuzhiyun 	mtk_ddp_write_relaxed(cmdq_pkt, addr, comp,
291*4882a593Smuzhiyun 			      DISP_REG_OVL_ADDR(ovl, idx));
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	mtk_ovl_layer_on(comp, idx, cmdq_pkt);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
mtk_ovl_bgclr_in_on(struct mtk_ddp_comp * comp)296*4882a593Smuzhiyun static void mtk_ovl_bgclr_in_on(struct mtk_ddp_comp *comp)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun 	unsigned int reg;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	reg = readl(comp->regs + DISP_REG_OVL_DATAPATH_CON);
301*4882a593Smuzhiyun 	reg = reg | OVL_BGCLR_SEL_IN;
302*4882a593Smuzhiyun 	writel(reg, comp->regs + DISP_REG_OVL_DATAPATH_CON);
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun 
mtk_ovl_bgclr_in_off(struct mtk_ddp_comp * comp)305*4882a593Smuzhiyun static void mtk_ovl_bgclr_in_off(struct mtk_ddp_comp *comp)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun 	unsigned int reg;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	reg = readl(comp->regs + DISP_REG_OVL_DATAPATH_CON);
310*4882a593Smuzhiyun 	reg = reg & ~OVL_BGCLR_SEL_IN;
311*4882a593Smuzhiyun 	writel(reg, comp->regs + DISP_REG_OVL_DATAPATH_CON);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun static const struct mtk_ddp_comp_funcs mtk_disp_ovl_funcs = {
315*4882a593Smuzhiyun 	.config = mtk_ovl_config,
316*4882a593Smuzhiyun 	.start = mtk_ovl_start,
317*4882a593Smuzhiyun 	.stop = mtk_ovl_stop,
318*4882a593Smuzhiyun 	.enable_vblank = mtk_ovl_enable_vblank,
319*4882a593Smuzhiyun 	.disable_vblank = mtk_ovl_disable_vblank,
320*4882a593Smuzhiyun 	.supported_rotations = mtk_ovl_supported_rotations,
321*4882a593Smuzhiyun 	.layer_nr = mtk_ovl_layer_nr,
322*4882a593Smuzhiyun 	.layer_check = mtk_ovl_layer_check,
323*4882a593Smuzhiyun 	.layer_config = mtk_ovl_layer_config,
324*4882a593Smuzhiyun 	.bgclr_in_on = mtk_ovl_bgclr_in_on,
325*4882a593Smuzhiyun 	.bgclr_in_off = mtk_ovl_bgclr_in_off,
326*4882a593Smuzhiyun };
327*4882a593Smuzhiyun 
mtk_disp_ovl_bind(struct device * dev,struct device * master,void * data)328*4882a593Smuzhiyun static int mtk_disp_ovl_bind(struct device *dev, struct device *master,
329*4882a593Smuzhiyun 			     void *data)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	struct mtk_disp_ovl *priv = dev_get_drvdata(dev);
332*4882a593Smuzhiyun 	struct drm_device *drm_dev = data;
333*4882a593Smuzhiyun 	int ret;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp);
336*4882a593Smuzhiyun 	if (ret < 0) {
337*4882a593Smuzhiyun 		dev_err(dev, "Failed to register component %pOF: %d\n",
338*4882a593Smuzhiyun 			dev->of_node, ret);
339*4882a593Smuzhiyun 		return ret;
340*4882a593Smuzhiyun 	}
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	return 0;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
mtk_disp_ovl_unbind(struct device * dev,struct device * master,void * data)345*4882a593Smuzhiyun static void mtk_disp_ovl_unbind(struct device *dev, struct device *master,
346*4882a593Smuzhiyun 				void *data)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	struct mtk_disp_ovl *priv = dev_get_drvdata(dev);
349*4882a593Smuzhiyun 	struct drm_device *drm_dev = data;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp);
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun static const struct component_ops mtk_disp_ovl_component_ops = {
355*4882a593Smuzhiyun 	.bind	= mtk_disp_ovl_bind,
356*4882a593Smuzhiyun 	.unbind = mtk_disp_ovl_unbind,
357*4882a593Smuzhiyun };
358*4882a593Smuzhiyun 
mtk_disp_ovl_probe(struct platform_device * pdev)359*4882a593Smuzhiyun static int mtk_disp_ovl_probe(struct platform_device *pdev)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
362*4882a593Smuzhiyun 	struct mtk_disp_ovl *priv;
363*4882a593Smuzhiyun 	int comp_id;
364*4882a593Smuzhiyun 	int irq;
365*4882a593Smuzhiyun 	int ret;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
368*4882a593Smuzhiyun 	if (!priv)
369*4882a593Smuzhiyun 		return -ENOMEM;
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	irq = platform_get_irq(pdev, 0);
372*4882a593Smuzhiyun 	if (irq < 0)
373*4882a593Smuzhiyun 		return irq;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	priv->data = of_device_get_match_data(dev);
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	comp_id = mtk_ddp_comp_get_id(dev->of_node,
378*4882a593Smuzhiyun 				      priv->data->layer_nr == 4 ?
379*4882a593Smuzhiyun 				      MTK_DISP_OVL :
380*4882a593Smuzhiyun 				      MTK_DISP_OVL_2L);
381*4882a593Smuzhiyun 	if (comp_id < 0) {
382*4882a593Smuzhiyun 		dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
383*4882a593Smuzhiyun 		return comp_id;
384*4882a593Smuzhiyun 	}
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id,
387*4882a593Smuzhiyun 				&mtk_disp_ovl_funcs);
388*4882a593Smuzhiyun 	if (ret) {
389*4882a593Smuzhiyun 		if (ret != -EPROBE_DEFER)
390*4882a593Smuzhiyun 			dev_err(dev, "Failed to initialize component: %d\n",
391*4882a593Smuzhiyun 				ret);
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 		return ret;
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	platform_set_drvdata(pdev, priv);
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler,
399*4882a593Smuzhiyun 			       IRQF_TRIGGER_NONE, dev_name(dev), priv);
400*4882a593Smuzhiyun 	if (ret < 0) {
401*4882a593Smuzhiyun 		dev_err(dev, "Failed to request irq %d: %d\n", irq, ret);
402*4882a593Smuzhiyun 		return ret;
403*4882a593Smuzhiyun 	}
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	ret = component_add(dev, &mtk_disp_ovl_component_ops);
406*4882a593Smuzhiyun 	if (ret)
407*4882a593Smuzhiyun 		dev_err(dev, "Failed to add component: %d\n", ret);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	return ret;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
mtk_disp_ovl_remove(struct platform_device * pdev)412*4882a593Smuzhiyun static int mtk_disp_ovl_remove(struct platform_device *pdev)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun 	component_del(&pdev->dev, &mtk_disp_ovl_component_ops);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	return 0;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun static const struct mtk_disp_ovl_data mt2701_ovl_driver_data = {
420*4882a593Smuzhiyun 	.addr = DISP_REG_OVL_ADDR_MT2701,
421*4882a593Smuzhiyun 	.gmc_bits = 8,
422*4882a593Smuzhiyun 	.layer_nr = 4,
423*4882a593Smuzhiyun 	.fmt_rgb565_is_0 = false,
424*4882a593Smuzhiyun };
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
427*4882a593Smuzhiyun 	.addr = DISP_REG_OVL_ADDR_MT8173,
428*4882a593Smuzhiyun 	.gmc_bits = 8,
429*4882a593Smuzhiyun 	.layer_nr = 4,
430*4882a593Smuzhiyun 	.fmt_rgb565_is_0 = true,
431*4882a593Smuzhiyun };
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
434*4882a593Smuzhiyun 	{ .compatible = "mediatek,mt2701-disp-ovl",
435*4882a593Smuzhiyun 	  .data = &mt2701_ovl_driver_data},
436*4882a593Smuzhiyun 	{ .compatible = "mediatek,mt8173-disp-ovl",
437*4882a593Smuzhiyun 	  .data = &mt8173_ovl_driver_data},
438*4882a593Smuzhiyun 	{},
439*4882a593Smuzhiyun };
440*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun struct platform_driver mtk_disp_ovl_driver = {
443*4882a593Smuzhiyun 	.probe		= mtk_disp_ovl_probe,
444*4882a593Smuzhiyun 	.remove		= mtk_disp_ovl_remove,
445*4882a593Smuzhiyun 	.driver		= {
446*4882a593Smuzhiyun 		.name	= "mediatek-disp-ovl",
447*4882a593Smuzhiyun 		.owner	= THIS_MODULE,
448*4882a593Smuzhiyun 		.of_match_table = mtk_disp_ovl_driver_dt_match,
449*4882a593Smuzhiyun 	},
450*4882a593Smuzhiyun };
451