11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2119f5173SCK Hu /*
3119f5173SCK Hu * Copyright (c) 2015 MediaTek Inc.
4119f5173SCK Hu */
5119f5173SCK Hu
69aef5867SSam Ravnborg #include <linux/clk.h>
71ee07a68SChun-Kuang Hu #include <linux/dma-mapping.h>
81ee07a68SChun-Kuang Hu #include <linux/mailbox_controller.h>
9722d4f06SRob Herring #include <linux/of.h>
109aef5867SSam Ravnborg #include <linux/pm_runtime.h>
112f965be7SBibby Hsieh #include <linux/soc/mediatek/mtk-cmdq.h>
122c758e30SEnric Balletbo i Serra #include <linux/soc/mediatek/mtk-mmsys.h>
13e1e4f7feSCK Hu #include <linux/soc/mediatek/mtk-mutex.h>
149aef5867SSam Ravnborg
15119f5173SCK Hu #include <asm/barrier.h>
169aef5867SSam Ravnborg
17253f28b6SMaxime Ripard #include <drm/drm_atomic.h>
18119f5173SCK Hu #include <drm/drm_atomic_helper.h>
19fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h>
209aef5867SSam Ravnborg #include <drm/drm_vblank.h>
21119f5173SCK Hu
22119f5173SCK Hu #include "mtk_drm_drv.h"
23119f5173SCK Hu #include "mtk_drm_crtc.h"
24119f5173SCK Hu #include "mtk_drm_ddp_comp.h"
25119f5173SCK Hu #include "mtk_drm_gem.h"
26119f5173SCK Hu #include "mtk_drm_plane.h"
27119f5173SCK Hu
28eaa4d562SLee Jones /*
29119f5173SCK Hu * struct mtk_drm_crtc - MediaTek specific crtc structure.
30119f5173SCK Hu * @base: crtc object.
31119f5173SCK Hu * @enabled: records whether crtc_enable succeeded
325bfafad8SDaniel Kurtz * @planes: array of 4 drm_plane structures, one for each overlay plane
33119f5173SCK Hu * @pending_planes: whether any plane has pending changes to be applied
342c758e30SEnric Balletbo i Serra * @mmsys_dev: pointer to the mmsys device for configuration registers
35119f5173SCK Hu * @mutex: handle to one of the ten disp_mutex streams
36119f5173SCK Hu * @ddp_comp_nr: number of components in ddp_comp
37119f5173SCK Hu * @ddp_comp: array of pointers the mtk_ddp_comp structures used by this crtc
38eaa4d562SLee Jones *
39eaa4d562SLee Jones * TODO: Needs update: this header is missing a bunch of member descriptions.
40119f5173SCK Hu */
41119f5173SCK Hu struct mtk_drm_crtc {
42119f5173SCK Hu struct drm_crtc base;
43119f5173SCK Hu bool enabled;
44119f5173SCK Hu
45119f5173SCK Hu bool pending_needs_vblank;
46119f5173SCK Hu struct drm_pending_vblank_event *event;
47119f5173SCK Hu
4866b2cf96SStu Hsieh struct drm_plane *planes;
4966b2cf96SStu Hsieh unsigned int layer_nr;
50119f5173SCK Hu bool pending_planes;
51920fffccSBibby Hsieh bool pending_async_planes;
52119f5173SCK Hu
532f965be7SBibby Hsieh #if IS_REACHABLE(CONFIG_MTK_CMDQ)
54563c9d4aSChun-Kuang Hu struct cmdq_client cmdq_client;
557627122fSChun-Kuang Hu struct cmdq_pkt cmdq_handle;
562f965be7SBibby Hsieh u32 cmdq_event;
57eaf80126SChun-Kuang Hu u32 cmdq_vblank_cnt;
58aa2d5f2fSjason-jh.lin wait_queue_head_t cb_blocking_queue;
592f965be7SBibby Hsieh #endif
602f965be7SBibby Hsieh
612c758e30SEnric Balletbo i Serra struct device *mmsys_dev;
62cb1d6bccSNancy.Lin struct device *dma_dev;
634971593fSCK Hu struct mtk_mutex *mutex;
64119f5173SCK Hu unsigned int ddp_comp_nr;
65119f5173SCK Hu struct mtk_ddp_comp **ddp_comp;
66920fffccSBibby Hsieh
67920fffccSBibby Hsieh /* lock for display hardware access */
68920fffccSBibby Hsieh struct mutex hw_lock;
69368166ecSChun-Kuang Hu bool config_updating;
705b9b8cd2SJason-JH.Lin /* lock for config_updating to cmd buffer */
715b9b8cd2SJason-JH.Lin spinlock_t config_lock;
72119f5173SCK Hu };
73119f5173SCK Hu
74119f5173SCK Hu struct mtk_crtc_state {
75119f5173SCK Hu struct drm_crtc_state base;
76119f5173SCK Hu
77119f5173SCK Hu bool pending_config;
78119f5173SCK Hu unsigned int pending_width;
79119f5173SCK Hu unsigned int pending_height;
80119f5173SCK Hu unsigned int pending_vrefresh;
81119f5173SCK Hu };
82119f5173SCK Hu
to_mtk_crtc(struct drm_crtc * c)83119f5173SCK Hu static inline struct mtk_drm_crtc *to_mtk_crtc(struct drm_crtc *c)
84119f5173SCK Hu {
85119f5173SCK Hu return container_of(c, struct mtk_drm_crtc, base);
86119f5173SCK Hu }
87119f5173SCK Hu
to_mtk_crtc_state(struct drm_crtc_state * s)88119f5173SCK Hu static inline struct mtk_crtc_state *to_mtk_crtc_state(struct drm_crtc_state *s)
89119f5173SCK Hu {
90119f5173SCK Hu return container_of(s, struct mtk_crtc_state, base);
91119f5173SCK Hu }
92119f5173SCK Hu
mtk_drm_crtc_finish_page_flip(struct mtk_drm_crtc * mtk_crtc)93119f5173SCK Hu static void mtk_drm_crtc_finish_page_flip(struct mtk_drm_crtc *mtk_crtc)
94119f5173SCK Hu {
95119f5173SCK Hu struct drm_crtc *crtc = &mtk_crtc->base;
96119f5173SCK Hu unsigned long flags;
97119f5173SCK Hu
98a3dd12b6SHsin-Yi Wang if (mtk_crtc->event) {
99119f5173SCK Hu spin_lock_irqsave(&crtc->dev->event_lock, flags);
100119f5173SCK Hu drm_crtc_send_vblank_event(crtc, mtk_crtc->event);
101119f5173SCK Hu drm_crtc_vblank_put(crtc);
102119f5173SCK Hu mtk_crtc->event = NULL;
103119f5173SCK Hu spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
104119f5173SCK Hu }
105a3dd12b6SHsin-Yi Wang }
106119f5173SCK Hu
mtk_drm_finish_page_flip(struct mtk_drm_crtc * mtk_crtc)107119f5173SCK Hu static void mtk_drm_finish_page_flip(struct mtk_drm_crtc *mtk_crtc)
108119f5173SCK Hu {
1095b9b8cd2SJason-JH.Lin unsigned long flags;
1105b9b8cd2SJason-JH.Lin
111119f5173SCK Hu drm_crtc_handle_vblank(&mtk_crtc->base);
1125b9b8cd2SJason-JH.Lin
1135b9b8cd2SJason-JH.Lin spin_lock_irqsave(&mtk_crtc->config_lock, flags);
114368166ecSChun-Kuang Hu if (!mtk_crtc->config_updating && mtk_crtc->pending_needs_vblank) {
115119f5173SCK Hu mtk_drm_crtc_finish_page_flip(mtk_crtc);
116119f5173SCK Hu mtk_crtc->pending_needs_vblank = false;
117119f5173SCK Hu }
1185b9b8cd2SJason-JH.Lin spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
119119f5173SCK Hu }
120119f5173SCK Hu
1217627122fSChun-Kuang Hu #if IS_REACHABLE(CONFIG_MTK_CMDQ)
mtk_drm_cmdq_pkt_create(struct cmdq_client * client,struct cmdq_pkt * pkt,size_t size)1227627122fSChun-Kuang Hu static int mtk_drm_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,
1237627122fSChun-Kuang Hu size_t size)
1247627122fSChun-Kuang Hu {
1257627122fSChun-Kuang Hu struct device *dev;
1267627122fSChun-Kuang Hu dma_addr_t dma_addr;
1277627122fSChun-Kuang Hu
1287627122fSChun-Kuang Hu pkt->va_base = kzalloc(size, GFP_KERNEL);
12927b9e2eaSJason-JH.Lin if (!pkt->va_base)
1307627122fSChun-Kuang Hu return -ENOMEM;
13127b9e2eaSJason-JH.Lin
1327627122fSChun-Kuang Hu pkt->buf_size = size;
1337627122fSChun-Kuang Hu pkt->cl = (void *)client;
1347627122fSChun-Kuang Hu
1357627122fSChun-Kuang Hu dev = client->chan->mbox->dev;
1367627122fSChun-Kuang Hu dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
1377627122fSChun-Kuang Hu DMA_TO_DEVICE);
1387627122fSChun-Kuang Hu if (dma_mapping_error(dev, dma_addr)) {
1397627122fSChun-Kuang Hu dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
1407627122fSChun-Kuang Hu kfree(pkt->va_base);
1417627122fSChun-Kuang Hu return -ENOMEM;
1427627122fSChun-Kuang Hu }
1437627122fSChun-Kuang Hu
1447627122fSChun-Kuang Hu pkt->pa_base = dma_addr;
1457627122fSChun-Kuang Hu
1467627122fSChun-Kuang Hu return 0;
1477627122fSChun-Kuang Hu }
1487627122fSChun-Kuang Hu
mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt * pkt)1497627122fSChun-Kuang Hu static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
1507627122fSChun-Kuang Hu {
1517627122fSChun-Kuang Hu struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
1527627122fSChun-Kuang Hu
1537627122fSChun-Kuang Hu dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
1547627122fSChun-Kuang Hu DMA_TO_DEVICE);
1557627122fSChun-Kuang Hu kfree(pkt->va_base);
1567627122fSChun-Kuang Hu }
1577627122fSChun-Kuang Hu #endif
1587627122fSChun-Kuang Hu
mtk_drm_crtc_destroy(struct drm_crtc * crtc)159119f5173SCK Hu static void mtk_drm_crtc_destroy(struct drm_crtc *crtc)
160119f5173SCK Hu {
161119f5173SCK Hu struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
162b74d921bSRex-BC Chen int i;
163119f5173SCK Hu
1644971593fSCK Hu mtk_mutex_put(mtk_crtc->mutex);
1657627122fSChun-Kuang Hu #if IS_REACHABLE(CONFIG_MTK_CMDQ)
1667627122fSChun-Kuang Hu mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle);
167593b655fSjason-jh.lin
168593b655fSjason-jh.lin if (mtk_crtc->cmdq_client.chan) {
169593b655fSjason-jh.lin mbox_free_channel(mtk_crtc->cmdq_client.chan);
170593b655fSjason-jh.lin mtk_crtc->cmdq_client.chan = NULL;
171593b655fSjason-jh.lin }
1727627122fSChun-Kuang Hu #endif
173b74d921bSRex-BC Chen
174b74d921bSRex-BC Chen for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
175b74d921bSRex-BC Chen struct mtk_ddp_comp *comp;
176b74d921bSRex-BC Chen
177b74d921bSRex-BC Chen comp = mtk_crtc->ddp_comp[i];
178b74d921bSRex-BC Chen mtk_ddp_comp_unregister_vblank_cb(comp);
179b74d921bSRex-BC Chen }
180b74d921bSRex-BC Chen
181119f5173SCK Hu drm_crtc_cleanup(crtc);
182119f5173SCK Hu }
183119f5173SCK Hu
mtk_drm_crtc_reset(struct drm_crtc * crtc)184119f5173SCK Hu static void mtk_drm_crtc_reset(struct drm_crtc *crtc)
185119f5173SCK Hu {
186119f5173SCK Hu struct mtk_crtc_state *state;
187119f5173SCK Hu
1882d267b81SDaniel Vetter if (crtc->state)
189903daff6SBibby Hsieh __drm_atomic_helper_crtc_destroy_state(crtc->state);
190119f5173SCK Hu
1912d267b81SDaniel Vetter kfree(to_mtk_crtc_state(crtc->state));
1922d267b81SDaniel Vetter crtc->state = NULL;
193119f5173SCK Hu
1942d267b81SDaniel Vetter state = kzalloc(sizeof(*state), GFP_KERNEL);
1952d267b81SDaniel Vetter if (state)
1962d267b81SDaniel Vetter __drm_atomic_helper_crtc_reset(crtc, &state->base);
197119f5173SCK Hu }
198119f5173SCK Hu
mtk_drm_crtc_duplicate_state(struct drm_crtc * crtc)199119f5173SCK Hu static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc)
200119f5173SCK Hu {
201119f5173SCK Hu struct mtk_crtc_state *state;
202119f5173SCK Hu
20307fb1e5bSAngeloGioacchino Del Regno state = kmalloc(sizeof(*state), GFP_KERNEL);
204119f5173SCK Hu if (!state)
205119f5173SCK Hu return NULL;
206119f5173SCK Hu
207119f5173SCK Hu __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
208119f5173SCK Hu
209119f5173SCK Hu WARN_ON(state->base.crtc != crtc);
210119f5173SCK Hu state->base.crtc = crtc;
21107fb1e5bSAngeloGioacchino Del Regno state->pending_config = false;
212119f5173SCK Hu
213119f5173SCK Hu return &state->base;
214119f5173SCK Hu }
215119f5173SCK Hu
mtk_drm_crtc_destroy_state(struct drm_crtc * crtc,struct drm_crtc_state * state)216119f5173SCK Hu static void mtk_drm_crtc_destroy_state(struct drm_crtc *crtc,
217119f5173SCK Hu struct drm_crtc_state *state)
218119f5173SCK Hu {
219ec2dc6a0SDaniel Vetter __drm_atomic_helper_crtc_destroy_state(state);
220119f5173SCK Hu kfree(to_mtk_crtc_state(state));
221119f5173SCK Hu }
222119f5173SCK Hu
mtk_drm_crtc_mode_fixup(struct drm_crtc * crtc,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)223119f5173SCK Hu static bool mtk_drm_crtc_mode_fixup(struct drm_crtc *crtc,
224119f5173SCK Hu const struct drm_display_mode *mode,
225119f5173SCK Hu struct drm_display_mode *adjusted_mode)
226119f5173SCK Hu {
227119f5173SCK Hu /* Nothing to do here, but this callback is mandatory. */
228119f5173SCK Hu return true;
229119f5173SCK Hu }
230119f5173SCK Hu
mtk_drm_crtc_mode_set_nofb(struct drm_crtc * crtc)231119f5173SCK Hu static void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
232119f5173SCK Hu {
233119f5173SCK Hu struct mtk_crtc_state *state = to_mtk_crtc_state(crtc->state);
234119f5173SCK Hu
235119f5173SCK Hu state->pending_width = crtc->mode.hdisplay;
236119f5173SCK Hu state->pending_height = crtc->mode.vdisplay;
2370425662fSVille Syrjälä state->pending_vrefresh = drm_mode_vrefresh(&crtc->mode);
238119f5173SCK Hu wmb(); /* Make sure the above parameters are set before update */
239119f5173SCK Hu state->pending_config = true;
240119f5173SCK Hu }
241119f5173SCK Hu
mtk_crtc_ddp_clk_enable(struct mtk_drm_crtc * mtk_crtc)242119f5173SCK Hu static int mtk_crtc_ddp_clk_enable(struct mtk_drm_crtc *mtk_crtc)
243119f5173SCK Hu {
244119f5173SCK Hu int ret;
245119f5173SCK Hu int i;
246119f5173SCK Hu
247119f5173SCK Hu for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
248c0d36de8SCK Hu ret = mtk_ddp_comp_clk_enable(mtk_crtc->ddp_comp[i]);
249119f5173SCK Hu if (ret) {
250119f5173SCK Hu DRM_ERROR("Failed to enable clock %d: %d\n", i, ret);
251119f5173SCK Hu goto err;
252119f5173SCK Hu }
253119f5173SCK Hu }
254119f5173SCK Hu
255119f5173SCK Hu return 0;
256119f5173SCK Hu err:
257119f5173SCK Hu while (--i >= 0)
258c0d36de8SCK Hu mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]);
259119f5173SCK Hu return ret;
260119f5173SCK Hu }
261119f5173SCK Hu
mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc * mtk_crtc)262119f5173SCK Hu static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc)
263119f5173SCK Hu {
264119f5173SCK Hu int i;
265119f5173SCK Hu
266119f5173SCK Hu for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
267c0d36de8SCK Hu mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]);
268119f5173SCK Hu }
269119f5173SCK Hu
270d6b53f68SSean Paul static
mtk_drm_ddp_comp_for_plane(struct drm_crtc * crtc,struct drm_plane * plane,unsigned int * local_layer)271d6b53f68SSean Paul struct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct drm_crtc *crtc,
272d6b53f68SSean Paul struct drm_plane *plane,
273d6b53f68SSean Paul unsigned int *local_layer)
274d6b53f68SSean Paul {
275d6b53f68SSean Paul struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
276d6b53f68SSean Paul struct mtk_ddp_comp *comp;
277d6b53f68SSean Paul int i, count = 0;
278138b80cbSYongqiang Niu unsigned int local_index = plane - mtk_crtc->planes;
279d6b53f68SSean Paul
280d6b53f68SSean Paul for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
281d6b53f68SSean Paul comp = mtk_crtc->ddp_comp[i];
282138b80cbSYongqiang Niu if (local_index < (count + mtk_ddp_comp_layer_nr(comp))) {
283138b80cbSYongqiang Niu *local_layer = local_index - count;
284d6b53f68SSean Paul return comp;
285d6b53f68SSean Paul }
286d6b53f68SSean Paul count += mtk_ddp_comp_layer_nr(comp);
287d6b53f68SSean Paul }
288d6b53f68SSean Paul
289d6b53f68SSean Paul WARN(1, "Failed to find component for plane %d\n", plane->index);
290d6b53f68SSean Paul return NULL;
291d6b53f68SSean Paul }
292d6b53f68SSean Paul
2932f965be7SBibby Hsieh #if IS_REACHABLE(CONFIG_MTK_CMDQ)
ddp_cmdq_cb(struct mbox_client * cl,void * mssg)2941ee07a68SChun-Kuang Hu static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
2952f965be7SBibby Hsieh {
2967f82d9c4SYongqiang Niu struct cmdq_cb_data *data = mssg;
297eaf80126SChun-Kuang Hu struct cmdq_client *cmdq_cl = container_of(cl, struct cmdq_client, client);
298eaf80126SChun-Kuang Hu struct mtk_drm_crtc *mtk_crtc = container_of(cmdq_cl, struct mtk_drm_crtc, cmdq_client);
2997f82d9c4SYongqiang Niu struct mtk_crtc_state *state;
3007f82d9c4SYongqiang Niu unsigned int i;
3015b9b8cd2SJason-JH.Lin unsigned long flags;
3027f82d9c4SYongqiang Niu
3037f82d9c4SYongqiang Niu if (data->sta < 0)
3047f82d9c4SYongqiang Niu return;
3057f82d9c4SYongqiang Niu
3067f82d9c4SYongqiang Niu state = to_mtk_crtc_state(mtk_crtc->base.state);
3077f82d9c4SYongqiang Niu
3085b9b8cd2SJason-JH.Lin spin_lock_irqsave(&mtk_crtc->config_lock, flags);
3095b9b8cd2SJason-JH.Lin if (mtk_crtc->config_updating) {
3105b9b8cd2SJason-JH.Lin spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
3115b9b8cd2SJason-JH.Lin goto ddp_cmdq_cb_out;
3125b9b8cd2SJason-JH.Lin }
3135b9b8cd2SJason-JH.Lin
3147f82d9c4SYongqiang Niu state->pending_config = false;
3157f82d9c4SYongqiang Niu
3167f82d9c4SYongqiang Niu if (mtk_crtc->pending_planes) {
3177f82d9c4SYongqiang Niu for (i = 0; i < mtk_crtc->layer_nr; i++) {
3187f82d9c4SYongqiang Niu struct drm_plane *plane = &mtk_crtc->planes[i];
3197f82d9c4SYongqiang Niu struct mtk_plane_state *plane_state;
3207f82d9c4SYongqiang Niu
3217f82d9c4SYongqiang Niu plane_state = to_mtk_plane_state(plane->state);
3227f82d9c4SYongqiang Niu
3237f82d9c4SYongqiang Niu plane_state->pending.config = false;
3247f82d9c4SYongqiang Niu }
3257f82d9c4SYongqiang Niu mtk_crtc->pending_planes = false;
3267f82d9c4SYongqiang Niu }
3277f82d9c4SYongqiang Niu
3287f82d9c4SYongqiang Niu if (mtk_crtc->pending_async_planes) {
3297f82d9c4SYongqiang Niu for (i = 0; i < mtk_crtc->layer_nr; i++) {
3307f82d9c4SYongqiang Niu struct drm_plane *plane = &mtk_crtc->planes[i];
3317f82d9c4SYongqiang Niu struct mtk_plane_state *plane_state;
3327f82d9c4SYongqiang Niu
3337f82d9c4SYongqiang Niu plane_state = to_mtk_plane_state(plane->state);
3347f82d9c4SYongqiang Niu
3357f82d9c4SYongqiang Niu plane_state->pending.async_config = false;
3367f82d9c4SYongqiang Niu }
3377f82d9c4SYongqiang Niu mtk_crtc->pending_async_planes = false;
3387f82d9c4SYongqiang Niu }
3391ee07a68SChun-Kuang Hu
3405b9b8cd2SJason-JH.Lin spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
3415b9b8cd2SJason-JH.Lin
3425b9b8cd2SJason-JH.Lin ddp_cmdq_cb_out:
3435b9b8cd2SJason-JH.Lin
344eaf80126SChun-Kuang Hu mtk_crtc->cmdq_vblank_cnt = 0;
345aa2d5f2fSjason-jh.lin wake_up(&mtk_crtc->cb_blocking_queue);
3462f965be7SBibby Hsieh }
3472f965be7SBibby Hsieh #endif
3482f965be7SBibby Hsieh
mtk_crtc_ddp_hw_init(struct mtk_drm_crtc * mtk_crtc)349119f5173SCK Hu static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
350119f5173SCK Hu {
351119f5173SCK Hu struct drm_crtc *crtc = &mtk_crtc->base;
35272164364SBibby Hsieh struct drm_connector *connector;
35372164364SBibby Hsieh struct drm_encoder *encoder;
354c8bf8b96SGustavo Padovan struct drm_connector_list_iter conn_iter;
35572164364SBibby Hsieh unsigned int width, height, vrefresh, bpc = MTK_MAX_BPC;
356119f5173SCK Hu int ret;
357119f5173SCK Hu int i;
358119f5173SCK Hu
359119f5173SCK Hu if (WARN_ON(!crtc->state))
360119f5173SCK Hu return -EINVAL;
361119f5173SCK Hu
362119f5173SCK Hu width = crtc->state->adjusted_mode.hdisplay;
363119f5173SCK Hu height = crtc->state->adjusted_mode.vdisplay;
3640425662fSVille Syrjälä vrefresh = drm_mode_vrefresh(&crtc->state->adjusted_mode);
365119f5173SCK Hu
36672164364SBibby Hsieh drm_for_each_encoder(encoder, crtc->dev) {
36772164364SBibby Hsieh if (encoder->crtc != crtc)
36872164364SBibby Hsieh continue;
36972164364SBibby Hsieh
370c8bf8b96SGustavo Padovan drm_connector_list_iter_begin(crtc->dev, &conn_iter);
371c8bf8b96SGustavo Padovan drm_for_each_connector_iter(connector, &conn_iter) {
37272164364SBibby Hsieh if (connector->encoder != encoder)
37372164364SBibby Hsieh continue;
37472164364SBibby Hsieh if (connector->display_info.bpc != 0 &&
37572164364SBibby Hsieh bpc > connector->display_info.bpc)
37672164364SBibby Hsieh bpc = connector->display_info.bpc;
37772164364SBibby Hsieh }
378c8bf8b96SGustavo Padovan drm_connector_list_iter_end(&conn_iter);
37972164364SBibby Hsieh }
38072164364SBibby Hsieh
38169777e6cSWang Li ret = pm_runtime_resume_and_get(crtc->dev->dev);
382119f5173SCK Hu if (ret < 0) {
383119f5173SCK Hu DRM_ERROR("Failed to enable power domain: %d\n", ret);
384119f5173SCK Hu return ret;
385119f5173SCK Hu }
386119f5173SCK Hu
3874971593fSCK Hu ret = mtk_mutex_prepare(mtk_crtc->mutex);
388119f5173SCK Hu if (ret < 0) {
389119f5173SCK Hu DRM_ERROR("Failed to enable mutex clock: %d\n", ret);
390119f5173SCK Hu goto err_pm_runtime_put;
391119f5173SCK Hu }
392119f5173SCK Hu
393119f5173SCK Hu ret = mtk_crtc_ddp_clk_enable(mtk_crtc);
394119f5173SCK Hu if (ret < 0) {
395119f5173SCK Hu DRM_ERROR("Failed to enable component clocks: %d\n", ret);
396119f5173SCK Hu goto err_mutex_unprepare;
397119f5173SCK Hu }
398119f5173SCK Hu
399119f5173SCK Hu for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) {
4000d9eee91SNancy.Lin if (!mtk_ddp_comp_connect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev,
4010d9eee91SNancy.Lin mtk_crtc->ddp_comp[i + 1]->id))
4022c758e30SEnric Balletbo i Serra mtk_mmsys_ddp_connect(mtk_crtc->mmsys_dev,
403119f5173SCK Hu mtk_crtc->ddp_comp[i]->id,
404119f5173SCK Hu mtk_crtc->ddp_comp[i + 1]->id);
4050d9eee91SNancy.Lin if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
4064971593fSCK Hu mtk_mutex_add_comp(mtk_crtc->mutex,
407119f5173SCK Hu mtk_crtc->ddp_comp[i]->id);
408119f5173SCK Hu }
4090d9eee91SNancy.Lin if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
4104971593fSCK Hu mtk_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id);
4114971593fSCK Hu mtk_mutex_enable(mtk_crtc->mutex);
412119f5173SCK Hu
413119f5173SCK Hu for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
414119f5173SCK Hu struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
415119f5173SCK Hu
416412b1e46SYongqiang Niu if (i == 1)
417412b1e46SYongqiang Niu mtk_ddp_comp_bgclr_in_on(comp);
418412b1e46SYongqiang Niu
419d0afe37fSBibby Hsieh mtk_ddp_comp_config(comp, width, height, vrefresh, bpc, NULL);
420119f5173SCK Hu mtk_ddp_comp_start(comp);
421119f5173SCK Hu }
422119f5173SCK Hu
423119f5173SCK Hu /* Initially configure all planes */
42466b2cf96SStu Hsieh for (i = 0; i < mtk_crtc->layer_nr; i++) {
4255bfafad8SDaniel Kurtz struct drm_plane *plane = &mtk_crtc->planes[i];
426119f5173SCK Hu struct mtk_plane_state *plane_state;
427d6b53f68SSean Paul struct mtk_ddp_comp *comp;
428412b1e46SYongqiang Niu unsigned int local_layer;
429119f5173SCK Hu
430119f5173SCK Hu plane_state = to_mtk_plane_state(plane->state);
43112d322fcSJason-JH.Lin
43212d322fcSJason-JH.Lin /* should not enable layer before crtc enabled */
43312d322fcSJason-JH.Lin plane_state->pending.enable = false;
434d6b53f68SSean Paul comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer);
4355bbb71cdSPi-Hsun Shih if (comp)
4365bbb71cdSPi-Hsun Shih mtk_ddp_comp_layer_config(comp, local_layer,
437d0afe37fSBibby Hsieh plane_state, NULL);
438119f5173SCK Hu }
439119f5173SCK Hu
440119f5173SCK Hu return 0;
441119f5173SCK Hu
442119f5173SCK Hu err_mutex_unprepare:
4434971593fSCK Hu mtk_mutex_unprepare(mtk_crtc->mutex);
444119f5173SCK Hu err_pm_runtime_put:
445119f5173SCK Hu pm_runtime_put(crtc->dev->dev);
446119f5173SCK Hu return ret;
447119f5173SCK Hu }
448119f5173SCK Hu
mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc * mtk_crtc)449119f5173SCK Hu static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc)
450119f5173SCK Hu {
451119f5173SCK Hu struct drm_device *drm = mtk_crtc->base.dev;
452411f5c1eSBibby Hsieh struct drm_crtc *crtc = &mtk_crtc->base;
453*415a2c21SFei Shao unsigned long flags;
454119f5173SCK Hu int i;
455119f5173SCK Hu
456412b1e46SYongqiang Niu for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
457119f5173SCK Hu mtk_ddp_comp_stop(mtk_crtc->ddp_comp[i]);
458412b1e46SYongqiang Niu if (i == 1)
459412b1e46SYongqiang Niu mtk_ddp_comp_bgclr_in_off(mtk_crtc->ddp_comp[i]);
460412b1e46SYongqiang Niu }
461412b1e46SYongqiang Niu
462119f5173SCK Hu for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
4630d9eee91SNancy.Lin if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
4644971593fSCK Hu mtk_mutex_remove_comp(mtk_crtc->mutex,
465119f5173SCK Hu mtk_crtc->ddp_comp[i]->id);
4664971593fSCK Hu mtk_mutex_disable(mtk_crtc->mutex);
467119f5173SCK Hu for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) {
4680d9eee91SNancy.Lin if (!mtk_ddp_comp_disconnect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev,
4690d9eee91SNancy.Lin mtk_crtc->ddp_comp[i + 1]->id))
4702c758e30SEnric Balletbo i Serra mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev,
471119f5173SCK Hu mtk_crtc->ddp_comp[i]->id,
472119f5173SCK Hu mtk_crtc->ddp_comp[i + 1]->id);
4730d9eee91SNancy.Lin if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
4744971593fSCK Hu mtk_mutex_remove_comp(mtk_crtc->mutex,
475119f5173SCK Hu mtk_crtc->ddp_comp[i]->id);
476119f5173SCK Hu }
4770d9eee91SNancy.Lin if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
4784971593fSCK Hu mtk_mutex_remove_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id);
479119f5173SCK Hu mtk_crtc_ddp_clk_disable(mtk_crtc);
4804971593fSCK Hu mtk_mutex_unprepare(mtk_crtc->mutex);
481119f5173SCK Hu
482119f5173SCK Hu pm_runtime_put(drm->dev);
483411f5c1eSBibby Hsieh
484411f5c1eSBibby Hsieh if (crtc->state->event && !crtc->state->active) {
485*415a2c21SFei Shao spin_lock_irqsave(&crtc->dev->event_lock, flags);
486411f5c1eSBibby Hsieh drm_crtc_send_vblank_event(crtc, crtc->state->event);
487411f5c1eSBibby Hsieh crtc->state->event = NULL;
488*415a2c21SFei Shao spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
489411f5c1eSBibby Hsieh }
490119f5173SCK Hu }
491119f5173SCK Hu
mtk_crtc_ddp_config(struct drm_crtc * crtc,struct cmdq_pkt * cmdq_handle)4922f965be7SBibby Hsieh static void mtk_crtc_ddp_config(struct drm_crtc *crtc,
4932f965be7SBibby Hsieh struct cmdq_pkt *cmdq_handle)
4949dc84e98Syt.shen@mediatek.com {
4959dc84e98Syt.shen@mediatek.com struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
4969dc84e98Syt.shen@mediatek.com struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
497f265905cSStu Hsieh struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
4989dc84e98Syt.shen@mediatek.com unsigned int i;
499412b1e46SYongqiang Niu unsigned int local_layer;
5009dc84e98Syt.shen@mediatek.com
5019dc84e98Syt.shen@mediatek.com /*
5029dc84e98Syt.shen@mediatek.com * TODO: instead of updating the registers here, we should prepare
5039dc84e98Syt.shen@mediatek.com * working registers in atomic_commit and let the hardware command
5049dc84e98Syt.shen@mediatek.com * queue update module registers on vblank.
5059dc84e98Syt.shen@mediatek.com */
5069dc84e98Syt.shen@mediatek.com if (state->pending_config) {
507f265905cSStu Hsieh mtk_ddp_comp_config(comp, state->pending_width,
5089dc84e98Syt.shen@mediatek.com state->pending_height,
5092f965be7SBibby Hsieh state->pending_vrefresh, 0,
5102f965be7SBibby Hsieh cmdq_handle);
5119dc84e98Syt.shen@mediatek.com
5127f82d9c4SYongqiang Niu if (!cmdq_handle)
5139dc84e98Syt.shen@mediatek.com state->pending_config = false;
5149dc84e98Syt.shen@mediatek.com }
5159dc84e98Syt.shen@mediatek.com
5169dc84e98Syt.shen@mediatek.com if (mtk_crtc->pending_planes) {
51766b2cf96SStu Hsieh for (i = 0; i < mtk_crtc->layer_nr; i++) {
5189dc84e98Syt.shen@mediatek.com struct drm_plane *plane = &mtk_crtc->planes[i];
5199dc84e98Syt.shen@mediatek.com struct mtk_plane_state *plane_state;
5209dc84e98Syt.shen@mediatek.com
5219dc84e98Syt.shen@mediatek.com plane_state = to_mtk_plane_state(plane->state);
5229dc84e98Syt.shen@mediatek.com
523d6b53f68SSean Paul if (!plane_state->pending.config)
524d6b53f68SSean Paul continue;
525d6b53f68SSean Paul
526d6b53f68SSean Paul comp = mtk_drm_ddp_comp_for_plane(crtc, plane,
527d6b53f68SSean Paul &local_layer);
528412b1e46SYongqiang Niu
5295bbb71cdSPi-Hsun Shih if (comp)
530412b1e46SYongqiang Niu mtk_ddp_comp_layer_config(comp, local_layer,
5312f965be7SBibby Hsieh plane_state,
5322f965be7SBibby Hsieh cmdq_handle);
5337f82d9c4SYongqiang Niu if (!cmdq_handle)
5349dc84e98Syt.shen@mediatek.com plane_state->pending.config = false;
5359dc84e98Syt.shen@mediatek.com }
5367f82d9c4SYongqiang Niu
5377f82d9c4SYongqiang Niu if (!cmdq_handle)
5389dc84e98Syt.shen@mediatek.com mtk_crtc->pending_planes = false;
5399dc84e98Syt.shen@mediatek.com }
540920fffccSBibby Hsieh
541920fffccSBibby Hsieh if (mtk_crtc->pending_async_planes) {
542920fffccSBibby Hsieh for (i = 0; i < mtk_crtc->layer_nr; i++) {
543920fffccSBibby Hsieh struct drm_plane *plane = &mtk_crtc->planes[i];
544920fffccSBibby Hsieh struct mtk_plane_state *plane_state;
545920fffccSBibby Hsieh
546920fffccSBibby Hsieh plane_state = to_mtk_plane_state(plane->state);
547920fffccSBibby Hsieh
548920fffccSBibby Hsieh if (!plane_state->pending.async_config)
549920fffccSBibby Hsieh continue;
550920fffccSBibby Hsieh
551920fffccSBibby Hsieh comp = mtk_drm_ddp_comp_for_plane(crtc, plane,
552920fffccSBibby Hsieh &local_layer);
553920fffccSBibby Hsieh
554920fffccSBibby Hsieh if (comp)
555920fffccSBibby Hsieh mtk_ddp_comp_layer_config(comp, local_layer,
5562f965be7SBibby Hsieh plane_state,
5572f965be7SBibby Hsieh cmdq_handle);
5587f82d9c4SYongqiang Niu if (!cmdq_handle)
559920fffccSBibby Hsieh plane_state->pending.async_config = false;
560920fffccSBibby Hsieh }
5617f82d9c4SYongqiang Niu
5627f82d9c4SYongqiang Niu if (!cmdq_handle)
563920fffccSBibby Hsieh mtk_crtc->pending_async_planes = false;
564920fffccSBibby Hsieh }
565920fffccSBibby Hsieh }
566920fffccSBibby Hsieh
mtk_drm_crtc_update_config(struct mtk_drm_crtc * mtk_crtc,bool needs_vblank)567368166ecSChun-Kuang Hu static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,
568368166ecSChun-Kuang Hu bool needs_vblank)
569920fffccSBibby Hsieh {
5702f965be7SBibby Hsieh #if IS_REACHABLE(CONFIG_MTK_CMDQ)
5717627122fSChun-Kuang Hu struct cmdq_pkt *cmdq_handle = &mtk_crtc->cmdq_handle;
5722f965be7SBibby Hsieh #endif
573920fffccSBibby Hsieh struct drm_crtc *crtc = &mtk_crtc->base;
574920fffccSBibby Hsieh struct mtk_drm_private *priv = crtc->dev->dev_private;
575920fffccSBibby Hsieh unsigned int pending_planes = 0, pending_async_planes = 0;
576920fffccSBibby Hsieh int i;
5775b9b8cd2SJason-JH.Lin unsigned long flags;
578920fffccSBibby Hsieh
579920fffccSBibby Hsieh mutex_lock(&mtk_crtc->hw_lock);
5805b9b8cd2SJason-JH.Lin
5815b9b8cd2SJason-JH.Lin spin_lock_irqsave(&mtk_crtc->config_lock, flags);
582368166ecSChun-Kuang Hu mtk_crtc->config_updating = true;
5835b9b8cd2SJason-JH.Lin spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
5845b9b8cd2SJason-JH.Lin
585368166ecSChun-Kuang Hu if (needs_vblank)
586368166ecSChun-Kuang Hu mtk_crtc->pending_needs_vblank = true;
587368166ecSChun-Kuang Hu
588920fffccSBibby Hsieh for (i = 0; i < mtk_crtc->layer_nr; i++) {
589920fffccSBibby Hsieh struct drm_plane *plane = &mtk_crtc->planes[i];
590920fffccSBibby Hsieh struct mtk_plane_state *plane_state;
591920fffccSBibby Hsieh
592920fffccSBibby Hsieh plane_state = to_mtk_plane_state(plane->state);
593920fffccSBibby Hsieh if (plane_state->pending.dirty) {
594920fffccSBibby Hsieh plane_state->pending.config = true;
595920fffccSBibby Hsieh plane_state->pending.dirty = false;
596920fffccSBibby Hsieh pending_planes |= BIT(i);
597920fffccSBibby Hsieh } else if (plane_state->pending.async_dirty) {
598920fffccSBibby Hsieh plane_state->pending.async_config = true;
599920fffccSBibby Hsieh plane_state->pending.async_dirty = false;
600920fffccSBibby Hsieh pending_async_planes |= BIT(i);
601920fffccSBibby Hsieh }
602920fffccSBibby Hsieh }
603920fffccSBibby Hsieh if (pending_planes)
604920fffccSBibby Hsieh mtk_crtc->pending_planes = true;
605920fffccSBibby Hsieh if (pending_async_planes)
606920fffccSBibby Hsieh mtk_crtc->pending_async_planes = true;
607920fffccSBibby Hsieh
608920fffccSBibby Hsieh if (priv->data->shadow_register) {
6094971593fSCK Hu mtk_mutex_acquire(mtk_crtc->mutex);
6102f965be7SBibby Hsieh mtk_crtc_ddp_config(crtc, NULL);
6114971593fSCK Hu mtk_mutex_release(mtk_crtc->mutex);
612920fffccSBibby Hsieh }
6132f965be7SBibby Hsieh #if IS_REACHABLE(CONFIG_MTK_CMDQ)
614563c9d4aSChun-Kuang Hu if (mtk_crtc->cmdq_client.chan) {
615563c9d4aSChun-Kuang Hu mbox_flush(mtk_crtc->cmdq_client.chan, 2000);
6167627122fSChun-Kuang Hu cmdq_handle->cmd_buf_size = 0;
6172f965be7SBibby Hsieh cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
618bee1abc9SDennis YC Hsieh cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false);
6192f965be7SBibby Hsieh mtk_crtc_ddp_config(crtc, cmdq_handle);
62099581858SDennis YC Hsieh cmdq_pkt_finalize(cmdq_handle);
621563c9d4aSChun-Kuang Hu dma_sync_single_for_device(mtk_crtc->cmdq_client.chan->mbox->dev,
6221ee07a68SChun-Kuang Hu cmdq_handle->pa_base,
6231ee07a68SChun-Kuang Hu cmdq_handle->cmd_buf_size,
6241ee07a68SChun-Kuang Hu DMA_TO_DEVICE);
625eaf80126SChun-Kuang Hu /*
626eaf80126SChun-Kuang Hu * CMDQ command should execute in next 3 vblank.
627eaf80126SChun-Kuang Hu * One vblank interrupt before send message (occasionally)
628eaf80126SChun-Kuang Hu * and one vblank interrupt after cmdq done,
629eaf80126SChun-Kuang Hu * so it's timeout after 3 vblank interrupt.
630eaf80126SChun-Kuang Hu * If it fail to execute in next 3 vblank, timeout happen.
631eaf80126SChun-Kuang Hu */
632eaf80126SChun-Kuang Hu mtk_crtc->cmdq_vblank_cnt = 3;
633eaf80126SChun-Kuang Hu
634563c9d4aSChun-Kuang Hu mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle);
635563c9d4aSChun-Kuang Hu mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0);
6362f965be7SBibby Hsieh }
6372f965be7SBibby Hsieh #endif
6385b9b8cd2SJason-JH.Lin spin_lock_irqsave(&mtk_crtc->config_lock, flags);
639368166ecSChun-Kuang Hu mtk_crtc->config_updating = false;
6405b9b8cd2SJason-JH.Lin spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
6415b9b8cd2SJason-JH.Lin
642920fffccSBibby Hsieh mutex_unlock(&mtk_crtc->hw_lock);
6439dc84e98Syt.shen@mediatek.com }
6449dc84e98Syt.shen@mediatek.com
mtk_crtc_ddp_irq(void * data)6459b070498SCK Hu static void mtk_crtc_ddp_irq(void *data)
6469b070498SCK Hu {
6479b070498SCK Hu struct drm_crtc *crtc = data;
6489b070498SCK Hu struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
6499b070498SCK Hu struct mtk_drm_private *priv = crtc->dev->dev_private;
6509b070498SCK Hu
6519b070498SCK Hu #if IS_REACHABLE(CONFIG_MTK_CMDQ)
652563c9d4aSChun-Kuang Hu if (!priv->data->shadow_register && !mtk_crtc->cmdq_client.chan)
653eaf80126SChun-Kuang Hu mtk_crtc_ddp_config(crtc, NULL);
654eaf80126SChun-Kuang Hu else if (mtk_crtc->cmdq_vblank_cnt > 0 && --mtk_crtc->cmdq_vblank_cnt == 0)
655eaf80126SChun-Kuang Hu DRM_ERROR("mtk_crtc %d CMDQ execute command timeout!\n",
656eaf80126SChun-Kuang Hu drm_crtc_index(&mtk_crtc->base));
6579b070498SCK Hu #else
6589b070498SCK Hu if (!priv->data->shadow_register)
6590cf54fffSChun-Kuang Hu mtk_crtc_ddp_config(crtc, NULL);
660eaf80126SChun-Kuang Hu #endif
6619b070498SCK Hu mtk_drm_finish_page_flip(mtk_crtc);
6629b070498SCK Hu }
6639b070498SCK Hu
mtk_drm_crtc_enable_vblank(struct drm_crtc * crtc)6649b070498SCK Hu static int mtk_drm_crtc_enable_vblank(struct drm_crtc *crtc)
6659b070498SCK Hu {
6669b070498SCK Hu struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
6679b070498SCK Hu struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
6689b070498SCK Hu
669b74d921bSRex-BC Chen mtk_ddp_comp_enable_vblank(comp);
6709b070498SCK Hu
6719b070498SCK Hu return 0;
6729b070498SCK Hu }
6739b070498SCK Hu
mtk_drm_crtc_disable_vblank(struct drm_crtc * crtc)6749b070498SCK Hu static void mtk_drm_crtc_disable_vblank(struct drm_crtc *crtc)
6759b070498SCK Hu {
6769b070498SCK Hu struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
6779b070498SCK Hu struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
6789b070498SCK Hu
6799b070498SCK Hu mtk_ddp_comp_disable_vblank(comp);
6809b070498SCK Hu }
6819b070498SCK Hu
mtk_drm_crtc_plane_check(struct drm_crtc * crtc,struct drm_plane * plane,struct mtk_plane_state * state)682f7c710d1SSean Paul int mtk_drm_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane,
683f7c710d1SSean Paul struct mtk_plane_state *state)
684f7c710d1SSean Paul {
685f7c710d1SSean Paul unsigned int local_layer;
686f7c710d1SSean Paul struct mtk_ddp_comp *comp;
687f7c710d1SSean Paul
688f7c710d1SSean Paul comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer);
6895bbb71cdSPi-Hsun Shih if (comp)
690f7c710d1SSean Paul return mtk_ddp_comp_layer_check(comp, local_layer, state);
6915bbb71cdSPi-Hsun Shih return 0;
692f7c710d1SSean Paul }
693f7c710d1SSean Paul
mtk_drm_crtc_async_update(struct drm_crtc * crtc,struct drm_plane * plane,struct drm_atomic_state * state)694920fffccSBibby Hsieh void mtk_drm_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane,
695977697e2SMaxime Ripard struct drm_atomic_state *state)
696920fffccSBibby Hsieh {
697920fffccSBibby Hsieh struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
698920fffccSBibby Hsieh
699920fffccSBibby Hsieh if (!mtk_crtc->enabled)
700920fffccSBibby Hsieh return;
701920fffccSBibby Hsieh
702368166ecSChun-Kuang Hu mtk_drm_crtc_update_config(mtk_crtc, false);
703920fffccSBibby Hsieh }
704920fffccSBibby Hsieh
mtk_drm_crtc_atomic_enable(struct drm_crtc * crtc,struct drm_atomic_state * state)7050b20a0f8SLaurent Pinchart static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc,
706351f950dSMaxime Ripard struct drm_atomic_state *state)
707119f5173SCK Hu {
708119f5173SCK Hu struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
709f265905cSStu Hsieh struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
710119f5173SCK Hu int ret;
711119f5173SCK Hu
712119f5173SCK Hu DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id);
713119f5173SCK Hu
7145db12f5dSYongqiang Niu ret = pm_runtime_resume_and_get(comp->dev);
7155db12f5dSYongqiang Niu if (ret < 0) {
7165db12f5dSYongqiang Niu DRM_DEV_ERROR(comp->dev, "Failed to enable power domain: %d\n", ret);
7175db12f5dSYongqiang Niu return;
7185db12f5dSYongqiang Niu }
7195db12f5dSYongqiang Niu
720119f5173SCK Hu ret = mtk_crtc_ddp_hw_init(mtk_crtc);
721119f5173SCK Hu if (ret) {
7225db12f5dSYongqiang Niu pm_runtime_put(comp->dev);
723119f5173SCK Hu return;
724119f5173SCK Hu }
725119f5173SCK Hu
726119f5173SCK Hu drm_crtc_vblank_on(crtc);
727119f5173SCK Hu mtk_crtc->enabled = true;
728119f5173SCK Hu }
729119f5173SCK Hu
mtk_drm_crtc_atomic_disable(struct drm_crtc * crtc,struct drm_atomic_state * state)73064581714SLaurent Pinchart static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc,
731351f950dSMaxime Ripard struct drm_atomic_state *state)
732119f5173SCK Hu {
733119f5173SCK Hu struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
734f265905cSStu Hsieh struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
7355db12f5dSYongqiang Niu int i, ret;
736119f5173SCK Hu
737119f5173SCK Hu DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id);
738119f5173SCK Hu if (!mtk_crtc->enabled)
739119f5173SCK Hu return;
740119f5173SCK Hu
741119f5173SCK Hu /* Set all pending plane state to disabled */
74266b2cf96SStu Hsieh for (i = 0; i < mtk_crtc->layer_nr; i++) {
7435bfafad8SDaniel Kurtz struct drm_plane *plane = &mtk_crtc->planes[i];
744119f5173SCK Hu struct mtk_plane_state *plane_state;
745119f5173SCK Hu
746119f5173SCK Hu plane_state = to_mtk_plane_state(plane->state);
747119f5173SCK Hu plane_state->pending.enable = false;
748119f5173SCK Hu plane_state->pending.config = true;
749119f5173SCK Hu }
750119f5173SCK Hu mtk_crtc->pending_planes = true;
751119f5173SCK Hu
752368166ecSChun-Kuang Hu mtk_drm_crtc_update_config(mtk_crtc, false);
753aa2d5f2fSjason-jh.lin #if IS_REACHABLE(CONFIG_MTK_CMDQ)
754aa2d5f2fSjason-jh.lin /* Wait for planes to be disabled by cmdq */
755aa2d5f2fSjason-jh.lin if (mtk_crtc->cmdq_client.chan)
756aa2d5f2fSjason-jh.lin wait_event_timeout(mtk_crtc->cb_blocking_queue,
757aa2d5f2fSjason-jh.lin mtk_crtc->cmdq_vblank_cnt == 0,
758aa2d5f2fSjason-jh.lin msecs_to_jiffies(500));
759aa2d5f2fSjason-jh.lin #endif
760119f5173SCK Hu /* Wait for planes to be disabled */
761119f5173SCK Hu drm_crtc_wait_one_vblank(crtc);
762119f5173SCK Hu
763119f5173SCK Hu drm_crtc_vblank_off(crtc);
764119f5173SCK Hu mtk_crtc_ddp_hw_fini(mtk_crtc);
7655db12f5dSYongqiang Niu ret = pm_runtime_put(comp->dev);
7665db12f5dSYongqiang Niu if (ret < 0)
7675db12f5dSYongqiang Niu DRM_DEV_ERROR(comp->dev, "Failed to disable power domain: %d\n", ret);
768119f5173SCK Hu
769119f5173SCK Hu mtk_crtc->enabled = false;
770119f5173SCK Hu }
771119f5173SCK Hu
mtk_drm_crtc_atomic_begin(struct drm_crtc * crtc,struct drm_atomic_state * state)772119f5173SCK Hu static void mtk_drm_crtc_atomic_begin(struct drm_crtc *crtc,
773f6ebe9f9SMaxime Ripard struct drm_atomic_state *state)
774119f5173SCK Hu {
775253f28b6SMaxime Ripard struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
776253f28b6SMaxime Ripard crtc);
777253f28b6SMaxime Ripard struct mtk_crtc_state *mtk_crtc_state = to_mtk_crtc_state(crtc_state);
778119f5173SCK Hu struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
7797d6e9cb7SJason-JH.Lin unsigned long flags;
780119f5173SCK Hu
781253f28b6SMaxime Ripard if (mtk_crtc->event && mtk_crtc_state->base.event)
782119f5173SCK Hu DRM_ERROR("new event while there is still a pending event\n");
783119f5173SCK Hu
784253f28b6SMaxime Ripard if (mtk_crtc_state->base.event) {
785253f28b6SMaxime Ripard mtk_crtc_state->base.event->pipe = drm_crtc_index(crtc);
786119f5173SCK Hu WARN_ON(drm_crtc_vblank_get(crtc) != 0);
7877d6e9cb7SJason-JH.Lin
7887d6e9cb7SJason-JH.Lin spin_lock_irqsave(&crtc->dev->event_lock, flags);
789253f28b6SMaxime Ripard mtk_crtc->event = mtk_crtc_state->base.event;
7907d6e9cb7SJason-JH.Lin spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
7917d6e9cb7SJason-JH.Lin
792253f28b6SMaxime Ripard mtk_crtc_state->base.event = NULL;
793119f5173SCK Hu }
794119f5173SCK Hu }
795119f5173SCK Hu
mtk_drm_crtc_atomic_flush(struct drm_crtc * crtc,struct drm_atomic_state * state)796119f5173SCK Hu static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
797f6ebe9f9SMaxime Ripard struct drm_atomic_state *state)
798119f5173SCK Hu {
799119f5173SCK Hu struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
800119f5173SCK Hu int i;
801119f5173SCK Hu
8022f3f4ddaSBibby Hsieh if (crtc->state->color_mgmt_changed)
80384abcf12SYongqiang Niu for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
8042f3f4ddaSBibby Hsieh mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state);
80584abcf12SYongqiang Niu mtk_ddp_ctm_set(mtk_crtc->ddp_comp[i], crtc->state);
80684abcf12SYongqiang Niu }
807368166ecSChun-Kuang Hu mtk_drm_crtc_update_config(mtk_crtc, !!mtk_crtc->event);
808119f5173SCK Hu }
809119f5173SCK Hu
810119f5173SCK Hu static const struct drm_crtc_funcs mtk_crtc_funcs = {
811119f5173SCK Hu .set_config = drm_atomic_helper_set_config,
812119f5173SCK Hu .page_flip = drm_atomic_helper_page_flip,
813119f5173SCK Hu .destroy = mtk_drm_crtc_destroy,
814119f5173SCK Hu .reset = mtk_drm_crtc_reset,
815119f5173SCK Hu .atomic_duplicate_state = mtk_drm_crtc_duplicate_state,
816119f5173SCK Hu .atomic_destroy_state = mtk_drm_crtc_destroy_state,
817a5073a5bSShawn Guo .enable_vblank = mtk_drm_crtc_enable_vblank,
818a5073a5bSShawn Guo .disable_vblank = mtk_drm_crtc_disable_vblank,
819119f5173SCK Hu };
820119f5173SCK Hu
821119f5173SCK Hu static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
822119f5173SCK Hu .mode_fixup = mtk_drm_crtc_mode_fixup,
823119f5173SCK Hu .mode_set_nofb = mtk_drm_crtc_mode_set_nofb,
824119f5173SCK Hu .atomic_begin = mtk_drm_crtc_atomic_begin,
825119f5173SCK Hu .atomic_flush = mtk_drm_crtc_atomic_flush,
8260b20a0f8SLaurent Pinchart .atomic_enable = mtk_drm_crtc_atomic_enable,
82764581714SLaurent Pinchart .atomic_disable = mtk_drm_crtc_atomic_disable,
828119f5173SCK Hu };
829119f5173SCK Hu
mtk_drm_crtc_init(struct drm_device * drm,struct mtk_drm_crtc * mtk_crtc,unsigned int pipe)830119f5173SCK Hu static int mtk_drm_crtc_init(struct drm_device *drm,
831119f5173SCK Hu struct mtk_drm_crtc *mtk_crtc,
832318caac7SEvan Benn unsigned int pipe)
833119f5173SCK Hu {
834318caac7SEvan Benn struct drm_plane *primary = NULL;
835318caac7SEvan Benn struct drm_plane *cursor = NULL;
836318caac7SEvan Benn int i, ret;
837318caac7SEvan Benn
838318caac7SEvan Benn for (i = 0; i < mtk_crtc->layer_nr; i++) {
839318caac7SEvan Benn if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_PRIMARY)
840318caac7SEvan Benn primary = &mtk_crtc->planes[i];
841318caac7SEvan Benn else if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_CURSOR)
842318caac7SEvan Benn cursor = &mtk_crtc->planes[i];
843318caac7SEvan Benn }
844119f5173SCK Hu
845119f5173SCK Hu ret = drm_crtc_init_with_planes(drm, &mtk_crtc->base, primary, cursor,
846119f5173SCK Hu &mtk_crtc_funcs, NULL);
847119f5173SCK Hu if (ret)
848119f5173SCK Hu goto err_cleanup_crtc;
849119f5173SCK Hu
850119f5173SCK Hu drm_crtc_helper_add(&mtk_crtc->base, &mtk_crtc_helper_funcs);
851119f5173SCK Hu
852119f5173SCK Hu return 0;
853119f5173SCK Hu
854119f5173SCK Hu err_cleanup_crtc:
855119f5173SCK Hu drm_crtc_cleanup(&mtk_crtc->base);
856119f5173SCK Hu return ret;
857119f5173SCK Hu }
858119f5173SCK Hu
mtk_drm_crtc_num_comp_planes(struct mtk_drm_crtc * mtk_crtc,int comp_idx)85931c5558dSSean Paul static int mtk_drm_crtc_num_comp_planes(struct mtk_drm_crtc *mtk_crtc,
86031c5558dSSean Paul int comp_idx)
86131c5558dSSean Paul {
86231c5558dSSean Paul struct mtk_ddp_comp *comp;
86331c5558dSSean Paul
86431c5558dSSean Paul if (comp_idx > 1)
86531c5558dSSean Paul return 0;
86631c5558dSSean Paul
86731c5558dSSean Paul comp = mtk_crtc->ddp_comp[comp_idx];
86831c5558dSSean Paul if (!comp->funcs)
86931c5558dSSean Paul return 0;
87031c5558dSSean Paul
87131c5558dSSean Paul if (comp_idx == 1 && !comp->funcs->bgclr_in_on)
87231c5558dSSean Paul return 0;
87331c5558dSSean Paul
87431c5558dSSean Paul return mtk_ddp_comp_layer_nr(comp);
87531c5558dSSean Paul }
87631c5558dSSean Paul
87731c5558dSSean Paul static inline
mtk_drm_crtc_plane_type(unsigned int plane_idx,unsigned int num_planes)87826d69619SSean Paul enum drm_plane_type mtk_drm_crtc_plane_type(unsigned int plane_idx,
87926d69619SSean Paul unsigned int num_planes)
88031c5558dSSean Paul {
88131c5558dSSean Paul if (plane_idx == 0)
88231c5558dSSean Paul return DRM_PLANE_TYPE_PRIMARY;
88326d69619SSean Paul else if (plane_idx == (num_planes - 1))
88431c5558dSSean Paul return DRM_PLANE_TYPE_CURSOR;
88531c5558dSSean Paul else
88631c5558dSSean Paul return DRM_PLANE_TYPE_OVERLAY;
88731c5558dSSean Paul
88831c5558dSSean Paul }
88931c5558dSSean Paul
mtk_drm_crtc_init_comp_planes(struct drm_device * drm_dev,struct mtk_drm_crtc * mtk_crtc,int comp_idx,int pipe)89031c5558dSSean Paul static int mtk_drm_crtc_init_comp_planes(struct drm_device *drm_dev,
89131c5558dSSean Paul struct mtk_drm_crtc *mtk_crtc,
89231c5558dSSean Paul int comp_idx, int pipe)
89331c5558dSSean Paul {
89431c5558dSSean Paul int num_planes = mtk_drm_crtc_num_comp_planes(mtk_crtc, comp_idx);
895ef87d3e2SSean Paul struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[comp_idx];
89631c5558dSSean Paul int i, ret;
89731c5558dSSean Paul
89831c5558dSSean Paul for (i = 0; i < num_planes; i++) {
89931c5558dSSean Paul ret = mtk_plane_init(drm_dev,
90031c5558dSSean Paul &mtk_crtc->planes[mtk_crtc->layer_nr],
90131c5558dSSean Paul BIT(pipe),
90226d69619SSean Paul mtk_drm_crtc_plane_type(mtk_crtc->layer_nr,
90326d69619SSean Paul num_planes),
904f287c66aSJustin Green mtk_ddp_comp_supported_rotations(comp),
905f287c66aSJustin Green mtk_ddp_comp_get_formats(comp),
906f287c66aSJustin Green mtk_ddp_comp_get_num_formats(comp));
90731c5558dSSean Paul if (ret)
90831c5558dSSean Paul return ret;
90931c5558dSSean Paul
91031c5558dSSean Paul mtk_crtc->layer_nr++;
91131c5558dSSean Paul }
91231c5558dSSean Paul return 0;
91331c5558dSSean Paul }
91431c5558dSSean Paul
mtk_drm_crtc_dma_dev_get(struct drm_crtc * crtc)915cb1d6bccSNancy.Lin struct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc *crtc)
916cb1d6bccSNancy.Lin {
91703e63e49SStuart Lee struct mtk_drm_crtc *mtk_crtc = NULL;
91803e63e49SStuart Lee
91903e63e49SStuart Lee if (!crtc)
92003e63e49SStuart Lee return NULL;
92103e63e49SStuart Lee
92203e63e49SStuart Lee mtk_crtc = to_mtk_crtc(crtc);
92303e63e49SStuart Lee if (!mtk_crtc)
92403e63e49SStuart Lee return NULL;
925cb1d6bccSNancy.Lin
926cb1d6bccSNancy.Lin return mtk_crtc->dma_dev;
927cb1d6bccSNancy.Lin }
928cb1d6bccSNancy.Lin
mtk_drm_crtc_create(struct drm_device * drm_dev,const unsigned int * path,unsigned int path_len,int priv_data_index)929119f5173SCK Hu int mtk_drm_crtc_create(struct drm_device *drm_dev,
9300d9eee91SNancy.Lin const unsigned int *path, unsigned int path_len,
9311ef7ed48SNancy.Lin int priv_data_index)
932119f5173SCK Hu {
933119f5173SCK Hu struct mtk_drm_private *priv = drm_dev->dev_private;
934119f5173SCK Hu struct device *dev = drm_dev->dev;
935119f5173SCK Hu struct mtk_drm_crtc *mtk_crtc;
93631c5558dSSean Paul unsigned int num_comp_planes = 0;
937119f5173SCK Hu int ret;
938119f5173SCK Hu int i;
93984abcf12SYongqiang Niu bool has_ctm = false;
9404cebc1deSYongqiang Niu uint gamma_lut_size = 0;
9411ef7ed48SNancy.Lin struct drm_crtc *tmp;
9421ef7ed48SNancy.Lin int crtc_i = 0;
943119f5173SCK Hu
944561fad31Sstu.hsieh@mediatek.com if (!path)
945561fad31Sstu.hsieh@mediatek.com return 0;
946561fad31Sstu.hsieh@mediatek.com
9471ef7ed48SNancy.Lin priv = priv->all_drm_private[priv_data_index];
9481ef7ed48SNancy.Lin
9491ef7ed48SNancy.Lin drm_for_each_crtc(tmp, drm_dev)
9501ef7ed48SNancy.Lin crtc_i++;
9511ef7ed48SNancy.Lin
952119f5173SCK Hu for (i = 0; i < path_len; i++) {
953119f5173SCK Hu enum mtk_ddp_comp_id comp_id = path[i];
954119f5173SCK Hu struct device_node *node;
9555b0ef98eSDafna Hirschfeld struct mtk_ddp_comp *comp;
956119f5173SCK Hu
957119f5173SCK Hu node = priv->comp_node[comp_id];
9585b0ef98eSDafna Hirschfeld comp = &priv->ddp_comp[comp_id];
9595b0ef98eSDafna Hirschfeld
9600d9eee91SNancy.Lin /* Not all drm components have a DTS device node, such as ovl_adaptor,
9610d9eee91SNancy.Lin * which is the drm bring up sub driver
9620d9eee91SNancy.Lin */
9630d9eee91SNancy.Lin if (!node && comp_id != DDP_COMPONENT_DRM_OVL_ADAPTOR) {
964119f5173SCK Hu dev_info(dev,
965119f5173SCK Hu "Not creating crtc %d because component %d is disabled or missing\n",
9661ef7ed48SNancy.Lin crtc_i, comp_id);
967119f5173SCK Hu return 0;
968119f5173SCK Hu }
9695b0ef98eSDafna Hirschfeld
9705b0ef98eSDafna Hirschfeld if (!comp->dev) {
9715b0ef98eSDafna Hirschfeld dev_err(dev, "Component %pOF not initialized\n", node);
9725b0ef98eSDafna Hirschfeld return -ENODEV;
9735b0ef98eSDafna Hirschfeld }
974119f5173SCK Hu }
975119f5173SCK Hu
976119f5173SCK Hu mtk_crtc = devm_kzalloc(dev, sizeof(*mtk_crtc), GFP_KERNEL);
977119f5173SCK Hu if (!mtk_crtc)
978119f5173SCK Hu return -ENOMEM;
979119f5173SCK Hu
9802c758e30SEnric Balletbo i Serra mtk_crtc->mmsys_dev = priv->mmsys_dev;
981119f5173SCK Hu mtk_crtc->ddp_comp_nr = path_len;
982119f5173SCK Hu mtk_crtc->ddp_comp = devm_kmalloc_array(dev, mtk_crtc->ddp_comp_nr,
983119f5173SCK Hu sizeof(*mtk_crtc->ddp_comp),
984119f5173SCK Hu GFP_KERNEL);
9854a3bfb5cSChristophe Jaillet if (!mtk_crtc->ddp_comp)
9864a3bfb5cSChristophe Jaillet return -ENOMEM;
987119f5173SCK Hu
98842a090b8SCK Hu mtk_crtc->mutex = mtk_mutex_get(priv->mutex_dev);
989119f5173SCK Hu if (IS_ERR(mtk_crtc->mutex)) {
990119f5173SCK Hu ret = PTR_ERR(mtk_crtc->mutex);
991119f5173SCK Hu dev_err(dev, "Failed to get mutex: %d\n", ret);
992119f5173SCK Hu return ret;
993119f5173SCK Hu }
994119f5173SCK Hu
995119f5173SCK Hu for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
9960d9eee91SNancy.Lin unsigned int comp_id = path[i];
997119f5173SCK Hu struct mtk_ddp_comp *comp;
998119f5173SCK Hu
999ff139560SCK Hu comp = &priv->ddp_comp[comp_id];
1000119f5173SCK Hu mtk_crtc->ddp_comp[i] = comp;
10014cebc1deSYongqiang Niu
100284abcf12SYongqiang Niu if (comp->funcs) {
100384abcf12SYongqiang Niu if (comp->funcs->gamma_set)
10044cebc1deSYongqiang Niu gamma_lut_size = MTK_LUT_SIZE;
100584abcf12SYongqiang Niu
100684abcf12SYongqiang Niu if (comp->funcs->ctm_set)
100784abcf12SYongqiang Niu has_ctm = true;
100884abcf12SYongqiang Niu }
1009b74d921bSRex-BC Chen
1010b74d921bSRex-BC Chen mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq,
1011b74d921bSRex-BC Chen &mtk_crtc->base);
1012119f5173SCK Hu }
1013119f5173SCK Hu
101431c5558dSSean Paul for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
101531c5558dSSean Paul num_comp_planes += mtk_drm_crtc_num_comp_planes(mtk_crtc, i);
1016412b1e46SYongqiang Niu
101731c5558dSSean Paul mtk_crtc->planes = devm_kcalloc(dev, num_comp_planes,
101831c5558dSSean Paul sizeof(struct drm_plane), GFP_KERNEL);
10195bf1e3bdSruanjinjie if (!mtk_crtc->planes)
10205bf1e3bdSruanjinjie return -ENOMEM;
102166b2cf96SStu Hsieh
102231c5558dSSean Paul for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
102331c5558dSSean Paul ret = mtk_drm_crtc_init_comp_planes(drm_dev, mtk_crtc, i,
10241ef7ed48SNancy.Lin crtc_i);
1025119f5173SCK Hu if (ret)
1026937f861dSYongqiang Niu return ret;
1027119f5173SCK Hu }
1028119f5173SCK Hu
1029cb1d6bccSNancy.Lin /*
1030cb1d6bccSNancy.Lin * Default to use the first component as the dma dev.
1031cb1d6bccSNancy.Lin * In the case of ovl_adaptor sub driver, it needs to use the
1032cb1d6bccSNancy.Lin * dma_dev_get function to get representative dma dev.
1033cb1d6bccSNancy.Lin */
1034cb1d6bccSNancy.Lin mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(&priv->ddp_comp[path[0]]);
1035cb1d6bccSNancy.Lin
10361ef7ed48SNancy.Lin ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, crtc_i);
1037119f5173SCK Hu if (ret < 0)
1038937f861dSYongqiang Niu return ret;
10394cebc1deSYongqiang Niu
10404cebc1deSYongqiang Niu if (gamma_lut_size)
10414cebc1deSYongqiang Niu drm_mode_crtc_set_gamma_size(&mtk_crtc->base, gamma_lut_size);
104284abcf12SYongqiang Niu drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, has_ctm, gamma_lut_size);
1043920fffccSBibby Hsieh mutex_init(&mtk_crtc->hw_lock);
10445b9b8cd2SJason-JH.Lin spin_lock_init(&mtk_crtc->config_lock);
1045119f5173SCK Hu
10462f965be7SBibby Hsieh #if IS_REACHABLE(CONFIG_MTK_CMDQ)
10471ef7ed48SNancy.Lin i = priv->mbox_index++;
1048563c9d4aSChun-Kuang Hu mtk_crtc->cmdq_client.client.dev = mtk_crtc->mmsys_dev;
1049563c9d4aSChun-Kuang Hu mtk_crtc->cmdq_client.client.tx_block = false;
1050563c9d4aSChun-Kuang Hu mtk_crtc->cmdq_client.client.knows_txdone = true;
1051563c9d4aSChun-Kuang Hu mtk_crtc->cmdq_client.client.rx_callback = ddp_cmdq_cb;
1052563c9d4aSChun-Kuang Hu mtk_crtc->cmdq_client.chan =
10531ef7ed48SNancy.Lin mbox_request_channel(&mtk_crtc->cmdq_client.client, i);
1054563c9d4aSChun-Kuang Hu if (IS_ERR(mtk_crtc->cmdq_client.chan)) {
10552f965be7SBibby Hsieh dev_dbg(dev, "mtk_crtc %d failed to create mailbox client, writing register by CPU now\n",
10562f965be7SBibby Hsieh drm_crtc_index(&mtk_crtc->base));
1057563c9d4aSChun-Kuang Hu mtk_crtc->cmdq_client.chan = NULL;
10582f965be7SBibby Hsieh }
1059f85acdadSChun-Kuang Hu
1060563c9d4aSChun-Kuang Hu if (mtk_crtc->cmdq_client.chan) {
106160fa8c13SBibby Hsieh ret = of_property_read_u32_index(priv->mutex_node,
106260fa8c13SBibby Hsieh "mediatek,gce-events",
10631ef7ed48SNancy.Lin i,
10642f965be7SBibby Hsieh &mtk_crtc->cmdq_event);
1065f85acdadSChun-Kuang Hu if (ret) {
10662f965be7SBibby Hsieh dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n",
10672f965be7SBibby Hsieh drm_crtc_index(&mtk_crtc->base));
1068563c9d4aSChun-Kuang Hu mbox_free_channel(mtk_crtc->cmdq_client.chan);
1069563c9d4aSChun-Kuang Hu mtk_crtc->cmdq_client.chan = NULL;
10707627122fSChun-Kuang Hu } else {
10717627122fSChun-Kuang Hu ret = mtk_drm_cmdq_pkt_create(&mtk_crtc->cmdq_client,
10727627122fSChun-Kuang Hu &mtk_crtc->cmdq_handle,
10737627122fSChun-Kuang Hu PAGE_SIZE);
10747627122fSChun-Kuang Hu if (ret) {
10757627122fSChun-Kuang Hu dev_dbg(dev, "mtk_crtc %d failed to create cmdq packet\n",
10767627122fSChun-Kuang Hu drm_crtc_index(&mtk_crtc->base));
10777627122fSChun-Kuang Hu mbox_free_channel(mtk_crtc->cmdq_client.chan);
10787627122fSChun-Kuang Hu mtk_crtc->cmdq_client.chan = NULL;
10797627122fSChun-Kuang Hu }
1080f85acdadSChun-Kuang Hu }
1081aa2d5f2fSjason-jh.lin
1082aa2d5f2fSjason-jh.lin /* for sending blocking cmd in crtc disable */
1083aa2d5f2fSjason-jh.lin init_waitqueue_head(&mtk_crtc->cb_blocking_queue);
1084f85acdadSChun-Kuang Hu }
10852f965be7SBibby Hsieh #endif
1086119f5173SCK Hu return 0;
1087119f5173SCK Hu }
1088