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