Commit | Line | Data |
---|---|---|
1802d0be | 1 | // SPDX-License-Identifier: GPL-2.0-only |
119f5173 CH |
2 | /* |
3 | * Copyright (c) 2015 MediaTek Inc. | |
119f5173 CH |
4 | */ |
5 | ||
90bb087f | 6 | #include <drm/drm_blend.h> |
84d80575 | 7 | #include <drm/drm_fourcc.h> |
720cf96d | 8 | #include <drm/drm_framebuffer.h> |
84d80575 | 9 | |
119f5173 CH |
10 | #include <linux/clk.h> |
11 | #include <linux/component.h> | |
9aef5867 | 12 | #include <linux/module.h> |
722d4f06 | 13 | #include <linux/of.h> |
119f5173 | 14 | #include <linux/platform_device.h> |
5db12f5d | 15 | #include <linux/pm_runtime.h> |
d0afe37f | 16 | #include <linux/soc/mediatek/mtk-cmdq.h> |
119f5173 | 17 | |
f5214df8 | 18 | #include "mtk_crtc.h" |
7026ee0b | 19 | #include "mtk_ddp_comp.h" |
1d33f13a | 20 | #include "mtk_disp_drv.h" |
807e2f3f | 21 | #include "mtk_drm_drv.h" |
119f5173 CH |
22 | |
23 | #define DISP_REG_OVL_INTEN 0x0004 | |
24 | #define OVL_FME_CPL_INT BIT(1) | |
25 | #define DISP_REG_OVL_INTSTA 0x0008 | |
26 | #define DISP_REG_OVL_EN 0x000c | |
27 | #define DISP_REG_OVL_RST 0x0014 | |
28 | #define DISP_REG_OVL_ROI_SIZE 0x0020 | |
318462d1 | 29 | #define DISP_REG_OVL_DATAPATH_CON 0x0024 |
d41ff4dc | 30 | #define OVL_LAYER_SMI_ID_EN BIT(0) |
318462d1 | 31 | #define OVL_BGCLR_SEL_IN BIT(2) |
c410fa9b | 32 | #define OVL_LAYER_AFBC_EN(n) BIT(4+n) |
119f5173 CH |
33 | #define DISP_REG_OVL_ROI_BGCLR 0x0028 |
34 | #define DISP_REG_OVL_SRC_CON 0x002c | |
35 | #define DISP_REG_OVL_CON(n) (0x0030 + 0x20 * (n)) | |
36 | #define DISP_REG_OVL_SRC_SIZE(n) (0x0038 + 0x20 * (n)) | |
37 | #define DISP_REG_OVL_OFFSET(n) (0x003c + 0x20 * (n)) | |
c410fa9b JG |
38 | #define DISP_REG_OVL_PITCH_MSB(n) (0x0040 + 0x20 * (n)) |
39 | #define OVL_PITCH_MSB_2ND_SUBBUF BIT(16) | |
119f5173 | 40 | #define DISP_REG_OVL_PITCH(n) (0x0044 + 0x20 * (n)) |
765f284f | 41 | #define OVL_CONST_BLEND BIT(28) |
119f5173 CH |
42 | #define DISP_REG_OVL_RDMA_CTRL(n) (0x00c0 + 0x20 * (n)) |
43 | #define DISP_REG_OVL_RDMA_GMC(n) (0x00c8 + 0x20 * (n)) | |
84a5ead1 | 44 | #define DISP_REG_OVL_ADDR_MT2701 0x0040 |
e7df7a20 JJL |
45 | #define DISP_REG_OVL_CLRFMT_EXT 0x02d0 |
46 | #define OVL_CON_CLRFMT_BIT_DEPTH_MASK(n) (GENMASK(1, 0) << (4 * (n))) | |
47 | #define OVL_CON_CLRFMT_BIT_DEPTH(depth, n) ((depth) << (4 * (n))) | |
48 | #define OVL_CON_CLRFMT_8_BIT (0) | |
49 | #define OVL_CON_CLRFMT_10_BIT (1) | |
c5f228ef | 50 | #define DISP_REG_OVL_ADDR_MT8173 0x0f40 |
51 | #define DISP_REG_OVL_ADDR(ovl, n) ((ovl)->data->addr + 0x20 * (n)) | |
c410fa9b JG |
52 | #define DISP_REG_OVL_HDR_ADDR(ovl, n) ((ovl)->data->addr + 0x20 * (n) + 0x04) |
53 | #define DISP_REG_OVL_HDR_PITCH(ovl, n) ((ovl)->data->addr + 0x20 * (n) + 0x08) | |
119f5173 | 54 | |
d5abb5f2 YN |
55 | #define GMC_THRESHOLD_BITS 16 |
56 | #define GMC_THRESHOLD_HIGH ((1 << GMC_THRESHOLD_BITS) / 4) | |
57 | #define GMC_THRESHOLD_LOW ((1 << GMC_THRESHOLD_BITS) / 8) | |
119f5173 | 58 | |
a3f7f7ef | 59 | #define OVL_CON_CLRFMT_MAN BIT(23) |
119f5173 | 60 | #define OVL_CON_BYTE_SWAP BIT(24) |
a3f7f7ef HCS |
61 | |
62 | /* OVL_CON_RGB_SWAP works only if OVL_CON_CLRFMT_MAN is enabled */ | |
63 | #define OVL_CON_RGB_SWAP BIT(25) | |
64 | ||
c5f228ef | 65 | #define OVL_CON_CLRFMT_RGB (1 << 12) |
9f428b95 HCS |
66 | #define OVL_CON_CLRFMT_ARGB8888 (2 << 12) |
67 | #define OVL_CON_CLRFMT_RGBA8888 (3 << 12) | |
68 | #define OVL_CON_CLRFMT_ABGR8888 (OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP) | |
69 | #define OVL_CON_CLRFMT_BGRA8888 (OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP) | |
170748db BH |
70 | #define OVL_CON_CLRFMT_UYVY (4 << 12) |
71 | #define OVL_CON_CLRFMT_YUYV (5 << 12) | |
a3f7f7ef HCS |
72 | #define OVL_CON_MTX_YUV_TO_RGB (6 << 16) |
73 | #define OVL_CON_CLRFMT_PARGB8888 ((3 << 12) | OVL_CON_CLRFMT_MAN) | |
74 | #define OVL_CON_CLRFMT_PABGR8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_RGB_SWAP) | |
75 | #define OVL_CON_CLRFMT_PBGRA8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_BYTE_SWAP) | |
76 | #define OVL_CON_CLRFMT_PRGBA8888 (OVL_CON_CLRFMT_PABGR8888 | OVL_CON_BYTE_SWAP) | |
c5f228ef | 77 | #define OVL_CON_CLRFMT_RGB565(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \ |
78 | 0 : OVL_CON_CLRFMT_RGB) | |
79 | #define OVL_CON_CLRFMT_RGB888(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \ | |
80 | OVL_CON_CLRFMT_RGB : 0) | |
119f5173 CH |
81 | #define OVL_CON_AEN BIT(8) |
82 | #define OVL_CON_ALPHA 0xff | |
84d80575 | 83 | #define OVL_CON_VIRT_FLIP BIT(9) |
b368d3ec | 84 | #define OVL_CON_HORZ_FLIP BIT(10) |
119f5173 | 85 | |
31c0fbf6 HCS |
86 | #define OVL_COLOR_ALPHA GENMASK(31, 24) |
87 | ||
46ed6ff6 HCS |
88 | static inline bool is_10bit_rgb(u32 fmt) |
89 | { | |
90 | switch (fmt) { | |
91 | case DRM_FORMAT_XRGB2101010: | |
92 | case DRM_FORMAT_ARGB2101010: | |
93 | case DRM_FORMAT_RGBX1010102: | |
94 | case DRM_FORMAT_RGBA1010102: | |
95 | case DRM_FORMAT_XBGR2101010: | |
96 | case DRM_FORMAT_ABGR2101010: | |
97 | case DRM_FORMAT_BGRX1010102: | |
98 | case DRM_FORMAT_BGRA1010102: | |
99 | return true; | |
100 | } | |
101 | return false; | |
102 | } | |
103 | ||
f287c66a JG |
104 | static const u32 mt8173_formats[] = { |
105 | DRM_FORMAT_XRGB8888, | |
106 | DRM_FORMAT_ARGB8888, | |
107 | DRM_FORMAT_BGRX8888, | |
108 | DRM_FORMAT_BGRA8888, | |
109 | DRM_FORMAT_ABGR8888, | |
110 | DRM_FORMAT_XBGR8888, | |
111 | DRM_FORMAT_RGB888, | |
112 | DRM_FORMAT_BGR888, | |
113 | DRM_FORMAT_RGB565, | |
114 | DRM_FORMAT_UYVY, | |
115 | DRM_FORMAT_YUYV, | |
116 | }; | |
117 | ||
ed715684 JG |
118 | static const u32 mt8195_formats[] = { |
119 | DRM_FORMAT_XRGB8888, | |
120 | DRM_FORMAT_ARGB8888, | |
46ed6ff6 | 121 | DRM_FORMAT_XRGB2101010, |
ed715684 JG |
122 | DRM_FORMAT_ARGB2101010, |
123 | DRM_FORMAT_BGRX8888, | |
124 | DRM_FORMAT_BGRA8888, | |
46ed6ff6 | 125 | DRM_FORMAT_BGRX1010102, |
ed715684 JG |
126 | DRM_FORMAT_BGRA1010102, |
127 | DRM_FORMAT_ABGR8888, | |
128 | DRM_FORMAT_XBGR8888, | |
46ed6ff6 HCS |
129 | DRM_FORMAT_XBGR2101010, |
130 | DRM_FORMAT_ABGR2101010, | |
2606aac5 HCS |
131 | DRM_FORMAT_RGBX8888, |
132 | DRM_FORMAT_RGBA8888, | |
46ed6ff6 HCS |
133 | DRM_FORMAT_RGBX1010102, |
134 | DRM_FORMAT_RGBA1010102, | |
ed715684 JG |
135 | DRM_FORMAT_RGB888, |
136 | DRM_FORMAT_BGR888, | |
137 | DRM_FORMAT_RGB565, | |
138 | DRM_FORMAT_UYVY, | |
139 | DRM_FORMAT_YUYV, | |
140 | }; | |
141 | ||
c5f228ef | 142 | struct mtk_disp_ovl_data { |
143 | unsigned int addr; | |
d5abb5f2 | 144 | unsigned int gmc_bits; |
0a5ccda4 | 145 | unsigned int layer_nr; |
c5f228ef | 146 | bool fmt_rgb565_is_0; |
d41ff4dc | 147 | bool smi_id_en; |
c410fa9b | 148 | bool supports_afbc; |
f287c66a JG |
149 | const u32 *formats; |
150 | size_t num_formats; | |
fb36c502 | 151 | bool supports_clrfmt_ext; |
c5f228ef | 152 | }; |
153 | ||
ae727f67 | 154 | /* |
119f5173 | 155 | * struct mtk_disp_ovl - DISP_OVL driver structure |
e772a89d LJ |
156 | * @crtc: associated crtc to report vblank events to |
157 | * @data: platform data | |
119f5173 CH |
158 | */ |
159 | struct mtk_disp_ovl { | |
119f5173 | 160 | struct drm_crtc *crtc; |
c0d36de8 | 161 | struct clk *clk; |
3c87daef | 162 | void __iomem *regs; |
616443ca | 163 | struct cmdq_client_reg cmdq_reg; |
c5f228ef | 164 | const struct mtk_disp_ovl_data *data; |
9b070498 CH |
165 | void (*vblank_cb)(void *data); |
166 | void *vblank_cb_data; | |
119f5173 CH |
167 | }; |
168 | ||
169 | static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id) | |
170 | { | |
171 | struct mtk_disp_ovl *priv = dev_id; | |
119f5173 CH |
172 | |
173 | /* Clear frame completion interrupt */ | |
3c87daef | 174 | writel(0x0, priv->regs + DISP_REG_OVL_INTSTA); |
119f5173 | 175 | |
9b070498 | 176 | if (!priv->vblank_cb) |
119f5173 CH |
177 | return IRQ_NONE; |
178 | ||
9b070498 | 179 | priv->vblank_cb(priv->vblank_cb_data); |
119f5173 CH |
180 | |
181 | return IRQ_HANDLED; | |
182 | } | |
183 | ||
b74d921b RBC |
184 | void mtk_ovl_register_vblank_cb(struct device *dev, |
185 | void (*vblank_cb)(void *), | |
186 | void *vblank_cb_data) | |
119f5173 | 187 | { |
4d510659 | 188 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
119f5173 | 189 | |
9b070498 CH |
190 | ovl->vblank_cb = vblank_cb; |
191 | ovl->vblank_cb_data = vblank_cb_data; | |
b74d921b RBC |
192 | } |
193 | ||
194 | void mtk_ovl_unregister_vblank_cb(struct device *dev) | |
195 | { | |
196 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
197 | ||
198 | ovl->vblank_cb = NULL; | |
199 | ovl->vblank_cb_data = NULL; | |
200 | } | |
201 | ||
202 | void mtk_ovl_enable_vblank(struct device *dev) | |
203 | { | |
204 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
205 | ||
3c87daef CH |
206 | writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA); |
207 | writel_relaxed(OVL_FME_CPL_INT, ovl->regs + DISP_REG_OVL_INTEN); | |
119f5173 CH |
208 | } |
209 | ||
1d33f13a | 210 | void mtk_ovl_disable_vblank(struct device *dev) |
119f5173 | 211 | { |
4d510659 | 212 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
119f5173 | 213 | |
3c87daef | 214 | writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN); |
119f5173 CH |
215 | } |
216 | ||
f287c66a JG |
217 | const u32 *mtk_ovl_get_formats(struct device *dev) |
218 | { | |
219 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
220 | ||
221 | return ovl->data->formats; | |
222 | } | |
223 | ||
224 | size_t mtk_ovl_get_num_formats(struct device *dev) | |
225 | { | |
226 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
227 | ||
228 | return ovl->data->num_formats; | |
229 | } | |
230 | ||
1d33f13a | 231 | int mtk_ovl_clk_enable(struct device *dev) |
c0d36de8 CH |
232 | { |
233 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
234 | ||
235 | return clk_prepare_enable(ovl->clk); | |
236 | } | |
237 | ||
1d33f13a | 238 | void mtk_ovl_clk_disable(struct device *dev) |
c0d36de8 CH |
239 | { |
240 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
241 | ||
242 | clk_disable_unprepare(ovl->clk); | |
243 | } | |
244 | ||
1d33f13a | 245 | void mtk_ovl_start(struct device *dev) |
119f5173 | 246 | { |
4d510659 | 247 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
3c87daef | 248 | |
d41ff4dc YN |
249 | if (ovl->data->smi_id_en) { |
250 | unsigned int reg; | |
251 | ||
252 | reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON); | |
253 | reg = reg | OVL_LAYER_SMI_ID_EN; | |
254 | writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON); | |
255 | } | |
3c87daef | 256 | writel_relaxed(0x1, ovl->regs + DISP_REG_OVL_EN); |
119f5173 CH |
257 | } |
258 | ||
1d33f13a | 259 | void mtk_ovl_stop(struct device *dev) |
119f5173 | 260 | { |
4d510659 | 261 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
3c87daef CH |
262 | |
263 | writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_EN); | |
d41ff4dc YN |
264 | if (ovl->data->smi_id_en) { |
265 | unsigned int reg; | |
266 | ||
267 | reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON); | |
268 | reg = reg & ~OVL_LAYER_SMI_ID_EN; | |
269 | writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON); | |
270 | } | |
c410fa9b | 271 | } |
d41ff4dc | 272 | |
c410fa9b JG |
273 | static void mtk_ovl_set_afbc(struct mtk_disp_ovl *ovl, struct cmdq_pkt *cmdq_pkt, |
274 | int idx, bool enabled) | |
275 | { | |
276 | mtk_ddp_write_mask(cmdq_pkt, enabled ? OVL_LAYER_AFBC_EN(idx) : 0, | |
277 | &ovl->cmdq_reg, ovl->regs, | |
278 | DISP_REG_OVL_DATAPATH_CON, OVL_LAYER_AFBC_EN(idx)); | |
119f5173 CH |
279 | } |
280 | ||
fb36c502 JG |
281 | static void mtk_ovl_set_bit_depth(struct device *dev, int idx, u32 format, |
282 | struct cmdq_pkt *cmdq_pkt) | |
283 | { | |
284 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
fb36c502 JG |
285 | unsigned int bit_depth = OVL_CON_CLRFMT_8_BIT; |
286 | ||
287 | if (!ovl->data->supports_clrfmt_ext) | |
288 | return; | |
289 | ||
46ed6ff6 | 290 | if (is_10bit_rgb(format)) |
fb36c502 JG |
291 | bit_depth = OVL_CON_CLRFMT_10_BIT; |
292 | ||
e7df7a20 JJL |
293 | mtk_ddp_write_mask(cmdq_pkt, OVL_CON_CLRFMT_BIT_DEPTH(bit_depth, idx), |
294 | &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_CLRFMT_EXT, | |
295 | OVL_CON_CLRFMT_BIT_DEPTH_MASK(idx)); | |
fb36c502 JG |
296 | } |
297 | ||
1d33f13a CH |
298 | void mtk_ovl_config(struct device *dev, unsigned int w, |
299 | unsigned int h, unsigned int vrefresh, | |
300 | unsigned int bpc, struct cmdq_pkt *cmdq_pkt) | |
119f5173 | 301 | { |
4d510659 | 302 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
3c87daef | 303 | |
119f5173 | 304 | if (w != 0 && h != 0) |
616443ca | 305 | mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 306 | DISP_REG_OVL_ROI_SIZE); |
31c0fbf6 HCS |
307 | |
308 | /* | |
309 | * The background color must be opaque black (ARGB), | |
310 | * otherwise the alpha blending will have no effect | |
311 | */ | |
312 | mtk_ddp_write_relaxed(cmdq_pkt, OVL_COLOR_ALPHA, &ovl->cmdq_reg, | |
313 | ovl->regs, DISP_REG_OVL_ROI_BGCLR); | |
119f5173 | 314 | |
616443ca CH |
315 | mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST); |
316 | mtk_ddp_write(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST); | |
119f5173 CH |
317 | } |
318 | ||
1d33f13a | 319 | unsigned int mtk_ovl_layer_nr(struct device *dev) |
1cbcb763 | 320 | { |
4d510659 | 321 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
0a5ccda4 YN |
322 | |
323 | return ovl->data->layer_nr; | |
1cbcb763 SH |
324 | } |
325 | ||
1d33f13a | 326 | unsigned int mtk_ovl_supported_rotations(struct device *dev) |
84d80575 | 327 | { |
df444457 SP |
328 | return DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 | |
329 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y; | |
84d80575 SP |
330 | } |
331 | ||
1d33f13a CH |
332 | int mtk_ovl_layer_check(struct device *dev, unsigned int idx, |
333 | struct mtk_plane_state *mtk_state) | |
84d80575 SP |
334 | { |
335 | struct drm_plane_state *state = &mtk_state->base; | |
84d80575 | 336 | |
74608d8f HCS |
337 | /* check if any unsupported rotation is set */ |
338 | if (state->rotation & ~mtk_ovl_supported_rotations(dev)) | |
84d80575 SP |
339 | return -EINVAL; |
340 | ||
341 | /* | |
342 | * TODO: Rotating/reflecting YUV buffers is not supported at this time. | |
343 | * Only RGB[AX] variants are supported. | |
74608d8f HCS |
344 | * Since DRM_MODE_ROTATE_0 means "no rotation", we should not |
345 | * reject layers with this property. | |
84d80575 | 346 | */ |
74608d8f | 347 | if (state->fb->format->is_yuv && (state->rotation & ~DRM_MODE_ROTATE_0)) |
84d80575 SP |
348 | return -EINVAL; |
349 | ||
84d80575 SP |
350 | return 0; |
351 | } | |
352 | ||
1d33f13a CH |
353 | void mtk_ovl_layer_on(struct device *dev, unsigned int idx, |
354 | struct cmdq_pkt *cmdq_pkt) | |
119f5173 | 355 | { |
d5abb5f2 YN |
356 | unsigned int gmc_thrshd_l; |
357 | unsigned int gmc_thrshd_h; | |
358 | unsigned int gmc_value; | |
4d510659 | 359 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
119f5173 | 360 | |
616443ca | 361 | mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 362 | DISP_REG_OVL_RDMA_CTRL(idx)); |
d5abb5f2 YN |
363 | gmc_thrshd_l = GMC_THRESHOLD_LOW >> |
364 | (GMC_THRESHOLD_BITS - ovl->data->gmc_bits); | |
365 | gmc_thrshd_h = GMC_THRESHOLD_HIGH >> | |
366 | (GMC_THRESHOLD_BITS - ovl->data->gmc_bits); | |
367 | if (ovl->data->gmc_bits == 10) | |
368 | gmc_value = gmc_thrshd_h | gmc_thrshd_h << 16; | |
369 | else | |
370 | gmc_value = gmc_thrshd_l | gmc_thrshd_l << 8 | | |
371 | gmc_thrshd_h << 16 | gmc_thrshd_h << 24; | |
d0afe37f | 372 | mtk_ddp_write(cmdq_pkt, gmc_value, |
616443ca CH |
373 | &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RDMA_GMC(idx)); |
374 | mtk_ddp_write_mask(cmdq_pkt, BIT(idx), &ovl->cmdq_reg, ovl->regs, | |
d0afe37f | 375 | DISP_REG_OVL_SRC_CON, BIT(idx)); |
119f5173 CH |
376 | } |
377 | ||
1d33f13a CH |
378 | void mtk_ovl_layer_off(struct device *dev, unsigned int idx, |
379 | struct cmdq_pkt *cmdq_pkt) | |
119f5173 | 380 | { |
4d510659 | 381 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
3c87daef | 382 | |
616443ca | 383 | mtk_ddp_write_mask(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 384 | DISP_REG_OVL_SRC_CON, BIT(idx)); |
616443ca | 385 | mtk_ddp_write(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 386 | DISP_REG_OVL_RDMA_CTRL(idx)); |
119f5173 CH |
387 | } |
388 | ||
a3f7f7ef HCS |
389 | static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt, |
390 | unsigned int blend_mode) | |
119f5173 | 391 | { |
55b53f6f SH |
392 | /* The return value in switch "MEM_MODE_INPUT_FORMAT_XXX" |
393 | * is defined in mediatek HW data sheet. | |
394 | * The alphabet order in XXX is no relation to data | |
395 | * arrangement in memory. | |
396 | */ | |
119f5173 CH |
397 | switch (fmt) { |
398 | default: | |
399 | case DRM_FORMAT_RGB565: | |
c5f228ef | 400 | return OVL_CON_CLRFMT_RGB565(ovl); |
119f5173 | 401 | case DRM_FORMAT_BGR565: |
c5f228ef | 402 | return OVL_CON_CLRFMT_RGB565(ovl) | OVL_CON_BYTE_SWAP; |
119f5173 | 403 | case DRM_FORMAT_RGB888: |
c5f228ef | 404 | return OVL_CON_CLRFMT_RGB888(ovl); |
119f5173 | 405 | case DRM_FORMAT_BGR888: |
c5f228ef | 406 | return OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP; |
119f5173 CH |
407 | case DRM_FORMAT_RGBX8888: |
408 | case DRM_FORMAT_RGBA8888: | |
46ed6ff6 HCS |
409 | case DRM_FORMAT_RGBX1010102: |
410 | case DRM_FORMAT_RGBA1010102: | |
a3f7f7ef HCS |
411 | return blend_mode == DRM_MODE_BLEND_COVERAGE ? |
412 | OVL_CON_CLRFMT_RGBA8888 : | |
413 | OVL_CON_CLRFMT_PRGBA8888; | |
119f5173 CH |
414 | case DRM_FORMAT_BGRX8888: |
415 | case DRM_FORMAT_BGRA8888: | |
46ed6ff6 | 416 | case DRM_FORMAT_BGRX1010102: |
fb36c502 | 417 | case DRM_FORMAT_BGRA1010102: |
a3f7f7ef HCS |
418 | return blend_mode == DRM_MODE_BLEND_COVERAGE ? |
419 | OVL_CON_CLRFMT_BGRA8888 : | |
420 | OVL_CON_CLRFMT_PBGRA8888; | |
119f5173 CH |
421 | case DRM_FORMAT_XRGB8888: |
422 | case DRM_FORMAT_ARGB8888: | |
46ed6ff6 | 423 | case DRM_FORMAT_XRGB2101010: |
fb36c502 | 424 | case DRM_FORMAT_ARGB2101010: |
a3f7f7ef HCS |
425 | return blend_mode == DRM_MODE_BLEND_COVERAGE ? |
426 | OVL_CON_CLRFMT_ARGB8888 : | |
427 | OVL_CON_CLRFMT_PARGB8888; | |
119f5173 CH |
428 | case DRM_FORMAT_XBGR8888: |
429 | case DRM_FORMAT_ABGR8888: | |
46ed6ff6 HCS |
430 | case DRM_FORMAT_XBGR2101010: |
431 | case DRM_FORMAT_ABGR2101010: | |
a3f7f7ef HCS |
432 | return blend_mode == DRM_MODE_BLEND_COVERAGE ? |
433 | OVL_CON_CLRFMT_ABGR8888 : | |
434 | OVL_CON_CLRFMT_PABGR8888; | |
170748db BH |
435 | case DRM_FORMAT_UYVY: |
436 | return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB; | |
437 | case DRM_FORMAT_YUYV: | |
438 | return OVL_CON_CLRFMT_YUYV | OVL_CON_MTX_YUV_TO_RGB; | |
119f5173 CH |
439 | } |
440 | } | |
441 | ||
1d33f13a CH |
442 | void mtk_ovl_layer_config(struct device *dev, unsigned int idx, |
443 | struct mtk_plane_state *state, | |
444 | struct cmdq_pkt *cmdq_pkt) | |
119f5173 | 445 | { |
4d510659 | 446 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
119f5173 CH |
447 | struct mtk_plane_pending_state *pending = &state->pending; |
448 | unsigned int addr = pending->addr; | |
c410fa9b JG |
449 | unsigned int hdr_addr = pending->hdr_addr; |
450 | unsigned int pitch = pending->pitch; | |
451 | unsigned int hdr_pitch = pending->hdr_pitch; | |
119f5173 CH |
452 | unsigned int fmt = pending->format; |
453 | unsigned int offset = (pending->y << 16) | pending->x; | |
454 | unsigned int src_size = (pending->height << 16) | pending->width; | |
1f66fe62 | 455 | unsigned int blend_mode = state->base.pixel_blend_mode; |
765f284f | 456 | unsigned int ignore_pixel_alpha = 0; |
119f5173 | 457 | unsigned int con; |
c410fa9b JG |
458 | bool is_afbc = pending->modifier != DRM_FORMAT_MOD_LINEAR; |
459 | union overlay_pitch { | |
460 | struct split_pitch { | |
461 | u16 lsb; | |
462 | u16 msb; | |
463 | } split_pitch; | |
464 | u32 pitch; | |
465 | } overlay_pitch; | |
466 | ||
467 | overlay_pitch.pitch = pitch; | |
119f5173 | 468 | |
039cf36c | 469 | if (!pending->enable) { |
4d510659 | 470 | mtk_ovl_layer_off(dev, idx, cmdq_pkt); |
039cf36c MY |
471 | return; |
472 | } | |
119f5173 | 473 | |
a3f7f7ef | 474 | con = ovl_fmt_convert(ovl, fmt, blend_mode); |
bc46eb5d HCS |
475 | if (state->base.fb) { |
476 | con |= OVL_CON_AEN; | |
477 | con |= state->base.alpha & OVL_CON_ALPHA; | |
478 | } | |
119f5173 | 479 | |
765f284f HCS |
480 | /* CONST_BLD must be enabled for XRGB formats although the alpha channel |
481 | * can be ignored, or OVL will still read the value from memory. | |
482 | * For RGB888 related formats, whether CONST_BLD is enabled or not won't | |
483 | * affect the result. Therefore we use !has_alpha as the condition. | |
484 | */ | |
1f66fe62 HCS |
485 | if ((state->base.fb && !state->base.fb->format->has_alpha) || |
486 | blend_mode == DRM_MODE_BLEND_PIXEL_NONE) | |
765f284f HCS |
487 | ignore_pixel_alpha = OVL_CONST_BLEND; |
488 | ||
84d80575 SP |
489 | if (pending->rotation & DRM_MODE_REFLECT_Y) { |
490 | con |= OVL_CON_VIRT_FLIP; | |
491 | addr += (pending->height - 1) * pending->pitch; | |
492 | } | |
493 | ||
b368d3ec SP |
494 | if (pending->rotation & DRM_MODE_REFLECT_X) { |
495 | con |= OVL_CON_HORZ_FLIP; | |
496 | addr += pending->pitch - 1; | |
497 | } | |
498 | ||
c410fa9b JG |
499 | if (ovl->data->supports_afbc) |
500 | mtk_ovl_set_afbc(ovl, cmdq_pkt, idx, is_afbc); | |
501 | ||
616443ca | 502 | mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 503 | DISP_REG_OVL_CON(idx)); |
765f284f HCS |
504 | mtk_ddp_write_relaxed(cmdq_pkt, overlay_pitch.split_pitch.lsb | ignore_pixel_alpha, |
505 | &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH(idx)); | |
616443ca | 506 | mtk_ddp_write_relaxed(cmdq_pkt, src_size, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 507 | DISP_REG_OVL_SRC_SIZE(idx)); |
616443ca | 508 | mtk_ddp_write_relaxed(cmdq_pkt, offset, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 509 | DISP_REG_OVL_OFFSET(idx)); |
616443ca | 510 | mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 511 | DISP_REG_OVL_ADDR(ovl, idx)); |
119f5173 | 512 | |
c410fa9b JG |
513 | if (is_afbc) { |
514 | mtk_ddp_write_relaxed(cmdq_pkt, hdr_addr, &ovl->cmdq_reg, ovl->regs, | |
515 | DISP_REG_OVL_HDR_ADDR(ovl, idx)); | |
516 | mtk_ddp_write_relaxed(cmdq_pkt, | |
517 | OVL_PITCH_MSB_2ND_SUBBUF | overlay_pitch.split_pitch.msb, | |
518 | &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH_MSB(idx)); | |
519 | mtk_ddp_write_relaxed(cmdq_pkt, hdr_pitch, &ovl->cmdq_reg, ovl->regs, | |
520 | DISP_REG_OVL_HDR_PITCH(ovl, idx)); | |
521 | } else { | |
522 | mtk_ddp_write_relaxed(cmdq_pkt, | |
523 | overlay_pitch.split_pitch.msb, | |
524 | &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH_MSB(idx)); | |
525 | } | |
526 | ||
fb36c502 | 527 | mtk_ovl_set_bit_depth(dev, idx, fmt, cmdq_pkt); |
4d510659 | 528 | mtk_ovl_layer_on(dev, idx, cmdq_pkt); |
119f5173 CH |
529 | } |
530 | ||
1d33f13a | 531 | void mtk_ovl_bgclr_in_on(struct device *dev) |
318462d1 | 532 | { |
4d510659 | 533 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
318462d1 YN |
534 | unsigned int reg; |
535 | ||
3c87daef | 536 | reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON); |
318462d1 | 537 | reg = reg | OVL_BGCLR_SEL_IN; |
3c87daef | 538 | writel(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON); |
318462d1 YN |
539 | } |
540 | ||
1d33f13a | 541 | void mtk_ovl_bgclr_in_off(struct device *dev) |
318462d1 | 542 | { |
4d510659 | 543 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
318462d1 YN |
544 | unsigned int reg; |
545 | ||
3c87daef | 546 | reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON); |
318462d1 | 547 | reg = reg & ~OVL_BGCLR_SEL_IN; |
3c87daef | 548 | writel(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON); |
318462d1 YN |
549 | } |
550 | ||
119f5173 CH |
551 | static int mtk_disp_ovl_bind(struct device *dev, struct device *master, |
552 | void *data) | |
553 | { | |
119f5173 CH |
554 | return 0; |
555 | } | |
556 | ||
557 | static void mtk_disp_ovl_unbind(struct device *dev, struct device *master, | |
558 | void *data) | |
559 | { | |
119f5173 CH |
560 | } |
561 | ||
562 | static const struct component_ops mtk_disp_ovl_component_ops = { | |
563 | .bind = mtk_disp_ovl_bind, | |
564 | .unbind = mtk_disp_ovl_unbind, | |
565 | }; | |
566 | ||
567 | static int mtk_disp_ovl_probe(struct platform_device *pdev) | |
568 | { | |
569 | struct device *dev = &pdev->dev; | |
570 | struct mtk_disp_ovl *priv; | |
3c87daef | 571 | struct resource *res; |
119f5173 CH |
572 | int irq; |
573 | int ret; | |
574 | ||
575 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
576 | if (!priv) | |
577 | return -ENOMEM; | |
578 | ||
579 | irq = platform_get_irq(pdev, 0); | |
580 | if (irq < 0) | |
581 | return irq; | |
582 | ||
c0d36de8 | 583 | priv->clk = devm_clk_get(dev, NULL); |
45b70f71 NP |
584 | if (IS_ERR(priv->clk)) |
585 | return dev_err_probe(dev, PTR_ERR(priv->clk), | |
586 | "failed to get ovl clk\n"); | |
c0d36de8 | 587 | |
3c87daef CH |
588 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
589 | priv->regs = devm_ioremap_resource(dev, res); | |
45b70f71 NP |
590 | if (IS_ERR(priv->regs)) |
591 | return dev_err_probe(dev, PTR_ERR(priv->regs), | |
592 | "failed to ioremap ovl\n"); | |
616443ca CH |
593 | #if IS_REACHABLE(CONFIG_MTK_CMDQ) |
594 | ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0); | |
595 | if (ret) | |
596 | dev_dbg(dev, "get mediatek,gce-client-reg fail!\n"); | |
597 | #endif | |
3c87daef | 598 | |
57148baa | 599 | priv->data = of_device_get_match_data(dev); |
119f5173 CH |
600 | platform_set_drvdata(pdev, priv); |
601 | ||
5ad45307 MB |
602 | ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler, |
603 | IRQF_TRIGGER_NONE, dev_name(dev), priv); | |
45b70f71 NP |
604 | if (ret < 0) |
605 | return dev_err_probe(dev, ret, "Failed to request irq %d\n", irq); | |
5ad45307 | 606 | |
5db12f5d YN |
607 | pm_runtime_enable(dev); |
608 | ||
119f5173 | 609 | ret = component_add(dev, &mtk_disp_ovl_component_ops); |
5db12f5d YN |
610 | if (ret) { |
611 | pm_runtime_disable(dev); | |
45b70f71 | 612 | return dev_err_probe(dev, ret, "Failed to add component\n"); |
5db12f5d | 613 | } |
119f5173 | 614 | |
45b70f71 | 615 | return 0; |
119f5173 CH |
616 | } |
617 | ||
b3af12a0 | 618 | static void mtk_disp_ovl_remove(struct platform_device *pdev) |
119f5173 | 619 | { |
da4d4517 | 620 | component_del(&pdev->dev, &mtk_disp_ovl_component_ops); |
5db12f5d | 621 | pm_runtime_disable(&pdev->dev); |
119f5173 CH |
622 | } |
623 | ||
84a5ead1 | 624 | static const struct mtk_disp_ovl_data mt2701_ovl_driver_data = { |
625 | .addr = DISP_REG_OVL_ADDR_MT2701, | |
d5abb5f2 | 626 | .gmc_bits = 8, |
0a5ccda4 | 627 | .layer_nr = 4, |
84a5ead1 | 628 | .fmt_rgb565_is_0 = false, |
f287c66a JG |
629 | .formats = mt8173_formats, |
630 | .num_formats = ARRAY_SIZE(mt8173_formats), | |
84a5ead1 | 631 | }; |
632 | ||
c5f228ef | 633 | static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = { |
634 | .addr = DISP_REG_OVL_ADDR_MT8173, | |
d5abb5f2 | 635 | .gmc_bits = 8, |
0a5ccda4 | 636 | .layer_nr = 4, |
c5f228ef | 637 | .fmt_rgb565_is_0 = true, |
f287c66a JG |
638 | .formats = mt8173_formats, |
639 | .num_formats = ARRAY_SIZE(mt8173_formats), | |
c5f228ef | 640 | }; |
641 | ||
641ef9e7 YN |
642 | static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = { |
643 | .addr = DISP_REG_OVL_ADDR_MT8173, | |
644 | .gmc_bits = 10, | |
645 | .layer_nr = 4, | |
646 | .fmt_rgb565_is_0 = true, | |
f287c66a JG |
647 | .formats = mt8173_formats, |
648 | .num_formats = ARRAY_SIZE(mt8173_formats), | |
641ef9e7 YN |
649 | }; |
650 | ||
651 | static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = { | |
652 | .addr = DISP_REG_OVL_ADDR_MT8173, | |
653 | .gmc_bits = 10, | |
654 | .layer_nr = 2, | |
655 | .fmt_rgb565_is_0 = true, | |
f287c66a JG |
656 | .formats = mt8173_formats, |
657 | .num_formats = ARRAY_SIZE(mt8173_formats), | |
641ef9e7 YN |
658 | }; |
659 | ||
01365f54 YN |
660 | static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = { |
661 | .addr = DISP_REG_OVL_ADDR_MT8173, | |
662 | .gmc_bits = 10, | |
663 | .layer_nr = 4, | |
664 | .fmt_rgb565_is_0 = true, | |
665 | .smi_id_en = true, | |
f287c66a JG |
666 | .formats = mt8173_formats, |
667 | .num_formats = ARRAY_SIZE(mt8173_formats), | |
01365f54 YN |
668 | }; |
669 | ||
670 | static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = { | |
671 | .addr = DISP_REG_OVL_ADDR_MT8173, | |
672 | .gmc_bits = 10, | |
673 | .layer_nr = 2, | |
674 | .fmt_rgb565_is_0 = true, | |
675 | .smi_id_en = true, | |
f287c66a JG |
676 | .formats = mt8173_formats, |
677 | .num_formats = ARRAY_SIZE(mt8173_formats), | |
01365f54 YN |
678 | }; |
679 | ||
76cdcb87 JG |
680 | static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = { |
681 | .addr = DISP_REG_OVL_ADDR_MT8173, | |
682 | .gmc_bits = 10, | |
683 | .layer_nr = 4, | |
684 | .fmt_rgb565_is_0 = true, | |
685 | .smi_id_en = true, | |
686 | .supports_afbc = true, | |
ed715684 JG |
687 | .formats = mt8195_formats, |
688 | .num_formats = ARRAY_SIZE(mt8195_formats), | |
689 | .supports_clrfmt_ext = true, | |
76cdcb87 JG |
690 | }; |
691 | ||
119f5173 | 692 | static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = { |
84a5ead1 | 693 | { .compatible = "mediatek,mt2701-disp-ovl", |
694 | .data = &mt2701_ovl_driver_data}, | |
c5f228ef | 695 | { .compatible = "mediatek,mt8173-disp-ovl", |
696 | .data = &mt8173_ovl_driver_data}, | |
641ef9e7 YN |
697 | { .compatible = "mediatek,mt8183-disp-ovl", |
698 | .data = &mt8183_ovl_driver_data}, | |
699 | { .compatible = "mediatek,mt8183-disp-ovl-2l", | |
700 | .data = &mt8183_ovl_2l_driver_data}, | |
01365f54 YN |
701 | { .compatible = "mediatek,mt8192-disp-ovl", |
702 | .data = &mt8192_ovl_driver_data}, | |
703 | { .compatible = "mediatek,mt8192-disp-ovl-2l", | |
704 | .data = &mt8192_ovl_2l_driver_data}, | |
76cdcb87 JG |
705 | { .compatible = "mediatek,mt8195-disp-ovl", |
706 | .data = &mt8195_ovl_driver_data}, | |
119f5173 CH |
707 | {}, |
708 | }; | |
709 | MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match); | |
710 | ||
711 | struct platform_driver mtk_disp_ovl_driver = { | |
712 | .probe = mtk_disp_ovl_probe, | |
b3af12a0 | 713 | .remove_new = mtk_disp_ovl_remove, |
119f5173 CH |
714 | .driver = { |
715 | .name = "mediatek-disp-ovl", | |
119f5173 CH |
716 | .of_match_table = mtk_disp_ovl_driver_dt_match, |
717 | }, | |
718 | }; |