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) | |
655c6c1b HTY |
68 | #define OVL_CON_CLRFMT_ABGR8888 (OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP) |
69 | #define OVL_CON_CLRFMT_BGRA8888 (OVL_CON_CLRFMT_RGBA8888 | 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; |
333ab436 | 149 | const u32 blend_modes; |
f287c66a JG |
150 | const u32 *formats; |
151 | size_t num_formats; | |
fb36c502 | 152 | bool supports_clrfmt_ext; |
c5f228ef | 153 | }; |
154 | ||
ae727f67 | 155 | /* |
119f5173 | 156 | * struct mtk_disp_ovl - DISP_OVL driver structure |
e772a89d LJ |
157 | * @crtc: associated crtc to report vblank events to |
158 | * @data: platform data | |
119f5173 CH |
159 | */ |
160 | struct mtk_disp_ovl { | |
119f5173 | 161 | struct drm_crtc *crtc; |
c0d36de8 | 162 | struct clk *clk; |
3c87daef | 163 | void __iomem *regs; |
616443ca | 164 | struct cmdq_client_reg cmdq_reg; |
c5f228ef | 165 | const struct mtk_disp_ovl_data *data; |
9b070498 CH |
166 | void (*vblank_cb)(void *data); |
167 | void *vblank_cb_data; | |
119f5173 CH |
168 | }; |
169 | ||
170 | static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id) | |
171 | { | |
172 | struct mtk_disp_ovl *priv = dev_id; | |
119f5173 CH |
173 | |
174 | /* Clear frame completion interrupt */ | |
3c87daef | 175 | writel(0x0, priv->regs + DISP_REG_OVL_INTSTA); |
119f5173 | 176 | |
9b070498 | 177 | if (!priv->vblank_cb) |
119f5173 CH |
178 | return IRQ_NONE; |
179 | ||
9b070498 | 180 | priv->vblank_cb(priv->vblank_cb_data); |
119f5173 CH |
181 | |
182 | return IRQ_HANDLED; | |
183 | } | |
184 | ||
b74d921b RBC |
185 | void mtk_ovl_register_vblank_cb(struct device *dev, |
186 | void (*vblank_cb)(void *), | |
187 | void *vblank_cb_data) | |
119f5173 | 188 | { |
4d510659 | 189 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
119f5173 | 190 | |
9b070498 CH |
191 | ovl->vblank_cb = vblank_cb; |
192 | ovl->vblank_cb_data = vblank_cb_data; | |
b74d921b RBC |
193 | } |
194 | ||
195 | void mtk_ovl_unregister_vblank_cb(struct device *dev) | |
196 | { | |
197 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
198 | ||
199 | ovl->vblank_cb = NULL; | |
200 | ovl->vblank_cb_data = NULL; | |
201 | } | |
202 | ||
203 | void mtk_ovl_enable_vblank(struct device *dev) | |
204 | { | |
205 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
206 | ||
3c87daef CH |
207 | writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA); |
208 | writel_relaxed(OVL_FME_CPL_INT, ovl->regs + DISP_REG_OVL_INTEN); | |
119f5173 CH |
209 | } |
210 | ||
1d33f13a | 211 | void mtk_ovl_disable_vblank(struct device *dev) |
119f5173 | 212 | { |
4d510659 | 213 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
119f5173 | 214 | |
3c87daef | 215 | writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN); |
119f5173 CH |
216 | } |
217 | ||
e6411bf2 JJL |
218 | u32 mtk_ovl_get_blend_modes(struct device *dev) |
219 | { | |
220 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
221 | ||
222 | return ovl->data->blend_modes; | |
223 | } | |
224 | ||
f287c66a JG |
225 | const u32 *mtk_ovl_get_formats(struct device *dev) |
226 | { | |
227 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
228 | ||
229 | return ovl->data->formats; | |
230 | } | |
231 | ||
232 | size_t mtk_ovl_get_num_formats(struct device *dev) | |
233 | { | |
234 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
235 | ||
236 | return ovl->data->num_formats; | |
237 | } | |
238 | ||
1d33f13a | 239 | int mtk_ovl_clk_enable(struct device *dev) |
c0d36de8 CH |
240 | { |
241 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
242 | ||
243 | return clk_prepare_enable(ovl->clk); | |
244 | } | |
245 | ||
1d33f13a | 246 | void mtk_ovl_clk_disable(struct device *dev) |
c0d36de8 CH |
247 | { |
248 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
249 | ||
250 | clk_disable_unprepare(ovl->clk); | |
251 | } | |
252 | ||
1d33f13a | 253 | void mtk_ovl_start(struct device *dev) |
119f5173 | 254 | { |
4d510659 | 255 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
3c87daef | 256 | |
d41ff4dc YN |
257 | if (ovl->data->smi_id_en) { |
258 | unsigned int reg; | |
259 | ||
260 | reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON); | |
261 | reg = reg | OVL_LAYER_SMI_ID_EN; | |
262 | writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON); | |
263 | } | |
3c87daef | 264 | writel_relaxed(0x1, ovl->regs + DISP_REG_OVL_EN); |
119f5173 CH |
265 | } |
266 | ||
1d33f13a | 267 | void mtk_ovl_stop(struct device *dev) |
119f5173 | 268 | { |
4d510659 | 269 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
3c87daef CH |
270 | |
271 | writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_EN); | |
d41ff4dc YN |
272 | if (ovl->data->smi_id_en) { |
273 | unsigned int reg; | |
274 | ||
275 | reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON); | |
276 | reg = reg & ~OVL_LAYER_SMI_ID_EN; | |
277 | writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON); | |
278 | } | |
c410fa9b | 279 | } |
d41ff4dc | 280 | |
c410fa9b JG |
281 | static void mtk_ovl_set_afbc(struct mtk_disp_ovl *ovl, struct cmdq_pkt *cmdq_pkt, |
282 | int idx, bool enabled) | |
283 | { | |
284 | mtk_ddp_write_mask(cmdq_pkt, enabled ? OVL_LAYER_AFBC_EN(idx) : 0, | |
285 | &ovl->cmdq_reg, ovl->regs, | |
286 | DISP_REG_OVL_DATAPATH_CON, OVL_LAYER_AFBC_EN(idx)); | |
119f5173 CH |
287 | } |
288 | ||
fb36c502 JG |
289 | static void mtk_ovl_set_bit_depth(struct device *dev, int idx, u32 format, |
290 | struct cmdq_pkt *cmdq_pkt) | |
291 | { | |
292 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); | |
fb36c502 JG |
293 | unsigned int bit_depth = OVL_CON_CLRFMT_8_BIT; |
294 | ||
295 | if (!ovl->data->supports_clrfmt_ext) | |
296 | return; | |
297 | ||
46ed6ff6 | 298 | if (is_10bit_rgb(format)) |
fb36c502 JG |
299 | bit_depth = OVL_CON_CLRFMT_10_BIT; |
300 | ||
e7df7a20 JJL |
301 | mtk_ddp_write_mask(cmdq_pkt, OVL_CON_CLRFMT_BIT_DEPTH(bit_depth, idx), |
302 | &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_CLRFMT_EXT, | |
303 | OVL_CON_CLRFMT_BIT_DEPTH_MASK(idx)); | |
fb36c502 JG |
304 | } |
305 | ||
1d33f13a CH |
306 | void mtk_ovl_config(struct device *dev, unsigned int w, |
307 | unsigned int h, unsigned int vrefresh, | |
308 | unsigned int bpc, struct cmdq_pkt *cmdq_pkt) | |
119f5173 | 309 | { |
4d510659 | 310 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
3c87daef | 311 | |
119f5173 | 312 | if (w != 0 && h != 0) |
616443ca | 313 | mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 314 | DISP_REG_OVL_ROI_SIZE); |
31c0fbf6 HCS |
315 | |
316 | /* | |
317 | * The background color must be opaque black (ARGB), | |
318 | * otherwise the alpha blending will have no effect | |
319 | */ | |
320 | mtk_ddp_write_relaxed(cmdq_pkt, OVL_COLOR_ALPHA, &ovl->cmdq_reg, | |
321 | ovl->regs, DISP_REG_OVL_ROI_BGCLR); | |
119f5173 | 322 | |
616443ca CH |
323 | mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST); |
324 | mtk_ddp_write(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST); | |
119f5173 CH |
325 | } |
326 | ||
1d33f13a | 327 | unsigned int mtk_ovl_layer_nr(struct device *dev) |
1cbcb763 | 328 | { |
4d510659 | 329 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
0a5ccda4 YN |
330 | |
331 | return ovl->data->layer_nr; | |
1cbcb763 SH |
332 | } |
333 | ||
1d33f13a | 334 | unsigned int mtk_ovl_supported_rotations(struct device *dev) |
84d80575 | 335 | { |
df444457 SP |
336 | return DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 | |
337 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y; | |
84d80575 SP |
338 | } |
339 | ||
1d33f13a CH |
340 | int mtk_ovl_layer_check(struct device *dev, unsigned int idx, |
341 | struct mtk_plane_state *mtk_state) | |
84d80575 SP |
342 | { |
343 | struct drm_plane_state *state = &mtk_state->base; | |
84d80575 | 344 | |
74608d8f HCS |
345 | /* check if any unsupported rotation is set */ |
346 | if (state->rotation & ~mtk_ovl_supported_rotations(dev)) | |
84d80575 SP |
347 | return -EINVAL; |
348 | ||
349 | /* | |
350 | * TODO: Rotating/reflecting YUV buffers is not supported at this time. | |
351 | * Only RGB[AX] variants are supported. | |
74608d8f HCS |
352 | * Since DRM_MODE_ROTATE_0 means "no rotation", we should not |
353 | * reject layers with this property. | |
84d80575 | 354 | */ |
74608d8f | 355 | if (state->fb->format->is_yuv && (state->rotation & ~DRM_MODE_ROTATE_0)) |
84d80575 SP |
356 | return -EINVAL; |
357 | ||
84d80575 SP |
358 | return 0; |
359 | } | |
360 | ||
1d33f13a CH |
361 | void mtk_ovl_layer_on(struct device *dev, unsigned int idx, |
362 | struct cmdq_pkt *cmdq_pkt) | |
119f5173 | 363 | { |
d5abb5f2 YN |
364 | unsigned int gmc_thrshd_l; |
365 | unsigned int gmc_thrshd_h; | |
366 | unsigned int gmc_value; | |
4d510659 | 367 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
119f5173 | 368 | |
616443ca | 369 | mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 370 | DISP_REG_OVL_RDMA_CTRL(idx)); |
d5abb5f2 YN |
371 | gmc_thrshd_l = GMC_THRESHOLD_LOW >> |
372 | (GMC_THRESHOLD_BITS - ovl->data->gmc_bits); | |
373 | gmc_thrshd_h = GMC_THRESHOLD_HIGH >> | |
374 | (GMC_THRESHOLD_BITS - ovl->data->gmc_bits); | |
375 | if (ovl->data->gmc_bits == 10) | |
376 | gmc_value = gmc_thrshd_h | gmc_thrshd_h << 16; | |
377 | else | |
378 | gmc_value = gmc_thrshd_l | gmc_thrshd_l << 8 | | |
379 | gmc_thrshd_h << 16 | gmc_thrshd_h << 24; | |
d0afe37f | 380 | mtk_ddp_write(cmdq_pkt, gmc_value, |
616443ca CH |
381 | &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RDMA_GMC(idx)); |
382 | mtk_ddp_write_mask(cmdq_pkt, BIT(idx), &ovl->cmdq_reg, ovl->regs, | |
d0afe37f | 383 | DISP_REG_OVL_SRC_CON, BIT(idx)); |
119f5173 CH |
384 | } |
385 | ||
1d33f13a CH |
386 | void mtk_ovl_layer_off(struct device *dev, unsigned int idx, |
387 | struct cmdq_pkt *cmdq_pkt) | |
119f5173 | 388 | { |
4d510659 | 389 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
3c87daef | 390 | |
616443ca | 391 | mtk_ddp_write_mask(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 392 | DISP_REG_OVL_SRC_CON, BIT(idx)); |
616443ca | 393 | mtk_ddp_write(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 394 | DISP_REG_OVL_RDMA_CTRL(idx)); |
119f5173 CH |
395 | } |
396 | ||
333ab436 JJL |
397 | static unsigned int mtk_ovl_fmt_convert(struct mtk_disp_ovl *ovl, |
398 | struct mtk_plane_state *state) | |
119f5173 | 399 | { |
333ab436 JJL |
400 | unsigned int fmt = state->pending.format; |
401 | unsigned int blend_mode = DRM_MODE_BLEND_COVERAGE; | |
402 | ||
403 | /* | |
404 | * For the platforms where OVL_CON_CLRFMT_MAN is defined in the hardware data sheet | |
405 | * and supports premultiplied color formats, such as OVL_CON_CLRFMT_PARGB8888. | |
406 | * | |
407 | * Check blend_modes in the driver data to see if premultiplied mode is supported. | |
408 | * If not, use coverage mode instead to set it to the supported color formats. | |
409 | * | |
410 | * Current DRM assumption is that alpha is default premultiplied, so the bitmask of | |
411 | * blend_modes must include BIT(DRM_MODE_BLEND_PREMULTI). Otherwise, mtk_plane_init() | |
412 | * will get an error return from drm_plane_create_blend_mode_property() and | |
413 | * state->base.pixel_blend_mode should not be used. | |
414 | */ | |
415 | if (ovl->data->blend_modes & BIT(DRM_MODE_BLEND_PREMULTI)) | |
416 | blend_mode = state->base.pixel_blend_mode; | |
417 | ||
119f5173 CH |
418 | switch (fmt) { |
419 | default: | |
420 | case DRM_FORMAT_RGB565: | |
c5f228ef | 421 | return OVL_CON_CLRFMT_RGB565(ovl); |
119f5173 | 422 | case DRM_FORMAT_BGR565: |
c5f228ef | 423 | return OVL_CON_CLRFMT_RGB565(ovl) | OVL_CON_BYTE_SWAP; |
119f5173 | 424 | case DRM_FORMAT_RGB888: |
c5f228ef | 425 | return OVL_CON_CLRFMT_RGB888(ovl); |
119f5173 | 426 | case DRM_FORMAT_BGR888: |
c5f228ef | 427 | return OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP; |
119f5173 CH |
428 | case DRM_FORMAT_RGBX8888: |
429 | case DRM_FORMAT_RGBA8888: | |
46ed6ff6 HCS |
430 | case DRM_FORMAT_RGBX1010102: |
431 | case DRM_FORMAT_RGBA1010102: | |
a3f7f7ef HCS |
432 | return blend_mode == DRM_MODE_BLEND_COVERAGE ? |
433 | OVL_CON_CLRFMT_RGBA8888 : | |
434 | OVL_CON_CLRFMT_PRGBA8888; | |
119f5173 CH |
435 | case DRM_FORMAT_BGRX8888: |
436 | case DRM_FORMAT_BGRA8888: | |
46ed6ff6 | 437 | case DRM_FORMAT_BGRX1010102: |
fb36c502 | 438 | case DRM_FORMAT_BGRA1010102: |
a3f7f7ef HCS |
439 | return blend_mode == DRM_MODE_BLEND_COVERAGE ? |
440 | OVL_CON_CLRFMT_BGRA8888 : | |
441 | OVL_CON_CLRFMT_PBGRA8888; | |
119f5173 CH |
442 | case DRM_FORMAT_XRGB8888: |
443 | case DRM_FORMAT_ARGB8888: | |
46ed6ff6 | 444 | case DRM_FORMAT_XRGB2101010: |
fb36c502 | 445 | case DRM_FORMAT_ARGB2101010: |
a3f7f7ef HCS |
446 | return blend_mode == DRM_MODE_BLEND_COVERAGE ? |
447 | OVL_CON_CLRFMT_ARGB8888 : | |
448 | OVL_CON_CLRFMT_PARGB8888; | |
119f5173 CH |
449 | case DRM_FORMAT_XBGR8888: |
450 | case DRM_FORMAT_ABGR8888: | |
46ed6ff6 HCS |
451 | case DRM_FORMAT_XBGR2101010: |
452 | case DRM_FORMAT_ABGR2101010: | |
a3f7f7ef HCS |
453 | return blend_mode == DRM_MODE_BLEND_COVERAGE ? |
454 | OVL_CON_CLRFMT_ABGR8888 : | |
455 | OVL_CON_CLRFMT_PABGR8888; | |
170748db BH |
456 | case DRM_FORMAT_UYVY: |
457 | return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB; | |
458 | case DRM_FORMAT_YUYV: | |
459 | return OVL_CON_CLRFMT_YUYV | OVL_CON_MTX_YUV_TO_RGB; | |
119f5173 CH |
460 | } |
461 | } | |
462 | ||
f8d9b917 DG |
463 | static void mtk_ovl_afbc_layer_config(struct mtk_disp_ovl *ovl, |
464 | unsigned int idx, | |
465 | struct mtk_plane_pending_state *pending, | |
466 | struct cmdq_pkt *cmdq_pkt) | |
467 | { | |
468 | unsigned int pitch_msb = pending->pitch >> 16; | |
469 | unsigned int hdr_pitch = pending->hdr_pitch; | |
470 | unsigned int hdr_addr = pending->hdr_addr; | |
471 | ||
472 | if (pending->modifier != DRM_FORMAT_MOD_LINEAR) { | |
473 | mtk_ddp_write_relaxed(cmdq_pkt, hdr_addr, &ovl->cmdq_reg, ovl->regs, | |
474 | DISP_REG_OVL_HDR_ADDR(ovl, idx)); | |
475 | mtk_ddp_write_relaxed(cmdq_pkt, | |
476 | OVL_PITCH_MSB_2ND_SUBBUF | pitch_msb, | |
477 | &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH_MSB(idx)); | |
478 | mtk_ddp_write_relaxed(cmdq_pkt, hdr_pitch, &ovl->cmdq_reg, ovl->regs, | |
479 | DISP_REG_OVL_HDR_PITCH(ovl, idx)); | |
480 | } else { | |
481 | mtk_ddp_write_relaxed(cmdq_pkt, pitch_msb, | |
482 | &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH_MSB(idx)); | |
483 | } | |
484 | } | |
485 | ||
1d33f13a CH |
486 | void mtk_ovl_layer_config(struct device *dev, unsigned int idx, |
487 | struct mtk_plane_state *state, | |
488 | struct cmdq_pkt *cmdq_pkt) | |
119f5173 | 489 | { |
4d510659 | 490 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
119f5173 CH |
491 | struct mtk_plane_pending_state *pending = &state->pending; |
492 | unsigned int addr = pending->addr; | |
f8d9b917 | 493 | unsigned int pitch_lsb = pending->pitch & GENMASK(15, 0); |
119f5173 | 494 | unsigned int fmt = pending->format; |
5c9d7e79 | 495 | unsigned int rotation = pending->rotation; |
119f5173 CH |
496 | unsigned int offset = (pending->y << 16) | pending->x; |
497 | unsigned int src_size = (pending->height << 16) | pending->width; | |
1f66fe62 | 498 | unsigned int blend_mode = state->base.pixel_blend_mode; |
765f284f | 499 | unsigned int ignore_pixel_alpha = 0; |
119f5173 CH |
500 | unsigned int con; |
501 | ||
039cf36c | 502 | if (!pending->enable) { |
4d510659 | 503 | mtk_ovl_layer_off(dev, idx, cmdq_pkt); |
039cf36c MY |
504 | return; |
505 | } | |
119f5173 | 506 | |
333ab436 | 507 | con = mtk_ovl_fmt_convert(ovl, state); |
bc46eb5d | 508 | if (state->base.fb) { |
bc46eb5d | 509 | con |= state->base.alpha & OVL_CON_ALPHA; |
995d4d55 JJL |
510 | |
511 | /* | |
512 | * For blend_modes supported SoCs, always enable alpha blending. | |
513 | * For blend_modes unsupported SoCs, enable alpha blending when has_alpha is set. | |
514 | */ | |
515 | if (blend_mode || state->base.fb->format->has_alpha) | |
516 | con |= OVL_CON_AEN; | |
119f5173 | 517 | |
28fbc329 JJL |
518 | /* |
519 | * Although the alpha channel can be ignored, CONST_BLD must be enabled | |
520 | * for XRGB format, otherwise OVL will still read the value from memory. | |
521 | * For RGB888 related formats, whether CONST_BLD is enabled or not won't | |
522 | * affect the result. Therefore we use !has_alpha as the condition. | |
523 | */ | |
524 | if (blend_mode == DRM_MODE_BLEND_PIXEL_NONE || !state->base.fb->format->has_alpha) | |
525 | ignore_pixel_alpha = OVL_CONST_BLEND; | |
526 | } | |
765f284f | 527 | |
5c9d7e79 JJL |
528 | /* |
529 | * Treat rotate 180 as flip x + flip y, and XOR the original rotation value | |
530 | * to flip x + flip y to support both in the same time. | |
531 | */ | |
532 | if (rotation & DRM_MODE_ROTATE_180) | |
533 | rotation ^= DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y; | |
534 | ||
535 | if (rotation & DRM_MODE_REFLECT_Y) { | |
84d80575 SP |
536 | con |= OVL_CON_VIRT_FLIP; |
537 | addr += (pending->height - 1) * pending->pitch; | |
538 | } | |
539 | ||
5c9d7e79 | 540 | if (rotation & DRM_MODE_REFLECT_X) { |
b368d3ec SP |
541 | con |= OVL_CON_HORZ_FLIP; |
542 | addr += pending->pitch - 1; | |
543 | } | |
544 | ||
c410fa9b | 545 | if (ovl->data->supports_afbc) |
f8d9b917 DG |
546 | mtk_ovl_set_afbc(ovl, cmdq_pkt, idx, |
547 | pending->modifier != DRM_FORMAT_MOD_LINEAR); | |
c410fa9b | 548 | |
616443ca | 549 | mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 550 | DISP_REG_OVL_CON(idx)); |
f8d9b917 | 551 | mtk_ddp_write_relaxed(cmdq_pkt, pitch_lsb | ignore_pixel_alpha, |
765f284f | 552 | &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH(idx)); |
616443ca | 553 | mtk_ddp_write_relaxed(cmdq_pkt, src_size, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 554 | DISP_REG_OVL_SRC_SIZE(idx)); |
616443ca | 555 | mtk_ddp_write_relaxed(cmdq_pkt, offset, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 556 | DISP_REG_OVL_OFFSET(idx)); |
616443ca | 557 | mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs, |
d0afe37f | 558 | DISP_REG_OVL_ADDR(ovl, idx)); |
119f5173 | 559 | |
f8d9b917 DG |
560 | if (ovl->data->supports_afbc) |
561 | mtk_ovl_afbc_layer_config(ovl, idx, pending, cmdq_pkt); | |
c410fa9b | 562 | |
fb36c502 | 563 | mtk_ovl_set_bit_depth(dev, idx, fmt, cmdq_pkt); |
4d510659 | 564 | mtk_ovl_layer_on(dev, idx, cmdq_pkt); |
119f5173 CH |
565 | } |
566 | ||
1d33f13a | 567 | void mtk_ovl_bgclr_in_on(struct device *dev) |
318462d1 | 568 | { |
4d510659 | 569 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
318462d1 YN |
570 | unsigned int reg; |
571 | ||
3c87daef | 572 | reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON); |
318462d1 | 573 | reg = reg | OVL_BGCLR_SEL_IN; |
3c87daef | 574 | writel(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON); |
318462d1 YN |
575 | } |
576 | ||
1d33f13a | 577 | void mtk_ovl_bgclr_in_off(struct device *dev) |
318462d1 | 578 | { |
4d510659 | 579 | struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); |
318462d1 YN |
580 | unsigned int reg; |
581 | ||
3c87daef | 582 | reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON); |
318462d1 | 583 | reg = reg & ~OVL_BGCLR_SEL_IN; |
3c87daef | 584 | writel(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON); |
318462d1 YN |
585 | } |
586 | ||
119f5173 CH |
587 | static int mtk_disp_ovl_bind(struct device *dev, struct device *master, |
588 | void *data) | |
589 | { | |
119f5173 CH |
590 | return 0; |
591 | } | |
592 | ||
593 | static void mtk_disp_ovl_unbind(struct device *dev, struct device *master, | |
594 | void *data) | |
595 | { | |
119f5173 CH |
596 | } |
597 | ||
598 | static const struct component_ops mtk_disp_ovl_component_ops = { | |
599 | .bind = mtk_disp_ovl_bind, | |
600 | .unbind = mtk_disp_ovl_unbind, | |
601 | }; | |
602 | ||
603 | static int mtk_disp_ovl_probe(struct platform_device *pdev) | |
604 | { | |
605 | struct device *dev = &pdev->dev; | |
606 | struct mtk_disp_ovl *priv; | |
119f5173 CH |
607 | int irq; |
608 | int ret; | |
609 | ||
610 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
611 | if (!priv) | |
612 | return -ENOMEM; | |
613 | ||
614 | irq = platform_get_irq(pdev, 0); | |
615 | if (irq < 0) | |
616 | return irq; | |
617 | ||
c0d36de8 | 618 | priv->clk = devm_clk_get(dev, NULL); |
45b70f71 NP |
619 | if (IS_ERR(priv->clk)) |
620 | return dev_err_probe(dev, PTR_ERR(priv->clk), | |
621 | "failed to get ovl clk\n"); | |
c0d36de8 | 622 | |
555313ff | 623 | priv->regs = devm_platform_ioremap_resource(pdev, 0); |
45b70f71 NP |
624 | if (IS_ERR(priv->regs)) |
625 | return dev_err_probe(dev, PTR_ERR(priv->regs), | |
626 | "failed to ioremap ovl\n"); | |
616443ca CH |
627 | #if IS_REACHABLE(CONFIG_MTK_CMDQ) |
628 | ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0); | |
629 | if (ret) | |
630 | dev_dbg(dev, "get mediatek,gce-client-reg fail!\n"); | |
631 | #endif | |
3c87daef | 632 | |
57148baa | 633 | priv->data = of_device_get_match_data(dev); |
119f5173 CH |
634 | platform_set_drvdata(pdev, priv); |
635 | ||
5ad45307 MB |
636 | ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler, |
637 | IRQF_TRIGGER_NONE, dev_name(dev), priv); | |
45b70f71 NP |
638 | if (ret < 0) |
639 | return dev_err_probe(dev, ret, "Failed to request irq %d\n", irq); | |
5ad45307 | 640 | |
5db12f5d YN |
641 | pm_runtime_enable(dev); |
642 | ||
119f5173 | 643 | ret = component_add(dev, &mtk_disp_ovl_component_ops); |
5db12f5d YN |
644 | if (ret) { |
645 | pm_runtime_disable(dev); | |
45b70f71 | 646 | return dev_err_probe(dev, ret, "Failed to add component\n"); |
5db12f5d | 647 | } |
119f5173 | 648 | |
45b70f71 | 649 | return 0; |
119f5173 CH |
650 | } |
651 | ||
b3af12a0 | 652 | static void mtk_disp_ovl_remove(struct platform_device *pdev) |
119f5173 | 653 | { |
da4d4517 | 654 | component_del(&pdev->dev, &mtk_disp_ovl_component_ops); |
5db12f5d | 655 | pm_runtime_disable(&pdev->dev); |
119f5173 CH |
656 | } |
657 | ||
84a5ead1 | 658 | static const struct mtk_disp_ovl_data mt2701_ovl_driver_data = { |
659 | .addr = DISP_REG_OVL_ADDR_MT2701, | |
d5abb5f2 | 660 | .gmc_bits = 8, |
0a5ccda4 | 661 | .layer_nr = 4, |
84a5ead1 | 662 | .fmt_rgb565_is_0 = false, |
f287c66a JG |
663 | .formats = mt8173_formats, |
664 | .num_formats = ARRAY_SIZE(mt8173_formats), | |
84a5ead1 | 665 | }; |
666 | ||
c5f228ef | 667 | static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = { |
668 | .addr = DISP_REG_OVL_ADDR_MT8173, | |
d5abb5f2 | 669 | .gmc_bits = 8, |
0a5ccda4 | 670 | .layer_nr = 4, |
c5f228ef | 671 | .fmt_rgb565_is_0 = true, |
f287c66a JG |
672 | .formats = mt8173_formats, |
673 | .num_formats = ARRAY_SIZE(mt8173_formats), | |
c5f228ef | 674 | }; |
675 | ||
641ef9e7 YN |
676 | static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = { |
677 | .addr = DISP_REG_OVL_ADDR_MT8173, | |
678 | .gmc_bits = 10, | |
679 | .layer_nr = 4, | |
680 | .fmt_rgb565_is_0 = true, | |
f287c66a JG |
681 | .formats = mt8173_formats, |
682 | .num_formats = ARRAY_SIZE(mt8173_formats), | |
641ef9e7 YN |
683 | }; |
684 | ||
685 | static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = { | |
686 | .addr = DISP_REG_OVL_ADDR_MT8173, | |
687 | .gmc_bits = 10, | |
688 | .layer_nr = 2, | |
689 | .fmt_rgb565_is_0 = true, | |
f287c66a JG |
690 | .formats = mt8173_formats, |
691 | .num_formats = ARRAY_SIZE(mt8173_formats), | |
641ef9e7 YN |
692 | }; |
693 | ||
01365f54 YN |
694 | static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = { |
695 | .addr = DISP_REG_OVL_ADDR_MT8173, | |
696 | .gmc_bits = 10, | |
697 | .layer_nr = 4, | |
698 | .fmt_rgb565_is_0 = true, | |
699 | .smi_id_en = true, | |
333ab436 JJL |
700 | .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) | |
701 | BIT(DRM_MODE_BLEND_COVERAGE) | | |
702 | BIT(DRM_MODE_BLEND_PIXEL_NONE), | |
f287c66a JG |
703 | .formats = mt8173_formats, |
704 | .num_formats = ARRAY_SIZE(mt8173_formats), | |
01365f54 YN |
705 | }; |
706 | ||
707 | static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = { | |
708 | .addr = DISP_REG_OVL_ADDR_MT8173, | |
709 | .gmc_bits = 10, | |
710 | .layer_nr = 2, | |
711 | .fmt_rgb565_is_0 = true, | |
712 | .smi_id_en = true, | |
333ab436 JJL |
713 | .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) | |
714 | BIT(DRM_MODE_BLEND_COVERAGE) | | |
715 | BIT(DRM_MODE_BLEND_PIXEL_NONE), | |
f287c66a JG |
716 | .formats = mt8173_formats, |
717 | .num_formats = ARRAY_SIZE(mt8173_formats), | |
01365f54 YN |
718 | }; |
719 | ||
76cdcb87 JG |
720 | static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = { |
721 | .addr = DISP_REG_OVL_ADDR_MT8173, | |
722 | .gmc_bits = 10, | |
723 | .layer_nr = 4, | |
724 | .fmt_rgb565_is_0 = true, | |
725 | .smi_id_en = true, | |
726 | .supports_afbc = true, | |
333ab436 JJL |
727 | .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) | |
728 | BIT(DRM_MODE_BLEND_COVERAGE) | | |
729 | BIT(DRM_MODE_BLEND_PIXEL_NONE), | |
ed715684 JG |
730 | .formats = mt8195_formats, |
731 | .num_formats = ARRAY_SIZE(mt8195_formats), | |
732 | .supports_clrfmt_ext = true, | |
76cdcb87 JG |
733 | }; |
734 | ||
119f5173 | 735 | static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = { |
84a5ead1 | 736 | { .compatible = "mediatek,mt2701-disp-ovl", |
737 | .data = &mt2701_ovl_driver_data}, | |
c5f228ef | 738 | { .compatible = "mediatek,mt8173-disp-ovl", |
739 | .data = &mt8173_ovl_driver_data}, | |
641ef9e7 YN |
740 | { .compatible = "mediatek,mt8183-disp-ovl", |
741 | .data = &mt8183_ovl_driver_data}, | |
742 | { .compatible = "mediatek,mt8183-disp-ovl-2l", | |
743 | .data = &mt8183_ovl_2l_driver_data}, | |
01365f54 YN |
744 | { .compatible = "mediatek,mt8192-disp-ovl", |
745 | .data = &mt8192_ovl_driver_data}, | |
746 | { .compatible = "mediatek,mt8192-disp-ovl-2l", | |
747 | .data = &mt8192_ovl_2l_driver_data}, | |
76cdcb87 JG |
748 | { .compatible = "mediatek,mt8195-disp-ovl", |
749 | .data = &mt8195_ovl_driver_data}, | |
119f5173 CH |
750 | {}, |
751 | }; | |
752 | MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match); | |
753 | ||
754 | struct platform_driver mtk_disp_ovl_driver = { | |
755 | .probe = mtk_disp_ovl_probe, | |
e70140ba | 756 | .remove = mtk_disp_ovl_remove, |
119f5173 CH |
757 | .driver = { |
758 | .name = "mediatek-disp-ovl", | |
119f5173 CH |
759 | .of_match_table = mtk_disp_ovl_driver_dt_match, |
760 | }, | |
761 | }; |