162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2015 MediaTek Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/clk.h> 762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 862306a36Sopenharmony_ci#include <linux/mailbox_controller.h> 962306a36Sopenharmony_ci#include <linux/of.h> 1062306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1162306a36Sopenharmony_ci#include <linux/soc/mediatek/mtk-cmdq.h> 1262306a36Sopenharmony_ci#include <linux/soc/mediatek/mtk-mmsys.h> 1362306a36Sopenharmony_ci#include <linux/soc/mediatek/mtk-mutex.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <asm/barrier.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <drm/drm_atomic.h> 1862306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h> 1962306a36Sopenharmony_ci#include <drm/drm_probe_helper.h> 2062306a36Sopenharmony_ci#include <drm/drm_vblank.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "mtk_drm_drv.h" 2362306a36Sopenharmony_ci#include "mtk_drm_crtc.h" 2462306a36Sopenharmony_ci#include "mtk_drm_ddp_comp.h" 2562306a36Sopenharmony_ci#include "mtk_drm_gem.h" 2662306a36Sopenharmony_ci#include "mtk_drm_plane.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * struct mtk_drm_crtc - MediaTek specific crtc structure. 3062306a36Sopenharmony_ci * @base: crtc object. 3162306a36Sopenharmony_ci * @enabled: records whether crtc_enable succeeded 3262306a36Sopenharmony_ci * @planes: array of 4 drm_plane structures, one for each overlay plane 3362306a36Sopenharmony_ci * @pending_planes: whether any plane has pending changes to be applied 3462306a36Sopenharmony_ci * @mmsys_dev: pointer to the mmsys device for configuration registers 3562306a36Sopenharmony_ci * @mutex: handle to one of the ten disp_mutex streams 3662306a36Sopenharmony_ci * @ddp_comp_nr: number of components in ddp_comp 3762306a36Sopenharmony_ci * @ddp_comp: array of pointers the mtk_ddp_comp structures used by this crtc 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * TODO: Needs update: this header is missing a bunch of member descriptions. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_cistruct mtk_drm_crtc { 4262306a36Sopenharmony_ci struct drm_crtc base; 4362306a36Sopenharmony_ci bool enabled; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci bool pending_needs_vblank; 4662306a36Sopenharmony_ci struct drm_pending_vblank_event *event; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci struct drm_plane *planes; 4962306a36Sopenharmony_ci unsigned int layer_nr; 5062306a36Sopenharmony_ci bool pending_planes; 5162306a36Sopenharmony_ci bool pending_async_planes; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_MTK_CMDQ) 5462306a36Sopenharmony_ci struct cmdq_client cmdq_client; 5562306a36Sopenharmony_ci struct cmdq_pkt cmdq_handle; 5662306a36Sopenharmony_ci u32 cmdq_event; 5762306a36Sopenharmony_ci u32 cmdq_vblank_cnt; 5862306a36Sopenharmony_ci wait_queue_head_t cb_blocking_queue; 5962306a36Sopenharmony_ci#endif 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci struct device *mmsys_dev; 6262306a36Sopenharmony_ci struct device *dma_dev; 6362306a36Sopenharmony_ci struct mtk_mutex *mutex; 6462306a36Sopenharmony_ci unsigned int ddp_comp_nr; 6562306a36Sopenharmony_ci struct mtk_ddp_comp **ddp_comp; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* lock for display hardware access */ 6862306a36Sopenharmony_ci struct mutex hw_lock; 6962306a36Sopenharmony_ci bool config_updating; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct mtk_crtc_state { 7362306a36Sopenharmony_ci struct drm_crtc_state base; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci bool pending_config; 7662306a36Sopenharmony_ci unsigned int pending_width; 7762306a36Sopenharmony_ci unsigned int pending_height; 7862306a36Sopenharmony_ci unsigned int pending_vrefresh; 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic inline struct mtk_drm_crtc *to_mtk_crtc(struct drm_crtc *c) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci return container_of(c, struct mtk_drm_crtc, base); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic inline struct mtk_crtc_state *to_mtk_crtc_state(struct drm_crtc_state *s) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci return container_of(s, struct mtk_crtc_state, base); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void mtk_drm_crtc_finish_page_flip(struct mtk_drm_crtc *mtk_crtc) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct drm_crtc *crtc = &mtk_crtc->base; 9462306a36Sopenharmony_ci unsigned long flags; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (mtk_crtc->event) { 9762306a36Sopenharmony_ci spin_lock_irqsave(&crtc->dev->event_lock, flags); 9862306a36Sopenharmony_ci drm_crtc_send_vblank_event(crtc, mtk_crtc->event); 9962306a36Sopenharmony_ci drm_crtc_vblank_put(crtc); 10062306a36Sopenharmony_ci mtk_crtc->event = NULL; 10162306a36Sopenharmony_ci spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void mtk_drm_finish_page_flip(struct mtk_drm_crtc *mtk_crtc) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci drm_crtc_handle_vblank(&mtk_crtc->base); 10862306a36Sopenharmony_ci if (!mtk_crtc->config_updating && mtk_crtc->pending_needs_vblank) { 10962306a36Sopenharmony_ci mtk_drm_crtc_finish_page_flip(mtk_crtc); 11062306a36Sopenharmony_ci mtk_crtc->pending_needs_vblank = false; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_MTK_CMDQ) 11562306a36Sopenharmony_cistatic int mtk_drm_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, 11662306a36Sopenharmony_ci size_t size) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct device *dev; 11962306a36Sopenharmony_ci dma_addr_t dma_addr; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci pkt->va_base = kzalloc(size, GFP_KERNEL); 12262306a36Sopenharmony_ci if (!pkt->va_base) 12362306a36Sopenharmony_ci return -ENOMEM; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci pkt->buf_size = size; 12662306a36Sopenharmony_ci pkt->cl = (void *)client; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci dev = client->chan->mbox->dev; 12962306a36Sopenharmony_ci dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size, 13062306a36Sopenharmony_ci DMA_TO_DEVICE); 13162306a36Sopenharmony_ci if (dma_mapping_error(dev, dma_addr)) { 13262306a36Sopenharmony_ci dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); 13362306a36Sopenharmony_ci kfree(pkt->va_base); 13462306a36Sopenharmony_ci return -ENOMEM; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci pkt->pa_base = dma_addr; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return 0; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct cmdq_client *client = (struct cmdq_client *)pkt->cl; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size, 14762306a36Sopenharmony_ci DMA_TO_DEVICE); 14862306a36Sopenharmony_ci kfree(pkt->va_base); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci#endif 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void mtk_drm_crtc_destroy(struct drm_crtc *crtc) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 15562306a36Sopenharmony_ci int i; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci mtk_mutex_put(mtk_crtc->mutex); 15862306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_MTK_CMDQ) 15962306a36Sopenharmony_ci mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (mtk_crtc->cmdq_client.chan) { 16262306a36Sopenharmony_ci mbox_free_channel(mtk_crtc->cmdq_client.chan); 16362306a36Sopenharmony_ci mtk_crtc->cmdq_client.chan = NULL; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci#endif 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { 16862306a36Sopenharmony_ci struct mtk_ddp_comp *comp; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci comp = mtk_crtc->ddp_comp[i]; 17162306a36Sopenharmony_ci mtk_ddp_comp_unregister_vblank_cb(comp); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci drm_crtc_cleanup(crtc); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void mtk_drm_crtc_reset(struct drm_crtc *crtc) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct mtk_crtc_state *state; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (crtc->state) 18262306a36Sopenharmony_ci __drm_atomic_helper_crtc_destroy_state(crtc->state); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci kfree(to_mtk_crtc_state(crtc->state)); 18562306a36Sopenharmony_ci crtc->state = NULL; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci state = kzalloc(sizeof(*state), GFP_KERNEL); 18862306a36Sopenharmony_ci if (state) 18962306a36Sopenharmony_ci __drm_atomic_helper_crtc_reset(crtc, &state->base); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct mtk_crtc_state *state; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci state = kmalloc(sizeof(*state), GFP_KERNEL); 19762306a36Sopenharmony_ci if (!state) 19862306a36Sopenharmony_ci return NULL; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci WARN_ON(state->base.crtc != crtc); 20362306a36Sopenharmony_ci state->base.crtc = crtc; 20462306a36Sopenharmony_ci state->pending_config = false; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci return &state->base; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic void mtk_drm_crtc_destroy_state(struct drm_crtc *crtc, 21062306a36Sopenharmony_ci struct drm_crtc_state *state) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci __drm_atomic_helper_crtc_destroy_state(state); 21362306a36Sopenharmony_ci kfree(to_mtk_crtc_state(state)); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic bool mtk_drm_crtc_mode_fixup(struct drm_crtc *crtc, 21762306a36Sopenharmony_ci const struct drm_display_mode *mode, 21862306a36Sopenharmony_ci struct drm_display_mode *adjusted_mode) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci /* Nothing to do here, but this callback is mandatory. */ 22162306a36Sopenharmony_ci return true; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct mtk_crtc_state *state = to_mtk_crtc_state(crtc->state); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci state->pending_width = crtc->mode.hdisplay; 22962306a36Sopenharmony_ci state->pending_height = crtc->mode.vdisplay; 23062306a36Sopenharmony_ci state->pending_vrefresh = drm_mode_vrefresh(&crtc->mode); 23162306a36Sopenharmony_ci wmb(); /* Make sure the above parameters are set before update */ 23262306a36Sopenharmony_ci state->pending_config = true; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int mtk_crtc_ddp_clk_enable(struct mtk_drm_crtc *mtk_crtc) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci int ret; 23862306a36Sopenharmony_ci int i; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { 24162306a36Sopenharmony_ci ret = mtk_ddp_comp_clk_enable(mtk_crtc->ddp_comp[i]); 24262306a36Sopenharmony_ci if (ret) { 24362306a36Sopenharmony_ci DRM_ERROR("Failed to enable clock %d: %d\n", i, ret); 24462306a36Sopenharmony_ci goto err; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_cierr: 25062306a36Sopenharmony_ci while (--i >= 0) 25162306a36Sopenharmony_ci mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]); 25262306a36Sopenharmony_ci return ret; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci int i; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) 26062306a36Sopenharmony_ci mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic 26462306a36Sopenharmony_cistruct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct drm_crtc *crtc, 26562306a36Sopenharmony_ci struct drm_plane *plane, 26662306a36Sopenharmony_ci unsigned int *local_layer) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 26962306a36Sopenharmony_ci struct mtk_ddp_comp *comp; 27062306a36Sopenharmony_ci int i, count = 0; 27162306a36Sopenharmony_ci unsigned int local_index = plane - mtk_crtc->planes; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { 27462306a36Sopenharmony_ci comp = mtk_crtc->ddp_comp[i]; 27562306a36Sopenharmony_ci if (local_index < (count + mtk_ddp_comp_layer_nr(comp))) { 27662306a36Sopenharmony_ci *local_layer = local_index - count; 27762306a36Sopenharmony_ci return comp; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci count += mtk_ddp_comp_layer_nr(comp); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci WARN(1, "Failed to find component for plane %d\n", plane->index); 28362306a36Sopenharmony_ci return NULL; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_MTK_CMDQ) 28762306a36Sopenharmony_cistatic void ddp_cmdq_cb(struct mbox_client *cl, void *mssg) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct cmdq_cb_data *data = mssg; 29062306a36Sopenharmony_ci struct cmdq_client *cmdq_cl = container_of(cl, struct cmdq_client, client); 29162306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = container_of(cmdq_cl, struct mtk_drm_crtc, cmdq_client); 29262306a36Sopenharmony_ci struct mtk_crtc_state *state; 29362306a36Sopenharmony_ci unsigned int i; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (data->sta < 0) 29662306a36Sopenharmony_ci return; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci state = to_mtk_crtc_state(mtk_crtc->base.state); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci state->pending_config = false; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (mtk_crtc->pending_planes) { 30362306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->layer_nr; i++) { 30462306a36Sopenharmony_ci struct drm_plane *plane = &mtk_crtc->planes[i]; 30562306a36Sopenharmony_ci struct mtk_plane_state *plane_state; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci plane_state = to_mtk_plane_state(plane->state); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci plane_state->pending.config = false; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci mtk_crtc->pending_planes = false; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (mtk_crtc->pending_async_planes) { 31562306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->layer_nr; i++) { 31662306a36Sopenharmony_ci struct drm_plane *plane = &mtk_crtc->planes[i]; 31762306a36Sopenharmony_ci struct mtk_plane_state *plane_state; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci plane_state = to_mtk_plane_state(plane->state); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci plane_state->pending.async_config = false; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci mtk_crtc->pending_async_planes = false; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci mtk_crtc->cmdq_vblank_cnt = 0; 32762306a36Sopenharmony_ci wake_up(&mtk_crtc->cb_blocking_queue); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci#endif 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct drm_crtc *crtc = &mtk_crtc->base; 33462306a36Sopenharmony_ci struct drm_connector *connector; 33562306a36Sopenharmony_ci struct drm_encoder *encoder; 33662306a36Sopenharmony_ci struct drm_connector_list_iter conn_iter; 33762306a36Sopenharmony_ci unsigned int width, height, vrefresh, bpc = MTK_MAX_BPC; 33862306a36Sopenharmony_ci int ret; 33962306a36Sopenharmony_ci int i; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (WARN_ON(!crtc->state)) 34262306a36Sopenharmony_ci return -EINVAL; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci width = crtc->state->adjusted_mode.hdisplay; 34562306a36Sopenharmony_ci height = crtc->state->adjusted_mode.vdisplay; 34662306a36Sopenharmony_ci vrefresh = drm_mode_vrefresh(&crtc->state->adjusted_mode); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci drm_for_each_encoder(encoder, crtc->dev) { 34962306a36Sopenharmony_ci if (encoder->crtc != crtc) 35062306a36Sopenharmony_ci continue; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci drm_connector_list_iter_begin(crtc->dev, &conn_iter); 35362306a36Sopenharmony_ci drm_for_each_connector_iter(connector, &conn_iter) { 35462306a36Sopenharmony_ci if (connector->encoder != encoder) 35562306a36Sopenharmony_ci continue; 35662306a36Sopenharmony_ci if (connector->display_info.bpc != 0 && 35762306a36Sopenharmony_ci bpc > connector->display_info.bpc) 35862306a36Sopenharmony_ci bpc = connector->display_info.bpc; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci drm_connector_list_iter_end(&conn_iter); 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(crtc->dev->dev); 36462306a36Sopenharmony_ci if (ret < 0) { 36562306a36Sopenharmony_ci DRM_ERROR("Failed to enable power domain: %d\n", ret); 36662306a36Sopenharmony_ci return ret; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci ret = mtk_mutex_prepare(mtk_crtc->mutex); 37062306a36Sopenharmony_ci if (ret < 0) { 37162306a36Sopenharmony_ci DRM_ERROR("Failed to enable mutex clock: %d\n", ret); 37262306a36Sopenharmony_ci goto err_pm_runtime_put; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci ret = mtk_crtc_ddp_clk_enable(mtk_crtc); 37662306a36Sopenharmony_ci if (ret < 0) { 37762306a36Sopenharmony_ci DRM_ERROR("Failed to enable component clocks: %d\n", ret); 37862306a36Sopenharmony_ci goto err_mutex_unprepare; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { 38262306a36Sopenharmony_ci if (!mtk_ddp_comp_connect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev, 38362306a36Sopenharmony_ci mtk_crtc->ddp_comp[i + 1]->id)) 38462306a36Sopenharmony_ci mtk_mmsys_ddp_connect(mtk_crtc->mmsys_dev, 38562306a36Sopenharmony_ci mtk_crtc->ddp_comp[i]->id, 38662306a36Sopenharmony_ci mtk_crtc->ddp_comp[i + 1]->id); 38762306a36Sopenharmony_ci if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) 38862306a36Sopenharmony_ci mtk_mutex_add_comp(mtk_crtc->mutex, 38962306a36Sopenharmony_ci mtk_crtc->ddp_comp[i]->id); 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) 39262306a36Sopenharmony_ci mtk_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); 39362306a36Sopenharmony_ci mtk_mutex_enable(mtk_crtc->mutex); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { 39662306a36Sopenharmony_ci struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i]; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (i == 1) 39962306a36Sopenharmony_ci mtk_ddp_comp_bgclr_in_on(comp); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci mtk_ddp_comp_config(comp, width, height, vrefresh, bpc, NULL); 40262306a36Sopenharmony_ci mtk_ddp_comp_start(comp); 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* Initially configure all planes */ 40662306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->layer_nr; i++) { 40762306a36Sopenharmony_ci struct drm_plane *plane = &mtk_crtc->planes[i]; 40862306a36Sopenharmony_ci struct mtk_plane_state *plane_state; 40962306a36Sopenharmony_ci struct mtk_ddp_comp *comp; 41062306a36Sopenharmony_ci unsigned int local_layer; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci plane_state = to_mtk_plane_state(plane->state); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* should not enable layer before crtc enabled */ 41562306a36Sopenharmony_ci plane_state->pending.enable = false; 41662306a36Sopenharmony_ci comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer); 41762306a36Sopenharmony_ci if (comp) 41862306a36Sopenharmony_ci mtk_ddp_comp_layer_config(comp, local_layer, 41962306a36Sopenharmony_ci plane_state, NULL); 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return 0; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cierr_mutex_unprepare: 42562306a36Sopenharmony_ci mtk_mutex_unprepare(mtk_crtc->mutex); 42662306a36Sopenharmony_cierr_pm_runtime_put: 42762306a36Sopenharmony_ci pm_runtime_put(crtc->dev->dev); 42862306a36Sopenharmony_ci return ret; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct drm_device *drm = mtk_crtc->base.dev; 43462306a36Sopenharmony_ci struct drm_crtc *crtc = &mtk_crtc->base; 43562306a36Sopenharmony_ci int i; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { 43862306a36Sopenharmony_ci mtk_ddp_comp_stop(mtk_crtc->ddp_comp[i]); 43962306a36Sopenharmony_ci if (i == 1) 44062306a36Sopenharmony_ci mtk_ddp_comp_bgclr_in_off(mtk_crtc->ddp_comp[i]); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) 44462306a36Sopenharmony_ci if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) 44562306a36Sopenharmony_ci mtk_mutex_remove_comp(mtk_crtc->mutex, 44662306a36Sopenharmony_ci mtk_crtc->ddp_comp[i]->id); 44762306a36Sopenharmony_ci mtk_mutex_disable(mtk_crtc->mutex); 44862306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { 44962306a36Sopenharmony_ci if (!mtk_ddp_comp_disconnect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev, 45062306a36Sopenharmony_ci mtk_crtc->ddp_comp[i + 1]->id)) 45162306a36Sopenharmony_ci mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev, 45262306a36Sopenharmony_ci mtk_crtc->ddp_comp[i]->id, 45362306a36Sopenharmony_ci mtk_crtc->ddp_comp[i + 1]->id); 45462306a36Sopenharmony_ci if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) 45562306a36Sopenharmony_ci mtk_mutex_remove_comp(mtk_crtc->mutex, 45662306a36Sopenharmony_ci mtk_crtc->ddp_comp[i]->id); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) 45962306a36Sopenharmony_ci mtk_mutex_remove_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); 46062306a36Sopenharmony_ci mtk_crtc_ddp_clk_disable(mtk_crtc); 46162306a36Sopenharmony_ci mtk_mutex_unprepare(mtk_crtc->mutex); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci pm_runtime_put(drm->dev); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (crtc->state->event && !crtc->state->active) { 46662306a36Sopenharmony_ci spin_lock_irq(&crtc->dev->event_lock); 46762306a36Sopenharmony_ci drm_crtc_send_vblank_event(crtc, crtc->state->event); 46862306a36Sopenharmony_ci crtc->state->event = NULL; 46962306a36Sopenharmony_ci spin_unlock_irq(&crtc->dev->event_lock); 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic void mtk_crtc_ddp_config(struct drm_crtc *crtc, 47462306a36Sopenharmony_ci struct cmdq_pkt *cmdq_handle) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 47762306a36Sopenharmony_ci struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state); 47862306a36Sopenharmony_ci struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; 47962306a36Sopenharmony_ci unsigned int i; 48062306a36Sopenharmony_ci unsigned int local_layer; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* 48362306a36Sopenharmony_ci * TODO: instead of updating the registers here, we should prepare 48462306a36Sopenharmony_ci * working registers in atomic_commit and let the hardware command 48562306a36Sopenharmony_ci * queue update module registers on vblank. 48662306a36Sopenharmony_ci */ 48762306a36Sopenharmony_ci if (state->pending_config) { 48862306a36Sopenharmony_ci mtk_ddp_comp_config(comp, state->pending_width, 48962306a36Sopenharmony_ci state->pending_height, 49062306a36Sopenharmony_ci state->pending_vrefresh, 0, 49162306a36Sopenharmony_ci cmdq_handle); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (!cmdq_handle) 49462306a36Sopenharmony_ci state->pending_config = false; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (mtk_crtc->pending_planes) { 49862306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->layer_nr; i++) { 49962306a36Sopenharmony_ci struct drm_plane *plane = &mtk_crtc->planes[i]; 50062306a36Sopenharmony_ci struct mtk_plane_state *plane_state; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci plane_state = to_mtk_plane_state(plane->state); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (!plane_state->pending.config) 50562306a36Sopenharmony_ci continue; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci comp = mtk_drm_ddp_comp_for_plane(crtc, plane, 50862306a36Sopenharmony_ci &local_layer); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (comp) 51162306a36Sopenharmony_ci mtk_ddp_comp_layer_config(comp, local_layer, 51262306a36Sopenharmony_ci plane_state, 51362306a36Sopenharmony_ci cmdq_handle); 51462306a36Sopenharmony_ci if (!cmdq_handle) 51562306a36Sopenharmony_ci plane_state->pending.config = false; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (!cmdq_handle) 51962306a36Sopenharmony_ci mtk_crtc->pending_planes = false; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (mtk_crtc->pending_async_planes) { 52362306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->layer_nr; i++) { 52462306a36Sopenharmony_ci struct drm_plane *plane = &mtk_crtc->planes[i]; 52562306a36Sopenharmony_ci struct mtk_plane_state *plane_state; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci plane_state = to_mtk_plane_state(plane->state); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (!plane_state->pending.async_config) 53062306a36Sopenharmony_ci continue; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci comp = mtk_drm_ddp_comp_for_plane(crtc, plane, 53362306a36Sopenharmony_ci &local_layer); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (comp) 53662306a36Sopenharmony_ci mtk_ddp_comp_layer_config(comp, local_layer, 53762306a36Sopenharmony_ci plane_state, 53862306a36Sopenharmony_ci cmdq_handle); 53962306a36Sopenharmony_ci if (!cmdq_handle) 54062306a36Sopenharmony_ci plane_state->pending.async_config = false; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (!cmdq_handle) 54462306a36Sopenharmony_ci mtk_crtc->pending_async_planes = false; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc, 54962306a36Sopenharmony_ci bool needs_vblank) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_MTK_CMDQ) 55262306a36Sopenharmony_ci struct cmdq_pkt *cmdq_handle = &mtk_crtc->cmdq_handle; 55362306a36Sopenharmony_ci#endif 55462306a36Sopenharmony_ci struct drm_crtc *crtc = &mtk_crtc->base; 55562306a36Sopenharmony_ci struct mtk_drm_private *priv = crtc->dev->dev_private; 55662306a36Sopenharmony_ci unsigned int pending_planes = 0, pending_async_planes = 0; 55762306a36Sopenharmony_ci int i; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci mutex_lock(&mtk_crtc->hw_lock); 56062306a36Sopenharmony_ci mtk_crtc->config_updating = true; 56162306a36Sopenharmony_ci if (needs_vblank) 56262306a36Sopenharmony_ci mtk_crtc->pending_needs_vblank = true; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->layer_nr; i++) { 56562306a36Sopenharmony_ci struct drm_plane *plane = &mtk_crtc->planes[i]; 56662306a36Sopenharmony_ci struct mtk_plane_state *plane_state; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci plane_state = to_mtk_plane_state(plane->state); 56962306a36Sopenharmony_ci if (plane_state->pending.dirty) { 57062306a36Sopenharmony_ci plane_state->pending.config = true; 57162306a36Sopenharmony_ci plane_state->pending.dirty = false; 57262306a36Sopenharmony_ci pending_planes |= BIT(i); 57362306a36Sopenharmony_ci } else if (plane_state->pending.async_dirty) { 57462306a36Sopenharmony_ci plane_state->pending.async_config = true; 57562306a36Sopenharmony_ci plane_state->pending.async_dirty = false; 57662306a36Sopenharmony_ci pending_async_planes |= BIT(i); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci if (pending_planes) 58062306a36Sopenharmony_ci mtk_crtc->pending_planes = true; 58162306a36Sopenharmony_ci if (pending_async_planes) 58262306a36Sopenharmony_ci mtk_crtc->pending_async_planes = true; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (priv->data->shadow_register) { 58562306a36Sopenharmony_ci mtk_mutex_acquire(mtk_crtc->mutex); 58662306a36Sopenharmony_ci mtk_crtc_ddp_config(crtc, NULL); 58762306a36Sopenharmony_ci mtk_mutex_release(mtk_crtc->mutex); 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_MTK_CMDQ) 59062306a36Sopenharmony_ci if (mtk_crtc->cmdq_client.chan) { 59162306a36Sopenharmony_ci mbox_flush(mtk_crtc->cmdq_client.chan, 2000); 59262306a36Sopenharmony_ci cmdq_handle->cmd_buf_size = 0; 59362306a36Sopenharmony_ci cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event); 59462306a36Sopenharmony_ci cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false); 59562306a36Sopenharmony_ci mtk_crtc_ddp_config(crtc, cmdq_handle); 59662306a36Sopenharmony_ci cmdq_pkt_finalize(cmdq_handle); 59762306a36Sopenharmony_ci dma_sync_single_for_device(mtk_crtc->cmdq_client.chan->mbox->dev, 59862306a36Sopenharmony_ci cmdq_handle->pa_base, 59962306a36Sopenharmony_ci cmdq_handle->cmd_buf_size, 60062306a36Sopenharmony_ci DMA_TO_DEVICE); 60162306a36Sopenharmony_ci /* 60262306a36Sopenharmony_ci * CMDQ command should execute in next 3 vblank. 60362306a36Sopenharmony_ci * One vblank interrupt before send message (occasionally) 60462306a36Sopenharmony_ci * and one vblank interrupt after cmdq done, 60562306a36Sopenharmony_ci * so it's timeout after 3 vblank interrupt. 60662306a36Sopenharmony_ci * If it fail to execute in next 3 vblank, timeout happen. 60762306a36Sopenharmony_ci */ 60862306a36Sopenharmony_ci mtk_crtc->cmdq_vblank_cnt = 3; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle); 61162306a36Sopenharmony_ci mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0); 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci#endif 61462306a36Sopenharmony_ci mtk_crtc->config_updating = false; 61562306a36Sopenharmony_ci mutex_unlock(&mtk_crtc->hw_lock); 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic void mtk_crtc_ddp_irq(void *data) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci struct drm_crtc *crtc = data; 62162306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 62262306a36Sopenharmony_ci struct mtk_drm_private *priv = crtc->dev->dev_private; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_MTK_CMDQ) 62562306a36Sopenharmony_ci if (!priv->data->shadow_register && !mtk_crtc->cmdq_client.chan) 62662306a36Sopenharmony_ci mtk_crtc_ddp_config(crtc, NULL); 62762306a36Sopenharmony_ci else if (mtk_crtc->cmdq_vblank_cnt > 0 && --mtk_crtc->cmdq_vblank_cnt == 0) 62862306a36Sopenharmony_ci DRM_ERROR("mtk_crtc %d CMDQ execute command timeout!\n", 62962306a36Sopenharmony_ci drm_crtc_index(&mtk_crtc->base)); 63062306a36Sopenharmony_ci#else 63162306a36Sopenharmony_ci if (!priv->data->shadow_register) 63262306a36Sopenharmony_ci mtk_crtc_ddp_config(crtc, NULL); 63362306a36Sopenharmony_ci#endif 63462306a36Sopenharmony_ci mtk_drm_finish_page_flip(mtk_crtc); 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic int mtk_drm_crtc_enable_vblank(struct drm_crtc *crtc) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 64062306a36Sopenharmony_ci struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci mtk_ddp_comp_enable_vblank(comp); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci return 0; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic void mtk_drm_crtc_disable_vblank(struct drm_crtc *crtc) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 65062306a36Sopenharmony_ci struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci mtk_ddp_comp_disable_vblank(comp); 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ciint mtk_drm_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane, 65662306a36Sopenharmony_ci struct mtk_plane_state *state) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci unsigned int local_layer; 65962306a36Sopenharmony_ci struct mtk_ddp_comp *comp; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer); 66262306a36Sopenharmony_ci if (comp) 66362306a36Sopenharmony_ci return mtk_ddp_comp_layer_check(comp, local_layer, state); 66462306a36Sopenharmony_ci return 0; 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_civoid mtk_drm_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane, 66862306a36Sopenharmony_ci struct drm_atomic_state *state) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (!mtk_crtc->enabled) 67362306a36Sopenharmony_ci return; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci mtk_drm_crtc_update_config(mtk_crtc, false); 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc, 67962306a36Sopenharmony_ci struct drm_atomic_state *state) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 68262306a36Sopenharmony_ci struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; 68362306a36Sopenharmony_ci int ret; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(comp->dev); 68862306a36Sopenharmony_ci if (ret < 0) { 68962306a36Sopenharmony_ci DRM_DEV_ERROR(comp->dev, "Failed to enable power domain: %d\n", ret); 69062306a36Sopenharmony_ci return; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci ret = mtk_crtc_ddp_hw_init(mtk_crtc); 69462306a36Sopenharmony_ci if (ret) { 69562306a36Sopenharmony_ci pm_runtime_put(comp->dev); 69662306a36Sopenharmony_ci return; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci drm_crtc_vblank_on(crtc); 70062306a36Sopenharmony_ci mtk_crtc->enabled = true; 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc, 70462306a36Sopenharmony_ci struct drm_atomic_state *state) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 70762306a36Sopenharmony_ci struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; 70862306a36Sopenharmony_ci int i, ret; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id); 71162306a36Sopenharmony_ci if (!mtk_crtc->enabled) 71262306a36Sopenharmony_ci return; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* Set all pending plane state to disabled */ 71562306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->layer_nr; i++) { 71662306a36Sopenharmony_ci struct drm_plane *plane = &mtk_crtc->planes[i]; 71762306a36Sopenharmony_ci struct mtk_plane_state *plane_state; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci plane_state = to_mtk_plane_state(plane->state); 72062306a36Sopenharmony_ci plane_state->pending.enable = false; 72162306a36Sopenharmony_ci plane_state->pending.config = true; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci mtk_crtc->pending_planes = true; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci mtk_drm_crtc_update_config(mtk_crtc, false); 72662306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_MTK_CMDQ) 72762306a36Sopenharmony_ci /* Wait for planes to be disabled by cmdq */ 72862306a36Sopenharmony_ci if (mtk_crtc->cmdq_client.chan) 72962306a36Sopenharmony_ci wait_event_timeout(mtk_crtc->cb_blocking_queue, 73062306a36Sopenharmony_ci mtk_crtc->cmdq_vblank_cnt == 0, 73162306a36Sopenharmony_ci msecs_to_jiffies(500)); 73262306a36Sopenharmony_ci#endif 73362306a36Sopenharmony_ci /* Wait for planes to be disabled */ 73462306a36Sopenharmony_ci drm_crtc_wait_one_vblank(crtc); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci drm_crtc_vblank_off(crtc); 73762306a36Sopenharmony_ci mtk_crtc_ddp_hw_fini(mtk_crtc); 73862306a36Sopenharmony_ci ret = pm_runtime_put(comp->dev); 73962306a36Sopenharmony_ci if (ret < 0) 74062306a36Sopenharmony_ci DRM_DEV_ERROR(comp->dev, "Failed to disable power domain: %d\n", ret); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci mtk_crtc->enabled = false; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic void mtk_drm_crtc_atomic_begin(struct drm_crtc *crtc, 74662306a36Sopenharmony_ci struct drm_atomic_state *state) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, 74962306a36Sopenharmony_ci crtc); 75062306a36Sopenharmony_ci struct mtk_crtc_state *mtk_crtc_state = to_mtk_crtc_state(crtc_state); 75162306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 75262306a36Sopenharmony_ci unsigned long flags; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (mtk_crtc->event && mtk_crtc_state->base.event) 75562306a36Sopenharmony_ci DRM_ERROR("new event while there is still a pending event\n"); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (mtk_crtc_state->base.event) { 75862306a36Sopenharmony_ci mtk_crtc_state->base.event->pipe = drm_crtc_index(crtc); 75962306a36Sopenharmony_ci WARN_ON(drm_crtc_vblank_get(crtc) != 0); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci spin_lock_irqsave(&crtc->dev->event_lock, flags); 76262306a36Sopenharmony_ci mtk_crtc->event = mtk_crtc_state->base.event; 76362306a36Sopenharmony_ci spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci mtk_crtc_state->base.event = NULL; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc, 77062306a36Sopenharmony_ci struct drm_atomic_state *state) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 77362306a36Sopenharmony_ci int i; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (crtc->state->color_mgmt_changed) 77662306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { 77762306a36Sopenharmony_ci mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state); 77862306a36Sopenharmony_ci mtk_ddp_ctm_set(mtk_crtc->ddp_comp[i], crtc->state); 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci mtk_drm_crtc_update_config(mtk_crtc, !!mtk_crtc->event); 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic const struct drm_crtc_funcs mtk_crtc_funcs = { 78462306a36Sopenharmony_ci .set_config = drm_atomic_helper_set_config, 78562306a36Sopenharmony_ci .page_flip = drm_atomic_helper_page_flip, 78662306a36Sopenharmony_ci .destroy = mtk_drm_crtc_destroy, 78762306a36Sopenharmony_ci .reset = mtk_drm_crtc_reset, 78862306a36Sopenharmony_ci .atomic_duplicate_state = mtk_drm_crtc_duplicate_state, 78962306a36Sopenharmony_ci .atomic_destroy_state = mtk_drm_crtc_destroy_state, 79062306a36Sopenharmony_ci .enable_vblank = mtk_drm_crtc_enable_vblank, 79162306a36Sopenharmony_ci .disable_vblank = mtk_drm_crtc_disable_vblank, 79262306a36Sopenharmony_ci}; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = { 79562306a36Sopenharmony_ci .mode_fixup = mtk_drm_crtc_mode_fixup, 79662306a36Sopenharmony_ci .mode_set_nofb = mtk_drm_crtc_mode_set_nofb, 79762306a36Sopenharmony_ci .atomic_begin = mtk_drm_crtc_atomic_begin, 79862306a36Sopenharmony_ci .atomic_flush = mtk_drm_crtc_atomic_flush, 79962306a36Sopenharmony_ci .atomic_enable = mtk_drm_crtc_atomic_enable, 80062306a36Sopenharmony_ci .atomic_disable = mtk_drm_crtc_atomic_disable, 80162306a36Sopenharmony_ci}; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic int mtk_drm_crtc_init(struct drm_device *drm, 80462306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc, 80562306a36Sopenharmony_ci unsigned int pipe) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci struct drm_plane *primary = NULL; 80862306a36Sopenharmony_ci struct drm_plane *cursor = NULL; 80962306a36Sopenharmony_ci int i, ret; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->layer_nr; i++) { 81262306a36Sopenharmony_ci if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_PRIMARY) 81362306a36Sopenharmony_ci primary = &mtk_crtc->planes[i]; 81462306a36Sopenharmony_ci else if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_CURSOR) 81562306a36Sopenharmony_ci cursor = &mtk_crtc->planes[i]; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci ret = drm_crtc_init_with_planes(drm, &mtk_crtc->base, primary, cursor, 81962306a36Sopenharmony_ci &mtk_crtc_funcs, NULL); 82062306a36Sopenharmony_ci if (ret) 82162306a36Sopenharmony_ci goto err_cleanup_crtc; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci drm_crtc_helper_add(&mtk_crtc->base, &mtk_crtc_helper_funcs); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci return 0; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cierr_cleanup_crtc: 82862306a36Sopenharmony_ci drm_crtc_cleanup(&mtk_crtc->base); 82962306a36Sopenharmony_ci return ret; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic int mtk_drm_crtc_num_comp_planes(struct mtk_drm_crtc *mtk_crtc, 83362306a36Sopenharmony_ci int comp_idx) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci struct mtk_ddp_comp *comp; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (comp_idx > 1) 83862306a36Sopenharmony_ci return 0; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci comp = mtk_crtc->ddp_comp[comp_idx]; 84162306a36Sopenharmony_ci if (!comp->funcs) 84262306a36Sopenharmony_ci return 0; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (comp_idx == 1 && !comp->funcs->bgclr_in_on) 84562306a36Sopenharmony_ci return 0; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci return mtk_ddp_comp_layer_nr(comp); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic inline 85162306a36Sopenharmony_cienum drm_plane_type mtk_drm_crtc_plane_type(unsigned int plane_idx, 85262306a36Sopenharmony_ci unsigned int num_planes) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci if (plane_idx == 0) 85562306a36Sopenharmony_ci return DRM_PLANE_TYPE_PRIMARY; 85662306a36Sopenharmony_ci else if (plane_idx == (num_planes - 1)) 85762306a36Sopenharmony_ci return DRM_PLANE_TYPE_CURSOR; 85862306a36Sopenharmony_ci else 85962306a36Sopenharmony_ci return DRM_PLANE_TYPE_OVERLAY; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic int mtk_drm_crtc_init_comp_planes(struct drm_device *drm_dev, 86462306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc, 86562306a36Sopenharmony_ci int comp_idx, int pipe) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci int num_planes = mtk_drm_crtc_num_comp_planes(mtk_crtc, comp_idx); 86862306a36Sopenharmony_ci struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[comp_idx]; 86962306a36Sopenharmony_ci int i, ret; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci for (i = 0; i < num_planes; i++) { 87262306a36Sopenharmony_ci ret = mtk_plane_init(drm_dev, 87362306a36Sopenharmony_ci &mtk_crtc->planes[mtk_crtc->layer_nr], 87462306a36Sopenharmony_ci BIT(pipe), 87562306a36Sopenharmony_ci mtk_drm_crtc_plane_type(mtk_crtc->layer_nr, 87662306a36Sopenharmony_ci num_planes), 87762306a36Sopenharmony_ci mtk_ddp_comp_supported_rotations(comp), 87862306a36Sopenharmony_ci mtk_ddp_comp_get_formats(comp), 87962306a36Sopenharmony_ci mtk_ddp_comp_get_num_formats(comp)); 88062306a36Sopenharmony_ci if (ret) 88162306a36Sopenharmony_ci return ret; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci mtk_crtc->layer_nr++; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci return 0; 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistruct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc *crtc) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc = NULL; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (!crtc) 89362306a36Sopenharmony_ci return NULL; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci mtk_crtc = to_mtk_crtc(crtc); 89662306a36Sopenharmony_ci if (!mtk_crtc) 89762306a36Sopenharmony_ci return NULL; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci return mtk_crtc->dma_dev; 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ciint mtk_drm_crtc_create(struct drm_device *drm_dev, 90362306a36Sopenharmony_ci const unsigned int *path, unsigned int path_len, 90462306a36Sopenharmony_ci int priv_data_index) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci struct mtk_drm_private *priv = drm_dev->dev_private; 90762306a36Sopenharmony_ci struct device *dev = drm_dev->dev; 90862306a36Sopenharmony_ci struct mtk_drm_crtc *mtk_crtc; 90962306a36Sopenharmony_ci unsigned int num_comp_planes = 0; 91062306a36Sopenharmony_ci int ret; 91162306a36Sopenharmony_ci int i; 91262306a36Sopenharmony_ci bool has_ctm = false; 91362306a36Sopenharmony_ci uint gamma_lut_size = 0; 91462306a36Sopenharmony_ci struct drm_crtc *tmp; 91562306a36Sopenharmony_ci int crtc_i = 0; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci if (!path) 91862306a36Sopenharmony_ci return 0; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci priv = priv->all_drm_private[priv_data_index]; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci drm_for_each_crtc(tmp, drm_dev) 92362306a36Sopenharmony_ci crtc_i++; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci for (i = 0; i < path_len; i++) { 92662306a36Sopenharmony_ci enum mtk_ddp_comp_id comp_id = path[i]; 92762306a36Sopenharmony_ci struct device_node *node; 92862306a36Sopenharmony_ci struct mtk_ddp_comp *comp; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci node = priv->comp_node[comp_id]; 93162306a36Sopenharmony_ci comp = &priv->ddp_comp[comp_id]; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* Not all drm components have a DTS device node, such as ovl_adaptor, 93462306a36Sopenharmony_ci * which is the drm bring up sub driver 93562306a36Sopenharmony_ci */ 93662306a36Sopenharmony_ci if (!node && comp_id != DDP_COMPONENT_DRM_OVL_ADAPTOR) { 93762306a36Sopenharmony_ci dev_info(dev, 93862306a36Sopenharmony_ci "Not creating crtc %d because component %d is disabled or missing\n", 93962306a36Sopenharmony_ci crtc_i, comp_id); 94062306a36Sopenharmony_ci return 0; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci if (!comp->dev) { 94462306a36Sopenharmony_ci dev_err(dev, "Component %pOF not initialized\n", node); 94562306a36Sopenharmony_ci return -ENODEV; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci mtk_crtc = devm_kzalloc(dev, sizeof(*mtk_crtc), GFP_KERNEL); 95062306a36Sopenharmony_ci if (!mtk_crtc) 95162306a36Sopenharmony_ci return -ENOMEM; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci mtk_crtc->mmsys_dev = priv->mmsys_dev; 95462306a36Sopenharmony_ci mtk_crtc->ddp_comp_nr = path_len; 95562306a36Sopenharmony_ci mtk_crtc->ddp_comp = devm_kmalloc_array(dev, mtk_crtc->ddp_comp_nr, 95662306a36Sopenharmony_ci sizeof(*mtk_crtc->ddp_comp), 95762306a36Sopenharmony_ci GFP_KERNEL); 95862306a36Sopenharmony_ci if (!mtk_crtc->ddp_comp) 95962306a36Sopenharmony_ci return -ENOMEM; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci mtk_crtc->mutex = mtk_mutex_get(priv->mutex_dev); 96262306a36Sopenharmony_ci if (IS_ERR(mtk_crtc->mutex)) { 96362306a36Sopenharmony_ci ret = PTR_ERR(mtk_crtc->mutex); 96462306a36Sopenharmony_ci dev_err(dev, "Failed to get mutex: %d\n", ret); 96562306a36Sopenharmony_ci return ret; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { 96962306a36Sopenharmony_ci unsigned int comp_id = path[i]; 97062306a36Sopenharmony_ci struct mtk_ddp_comp *comp; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci comp = &priv->ddp_comp[comp_id]; 97362306a36Sopenharmony_ci mtk_crtc->ddp_comp[i] = comp; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (comp->funcs) { 97662306a36Sopenharmony_ci if (comp->funcs->gamma_set) 97762306a36Sopenharmony_ci gamma_lut_size = MTK_LUT_SIZE; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci if (comp->funcs->ctm_set) 98062306a36Sopenharmony_ci has_ctm = true; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq, 98462306a36Sopenharmony_ci &mtk_crtc->base); 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) 98862306a36Sopenharmony_ci num_comp_planes += mtk_drm_crtc_num_comp_planes(mtk_crtc, i); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci mtk_crtc->planes = devm_kcalloc(dev, num_comp_planes, 99162306a36Sopenharmony_ci sizeof(struct drm_plane), GFP_KERNEL); 99262306a36Sopenharmony_ci if (!mtk_crtc->planes) 99362306a36Sopenharmony_ci return -ENOMEM; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { 99662306a36Sopenharmony_ci ret = mtk_drm_crtc_init_comp_planes(drm_dev, mtk_crtc, i, 99762306a36Sopenharmony_ci crtc_i); 99862306a36Sopenharmony_ci if (ret) 99962306a36Sopenharmony_ci return ret; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci /* 100362306a36Sopenharmony_ci * Default to use the first component as the dma dev. 100462306a36Sopenharmony_ci * In the case of ovl_adaptor sub driver, it needs to use the 100562306a36Sopenharmony_ci * dma_dev_get function to get representative dma dev. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_ci mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(&priv->ddp_comp[path[0]]); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, crtc_i); 101062306a36Sopenharmony_ci if (ret < 0) 101162306a36Sopenharmony_ci return ret; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci if (gamma_lut_size) 101462306a36Sopenharmony_ci drm_mode_crtc_set_gamma_size(&mtk_crtc->base, gamma_lut_size); 101562306a36Sopenharmony_ci drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, has_ctm, gamma_lut_size); 101662306a36Sopenharmony_ci mutex_init(&mtk_crtc->hw_lock); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_MTK_CMDQ) 101962306a36Sopenharmony_ci i = priv->mbox_index++; 102062306a36Sopenharmony_ci mtk_crtc->cmdq_client.client.dev = mtk_crtc->mmsys_dev; 102162306a36Sopenharmony_ci mtk_crtc->cmdq_client.client.tx_block = false; 102262306a36Sopenharmony_ci mtk_crtc->cmdq_client.client.knows_txdone = true; 102362306a36Sopenharmony_ci mtk_crtc->cmdq_client.client.rx_callback = ddp_cmdq_cb; 102462306a36Sopenharmony_ci mtk_crtc->cmdq_client.chan = 102562306a36Sopenharmony_ci mbox_request_channel(&mtk_crtc->cmdq_client.client, i); 102662306a36Sopenharmony_ci if (IS_ERR(mtk_crtc->cmdq_client.chan)) { 102762306a36Sopenharmony_ci dev_dbg(dev, "mtk_crtc %d failed to create mailbox client, writing register by CPU now\n", 102862306a36Sopenharmony_ci drm_crtc_index(&mtk_crtc->base)); 102962306a36Sopenharmony_ci mtk_crtc->cmdq_client.chan = NULL; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (mtk_crtc->cmdq_client.chan) { 103362306a36Sopenharmony_ci ret = of_property_read_u32_index(priv->mutex_node, 103462306a36Sopenharmony_ci "mediatek,gce-events", 103562306a36Sopenharmony_ci i, 103662306a36Sopenharmony_ci &mtk_crtc->cmdq_event); 103762306a36Sopenharmony_ci if (ret) { 103862306a36Sopenharmony_ci dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n", 103962306a36Sopenharmony_ci drm_crtc_index(&mtk_crtc->base)); 104062306a36Sopenharmony_ci mbox_free_channel(mtk_crtc->cmdq_client.chan); 104162306a36Sopenharmony_ci mtk_crtc->cmdq_client.chan = NULL; 104262306a36Sopenharmony_ci } else { 104362306a36Sopenharmony_ci ret = mtk_drm_cmdq_pkt_create(&mtk_crtc->cmdq_client, 104462306a36Sopenharmony_ci &mtk_crtc->cmdq_handle, 104562306a36Sopenharmony_ci PAGE_SIZE); 104662306a36Sopenharmony_ci if (ret) { 104762306a36Sopenharmony_ci dev_dbg(dev, "mtk_crtc %d failed to create cmdq packet\n", 104862306a36Sopenharmony_ci drm_crtc_index(&mtk_crtc->base)); 104962306a36Sopenharmony_ci mbox_free_channel(mtk_crtc->cmdq_client.chan); 105062306a36Sopenharmony_ci mtk_crtc->cmdq_client.chan = NULL; 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci } 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci /* for sending blocking cmd in crtc disable */ 105562306a36Sopenharmony_ci init_waitqueue_head(&mtk_crtc->cb_blocking_queue); 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci#endif 105862306a36Sopenharmony_ci return 0; 105962306a36Sopenharmony_ci} 1060