From 7f3a4257159dea8e7ef66d1a539dc6df708b8ed3 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 7 Aug 2024 15:17:46 +0200 Subject: Adding upstream version 6.10.3. Signed-off-by: Daniel Baumann --- drivers/gpu/drm/mediatek/Kconfig | 2 +- drivers/gpu/drm/mediatek/Makefile | 12 +- drivers/gpu/drm/mediatek/mtk_crtc.c | 1138 ++++++++++++++++++++++ drivers/gpu/drm/mediatek/mtk_crtc.h | 28 + drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 684 ++++++++++++++ drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 346 +++++++ drivers/gpu/drm/mediatek/mtk_disp_aal.c | 5 +- drivers/gpu/drm/mediatek/mtk_disp_ccorr.c | 5 +- drivers/gpu/drm/mediatek/mtk_disp_color.c | 5 +- drivers/gpu/drm/mediatek/mtk_disp_drv.h | 2 +- drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 5 +- drivers/gpu/drm/mediatek/mtk_disp_merge.c | 3 +- drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 46 +- drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c | 7 +- drivers/gpu/drm/mediatek/mtk_disp_rdma.c | 5 +- drivers/gpu/drm/mediatek/mtk_dp.c | 10 +- drivers/gpu/drm/mediatek/mtk_dpi.c | 7 +- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 1146 ----------------------- drivers/gpu/drm/mediatek/mtk_drm_crtc.h | 30 - drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 644 ------------- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 343 ------- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 58 +- drivers/gpu/drm/mediatek/mtk_drm_drv.h | 8 +- drivers/gpu/drm/mediatek/mtk_drm_gem.c | 288 ------ drivers/gpu/drm/mediatek/mtk_drm_gem.h | 49 - drivers/gpu/drm/mediatek/mtk_drm_plane.c | 350 ------- drivers/gpu/drm/mediatek/mtk_drm_plane.h | 54 -- drivers/gpu/drm/mediatek/mtk_dsi.c | 36 +- drivers/gpu/drm/mediatek/mtk_ethdr.c | 26 +- drivers/gpu/drm/mediatek/mtk_gem.c | 288 ++++++ drivers/gpu/drm/mediatek/mtk_gem.h | 48 + drivers/gpu/drm/mediatek/mtk_hdmi.c | 14 +- drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c | 3 +- drivers/gpu/drm/mediatek/mtk_mdp_rdma.c | 1 - drivers/gpu/drm/mediatek/mtk_padding.c | 5 +- drivers/gpu/drm/mediatek/mtk_plane.c | 352 +++++++ drivers/gpu/drm/mediatek/mtk_plane.h | 54 ++ 37 files changed, 3098 insertions(+), 3009 deletions(-) create mode 100644 drivers/gpu/drm/mediatek/mtk_crtc.c create mode 100644 drivers/gpu/drm/mediatek/mtk_crtc.h create mode 100644 drivers/gpu/drm/mediatek/mtk_ddp_comp.c create mode 100644 drivers/gpu/drm/mediatek/mtk_ddp_comp.h delete mode 100644 drivers/gpu/drm/mediatek/mtk_drm_crtc.c delete mode 100644 drivers/gpu/drm/mediatek/mtk_drm_crtc.h delete mode 100644 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c delete mode 100644 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h delete mode 100644 drivers/gpu/drm/mediatek/mtk_drm_gem.c delete mode 100644 drivers/gpu/drm/mediatek/mtk_drm_gem.h delete mode 100644 drivers/gpu/drm/mediatek/mtk_drm_plane.c delete mode 100644 drivers/gpu/drm/mediatek/mtk_drm_plane.h create mode 100644 drivers/gpu/drm/mediatek/mtk_gem.c create mode 100644 drivers/gpu/drm/mediatek/mtk_gem.h create mode 100644 drivers/gpu/drm/mediatek/mtk_plane.c create mode 100644 drivers/gpu/drm/mediatek/mtk_plane.h (limited to 'drivers/gpu/drm/mediatek') diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig index 76cab28e01..96cbe020f4 100644 --- a/drivers/gpu/drm/mediatek/Kconfig +++ b/drivers/gpu/drm/mediatek/Kconfig @@ -26,7 +26,7 @@ config DRM_MEDIATEK_DP select PHY_MTK_DP select DRM_DISPLAY_HELPER select DRM_DISPLAY_DP_HELPER - select DRM_DP_AUX_BUS + select DRM_DISPLAY_DP_AUX_BUS help DRM/KMS Display Port driver for MediaTek SoCs. diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile index 5e4436403b..32a2ed6c0c 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 -mediatek-drm-y := mtk_disp_aal.o \ +mediatek-drm-y := mtk_crtc.o \ + mtk_ddp_comp.o \ + mtk_disp_aal.o \ mtk_disp_ccorr.o \ mtk_disp_color.o \ mtk_disp_gamma.o \ @@ -8,16 +10,14 @@ mediatek-drm-y := mtk_disp_aal.o \ mtk_disp_ovl.o \ mtk_disp_ovl_adaptor.o \ mtk_disp_rdma.o \ - mtk_drm_crtc.o \ - mtk_drm_ddp_comp.o \ mtk_drm_drv.o \ - mtk_drm_gem.o \ - mtk_drm_plane.o \ mtk_dsi.o \ mtk_dpi.o \ mtk_ethdr.o \ + mtk_gem.o \ mtk_mdp_rdma.o \ - mtk_padding.o + mtk_padding.o \ + mtk_plane.o obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c new file mode 100644 index 0000000000..6f34f573e1 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_crtc.c @@ -0,0 +1,1138 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" +#include "mtk_drm_drv.h" +#include "mtk_gem.h" +#include "mtk_plane.h" + +/* + * struct mtk_crtc - MediaTek specific crtc structure. + * @base: crtc object. + * @enabled: records whether crtc_enable succeeded + * @planes: array of 4 drm_plane structures, one for each overlay plane + * @pending_planes: whether any plane has pending changes to be applied + * @mmsys_dev: pointer to the mmsys device for configuration registers + * @mutex: handle to one of the ten disp_mutex streams + * @ddp_comp_nr: number of components in ddp_comp + * @ddp_comp: array of pointers the mtk_ddp_comp structures used by this crtc + * + * TODO: Needs update: this header is missing a bunch of member descriptions. + */ +struct mtk_crtc { + struct drm_crtc base; + bool enabled; + + bool pending_needs_vblank; + struct drm_pending_vblank_event *event; + + struct drm_plane *planes; + unsigned int layer_nr; + bool pending_planes; + bool pending_async_planes; + +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + struct cmdq_client cmdq_client; + struct cmdq_pkt cmdq_handle; + u32 cmdq_event; + u32 cmdq_vblank_cnt; + wait_queue_head_t cb_blocking_queue; +#endif + + struct device *mmsys_dev; + struct device *dma_dev; + struct mtk_mutex *mutex; + unsigned int ddp_comp_nr; + struct mtk_ddp_comp **ddp_comp; + unsigned int num_conn_routes; + const struct mtk_drm_route *conn_routes; + + /* lock for display hardware access */ + struct mutex hw_lock; + bool config_updating; +}; + +struct mtk_crtc_state { + struct drm_crtc_state base; + + bool pending_config; + unsigned int pending_width; + unsigned int pending_height; + unsigned int pending_vrefresh; +}; + +static inline struct mtk_crtc *to_mtk_crtc(struct drm_crtc *c) +{ + return container_of(c, struct mtk_crtc, base); +} + +static inline struct mtk_crtc_state *to_mtk_crtc_state(struct drm_crtc_state *s) +{ + return container_of(s, struct mtk_crtc_state, base); +} + +static void mtk_crtc_finish_page_flip(struct mtk_crtc *mtk_crtc) +{ + struct drm_crtc *crtc = &mtk_crtc->base; + unsigned long flags; + + if (mtk_crtc->event) { + spin_lock_irqsave(&crtc->dev->event_lock, flags); + drm_crtc_send_vblank_event(crtc, mtk_crtc->event); + drm_crtc_vblank_put(crtc); + mtk_crtc->event = NULL; + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + } +} + +static void mtk_drm_finish_page_flip(struct mtk_crtc *mtk_crtc) +{ + drm_crtc_handle_vblank(&mtk_crtc->base); + if (!mtk_crtc->config_updating && mtk_crtc->pending_needs_vblank) { + mtk_crtc_finish_page_flip(mtk_crtc); + mtk_crtc->pending_needs_vblank = false; + } +} + +#if IS_REACHABLE(CONFIG_MTK_CMDQ) +static int mtk_drm_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, + size_t size) +{ + struct device *dev; + dma_addr_t dma_addr; + + pkt->va_base = kzalloc(size, GFP_KERNEL); + if (!pkt->va_base) + return -ENOMEM; + + pkt->buf_size = size; + pkt->cl = (void *)client; + + dev = client->chan->mbox->dev; + dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, dma_addr)) { + dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); + kfree(pkt->va_base); + return -ENOMEM; + } + + pkt->pa_base = dma_addr; + + return 0; +} + +static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt) +{ + struct cmdq_client *client = (struct cmdq_client *)pkt->cl; + + dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size, + DMA_TO_DEVICE); + kfree(pkt->va_base); +} +#endif + +static void mtk_crtc_destroy(struct drm_crtc *crtc) +{ + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + int i; + + mtk_mutex_put(mtk_crtc->mutex); +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle); + + if (mtk_crtc->cmdq_client.chan) { + mbox_free_channel(mtk_crtc->cmdq_client.chan); + mtk_crtc->cmdq_client.chan = NULL; + } +#endif + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { + struct mtk_ddp_comp *comp; + + comp = mtk_crtc->ddp_comp[i]; + mtk_ddp_comp_unregister_vblank_cb(comp); + } + + drm_crtc_cleanup(crtc); +} + +static void mtk_crtc_reset(struct drm_crtc *crtc) +{ + struct mtk_crtc_state *state; + + if (crtc->state) + __drm_atomic_helper_crtc_destroy_state(crtc->state); + + kfree(to_mtk_crtc_state(crtc->state)); + crtc->state = NULL; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_crtc_reset(crtc, &state->base); +} + +static struct drm_crtc_state *mtk_crtc_duplicate_state(struct drm_crtc *crtc) +{ + struct mtk_crtc_state *state; + + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); + + WARN_ON(state->base.crtc != crtc); + state->base.crtc = crtc; + state->pending_config = false; + + return &state->base; +} + +static void mtk_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + __drm_atomic_helper_crtc_destroy_state(state); + kfree(to_mtk_crtc_state(state)); +} + +static enum drm_mode_status +mtk_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) +{ + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + enum drm_mode_status status = MODE_OK; + int i; + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { + status = mtk_ddp_comp_mode_valid(mtk_crtc->ddp_comp[i], mode); + if (status != MODE_OK) + break; + } + return status; +} + +static bool mtk_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* Nothing to do here, but this callback is mandatory. */ + return true; +} + +static void mtk_crtc_mode_set_nofb(struct drm_crtc *crtc) +{ + struct mtk_crtc_state *state = to_mtk_crtc_state(crtc->state); + + state->pending_width = crtc->mode.hdisplay; + state->pending_height = crtc->mode.vdisplay; + state->pending_vrefresh = drm_mode_vrefresh(&crtc->mode); + wmb(); /* Make sure the above parameters are set before update */ + state->pending_config = true; +} + +static int mtk_crtc_ddp_clk_enable(struct mtk_crtc *mtk_crtc) +{ + int ret; + int i; + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { + ret = mtk_ddp_comp_clk_enable(mtk_crtc->ddp_comp[i]); + if (ret) { + DRM_ERROR("Failed to enable clock %d: %d\n", i, ret); + goto err; + } + } + + return 0; +err: + while (--i >= 0) + mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]); + return ret; +} + +static void mtk_crtc_ddp_clk_disable(struct mtk_crtc *mtk_crtc) +{ + int i; + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) + mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]); +} + +static +struct mtk_ddp_comp *mtk_ddp_comp_for_plane(struct drm_crtc *crtc, + struct drm_plane *plane, + unsigned int *local_layer) +{ + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + struct mtk_ddp_comp *comp; + int i, count = 0; + unsigned int local_index = plane - mtk_crtc->planes; + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { + comp = mtk_crtc->ddp_comp[i]; + if (local_index < (count + mtk_ddp_comp_layer_nr(comp))) { + *local_layer = local_index - count; + return comp; + } + count += mtk_ddp_comp_layer_nr(comp); + } + + WARN(1, "Failed to find component for plane %d\n", plane->index); + return NULL; +} + +#if IS_REACHABLE(CONFIG_MTK_CMDQ) +static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg) +{ + struct cmdq_cb_data *data = mssg; + struct cmdq_client *cmdq_cl = container_of(cl, struct cmdq_client, client); + struct mtk_crtc *mtk_crtc = container_of(cmdq_cl, struct mtk_crtc, cmdq_client); + struct mtk_crtc_state *state; + unsigned int i; + + if (data->sta < 0) + return; + + state = to_mtk_crtc_state(mtk_crtc->base.state); + + state->pending_config = false; + + if (mtk_crtc->pending_planes) { + for (i = 0; i < mtk_crtc->layer_nr; i++) { + struct drm_plane *plane = &mtk_crtc->planes[i]; + struct mtk_plane_state *plane_state; + + plane_state = to_mtk_plane_state(plane->state); + + plane_state->pending.config = false; + } + mtk_crtc->pending_planes = false; + } + + if (mtk_crtc->pending_async_planes) { + for (i = 0; i < mtk_crtc->layer_nr; i++) { + struct drm_plane *plane = &mtk_crtc->planes[i]; + struct mtk_plane_state *plane_state; + + plane_state = to_mtk_plane_state(plane->state); + + plane_state->pending.async_config = false; + } + mtk_crtc->pending_async_planes = false; + } + + mtk_crtc->cmdq_vblank_cnt = 0; + wake_up(&mtk_crtc->cb_blocking_queue); +} +#endif + +static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc) +{ + struct drm_crtc *crtc = &mtk_crtc->base; + struct drm_connector *connector; + struct drm_encoder *encoder; + struct drm_connector_list_iter conn_iter; + unsigned int width, height, vrefresh, bpc = MTK_MAX_BPC; + int ret; + int i; + + if (WARN_ON(!crtc->state)) + return -EINVAL; + + width = crtc->state->adjusted_mode.hdisplay; + height = crtc->state->adjusted_mode.vdisplay; + vrefresh = drm_mode_vrefresh(&crtc->state->adjusted_mode); + + drm_for_each_encoder(encoder, crtc->dev) { + if (encoder->crtc != crtc) + continue; + + drm_connector_list_iter_begin(crtc->dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + if (connector->encoder != encoder) + continue; + if (connector->display_info.bpc != 0 && + bpc > connector->display_info.bpc) + bpc = connector->display_info.bpc; + } + drm_connector_list_iter_end(&conn_iter); + } + + ret = pm_runtime_resume_and_get(crtc->dev->dev); + if (ret < 0) { + DRM_ERROR("Failed to enable power domain: %d\n", ret); + return ret; + } + + ret = mtk_mutex_prepare(mtk_crtc->mutex); + if (ret < 0) { + DRM_ERROR("Failed to enable mutex clock: %d\n", ret); + goto err_pm_runtime_put; + } + + ret = mtk_crtc_ddp_clk_enable(mtk_crtc); + if (ret < 0) { + DRM_ERROR("Failed to enable component clocks: %d\n", ret); + goto err_mutex_unprepare; + } + + for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { + if (!mtk_ddp_comp_connect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev, + mtk_crtc->ddp_comp[i + 1]->id)) + mtk_mmsys_ddp_connect(mtk_crtc->mmsys_dev, + mtk_crtc->ddp_comp[i]->id, + mtk_crtc->ddp_comp[i + 1]->id); + if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) + mtk_mutex_add_comp(mtk_crtc->mutex, + mtk_crtc->ddp_comp[i]->id); + } + if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) + mtk_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); + mtk_mutex_enable(mtk_crtc->mutex); + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { + struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i]; + + if (i == 1) + mtk_ddp_comp_bgclr_in_on(comp); + + mtk_ddp_comp_config(comp, width, height, vrefresh, bpc, NULL); + mtk_ddp_comp_start(comp); + } + + /* Initially configure all planes */ + for (i = 0; i < mtk_crtc->layer_nr; i++) { + struct drm_plane *plane = &mtk_crtc->planes[i]; + struct mtk_plane_state *plane_state; + struct mtk_ddp_comp *comp; + unsigned int local_layer; + + plane_state = to_mtk_plane_state(plane->state); + + /* should not enable layer before crtc enabled */ + plane_state->pending.enable = false; + comp = mtk_ddp_comp_for_plane(crtc, plane, &local_layer); + if (comp) + mtk_ddp_comp_layer_config(comp, local_layer, + plane_state, NULL); + } + + return 0; + +err_mutex_unprepare: + mtk_mutex_unprepare(mtk_crtc->mutex); +err_pm_runtime_put: + pm_runtime_put(crtc->dev->dev); + return ret; +} + +static void mtk_crtc_ddp_hw_fini(struct mtk_crtc *mtk_crtc) +{ + struct drm_device *drm = mtk_crtc->base.dev; + struct drm_crtc *crtc = &mtk_crtc->base; + int i; + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { + mtk_ddp_comp_stop(mtk_crtc->ddp_comp[i]); + if (i == 1) + mtk_ddp_comp_bgclr_in_off(mtk_crtc->ddp_comp[i]); + } + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) + if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) + mtk_mutex_remove_comp(mtk_crtc->mutex, + mtk_crtc->ddp_comp[i]->id); + mtk_mutex_disable(mtk_crtc->mutex); + for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { + if (!mtk_ddp_comp_disconnect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev, + mtk_crtc->ddp_comp[i + 1]->id)) + mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev, + mtk_crtc->ddp_comp[i]->id, + mtk_crtc->ddp_comp[i + 1]->id); + if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) + mtk_mutex_remove_comp(mtk_crtc->mutex, + mtk_crtc->ddp_comp[i]->id); + } + if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) + mtk_mutex_remove_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); + mtk_crtc_ddp_clk_disable(mtk_crtc); + mtk_mutex_unprepare(mtk_crtc->mutex); + + pm_runtime_put(drm->dev); + + if (crtc->state->event && !crtc->state->active) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + spin_unlock_irq(&crtc->dev->event_lock); + } +} + +static void mtk_crtc_ddp_config(struct drm_crtc *crtc, + struct cmdq_pkt *cmdq_handle) +{ + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state); + struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; + unsigned int i; + unsigned int local_layer; + + /* + * TODO: instead of updating the registers here, we should prepare + * working registers in atomic_commit and let the hardware command + * queue update module registers on vblank. + */ + if (state->pending_config) { + mtk_ddp_comp_config(comp, state->pending_width, + state->pending_height, + state->pending_vrefresh, 0, + cmdq_handle); + + if (!cmdq_handle) + state->pending_config = false; + } + + if (mtk_crtc->pending_planes) { + for (i = 0; i < mtk_crtc->layer_nr; i++) { + struct drm_plane *plane = &mtk_crtc->planes[i]; + struct mtk_plane_state *plane_state; + + plane_state = to_mtk_plane_state(plane->state); + + if (!plane_state->pending.config) + continue; + + comp = mtk_ddp_comp_for_plane(crtc, plane, &local_layer); + + if (comp) + mtk_ddp_comp_layer_config(comp, local_layer, + plane_state, + cmdq_handle); + if (!cmdq_handle) + plane_state->pending.config = false; + } + + if (!cmdq_handle) + mtk_crtc->pending_planes = false; + } + + if (mtk_crtc->pending_async_planes) { + for (i = 0; i < mtk_crtc->layer_nr; i++) { + struct drm_plane *plane = &mtk_crtc->planes[i]; + struct mtk_plane_state *plane_state; + + plane_state = to_mtk_plane_state(plane->state); + + if (!plane_state->pending.async_config) + continue; + + comp = mtk_ddp_comp_for_plane(crtc, plane, &local_layer); + + if (comp) + mtk_ddp_comp_layer_config(comp, local_layer, + plane_state, + cmdq_handle); + if (!cmdq_handle) + plane_state->pending.async_config = false; + } + + if (!cmdq_handle) + mtk_crtc->pending_async_planes = false; + } +} + +static void mtk_crtc_update_config(struct mtk_crtc *mtk_crtc, bool needs_vblank) +{ +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + struct cmdq_pkt *cmdq_handle = &mtk_crtc->cmdq_handle; +#endif + struct drm_crtc *crtc = &mtk_crtc->base; + struct mtk_drm_private *priv = crtc->dev->dev_private; + unsigned int pending_planes = 0, pending_async_planes = 0; + int i; + + mutex_lock(&mtk_crtc->hw_lock); + mtk_crtc->config_updating = true; + if (needs_vblank) + mtk_crtc->pending_needs_vblank = true; + + for (i = 0; i < mtk_crtc->layer_nr; i++) { + struct drm_plane *plane = &mtk_crtc->planes[i]; + struct mtk_plane_state *plane_state; + + plane_state = to_mtk_plane_state(plane->state); + if (plane_state->pending.dirty) { + plane_state->pending.config = true; + plane_state->pending.dirty = false; + pending_planes |= BIT(i); + } else if (plane_state->pending.async_dirty) { + plane_state->pending.async_config = true; + plane_state->pending.async_dirty = false; + pending_async_planes |= BIT(i); + } + } + if (pending_planes) + mtk_crtc->pending_planes = true; + if (pending_async_planes) + mtk_crtc->pending_async_planes = true; + + if (priv->data->shadow_register) { + mtk_mutex_acquire(mtk_crtc->mutex); + mtk_crtc_ddp_config(crtc, NULL); + mtk_mutex_release(mtk_crtc->mutex); + } +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + if (mtk_crtc->cmdq_client.chan) { + mbox_flush(mtk_crtc->cmdq_client.chan, 2000); + cmdq_handle->cmd_buf_size = 0; + cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event); + cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false); + mtk_crtc_ddp_config(crtc, cmdq_handle); + cmdq_pkt_finalize(cmdq_handle); + dma_sync_single_for_device(mtk_crtc->cmdq_client.chan->mbox->dev, + cmdq_handle->pa_base, + cmdq_handle->cmd_buf_size, + DMA_TO_DEVICE); + /* + * CMDQ command should execute in next 3 vblank. + * One vblank interrupt before send message (occasionally) + * and one vblank interrupt after cmdq done, + * so it's timeout after 3 vblank interrupt. + * If it fail to execute in next 3 vblank, timeout happen. + */ + mtk_crtc->cmdq_vblank_cnt = 3; + + mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle); + mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0); + } +#endif + mtk_crtc->config_updating = false; + mutex_unlock(&mtk_crtc->hw_lock); +} + +static void mtk_crtc_ddp_irq(void *data) +{ + struct drm_crtc *crtc = data; + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + struct mtk_drm_private *priv = crtc->dev->dev_private; + +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + if (!priv->data->shadow_register && !mtk_crtc->cmdq_client.chan) + mtk_crtc_ddp_config(crtc, NULL); + else if (mtk_crtc->cmdq_vblank_cnt > 0 && --mtk_crtc->cmdq_vblank_cnt == 0) + DRM_ERROR("mtk_crtc %d CMDQ execute command timeout!\n", + drm_crtc_index(&mtk_crtc->base)); +#else + if (!priv->data->shadow_register) + mtk_crtc_ddp_config(crtc, NULL); +#endif + mtk_drm_finish_page_flip(mtk_crtc); +} + +static int mtk_crtc_enable_vblank(struct drm_crtc *crtc) +{ + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; + + mtk_ddp_comp_enable_vblank(comp); + + return 0; +} + +static void mtk_crtc_disable_vblank(struct drm_crtc *crtc) +{ + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; + + mtk_ddp_comp_disable_vblank(comp); +} + +static void mtk_crtc_update_output(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + int crtc_index = drm_crtc_index(crtc); + int i; + struct device *dev; + struct drm_crtc_state *crtc_state = state->crtcs[crtc_index].new_state; + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + struct mtk_drm_private *priv; + unsigned int encoder_mask = crtc_state->encoder_mask; + + if (!crtc_state->connectors_changed) + return; + + if (!mtk_crtc->num_conn_routes) + return; + + priv = ((struct mtk_drm_private *)crtc->dev->dev_private)->all_drm_private[crtc_index]; + dev = priv->dev; + + dev_dbg(dev, "connector change:%d, encoder mask:0x%x for crtc:%d\n", + crtc_state->connectors_changed, encoder_mask, crtc_index); + + for (i = 0; i < mtk_crtc->num_conn_routes; i++) { + unsigned int comp_id = mtk_crtc->conn_routes[i].route_ddp; + struct mtk_ddp_comp *comp = &priv->ddp_comp[comp_id]; + + if (comp->encoder_index >= 0 && + (encoder_mask & BIT(comp->encoder_index))) { + mtk_crtc->ddp_comp[mtk_crtc->ddp_comp_nr - 1] = comp; + dev_dbg(dev, "Add comp_id: %d at path index %d\n", + comp->id, mtk_crtc->ddp_comp_nr - 1); + break; + } + } +} + +int mtk_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane, + struct mtk_plane_state *state) +{ + unsigned int local_layer; + struct mtk_ddp_comp *comp; + + comp = mtk_ddp_comp_for_plane(crtc, plane, &local_layer); + if (comp) + return mtk_ddp_comp_layer_check(comp, local_layer, state); + return 0; +} + +void mtk_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + + if (!mtk_crtc->enabled) + return; + + mtk_crtc_update_config(mtk_crtc, false); +} + +static void mtk_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; + int ret; + + DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id); + + ret = mtk_ddp_comp_power_on(comp); + if (ret < 0) { + DRM_DEV_ERROR(comp->dev, "Failed to enable power domain: %d\n", ret); + return; + } + + mtk_crtc_update_output(crtc, state); + + ret = mtk_crtc_ddp_hw_init(mtk_crtc); + if (ret) { + mtk_ddp_comp_power_off(comp); + return; + } + + drm_crtc_vblank_on(crtc); + mtk_crtc->enabled = true; +} + +static void mtk_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; + int i; + + DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id); + if (!mtk_crtc->enabled) + return; + + /* Set all pending plane state to disabled */ + for (i = 0; i < mtk_crtc->layer_nr; i++) { + struct drm_plane *plane = &mtk_crtc->planes[i]; + struct mtk_plane_state *plane_state; + + plane_state = to_mtk_plane_state(plane->state); + plane_state->pending.enable = false; + plane_state->pending.config = true; + } + mtk_crtc->pending_planes = true; + + mtk_crtc_update_config(mtk_crtc, false); +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + /* Wait for planes to be disabled by cmdq */ + if (mtk_crtc->cmdq_client.chan) + wait_event_timeout(mtk_crtc->cb_blocking_queue, + mtk_crtc->cmdq_vblank_cnt == 0, + msecs_to_jiffies(500)); +#endif + /* Wait for planes to be disabled */ + drm_crtc_wait_one_vblank(crtc); + + drm_crtc_vblank_off(crtc); + mtk_crtc_ddp_hw_fini(mtk_crtc); + mtk_ddp_comp_power_off(comp); + + mtk_crtc->enabled = false; +} + +static void mtk_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, + crtc); + struct mtk_crtc_state *mtk_crtc_state = to_mtk_crtc_state(crtc_state); + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + unsigned long flags; + + if (mtk_crtc->event && mtk_crtc_state->base.event) + DRM_ERROR("new event while there is still a pending event\n"); + + if (mtk_crtc_state->base.event) { + mtk_crtc_state->base.event->pipe = drm_crtc_index(crtc); + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + spin_lock_irqsave(&crtc->dev->event_lock, flags); + mtk_crtc->event = mtk_crtc_state->base.event; + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + + mtk_crtc_state->base.event = NULL; + } +} + +static void mtk_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc); + int i; + + if (crtc->state->color_mgmt_changed) + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { + mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state); + mtk_ddp_ctm_set(mtk_crtc->ddp_comp[i], crtc->state); + } + mtk_crtc_update_config(mtk_crtc, !!mtk_crtc->event); +} + +static const struct drm_crtc_funcs mtk_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .destroy = mtk_crtc_destroy, + .reset = mtk_crtc_reset, + .atomic_duplicate_state = mtk_crtc_duplicate_state, + .atomic_destroy_state = mtk_crtc_destroy_state, + .enable_vblank = mtk_crtc_enable_vblank, + .disable_vblank = mtk_crtc_disable_vblank, +}; + +static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = { + .mode_fixup = mtk_crtc_mode_fixup, + .mode_set_nofb = mtk_crtc_mode_set_nofb, + .mode_valid = mtk_crtc_mode_valid, + .atomic_begin = mtk_crtc_atomic_begin, + .atomic_flush = mtk_crtc_atomic_flush, + .atomic_enable = mtk_crtc_atomic_enable, + .atomic_disable = mtk_crtc_atomic_disable, +}; + +static int mtk_crtc_init(struct drm_device *drm, struct mtk_crtc *mtk_crtc, + unsigned int pipe) +{ + struct drm_plane *primary = NULL; + struct drm_plane *cursor = NULL; + int i, ret; + + for (i = 0; i < mtk_crtc->layer_nr; i++) { + if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_PRIMARY) + primary = &mtk_crtc->planes[i]; + else if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_CURSOR) + cursor = &mtk_crtc->planes[i]; + } + + ret = drm_crtc_init_with_planes(drm, &mtk_crtc->base, primary, cursor, + &mtk_crtc_funcs, NULL); + if (ret) + goto err_cleanup_crtc; + + drm_crtc_helper_add(&mtk_crtc->base, &mtk_crtc_helper_funcs); + + return 0; + +err_cleanup_crtc: + drm_crtc_cleanup(&mtk_crtc->base); + return ret; +} + +static int mtk_crtc_num_comp_planes(struct mtk_crtc *mtk_crtc, int comp_idx) +{ + struct mtk_ddp_comp *comp; + + if (comp_idx > 1) + return 0; + + comp = mtk_crtc->ddp_comp[comp_idx]; + if (!comp->funcs) + return 0; + + if (comp_idx == 1 && !comp->funcs->bgclr_in_on) + return 0; + + return mtk_ddp_comp_layer_nr(comp); +} + +static inline +enum drm_plane_type mtk_crtc_plane_type(unsigned int plane_idx, + unsigned int num_planes) +{ + if (plane_idx == 0) + return DRM_PLANE_TYPE_PRIMARY; + else if (plane_idx == (num_planes - 1)) + return DRM_PLANE_TYPE_CURSOR; + else + return DRM_PLANE_TYPE_OVERLAY; + +} + +static int mtk_crtc_init_comp_planes(struct drm_device *drm_dev, + struct mtk_crtc *mtk_crtc, + int comp_idx, int pipe) +{ + int num_planes = mtk_crtc_num_comp_planes(mtk_crtc, comp_idx); + struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[comp_idx]; + int i, ret; + + for (i = 0; i < num_planes; i++) { + ret = mtk_plane_init(drm_dev, + &mtk_crtc->planes[mtk_crtc->layer_nr], + BIT(pipe), + mtk_crtc_plane_type(mtk_crtc->layer_nr, num_planes), + mtk_ddp_comp_supported_rotations(comp), + mtk_ddp_comp_get_formats(comp), + mtk_ddp_comp_get_num_formats(comp)); + if (ret) + return ret; + + mtk_crtc->layer_nr++; + } + return 0; +} + +struct device *mtk_crtc_dma_dev_get(struct drm_crtc *crtc) +{ + struct mtk_crtc *mtk_crtc = NULL; + + if (!crtc) + return NULL; + + mtk_crtc = to_mtk_crtc(crtc); + if (!mtk_crtc) + return NULL; + + return mtk_crtc->dma_dev; +} + +int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path, + unsigned int path_len, int priv_data_index, + const struct mtk_drm_route *conn_routes, + unsigned int num_conn_routes) +{ + struct mtk_drm_private *priv = drm_dev->dev_private; + struct device *dev = drm_dev->dev; + struct mtk_crtc *mtk_crtc; + unsigned int num_comp_planes = 0; + int ret; + int i; + bool has_ctm = false; + uint gamma_lut_size = 0; + struct drm_crtc *tmp; + int crtc_i = 0; + + if (!path) + return 0; + + priv = priv->all_drm_private[priv_data_index]; + + drm_for_each_crtc(tmp, drm_dev) + crtc_i++; + + for (i = 0; i < path_len; i++) { + enum mtk_ddp_comp_id comp_id = path[i]; + struct device_node *node; + struct mtk_ddp_comp *comp; + + node = priv->comp_node[comp_id]; + comp = &priv->ddp_comp[comp_id]; + + /* Not all drm components have a DTS device node, such as ovl_adaptor, + * which is the drm bring up sub driver + */ + if (!node && comp_id != DDP_COMPONENT_DRM_OVL_ADAPTOR) { + dev_info(dev, + "Not creating crtc %d because component %d is disabled or missing\n", + crtc_i, comp_id); + return 0; + } + + if (!comp->dev) { + dev_err(dev, "Component %pOF not initialized\n", node); + return -ENODEV; + } + } + + mtk_crtc = devm_kzalloc(dev, sizeof(*mtk_crtc), GFP_KERNEL); + if (!mtk_crtc) + return -ENOMEM; + + mtk_crtc->mmsys_dev = priv->mmsys_dev; + mtk_crtc->ddp_comp_nr = path_len; + mtk_crtc->ddp_comp = devm_kcalloc(dev, + mtk_crtc->ddp_comp_nr + (conn_routes ? 1 : 0), + sizeof(*mtk_crtc->ddp_comp), + GFP_KERNEL); + if (!mtk_crtc->ddp_comp) + return -ENOMEM; + + mtk_crtc->mutex = mtk_mutex_get(priv->mutex_dev); + if (IS_ERR(mtk_crtc->mutex)) { + ret = PTR_ERR(mtk_crtc->mutex); + dev_err(dev, "Failed to get mutex: %d\n", ret); + return ret; + } + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { + unsigned int comp_id = path[i]; + struct mtk_ddp_comp *comp; + + comp = &priv->ddp_comp[comp_id]; + mtk_crtc->ddp_comp[i] = comp; + + if (comp->funcs) { + if (comp->funcs->gamma_set && comp->funcs->gamma_get_lut_size) { + unsigned int lut_sz = mtk_ddp_gamma_get_lut_size(comp); + + if (lut_sz) + gamma_lut_size = lut_sz; + } + + if (comp->funcs->ctm_set) + has_ctm = true; + } + + mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq, + &mtk_crtc->base); + } + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) + num_comp_planes += mtk_crtc_num_comp_planes(mtk_crtc, i); + + mtk_crtc->planes = devm_kcalloc(dev, num_comp_planes, + sizeof(struct drm_plane), GFP_KERNEL); + if (!mtk_crtc->planes) + return -ENOMEM; + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { + ret = mtk_crtc_init_comp_planes(drm_dev, mtk_crtc, i, crtc_i); + if (ret) + return ret; + } + + /* + * Default to use the first component as the dma dev. + * In the case of ovl_adaptor sub driver, it needs to use the + * dma_dev_get function to get representative dma dev. + */ + mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(&priv->ddp_comp[path[0]]); + + ret = mtk_crtc_init(drm_dev, mtk_crtc, crtc_i); + if (ret < 0) + return ret; + + if (gamma_lut_size) + drm_mode_crtc_set_gamma_size(&mtk_crtc->base, gamma_lut_size); + drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, has_ctm, gamma_lut_size); + mutex_init(&mtk_crtc->hw_lock); + +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + i = priv->mbox_index++; + mtk_crtc->cmdq_client.client.dev = mtk_crtc->mmsys_dev; + mtk_crtc->cmdq_client.client.tx_block = false; + mtk_crtc->cmdq_client.client.knows_txdone = true; + mtk_crtc->cmdq_client.client.rx_callback = ddp_cmdq_cb; + mtk_crtc->cmdq_client.chan = + mbox_request_channel(&mtk_crtc->cmdq_client.client, i); + if (IS_ERR(mtk_crtc->cmdq_client.chan)) { + dev_dbg(dev, "mtk_crtc %d failed to create mailbox client, writing register by CPU now\n", + drm_crtc_index(&mtk_crtc->base)); + mtk_crtc->cmdq_client.chan = NULL; + } + + if (mtk_crtc->cmdq_client.chan) { + ret = of_property_read_u32_index(priv->mutex_node, + "mediatek,gce-events", + i, + &mtk_crtc->cmdq_event); + if (ret) { + dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n", + drm_crtc_index(&mtk_crtc->base)); + mbox_free_channel(mtk_crtc->cmdq_client.chan); + mtk_crtc->cmdq_client.chan = NULL; + } else { + ret = mtk_drm_cmdq_pkt_create(&mtk_crtc->cmdq_client, + &mtk_crtc->cmdq_handle, + PAGE_SIZE); + if (ret) { + dev_dbg(dev, "mtk_crtc %d failed to create cmdq packet\n", + drm_crtc_index(&mtk_crtc->base)); + mbox_free_channel(mtk_crtc->cmdq_client.chan); + mtk_crtc->cmdq_client.chan = NULL; + } + } + + /* for sending blocking cmd in crtc disable */ + init_waitqueue_head(&mtk_crtc->cb_blocking_queue); + } +#endif + + if (conn_routes) { + for (i = 0; i < num_conn_routes; i++) { + unsigned int comp_id = conn_routes[i].route_ddp; + struct device_node *node = priv->comp_node[comp_id]; + struct mtk_ddp_comp *comp = &priv->ddp_comp[comp_id]; + + if (!comp->dev) { + dev_dbg(dev, "comp_id:%d, Component %pOF not initialized\n", + comp_id, node); + /* mark encoder_index to -1, if route comp device is not enabled */ + comp->encoder_index = -1; + continue; + } + + mtk_ddp_comp_encoder_index_set(&priv->ddp_comp[comp_id]); + } + + mtk_crtc->num_conn_routes = num_conn_routes; + mtk_crtc->conn_routes = conn_routes; + + /* increase ddp_comp_nr at the end of mtk_crtc_create */ + mtk_crtc->ddp_comp_nr++; + } + + return 0; +} diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.h b/drivers/gpu/drm/mediatek/mtk_crtc.h new file mode 100644 index 0000000000..388e900b6f --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_crtc.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015 MediaTek Inc. + */ + +#ifndef MTK_CRTC_H +#define MTK_CRTC_H + +#include +#include "mtk_ddp_comp.h" +#include "mtk_drm_drv.h" +#include "mtk_plane.h" + +#define MTK_MAX_BPC 10 +#define MTK_MIN_BPC 3 + +void mtk_crtc_commit(struct drm_crtc *crtc); +int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path, + unsigned int path_len, int priv_data_index, + const struct mtk_drm_route *conn_routes, + unsigned int num_conn_routes); +int mtk_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane, + struct mtk_plane_state *state); +void mtk_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane, + struct drm_atomic_state *plane_state); +struct device *mtk_crtc_dma_dev_get(struct drm_crtc *crtc); + +#endif /* MTK_CRTC_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c new file mode 100644 index 0000000000..be66d94be3 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c @@ -0,0 +1,684 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015 MediaTek Inc. + * Authors: + * YT Shen + * CK Hu + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" +#include "mtk_disp_drv.h" +#include "mtk_drm_drv.h" +#include "mtk_plane.h" + + +#define DISP_REG_DITHER_EN 0x0000 +#define DITHER_EN BIT(0) +#define DISP_REG_DITHER_CFG 0x0020 +#define DITHER_RELAY_MODE BIT(0) +#define DITHER_ENGINE_EN BIT(1) +#define DISP_DITHERING BIT(2) +#define DISP_REG_DITHER_SIZE 0x0030 +#define DISP_REG_DITHER_5 0x0114 +#define DISP_REG_DITHER_7 0x011c +#define DISP_REG_DITHER_15 0x013c +#define DITHER_LSB_ERR_SHIFT_R(x) (((x) & 0x7) << 28) +#define DITHER_ADD_LSHIFT_R(x) (((x) & 0x7) << 20) +#define DITHER_NEW_BIT_MODE BIT(0) +#define DISP_REG_DITHER_16 0x0140 +#define DITHER_LSB_ERR_SHIFT_B(x) (((x) & 0x7) << 28) +#define DITHER_ADD_LSHIFT_B(x) (((x) & 0x7) << 20) +#define DITHER_LSB_ERR_SHIFT_G(x) (((x) & 0x7) << 12) +#define DITHER_ADD_LSHIFT_G(x) (((x) & 0x7) << 4) + +#define DISP_REG_DSC_CON 0x0000 +#define DSC_EN BIT(0) +#define DSC_DUAL_INOUT BIT(2) +#define DSC_BYPASS BIT(4) +#define DSC_UFOE_SEL BIT(16) + +#define DISP_REG_OD_EN 0x0000 +#define DISP_REG_OD_CFG 0x0020 +#define OD_RELAYMODE BIT(0) +#define DISP_REG_OD_SIZE 0x0030 + +#define DISP_REG_POSTMASK_EN 0x0000 +#define POSTMASK_EN BIT(0) +#define DISP_REG_POSTMASK_CFG 0x0020 +#define POSTMASK_RELAY_MODE BIT(0) +#define DISP_REG_POSTMASK_SIZE 0x0030 + +#define DISP_REG_UFO_START 0x0000 +#define UFO_BYPASS BIT(2) + +struct mtk_ddp_comp_dev { + struct clk *clk; + void __iomem *regs; + struct cmdq_client_reg cmdq_reg; +}; + +void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value, + struct cmdq_client_reg *cmdq_reg, void __iomem *regs, + unsigned int offset) +{ +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + if (cmdq_pkt) + cmdq_pkt_write(cmdq_pkt, cmdq_reg->subsys, + cmdq_reg->offset + offset, value); + else +#endif + writel(value, regs + offset); +} + +void mtk_ddp_write_relaxed(struct cmdq_pkt *cmdq_pkt, unsigned int value, + struct cmdq_client_reg *cmdq_reg, void __iomem *regs, + unsigned int offset) +{ +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + if (cmdq_pkt) + cmdq_pkt_write(cmdq_pkt, cmdq_reg->subsys, + cmdq_reg->offset + offset, value); + else +#endif + writel_relaxed(value, regs + offset); +} + +void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, unsigned int value, + struct cmdq_client_reg *cmdq_reg, void __iomem *regs, + unsigned int offset, unsigned int mask) +{ +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + if (cmdq_pkt) { + cmdq_pkt_write_mask(cmdq_pkt, cmdq_reg->subsys, + cmdq_reg->offset + offset, value, mask); + } else { +#endif + u32 tmp = readl(regs + offset); + + tmp = (tmp & ~mask) | (value & mask); + writel(tmp, regs + offset); +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + } +#endif +} + +static int mtk_ddp_clk_enable(struct device *dev) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + return clk_prepare_enable(priv->clk); +} + +static void mtk_ddp_clk_disable(struct device *dev) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + clk_disable_unprepare(priv->clk); +} + +void mtk_dither_set_common(void __iomem *regs, struct cmdq_client_reg *cmdq_reg, + unsigned int bpc, unsigned int cfg, + unsigned int dither_en, struct cmdq_pkt *cmdq_pkt) +{ + /* If bpc equal to 0, the dithering function didn't be enabled */ + if (bpc == 0) + return; + + if (bpc >= MTK_MIN_BPC) { + mtk_ddp_write(cmdq_pkt, 0, cmdq_reg, regs, DISP_REG_DITHER_5); + mtk_ddp_write(cmdq_pkt, 0, cmdq_reg, regs, DISP_REG_DITHER_7); + mtk_ddp_write(cmdq_pkt, + DITHER_LSB_ERR_SHIFT_R(MTK_MAX_BPC - bpc) | + DITHER_ADD_LSHIFT_R(MTK_MAX_BPC - bpc) | + DITHER_NEW_BIT_MODE, + cmdq_reg, regs, DISP_REG_DITHER_15); + mtk_ddp_write(cmdq_pkt, + DITHER_LSB_ERR_SHIFT_B(MTK_MAX_BPC - bpc) | + DITHER_ADD_LSHIFT_B(MTK_MAX_BPC - bpc) | + DITHER_LSB_ERR_SHIFT_G(MTK_MAX_BPC - bpc) | + DITHER_ADD_LSHIFT_G(MTK_MAX_BPC - bpc), + cmdq_reg, regs, DISP_REG_DITHER_16); + mtk_ddp_write(cmdq_pkt, dither_en, cmdq_reg, regs, cfg); + } +} + +static void mtk_dither_config(struct device *dev, unsigned int w, + unsigned int h, unsigned int vrefresh, + unsigned int bpc, struct cmdq_pkt *cmdq_pkt) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, DISP_REG_DITHER_SIZE); + mtk_ddp_write(cmdq_pkt, DITHER_RELAY_MODE, &priv->cmdq_reg, priv->regs, + DISP_REG_DITHER_CFG); + mtk_dither_set_common(priv->regs, &priv->cmdq_reg, bpc, DISP_REG_DITHER_CFG, + DITHER_ENGINE_EN, cmdq_pkt); +} + +static void mtk_dither_start(struct device *dev) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + writel(DITHER_EN, priv->regs + DISP_REG_DITHER_EN); +} + +static void mtk_dither_stop(struct device *dev) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + writel_relaxed(0x0, priv->regs + DISP_REG_DITHER_EN); +} + +static void mtk_dither_set(struct device *dev, unsigned int bpc, + unsigned int cfg, struct cmdq_pkt *cmdq_pkt) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + mtk_dither_set_common(priv->regs, &priv->cmdq_reg, bpc, cfg, + DISP_DITHERING, cmdq_pkt); +} + +static void mtk_dsc_config(struct device *dev, unsigned int w, + unsigned int h, unsigned int vrefresh, + unsigned int bpc, struct cmdq_pkt *cmdq_pkt) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + /* dsc bypass mode */ + mtk_ddp_write_mask(cmdq_pkt, DSC_BYPASS, &priv->cmdq_reg, priv->regs, + DISP_REG_DSC_CON, DSC_BYPASS); + mtk_ddp_write_mask(cmdq_pkt, DSC_UFOE_SEL, &priv->cmdq_reg, priv->regs, + DISP_REG_DSC_CON, DSC_UFOE_SEL); + mtk_ddp_write_mask(cmdq_pkt, DSC_DUAL_INOUT, &priv->cmdq_reg, priv->regs, + DISP_REG_DSC_CON, DSC_DUAL_INOUT); +} + +static void mtk_dsc_start(struct device *dev) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + /* write with mask to reserve the value set in mtk_dsc_config */ + mtk_ddp_write_mask(NULL, DSC_EN, &priv->cmdq_reg, priv->regs, DISP_REG_DSC_CON, DSC_EN); +} + +static void mtk_dsc_stop(struct device *dev) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + writel_relaxed(0x0, priv->regs + DISP_REG_DSC_CON); +} + +static void mtk_od_config(struct device *dev, unsigned int w, + unsigned int h, unsigned int vrefresh, + unsigned int bpc, struct cmdq_pkt *cmdq_pkt) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, DISP_REG_OD_SIZE); + mtk_ddp_write(cmdq_pkt, OD_RELAYMODE, &priv->cmdq_reg, priv->regs, DISP_REG_OD_CFG); + mtk_dither_set(dev, bpc, DISP_REG_OD_CFG, cmdq_pkt); +} + +static void mtk_od_start(struct device *dev) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + writel(1, priv->regs + DISP_REG_OD_EN); +} + +static void mtk_postmask_config(struct device *dev, unsigned int w, + unsigned int h, unsigned int vrefresh, + unsigned int bpc, struct cmdq_pkt *cmdq_pkt) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, + DISP_REG_POSTMASK_SIZE); + mtk_ddp_write(cmdq_pkt, POSTMASK_RELAY_MODE, &priv->cmdq_reg, + priv->regs, DISP_REG_POSTMASK_CFG); +} + +static void mtk_postmask_start(struct device *dev) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + writel(POSTMASK_EN, priv->regs + DISP_REG_POSTMASK_EN); +} + +static void mtk_postmask_stop(struct device *dev) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + writel_relaxed(0x0, priv->regs + DISP_REG_POSTMASK_EN); +} + +static void mtk_ufoe_start(struct device *dev) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + writel(UFO_BYPASS, priv->regs + DISP_REG_UFO_START); +} + +static const struct mtk_ddp_comp_funcs ddp_aal = { + .clk_enable = mtk_aal_clk_enable, + .clk_disable = mtk_aal_clk_disable, + .gamma_get_lut_size = mtk_aal_gamma_get_lut_size, + .gamma_set = mtk_aal_gamma_set, + .config = mtk_aal_config, + .start = mtk_aal_start, + .stop = mtk_aal_stop, +}; + +static const struct mtk_ddp_comp_funcs ddp_ccorr = { + .clk_enable = mtk_ccorr_clk_enable, + .clk_disable = mtk_ccorr_clk_disable, + .config = mtk_ccorr_config, + .start = mtk_ccorr_start, + .stop = mtk_ccorr_stop, + .ctm_set = mtk_ccorr_ctm_set, +}; + +static const struct mtk_ddp_comp_funcs ddp_color = { + .clk_enable = mtk_color_clk_enable, + .clk_disable = mtk_color_clk_disable, + .config = mtk_color_config, + .start = mtk_color_start, +}; + +static const struct mtk_ddp_comp_funcs ddp_dither = { + .clk_enable = mtk_ddp_clk_enable, + .clk_disable = mtk_ddp_clk_disable, + .config = mtk_dither_config, + .start = mtk_dither_start, + .stop = mtk_dither_stop, +}; + +static const struct mtk_ddp_comp_funcs ddp_dpi = { + .start = mtk_dpi_start, + .stop = mtk_dpi_stop, + .encoder_index = mtk_dpi_encoder_index, +}; + +static const struct mtk_ddp_comp_funcs ddp_dsc = { + .clk_enable = mtk_ddp_clk_enable, + .clk_disable = mtk_ddp_clk_disable, + .config = mtk_dsc_config, + .start = mtk_dsc_start, + .stop = mtk_dsc_stop, +}; + +static const struct mtk_ddp_comp_funcs ddp_dsi = { + .start = mtk_dsi_ddp_start, + .stop = mtk_dsi_ddp_stop, + .encoder_index = mtk_dsi_encoder_index, +}; + +static const struct mtk_ddp_comp_funcs ddp_gamma = { + .clk_enable = mtk_gamma_clk_enable, + .clk_disable = mtk_gamma_clk_disable, + .gamma_get_lut_size = mtk_gamma_get_lut_size, + .gamma_set = mtk_gamma_set, + .config = mtk_gamma_config, + .start = mtk_gamma_start, + .stop = mtk_gamma_stop, +}; + +static const struct mtk_ddp_comp_funcs ddp_merge = { + .clk_enable = mtk_merge_clk_enable, + .clk_disable = mtk_merge_clk_disable, + .start = mtk_merge_start, + .stop = mtk_merge_stop, + .config = mtk_merge_config, +}; + +static const struct mtk_ddp_comp_funcs ddp_od = { + .clk_enable = mtk_ddp_clk_enable, + .clk_disable = mtk_ddp_clk_disable, + .config = mtk_od_config, + .start = mtk_od_start, +}; + +static const struct mtk_ddp_comp_funcs ddp_ovl = { + .clk_enable = mtk_ovl_clk_enable, + .clk_disable = mtk_ovl_clk_disable, + .config = mtk_ovl_config, + .start = mtk_ovl_start, + .stop = mtk_ovl_stop, + .register_vblank_cb = mtk_ovl_register_vblank_cb, + .unregister_vblank_cb = mtk_ovl_unregister_vblank_cb, + .enable_vblank = mtk_ovl_enable_vblank, + .disable_vblank = mtk_ovl_disable_vblank, + .supported_rotations = mtk_ovl_supported_rotations, + .layer_nr = mtk_ovl_layer_nr, + .layer_check = mtk_ovl_layer_check, + .layer_config = mtk_ovl_layer_config, + .bgclr_in_on = mtk_ovl_bgclr_in_on, + .bgclr_in_off = mtk_ovl_bgclr_in_off, + .get_formats = mtk_ovl_get_formats, + .get_num_formats = mtk_ovl_get_num_formats, +}; + +static const struct mtk_ddp_comp_funcs ddp_postmask = { + .clk_enable = mtk_ddp_clk_enable, + .clk_disable = mtk_ddp_clk_disable, + .config = mtk_postmask_config, + .start = mtk_postmask_start, + .stop = mtk_postmask_stop, +}; + +static const struct mtk_ddp_comp_funcs ddp_rdma = { + .clk_enable = mtk_rdma_clk_enable, + .clk_disable = mtk_rdma_clk_disable, + .config = mtk_rdma_config, + .start = mtk_rdma_start, + .stop = mtk_rdma_stop, + .register_vblank_cb = mtk_rdma_register_vblank_cb, + .unregister_vblank_cb = mtk_rdma_unregister_vblank_cb, + .enable_vblank = mtk_rdma_enable_vblank, + .disable_vblank = mtk_rdma_disable_vblank, + .layer_nr = mtk_rdma_layer_nr, + .layer_config = mtk_rdma_layer_config, + .get_formats = mtk_rdma_get_formats, + .get_num_formats = mtk_rdma_get_num_formats, +}; + +static const struct mtk_ddp_comp_funcs ddp_ufoe = { + .clk_enable = mtk_ddp_clk_enable, + .clk_disable = mtk_ddp_clk_disable, + .start = mtk_ufoe_start, +}; + +static const struct mtk_ddp_comp_funcs ddp_ovl_adaptor = { + .power_on = mtk_ovl_adaptor_power_on, + .power_off = mtk_ovl_adaptor_power_off, + .clk_enable = mtk_ovl_adaptor_clk_enable, + .clk_disable = mtk_ovl_adaptor_clk_disable, + .config = mtk_ovl_adaptor_config, + .start = mtk_ovl_adaptor_start, + .stop = mtk_ovl_adaptor_stop, + .layer_nr = mtk_ovl_adaptor_layer_nr, + .layer_config = mtk_ovl_adaptor_layer_config, + .register_vblank_cb = mtk_ovl_adaptor_register_vblank_cb, + .unregister_vblank_cb = mtk_ovl_adaptor_unregister_vblank_cb, + .enable_vblank = mtk_ovl_adaptor_enable_vblank, + .disable_vblank = mtk_ovl_adaptor_disable_vblank, + .dma_dev_get = mtk_ovl_adaptor_dma_dev_get, + .connect = mtk_ovl_adaptor_connect, + .disconnect = mtk_ovl_adaptor_disconnect, + .add = mtk_ovl_adaptor_add_comp, + .remove = mtk_ovl_adaptor_remove_comp, + .get_formats = mtk_ovl_adaptor_get_formats, + .get_num_formats = mtk_ovl_adaptor_get_num_formats, + .mode_valid = mtk_ovl_adaptor_mode_valid, +}; + +static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = { + [MTK_DISP_AAL] = "aal", + [MTK_DISP_BLS] = "bls", + [MTK_DISP_CCORR] = "ccorr", + [MTK_DISP_COLOR] = "color", + [MTK_DISP_DITHER] = "dither", + [MTK_DISP_DSC] = "dsc", + [MTK_DISP_GAMMA] = "gamma", + [MTK_DISP_MERGE] = "merge", + [MTK_DISP_MUTEX] = "mutex", + [MTK_DISP_OD] = "od", + [MTK_DISP_OVL] = "ovl", + [MTK_DISP_OVL_2L] = "ovl-2l", + [MTK_DISP_OVL_ADAPTOR] = "ovl_adaptor", + [MTK_DISP_POSTMASK] = "postmask", + [MTK_DISP_PWM] = "pwm", + [MTK_DISP_RDMA] = "rdma", + [MTK_DISP_UFOE] = "ufoe", + [MTK_DISP_WDMA] = "wdma", + [MTK_DP_INTF] = "dp-intf", + [MTK_DPI] = "dpi", + [MTK_DSI] = "dsi", +}; + +struct mtk_ddp_comp_match { + enum mtk_ddp_comp_type type; + int alias_id; + const struct mtk_ddp_comp_funcs *funcs; +}; + +static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_DRM_ID_MAX] = { + [DDP_COMPONENT_AAL0] = { MTK_DISP_AAL, 0, &ddp_aal }, + [DDP_COMPONENT_AAL1] = { MTK_DISP_AAL, 1, &ddp_aal }, + [DDP_COMPONENT_BLS] = { MTK_DISP_BLS, 0, NULL }, + [DDP_COMPONENT_CCORR] = { MTK_DISP_CCORR, 0, &ddp_ccorr }, + [DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, &ddp_color }, + [DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, &ddp_color }, + [DDP_COMPONENT_DITHER0] = { MTK_DISP_DITHER, 0, &ddp_dither }, + [DDP_COMPONENT_DP_INTF0] = { MTK_DP_INTF, 0, &ddp_dpi }, + [DDP_COMPONENT_DP_INTF1] = { MTK_DP_INTF, 1, &ddp_dpi }, + [DDP_COMPONENT_DPI0] = { MTK_DPI, 0, &ddp_dpi }, + [DDP_COMPONENT_DPI1] = { MTK_DPI, 1, &ddp_dpi }, + [DDP_COMPONENT_DRM_OVL_ADAPTOR] = { MTK_DISP_OVL_ADAPTOR, 0, &ddp_ovl_adaptor }, + [DDP_COMPONENT_DSC0] = { MTK_DISP_DSC, 0, &ddp_dsc }, + [DDP_COMPONENT_DSC1] = { MTK_DISP_DSC, 1, &ddp_dsc }, + [DDP_COMPONENT_DSI0] = { MTK_DSI, 0, &ddp_dsi }, + [DDP_COMPONENT_DSI1] = { MTK_DSI, 1, &ddp_dsi }, + [DDP_COMPONENT_DSI2] = { MTK_DSI, 2, &ddp_dsi }, + [DDP_COMPONENT_DSI3] = { MTK_DSI, 3, &ddp_dsi }, + [DDP_COMPONENT_GAMMA] = { MTK_DISP_GAMMA, 0, &ddp_gamma }, + [DDP_COMPONENT_MERGE0] = { MTK_DISP_MERGE, 0, &ddp_merge }, + [DDP_COMPONENT_MERGE1] = { MTK_DISP_MERGE, 1, &ddp_merge }, + [DDP_COMPONENT_MERGE2] = { MTK_DISP_MERGE, 2, &ddp_merge }, + [DDP_COMPONENT_MERGE3] = { MTK_DISP_MERGE, 3, &ddp_merge }, + [DDP_COMPONENT_MERGE4] = { MTK_DISP_MERGE, 4, &ddp_merge }, + [DDP_COMPONENT_MERGE5] = { MTK_DISP_MERGE, 5, &ddp_merge }, + [DDP_COMPONENT_OD0] = { MTK_DISP_OD, 0, &ddp_od }, + [DDP_COMPONENT_OD1] = { MTK_DISP_OD, 1, &ddp_od }, + [DDP_COMPONENT_OVL0] = { MTK_DISP_OVL, 0, &ddp_ovl }, + [DDP_COMPONENT_OVL1] = { MTK_DISP_OVL, 1, &ddp_ovl }, + [DDP_COMPONENT_OVL_2L0] = { MTK_DISP_OVL_2L, 0, &ddp_ovl }, + [DDP_COMPONENT_OVL_2L1] = { MTK_DISP_OVL_2L, 1, &ddp_ovl }, + [DDP_COMPONENT_OVL_2L2] = { MTK_DISP_OVL_2L, 2, &ddp_ovl }, + [DDP_COMPONENT_POSTMASK0] = { MTK_DISP_POSTMASK, 0, &ddp_postmask }, + [DDP_COMPONENT_PWM0] = { MTK_DISP_PWM, 0, NULL }, + [DDP_COMPONENT_PWM1] = { MTK_DISP_PWM, 1, NULL }, + [DDP_COMPONENT_PWM2] = { MTK_DISP_PWM, 2, NULL }, + [DDP_COMPONENT_RDMA0] = { MTK_DISP_RDMA, 0, &ddp_rdma }, + [DDP_COMPONENT_RDMA1] = { MTK_DISP_RDMA, 1, &ddp_rdma }, + [DDP_COMPONENT_RDMA2] = { MTK_DISP_RDMA, 2, &ddp_rdma }, + [DDP_COMPONENT_RDMA4] = { MTK_DISP_RDMA, 4, &ddp_rdma }, + [DDP_COMPONENT_UFOE] = { MTK_DISP_UFOE, 0, &ddp_ufoe }, + [DDP_COMPONENT_WDMA0] = { MTK_DISP_WDMA, 0, NULL }, + [DDP_COMPONENT_WDMA1] = { MTK_DISP_WDMA, 1, NULL }, +}; + +static bool mtk_ddp_comp_find(struct device *dev, + const unsigned int *path, + unsigned int path_len, + struct mtk_ddp_comp *ddp_comp) +{ + unsigned int i; + + if (path == NULL) + return false; + + for (i = 0U; i < path_len; i++) + if (dev == ddp_comp[path[i]].dev) + return true; + + return false; +} + +static int mtk_ddp_comp_find_in_route(struct device *dev, + const struct mtk_drm_route *routes, + unsigned int num_routes, + struct mtk_ddp_comp *ddp_comp) +{ + unsigned int i; + + if (!routes) + return -EINVAL; + + for (i = 0; i < num_routes; i++) + if (dev == ddp_comp[routes[i].route_ddp].dev) + return BIT(routes[i].crtc_id); + + return -ENODEV; +} + +static bool mtk_ddp_path_available(const unsigned int *path, + unsigned int path_len, + struct device_node **comp_node) +{ + unsigned int i; + + if (!path || !path_len) + return false; + + for (i = 0U; i < path_len; i++) { + /* OVL_ADAPTOR doesn't have a device node */ + if (path[i] == DDP_COMPONENT_DRM_OVL_ADAPTOR) + continue; + + if (!comp_node[path[i]]) + return false; + } + + return true; +} + +int mtk_ddp_comp_get_id(struct device_node *node, + enum mtk_ddp_comp_type comp_type) +{ + int id = of_alias_get_id(node, mtk_ddp_comp_stem[comp_type]); + int i; + + for (i = 0; i < ARRAY_SIZE(mtk_ddp_matches); i++) { + if (comp_type == mtk_ddp_matches[i].type && + (id < 0 || id == mtk_ddp_matches[i].alias_id)) + return i; + } + + return -EINVAL; +} + +int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev) +{ + struct mtk_drm_private *private = drm->dev_private; + const struct mtk_mmsys_driver_data *data; + struct mtk_drm_private *priv_n; + int i = 0, j; + int ret; + + for (j = 0; j < private->data->mmsys_dev_num; j++) { + priv_n = private->all_drm_private[j]; + data = priv_n->data; + + if (mtk_ddp_path_available(data->main_path, data->main_len, + priv_n->comp_node)) { + if (mtk_ddp_comp_find(dev, data->main_path, + data->main_len, + priv_n->ddp_comp)) + return BIT(i); + i++; + } + + if (mtk_ddp_path_available(data->ext_path, data->ext_len, + priv_n->comp_node)) { + if (mtk_ddp_comp_find(dev, data->ext_path, + data->ext_len, + priv_n->ddp_comp)) + return BIT(i); + i++; + } + + if (mtk_ddp_path_available(data->third_path, data->third_len, + priv_n->comp_node)) { + if (mtk_ddp_comp_find(dev, data->third_path, + data->third_len, + priv_n->ddp_comp)) + return BIT(i); + i++; + } + } + + ret = mtk_ddp_comp_find_in_route(dev, + private->data->conn_routes, + private->data->num_conn_routes, + private->ddp_comp); + + if (ret < 0) + DRM_INFO("Failed to find comp in ddp table, ret = %d\n", ret); + + return ret; +} + +int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp, + unsigned int comp_id) +{ + struct platform_device *comp_pdev; + enum mtk_ddp_comp_type type; + struct mtk_ddp_comp_dev *priv; +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + int ret; +#endif + + if (comp_id >= DDP_COMPONENT_DRM_ID_MAX) + return -EINVAL; + + type = mtk_ddp_matches[comp_id].type; + + comp->id = comp_id; + comp->funcs = mtk_ddp_matches[comp_id].funcs; + /* Not all drm components have a DTS device node, such as ovl_adaptor, + * which is the drm bring up sub driver + */ + if (!node) + return 0; + + comp_pdev = of_find_device_by_node(node); + if (!comp_pdev) { + DRM_INFO("Waiting for device %s\n", node->full_name); + return -EPROBE_DEFER; + } + comp->dev = &comp_pdev->dev; + + if (type == MTK_DISP_AAL || + type == MTK_DISP_BLS || + type == MTK_DISP_CCORR || + type == MTK_DISP_COLOR || + type == MTK_DISP_GAMMA || + type == MTK_DISP_MERGE || + type == MTK_DISP_OVL || + type == MTK_DISP_OVL_2L || + type == MTK_DISP_PWM || + type == MTK_DISP_RDMA || + type == MTK_DPI || + type == MTK_DP_INTF || + type == MTK_DSI) + return 0; + + priv = devm_kzalloc(comp->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regs = of_iomap(node, 0); + priv->clk = of_clk_get(node, 0); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + ret = cmdq_dev_get_client_reg(comp->dev, &priv->cmdq_reg, 0); + if (ret) + dev_dbg(comp->dev, "get mediatek,gce-client-reg fail!\n"); +#endif + + platform_set_drvdata(comp_pdev, priv); + + return 0; +} diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h new file mode 100644 index 0000000000..ecf6dc283c --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h @@ -0,0 +1,346 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015 MediaTek Inc. + */ + +#ifndef MTK_DDP_COMP_H +#define MTK_DDP_COMP_H + +#include +#include +#include +#include +#include + +#include + +struct device; +struct device_node; +struct drm_crtc; +struct drm_device; +struct mtk_plane_state; +struct drm_crtc_state; + +enum mtk_ddp_comp_type { + MTK_DISP_AAL, + MTK_DISP_BLS, + MTK_DISP_CCORR, + MTK_DISP_COLOR, + MTK_DISP_DITHER, + MTK_DISP_DSC, + MTK_DISP_GAMMA, + MTK_DISP_MERGE, + MTK_DISP_MUTEX, + MTK_DISP_OD, + MTK_DISP_OVL, + MTK_DISP_OVL_2L, + MTK_DISP_OVL_ADAPTOR, + MTK_DISP_POSTMASK, + MTK_DISP_PWM, + MTK_DISP_RDMA, + MTK_DISP_UFOE, + MTK_DISP_WDMA, + MTK_DPI, + MTK_DP_INTF, + MTK_DSI, + MTK_DDP_COMP_TYPE_MAX, +}; + +struct mtk_ddp_comp; +struct cmdq_pkt; +struct mtk_ddp_comp_funcs { + int (*power_on)(struct device *dev); + void (*power_off)(struct device *dev); + int (*clk_enable)(struct device *dev); + void (*clk_disable)(struct device *dev); + void (*config)(struct device *dev, unsigned int w, + unsigned int h, unsigned int vrefresh, + unsigned int bpc, struct cmdq_pkt *cmdq_pkt); + void (*start)(struct device *dev); + void (*stop)(struct device *dev); + void (*register_vblank_cb)(struct device *dev, + void (*vblank_cb)(void *), + void *vblank_cb_data); + void (*unregister_vblank_cb)(struct device *dev); + void (*enable_vblank)(struct device *dev); + void (*disable_vblank)(struct device *dev); + unsigned int (*supported_rotations)(struct device *dev); + unsigned int (*layer_nr)(struct device *dev); + int (*layer_check)(struct device *dev, + unsigned int idx, + struct mtk_plane_state *state); + void (*layer_config)(struct device *dev, unsigned int idx, + struct mtk_plane_state *state, + struct cmdq_pkt *cmdq_pkt); + unsigned int (*gamma_get_lut_size)(struct device *dev); + void (*gamma_set)(struct device *dev, + struct drm_crtc_state *state); + void (*bgclr_in_on)(struct device *dev); + void (*bgclr_in_off)(struct device *dev); + void (*ctm_set)(struct device *dev, + struct drm_crtc_state *state); + struct device * (*dma_dev_get)(struct device *dev); + const u32 *(*get_formats)(struct device *dev); + size_t (*get_num_formats)(struct device *dev); + void (*connect)(struct device *dev, struct device *mmsys_dev, unsigned int next); + void (*disconnect)(struct device *dev, struct device *mmsys_dev, unsigned int next); + void (*add)(struct device *dev, struct mtk_mutex *mutex); + void (*remove)(struct device *dev, struct mtk_mutex *mutex); + unsigned int (*encoder_index)(struct device *dev); + enum drm_mode_status (*mode_valid)(struct device *dev, const struct drm_display_mode *mode); +}; + +struct mtk_ddp_comp { + struct device *dev; + int irq; + unsigned int id; + int encoder_index; + const struct mtk_ddp_comp_funcs *funcs; +}; + +static inline int mtk_ddp_comp_power_on(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->power_on) + return comp->funcs->power_on(comp->dev); + else + return pm_runtime_resume_and_get(comp->dev); + return 0; +} + +static inline void mtk_ddp_comp_power_off(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->power_off) + comp->funcs->power_off(comp->dev); + else + pm_runtime_put(comp->dev); +} + +static inline int mtk_ddp_comp_clk_enable(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->clk_enable) + return comp->funcs->clk_enable(comp->dev); + + return 0; +} + +static inline void mtk_ddp_comp_clk_disable(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->clk_disable) + comp->funcs->clk_disable(comp->dev); +} + +static inline +enum drm_mode_status mtk_ddp_comp_mode_valid(struct mtk_ddp_comp *comp, + const struct drm_display_mode *mode) +{ + if (comp && comp->funcs && comp->funcs->mode_valid) + return comp->funcs->mode_valid(comp->dev, mode); + return MODE_OK; +} + +static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp, + unsigned int w, unsigned int h, + unsigned int vrefresh, unsigned int bpc, + struct cmdq_pkt *cmdq_pkt) +{ + if (comp->funcs && comp->funcs->config) + comp->funcs->config(comp->dev, w, h, vrefresh, bpc, cmdq_pkt); +} + +static inline void mtk_ddp_comp_start(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->start) + comp->funcs->start(comp->dev); +} + +static inline void mtk_ddp_comp_stop(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->stop) + comp->funcs->stop(comp->dev); +} + +static inline void mtk_ddp_comp_register_vblank_cb(struct mtk_ddp_comp *comp, + void (*vblank_cb)(void *), + void *vblank_cb_data) +{ + if (comp->funcs && comp->funcs->register_vblank_cb) + comp->funcs->register_vblank_cb(comp->dev, vblank_cb, + vblank_cb_data); +} + +static inline void mtk_ddp_comp_unregister_vblank_cb(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->unregister_vblank_cb) + comp->funcs->unregister_vblank_cb(comp->dev); +} + +static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->enable_vblank) + comp->funcs->enable_vblank(comp->dev); +} + +static inline void mtk_ddp_comp_disable_vblank(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->disable_vblank) + comp->funcs->disable_vblank(comp->dev); +} + +static inline +unsigned int mtk_ddp_comp_supported_rotations(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->supported_rotations) + return comp->funcs->supported_rotations(comp->dev); + + /* + * In order to pass IGT tests, DRM_MODE_ROTATE_0 is required when + * rotation is not supported. + */ + return DRM_MODE_ROTATE_0; +} + +static inline unsigned int mtk_ddp_comp_layer_nr(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->layer_nr) + return comp->funcs->layer_nr(comp->dev); + + return 0; +} + +static inline int mtk_ddp_comp_layer_check(struct mtk_ddp_comp *comp, + unsigned int idx, + struct mtk_plane_state *state) +{ + if (comp->funcs && comp->funcs->layer_check) + return comp->funcs->layer_check(comp->dev, idx, state); + return 0; +} + +static inline void mtk_ddp_comp_layer_config(struct mtk_ddp_comp *comp, + unsigned int idx, + struct mtk_plane_state *state, + struct cmdq_pkt *cmdq_pkt) +{ + if (comp->funcs && comp->funcs->layer_config) + comp->funcs->layer_config(comp->dev, idx, state, cmdq_pkt); +} + +static inline unsigned int mtk_ddp_gamma_get_lut_size(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->gamma_get_lut_size) + return comp->funcs->gamma_get_lut_size(comp->dev); + + return 0; +} + +static inline void mtk_ddp_gamma_set(struct mtk_ddp_comp *comp, + struct drm_crtc_state *state) +{ + if (comp->funcs && comp->funcs->gamma_set) + comp->funcs->gamma_set(comp->dev, state); +} + +static inline void mtk_ddp_comp_bgclr_in_on(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->bgclr_in_on) + comp->funcs->bgclr_in_on(comp->dev); +} + +static inline void mtk_ddp_comp_bgclr_in_off(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->bgclr_in_off) + comp->funcs->bgclr_in_off(comp->dev); +} + +static inline void mtk_ddp_ctm_set(struct mtk_ddp_comp *comp, + struct drm_crtc_state *state) +{ + if (comp->funcs && comp->funcs->ctm_set) + comp->funcs->ctm_set(comp->dev, state); +} + +static inline struct device *mtk_ddp_comp_dma_dev_get(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->dma_dev_get) + return comp->funcs->dma_dev_get(comp->dev); + return comp->dev; +} + +static inline +const u32 *mtk_ddp_comp_get_formats(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->get_formats) + return comp->funcs->get_formats(comp->dev); + + return NULL; +} + +static inline +size_t mtk_ddp_comp_get_num_formats(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->get_num_formats) + return comp->funcs->get_num_formats(comp->dev); + + return 0; +} + +static inline bool mtk_ddp_comp_add(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex) +{ + if (comp->funcs && comp->funcs->add) { + comp->funcs->add(comp->dev, mutex); + return true; + } + return false; +} + +static inline bool mtk_ddp_comp_remove(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex) +{ + if (comp->funcs && comp->funcs->remove) { + comp->funcs->remove(comp->dev, mutex); + return true; + } + return false; +} + +static inline bool mtk_ddp_comp_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev, + unsigned int next) +{ + if (comp->funcs && comp->funcs->connect) { + comp->funcs->connect(comp->dev, mmsys_dev, next); + return true; + } + return false; +} + +static inline bool mtk_ddp_comp_disconnect(struct mtk_ddp_comp *comp, struct device *mmsys_dev, + unsigned int next) +{ + if (comp->funcs && comp->funcs->disconnect) { + comp->funcs->disconnect(comp->dev, mmsys_dev, next); + return true; + } + return false; +} + +static inline void mtk_ddp_comp_encoder_index_set(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->encoder_index) + comp->encoder_index = (int)comp->funcs->encoder_index(comp->dev); +} + +int mtk_ddp_comp_get_id(struct device_node *node, + enum mtk_ddp_comp_type comp_type); +int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev); +int mtk_ddp_comp_init(struct device_node *comp_node, struct mtk_ddp_comp *comp, + unsigned int comp_id); +enum mtk_ddp_comp_type mtk_ddp_comp_get_type(unsigned int comp_id); +void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value, + struct cmdq_client_reg *cmdq_reg, void __iomem *regs, + unsigned int offset); +void mtk_ddp_write_relaxed(struct cmdq_pkt *cmdq_pkt, unsigned int value, + struct cmdq_client_reg *cmdq_reg, void __iomem *regs, + unsigned int offset); +void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, unsigned int value, + struct cmdq_client_reg *cmdq_reg, void __iomem *regs, + unsigned int offset, unsigned int mask); +#endif /* MTK_DDP_COMP_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c b/drivers/gpu/drm/mediatek/mtk_disp_aal.c index 40fe403086..3ce8f32b06 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c @@ -11,9 +11,9 @@ #include #include +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" #include "mtk_disp_drv.h" -#include "mtk_drm_crtc.h" -#include "mtk_drm_ddp_comp.h" #include "mtk_drm_drv.h" #define DISP_AAL_EN 0x0000 @@ -223,7 +223,6 @@ struct platform_driver mtk_disp_aal_driver = { .remove_new = mtk_disp_aal_remove, .driver = { .name = "mediatek-disp-aal", - .owner = THIS_MODULE, .of_match_table = mtk_disp_aal_driver_dt_match, }, }; diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c index 465cddce0d..df35e90dd2 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c @@ -10,9 +10,9 @@ #include #include +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" #include "mtk_disp_drv.h" -#include "mtk_drm_crtc.h" -#include "mtk_drm_ddp_comp.h" #include "mtk_drm_drv.h" #define DISP_CCORR_EN 0x0000 @@ -214,7 +214,6 @@ struct platform_driver mtk_disp_ccorr_driver = { .remove_new = mtk_disp_ccorr_remove, .driver = { .name = "mediatek-disp-ccorr", - .owner = THIS_MODULE, .of_match_table = mtk_disp_ccorr_driver_dt_match, }, }; diff --git a/drivers/gpu/drm/mediatek/mtk_disp_color.c b/drivers/gpu/drm/mediatek/mtk_disp_color.c index 78ea99f144..7f0085be56 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_color.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_color.c @@ -10,9 +10,9 @@ #include #include +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" #include "mtk_disp_drv.h" -#include "mtk_drm_crtc.h" -#include "mtk_drm_ddp_comp.h" #include "mtk_drm_drv.h" #define DISP_COLOR_CFG_MAIN 0x0400 @@ -164,7 +164,6 @@ struct platform_driver mtk_disp_color_driver = { .remove_new = mtk_disp_color_remove, .driver = { .name = "mediatek-disp-color", - .owner = THIS_MODULE, .of_match_table = mtk_disp_color_driver_dt_match, }, }; diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h index 90e64467ea..082ac18fe0 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h @@ -9,8 +9,8 @@ #include #include #include -#include "mtk_drm_plane.h" #include "mtk_mdp_rdma.h" +#include "mtk_plane.h" int mtk_aal_clk_enable(struct device *dev); void mtk_aal_clk_disable(struct device *dev); diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index c1bc8b00d9..ca8d1f3aca 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -11,9 +11,9 @@ #include #include +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" #include "mtk_disp_drv.h" -#include "mtk_drm_crtc.h" -#include "mtk_drm_ddp_comp.h" #include "mtk_drm_drv.h" #define DISP_GAMMA_EN 0x0000 @@ -334,7 +334,6 @@ struct platform_driver mtk_disp_gamma_driver = { .remove_new = mtk_disp_gamma_remove, .driver = { .name = "mediatek-disp-gamma", - .owner = THIS_MODULE, .of_match_table = mtk_disp_gamma_driver_dt_match, }, }; diff --git a/drivers/gpu/drm/mediatek/mtk_disp_merge.c b/drivers/gpu/drm/mediatek/mtk_disp_merge.c index 32a29924bd..77c057e0e6 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_merge.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_merge.c @@ -10,7 +10,7 @@ #include #include -#include "mtk_drm_ddp_comp.h" +#include "mtk_ddp_comp.h" #include "mtk_drm_drv.h" #include "mtk_disp_drv.h" @@ -376,7 +376,6 @@ struct platform_driver mtk_disp_merge_driver = { .remove_new = mtk_disp_merge_remove, .driver = { .name = "mediatek-disp-merge", - .owner = THIS_MODULE, .of_match_table = mtk_disp_merge_driver_dt_match, }, }; diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c index 2bffe42454..26b598b9f7 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c @@ -15,9 +15,9 @@ #include #include +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" #include "mtk_disp_drv.h" -#include "mtk_drm_crtc.h" -#include "mtk_drm_ddp_comp.h" #include "mtk_drm_drv.h" #define DISP_REG_OVL_INTEN 0x0004 @@ -38,6 +38,7 @@ #define DISP_REG_OVL_PITCH_MSB(n) (0x0040 + 0x20 * (n)) #define OVL_PITCH_MSB_2ND_SUBBUF BIT(16) #define DISP_REG_OVL_PITCH(n) (0x0044 + 0x20 * (n)) +#define OVL_CONST_BLEND BIT(28) #define DISP_REG_OVL_RDMA_CTRL(n) (0x00c0 + 0x20 * (n)) #define DISP_REG_OVL_RDMA_GMC(n) (0x00c8 + 0x20 * (n)) #define DISP_REG_OVL_ADDR_MT2701 0x0040 @@ -71,6 +72,8 @@ #define OVL_CON_VIRT_FLIP BIT(9) #define OVL_CON_HORZ_FLIP BIT(10) +#define OVL_COLOR_ALPHA GENMASK(31, 24) + static const u32 mt8173_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, @@ -273,7 +276,13 @@ void mtk_ovl_config(struct device *dev, unsigned int w, if (w != 0 && h != 0) mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_ROI_SIZE); - mtk_ddp_write_relaxed(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_ROI_BGCLR); + + /* + * The background color must be opaque black (ARGB), + * otherwise the alpha blending will have no effect + */ + mtk_ddp_write_relaxed(cmdq_pkt, OVL_COLOR_ALPHA, &ovl->cmdq_reg, + ovl->regs, DISP_REG_OVL_ROI_BGCLR); mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST); mtk_ddp_write(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST); @@ -296,27 +305,20 @@ int mtk_ovl_layer_check(struct device *dev, unsigned int idx, struct mtk_plane_state *mtk_state) { struct drm_plane_state *state = &mtk_state->base; - unsigned int rotation = 0; - rotation = drm_rotation_simplify(state->rotation, - DRM_MODE_ROTATE_0 | - DRM_MODE_REFLECT_X | - DRM_MODE_REFLECT_Y); - rotation &= ~DRM_MODE_ROTATE_0; - - /* We can only do reflection, not rotation */ - if ((rotation & DRM_MODE_ROTATE_MASK) != 0) + /* check if any unsupported rotation is set */ + if (state->rotation & ~mtk_ovl_supported_rotations(dev)) return -EINVAL; /* * TODO: Rotating/reflecting YUV buffers is not supported at this time. * Only RGB[AX] variants are supported. + * Since DRM_MODE_ROTATE_0 means "no rotation", we should not + * reject layers with this property. */ - if (state->fb->format->is_yuv && rotation != 0) + if (state->fb->format->is_yuv && (state->rotation & ~DRM_MODE_ROTATE_0)) return -EINVAL; - state->rotation = rotation; - return 0; } @@ -407,6 +409,7 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx, unsigned int fmt = pending->format; unsigned int offset = (pending->y << 16) | pending->x; unsigned int src_size = (pending->height << 16) | pending->width; + unsigned int ignore_pixel_alpha = 0; unsigned int con; bool is_afbc = pending->modifier != DRM_FORMAT_MOD_LINEAR; union overlay_pitch { @@ -428,6 +431,14 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx, if (state->base.fb && state->base.fb->format->has_alpha) con |= OVL_CON_AEN | OVL_CON_ALPHA; + /* CONST_BLD must be enabled for XRGB formats although the alpha channel + * can be ignored, or OVL will still read the value from memory. + * For RGB888 related formats, whether CONST_BLD is enabled or not won't + * affect the result. Therefore we use !has_alpha as the condition. + */ + if (state->base.fb && !state->base.fb->format->has_alpha) + ignore_pixel_alpha = OVL_CONST_BLEND; + if (pending->rotation & DRM_MODE_REFLECT_Y) { con |= OVL_CON_VIRT_FLIP; addr += (pending->height - 1) * pending->pitch; @@ -443,8 +454,8 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx, mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_CON(idx)); - mtk_ddp_write_relaxed(cmdq_pkt, overlay_pitch.split_pitch.lsb, &ovl->cmdq_reg, ovl->regs, - DISP_REG_OVL_PITCH(idx)); + mtk_ddp_write_relaxed(cmdq_pkt, overlay_pitch.split_pitch.lsb | ignore_pixel_alpha, + &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH(idx)); mtk_ddp_write_relaxed(cmdq_pkt, src_size, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_SRC_SIZE(idx)); mtk_ddp_write_relaxed(cmdq_pkt, offset, &ovl->cmdq_reg, ovl->regs, @@ -659,7 +670,6 @@ struct platform_driver mtk_disp_ovl_driver = { .remove_new = mtk_disp_ovl_remove, .driver = { .name = "mediatek-disp-ovl", - .owner = THIS_MODULE, .of_match_table = mtk_disp_ovl_driver_dt_match, }, }; diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c index 034d31824d..2b62d64759 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c @@ -17,9 +17,9 @@ #include #include +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" #include "mtk_disp_drv.h" -#include "mtk_drm_crtc.h" -#include "mtk_drm_ddp_comp.h" #include "mtk_drm_drv.h" #include "mtk_ethdr.h" @@ -158,7 +158,7 @@ void mtk_ovl_adaptor_layer_config(struct device *dev, unsigned int idx, merge = ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_MERGE0 + idx]; ethdr = ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0]; - if (!pending->enable) { + if (!pending->enable || !pending->width || !pending->height) { mtk_merge_stop_cmdq(merge, cmdq_pkt); mtk_mdp_rdma_stop(rdma_l, cmdq_pkt); mtk_mdp_rdma_stop(rdma_r, cmdq_pkt); @@ -629,6 +629,5 @@ struct platform_driver mtk_disp_ovl_adaptor_driver = { .remove_new = mtk_disp_ovl_adaptor_remove, .driver = { .name = "mediatek-disp-ovl-adaptor", - .owner = THIS_MODULE, }, }; diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c index faa907f2f4..7b1a6e6312 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c @@ -13,9 +13,9 @@ #include #include +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" #include "mtk_disp_drv.h" -#include "mtk_drm_crtc.h" -#include "mtk_drm_ddp_comp.h" #include "mtk_drm_drv.h" #define DISP_REG_RDMA_INT_ENABLE 0x0000 @@ -428,7 +428,6 @@ struct platform_driver mtk_disp_rdma_driver = { .remove_new = mtk_disp_rdma_remove, .driver = { .name = "mediatek-disp-rdma", - .owner = THIS_MODULE, .of_match_table = mtk_disp_rdma_driver_dt_match, }, }; diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index 5363669564..ada12927bb 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -2073,9 +2073,15 @@ static const struct drm_edid *mtk_dp_edid_read(struct drm_bridge *bridge, */ const struct edid *edid = drm_edid_raw(drm_edid); struct cea_sad *sads; + int ret; - audio_caps->sad_count = drm_edid_to_sad(edid, &sads); - kfree(sads); + ret = drm_edid_to_sad(edid, &sads); + /* Ignore any errors */ + if (ret < 0) + ret = 0; + if (ret) + kfree(sads); + audio_caps->sad_count = ret; /* * FIXME: This should use connector->display_info.has_audio from diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index beb7d9d08e..a08d206549 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -26,9 +26,9 @@ #include #include +#include "mtk_ddp_comp.h" #include "mtk_disp_drv.h" #include "mtk_dpi_regs.h" -#include "mtk_drm_ddp_comp.h" #include "mtk_drm_drv.h" enum mtk_dpi_out_bit_num { @@ -805,7 +805,10 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data) return ret; } - dpi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm_dev, dpi->dev); + ret = mtk_find_possible_crtcs(drm_dev, dpi->dev); + if (ret < 0) + goto err_cleanup; + dpi->encoder.possible_crtcs = ret; ret = drm_bridge_attach(&dpi->encoder, &dpi->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c deleted file mode 100644 index 29207b2756..0000000000 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ /dev/null @@ -1,1146 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2015 MediaTek Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "mtk_drm_drv.h" -#include "mtk_drm_crtc.h" -#include "mtk_drm_ddp_comp.h" -#include "mtk_drm_gem.h" -#include "mtk_drm_plane.h" - -/* - * struct mtk_drm_crtc - MediaTek specific crtc structure. - * @base: crtc object. - * @enabled: records whether crtc_enable succeeded - * @planes: array of 4 drm_plane structures, one for each overlay plane - * @pending_planes: whether any plane has pending changes to be applied - * @mmsys_dev: pointer to the mmsys device for configuration registers - * @mutex: handle to one of the ten disp_mutex streams - * @ddp_comp_nr: number of components in ddp_comp - * @ddp_comp: array of pointers the mtk_ddp_comp structures used by this crtc - * - * TODO: Needs update: this header is missing a bunch of member descriptions. - */ -struct mtk_drm_crtc { - struct drm_crtc base; - bool enabled; - - bool pending_needs_vblank; - struct drm_pending_vblank_event *event; - - struct drm_plane *planes; - unsigned int layer_nr; - bool pending_planes; - bool pending_async_planes; - -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - struct cmdq_client cmdq_client; - struct cmdq_pkt cmdq_handle; - u32 cmdq_event; - u32 cmdq_vblank_cnt; - wait_queue_head_t cb_blocking_queue; -#endif - - struct device *mmsys_dev; - struct device *dma_dev; - struct mtk_mutex *mutex; - unsigned int ddp_comp_nr; - struct mtk_ddp_comp **ddp_comp; - unsigned int num_conn_routes; - const struct mtk_drm_route *conn_routes; - - /* lock for display hardware access */ - struct mutex hw_lock; - bool config_updating; -}; - -struct mtk_crtc_state { - struct drm_crtc_state base; - - bool pending_config; - unsigned int pending_width; - unsigned int pending_height; - unsigned int pending_vrefresh; -}; - -static inline struct mtk_drm_crtc *to_mtk_crtc(struct drm_crtc *c) -{ - return container_of(c, struct mtk_drm_crtc, base); -} - -static inline struct mtk_crtc_state *to_mtk_crtc_state(struct drm_crtc_state *s) -{ - return container_of(s, struct mtk_crtc_state, base); -} - -static void mtk_drm_crtc_finish_page_flip(struct mtk_drm_crtc *mtk_crtc) -{ - struct drm_crtc *crtc = &mtk_crtc->base; - unsigned long flags; - - if (mtk_crtc->event) { - spin_lock_irqsave(&crtc->dev->event_lock, flags); - drm_crtc_send_vblank_event(crtc, mtk_crtc->event); - drm_crtc_vblank_put(crtc); - mtk_crtc->event = NULL; - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); - } -} - -static void mtk_drm_finish_page_flip(struct mtk_drm_crtc *mtk_crtc) -{ - drm_crtc_handle_vblank(&mtk_crtc->base); - if (!mtk_crtc->config_updating && mtk_crtc->pending_needs_vblank) { - mtk_drm_crtc_finish_page_flip(mtk_crtc); - mtk_crtc->pending_needs_vblank = false; - } -} - -#if IS_REACHABLE(CONFIG_MTK_CMDQ) -static int mtk_drm_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, - size_t size) -{ - struct device *dev; - dma_addr_t dma_addr; - - pkt->va_base = kzalloc(size, GFP_KERNEL); - if (!pkt->va_base) - return -ENOMEM; - - pkt->buf_size = size; - pkt->cl = (void *)client; - - dev = client->chan->mbox->dev; - dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, dma_addr)) { - dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); - kfree(pkt->va_base); - return -ENOMEM; - } - - pkt->pa_base = dma_addr; - - return 0; -} - -static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt) -{ - struct cmdq_client *client = (struct cmdq_client *)pkt->cl; - - dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size, - DMA_TO_DEVICE); - kfree(pkt->va_base); -} -#endif - -static void mtk_drm_crtc_destroy(struct drm_crtc *crtc) -{ - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - int i; - - mtk_mutex_put(mtk_crtc->mutex); -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle); - - if (mtk_crtc->cmdq_client.chan) { - mbox_free_channel(mtk_crtc->cmdq_client.chan); - mtk_crtc->cmdq_client.chan = NULL; - } -#endif - - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { - struct mtk_ddp_comp *comp; - - comp = mtk_crtc->ddp_comp[i]; - mtk_ddp_comp_unregister_vblank_cb(comp); - } - - drm_crtc_cleanup(crtc); -} - -static void mtk_drm_crtc_reset(struct drm_crtc *crtc) -{ - struct mtk_crtc_state *state; - - if (crtc->state) - __drm_atomic_helper_crtc_destroy_state(crtc->state); - - kfree(to_mtk_crtc_state(crtc->state)); - crtc->state = NULL; - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state) - __drm_atomic_helper_crtc_reset(crtc, &state->base); -} - -static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc) -{ - struct mtk_crtc_state *state; - - state = kmalloc(sizeof(*state), GFP_KERNEL); - if (!state) - return NULL; - - __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); - - WARN_ON(state->base.crtc != crtc); - state->base.crtc = crtc; - state->pending_config = false; - - return &state->base; -} - -static void mtk_drm_crtc_destroy_state(struct drm_crtc *crtc, - struct drm_crtc_state *state) -{ - __drm_atomic_helper_crtc_destroy_state(state); - kfree(to_mtk_crtc_state(state)); -} - -static enum drm_mode_status -mtk_drm_crtc_mode_valid(struct drm_crtc *crtc, - const struct drm_display_mode *mode) -{ - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - enum drm_mode_status status = MODE_OK; - int i; - - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { - status = mtk_ddp_comp_mode_valid(mtk_crtc->ddp_comp[i], mode); - if (status != MODE_OK) - break; - } - return status; -} - -static bool mtk_drm_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - /* Nothing to do here, but this callback is mandatory. */ - return true; -} - -static void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) -{ - struct mtk_crtc_state *state = to_mtk_crtc_state(crtc->state); - - state->pending_width = crtc->mode.hdisplay; - state->pending_height = crtc->mode.vdisplay; - state->pending_vrefresh = drm_mode_vrefresh(&crtc->mode); - wmb(); /* Make sure the above parameters are set before update */ - state->pending_config = true; -} - -static int mtk_crtc_ddp_clk_enable(struct mtk_drm_crtc *mtk_crtc) -{ - int ret; - int i; - - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { - ret = mtk_ddp_comp_clk_enable(mtk_crtc->ddp_comp[i]); - if (ret) { - DRM_ERROR("Failed to enable clock %d: %d\n", i, ret); - goto err; - } - } - - return 0; -err: - while (--i >= 0) - mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]); - return ret; -} - -static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc) -{ - int i; - - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) - mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]); -} - -static -struct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct drm_crtc *crtc, - struct drm_plane *plane, - unsigned int *local_layer) -{ - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - struct mtk_ddp_comp *comp; - int i, count = 0; - unsigned int local_index = plane - mtk_crtc->planes; - - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { - comp = mtk_crtc->ddp_comp[i]; - if (local_index < (count + mtk_ddp_comp_layer_nr(comp))) { - *local_layer = local_index - count; - return comp; - } - count += mtk_ddp_comp_layer_nr(comp); - } - - WARN(1, "Failed to find component for plane %d\n", plane->index); - return NULL; -} - -#if IS_REACHABLE(CONFIG_MTK_CMDQ) -static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg) -{ - struct cmdq_cb_data *data = mssg; - struct cmdq_client *cmdq_cl = container_of(cl, struct cmdq_client, client); - struct mtk_drm_crtc *mtk_crtc = container_of(cmdq_cl, struct mtk_drm_crtc, cmdq_client); - struct mtk_crtc_state *state; - unsigned int i; - - if (data->sta < 0) - return; - - state = to_mtk_crtc_state(mtk_crtc->base.state); - - state->pending_config = false; - - if (mtk_crtc->pending_planes) { - for (i = 0; i < mtk_crtc->layer_nr; i++) { - struct drm_plane *plane = &mtk_crtc->planes[i]; - struct mtk_plane_state *plane_state; - - plane_state = to_mtk_plane_state(plane->state); - - plane_state->pending.config = false; - } - mtk_crtc->pending_planes = false; - } - - if (mtk_crtc->pending_async_planes) { - for (i = 0; i < mtk_crtc->layer_nr; i++) { - struct drm_plane *plane = &mtk_crtc->planes[i]; - struct mtk_plane_state *plane_state; - - plane_state = to_mtk_plane_state(plane->state); - - plane_state->pending.async_config = false; - } - mtk_crtc->pending_async_planes = false; - } - - mtk_crtc->cmdq_vblank_cnt = 0; - wake_up(&mtk_crtc->cb_blocking_queue); -} -#endif - -static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc) -{ - struct drm_crtc *crtc = &mtk_crtc->base; - struct drm_connector *connector; - struct drm_encoder *encoder; - struct drm_connector_list_iter conn_iter; - unsigned int width, height, vrefresh, bpc = MTK_MAX_BPC; - int ret; - int i; - - if (WARN_ON(!crtc->state)) - return -EINVAL; - - width = crtc->state->adjusted_mode.hdisplay; - height = crtc->state->adjusted_mode.vdisplay; - vrefresh = drm_mode_vrefresh(&crtc->state->adjusted_mode); - - drm_for_each_encoder(encoder, crtc->dev) { - if (encoder->crtc != crtc) - continue; - - drm_connector_list_iter_begin(crtc->dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - if (connector->encoder != encoder) - continue; - if (connector->display_info.bpc != 0 && - bpc > connector->display_info.bpc) - bpc = connector->display_info.bpc; - } - drm_connector_list_iter_end(&conn_iter); - } - - ret = pm_runtime_resume_and_get(crtc->dev->dev); - if (ret < 0) { - DRM_ERROR("Failed to enable power domain: %d\n", ret); - return ret; - } - - ret = mtk_mutex_prepare(mtk_crtc->mutex); - if (ret < 0) { - DRM_ERROR("Failed to enable mutex clock: %d\n", ret); - goto err_pm_runtime_put; - } - - ret = mtk_crtc_ddp_clk_enable(mtk_crtc); - if (ret < 0) { - DRM_ERROR("Failed to enable component clocks: %d\n", ret); - goto err_mutex_unprepare; - } - - for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { - if (!mtk_ddp_comp_connect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev, - mtk_crtc->ddp_comp[i + 1]->id)) - mtk_mmsys_ddp_connect(mtk_crtc->mmsys_dev, - mtk_crtc->ddp_comp[i]->id, - mtk_crtc->ddp_comp[i + 1]->id); - if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) - mtk_mutex_add_comp(mtk_crtc->mutex, - mtk_crtc->ddp_comp[i]->id); - } - if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) - mtk_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); - mtk_mutex_enable(mtk_crtc->mutex); - - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { - struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i]; - - if (i == 1) - mtk_ddp_comp_bgclr_in_on(comp); - - mtk_ddp_comp_config(comp, width, height, vrefresh, bpc, NULL); - mtk_ddp_comp_start(comp); - } - - /* Initially configure all planes */ - for (i = 0; i < mtk_crtc->layer_nr; i++) { - struct drm_plane *plane = &mtk_crtc->planes[i]; - struct mtk_plane_state *plane_state; - struct mtk_ddp_comp *comp; - unsigned int local_layer; - - plane_state = to_mtk_plane_state(plane->state); - - /* should not enable layer before crtc enabled */ - plane_state->pending.enable = false; - comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer); - if (comp) - mtk_ddp_comp_layer_config(comp, local_layer, - plane_state, NULL); - } - - return 0; - -err_mutex_unprepare: - mtk_mutex_unprepare(mtk_crtc->mutex); -err_pm_runtime_put: - pm_runtime_put(crtc->dev->dev); - return ret; -} - -static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc) -{ - struct drm_device *drm = mtk_crtc->base.dev; - struct drm_crtc *crtc = &mtk_crtc->base; - int i; - - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { - mtk_ddp_comp_stop(mtk_crtc->ddp_comp[i]); - if (i == 1) - mtk_ddp_comp_bgclr_in_off(mtk_crtc->ddp_comp[i]); - } - - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) - if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) - mtk_mutex_remove_comp(mtk_crtc->mutex, - mtk_crtc->ddp_comp[i]->id); - mtk_mutex_disable(mtk_crtc->mutex); - for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { - if (!mtk_ddp_comp_disconnect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev, - mtk_crtc->ddp_comp[i + 1]->id)) - mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev, - mtk_crtc->ddp_comp[i]->id, - mtk_crtc->ddp_comp[i + 1]->id); - if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) - mtk_mutex_remove_comp(mtk_crtc->mutex, - mtk_crtc->ddp_comp[i]->id); - } - if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) - mtk_mutex_remove_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); - mtk_crtc_ddp_clk_disable(mtk_crtc); - mtk_mutex_unprepare(mtk_crtc->mutex); - - pm_runtime_put(drm->dev); - - if (crtc->state->event && !crtc->state->active) { - spin_lock_irq(&crtc->dev->event_lock); - drm_crtc_send_vblank_event(crtc, crtc->state->event); - crtc->state->event = NULL; - spin_unlock_irq(&crtc->dev->event_lock); - } -} - -static void mtk_crtc_ddp_config(struct drm_crtc *crtc, - struct cmdq_pkt *cmdq_handle) -{ - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state); - struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; - unsigned int i; - unsigned int local_layer; - - /* - * TODO: instead of updating the registers here, we should prepare - * working registers in atomic_commit and let the hardware command - * queue update module registers on vblank. - */ - if (state->pending_config) { - mtk_ddp_comp_config(comp, state->pending_width, - state->pending_height, - state->pending_vrefresh, 0, - cmdq_handle); - - if (!cmdq_handle) - state->pending_config = false; - } - - if (mtk_crtc->pending_planes) { - for (i = 0; i < mtk_crtc->layer_nr; i++) { - struct drm_plane *plane = &mtk_crtc->planes[i]; - struct mtk_plane_state *plane_state; - - plane_state = to_mtk_plane_state(plane->state); - - if (!plane_state->pending.config) - continue; - - comp = mtk_drm_ddp_comp_for_plane(crtc, plane, - &local_layer); - - if (comp) - mtk_ddp_comp_layer_config(comp, local_layer, - plane_state, - cmdq_handle); - if (!cmdq_handle) - plane_state->pending.config = false; - } - - if (!cmdq_handle) - mtk_crtc->pending_planes = false; - } - - if (mtk_crtc->pending_async_planes) { - for (i = 0; i < mtk_crtc->layer_nr; i++) { - struct drm_plane *plane = &mtk_crtc->planes[i]; - struct mtk_plane_state *plane_state; - - plane_state = to_mtk_plane_state(plane->state); - - if (!plane_state->pending.async_config) - continue; - - comp = mtk_drm_ddp_comp_for_plane(crtc, plane, - &local_layer); - - if (comp) - mtk_ddp_comp_layer_config(comp, local_layer, - plane_state, - cmdq_handle); - if (!cmdq_handle) - plane_state->pending.async_config = false; - } - - if (!cmdq_handle) - mtk_crtc->pending_async_planes = false; - } -} - -static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc, - bool needs_vblank) -{ -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - struct cmdq_pkt *cmdq_handle = &mtk_crtc->cmdq_handle; -#endif - struct drm_crtc *crtc = &mtk_crtc->base; - struct mtk_drm_private *priv = crtc->dev->dev_private; - unsigned int pending_planes = 0, pending_async_planes = 0; - int i; - - mutex_lock(&mtk_crtc->hw_lock); - mtk_crtc->config_updating = true; - if (needs_vblank) - mtk_crtc->pending_needs_vblank = true; - - for (i = 0; i < mtk_crtc->layer_nr; i++) { - struct drm_plane *plane = &mtk_crtc->planes[i]; - struct mtk_plane_state *plane_state; - - plane_state = to_mtk_plane_state(plane->state); - if (plane_state->pending.dirty) { - plane_state->pending.config = true; - plane_state->pending.dirty = false; - pending_planes |= BIT(i); - } else if (plane_state->pending.async_dirty) { - plane_state->pending.async_config = true; - plane_state->pending.async_dirty = false; - pending_async_planes |= BIT(i); - } - } - if (pending_planes) - mtk_crtc->pending_planes = true; - if (pending_async_planes) - mtk_crtc->pending_async_planes = true; - - if (priv->data->shadow_register) { - mtk_mutex_acquire(mtk_crtc->mutex); - mtk_crtc_ddp_config(crtc, NULL); - mtk_mutex_release(mtk_crtc->mutex); - } -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - if (mtk_crtc->cmdq_client.chan) { - mbox_flush(mtk_crtc->cmdq_client.chan, 2000); - cmdq_handle->cmd_buf_size = 0; - cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event); - cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false); - mtk_crtc_ddp_config(crtc, cmdq_handle); - cmdq_pkt_finalize(cmdq_handle); - dma_sync_single_for_device(mtk_crtc->cmdq_client.chan->mbox->dev, - cmdq_handle->pa_base, - cmdq_handle->cmd_buf_size, - DMA_TO_DEVICE); - /* - * CMDQ command should execute in next 3 vblank. - * One vblank interrupt before send message (occasionally) - * and one vblank interrupt after cmdq done, - * so it's timeout after 3 vblank interrupt. - * If it fail to execute in next 3 vblank, timeout happen. - */ - mtk_crtc->cmdq_vblank_cnt = 3; - - mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle); - mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0); - } -#endif - mtk_crtc->config_updating = false; - mutex_unlock(&mtk_crtc->hw_lock); -} - -static void mtk_crtc_ddp_irq(void *data) -{ - struct drm_crtc *crtc = data; - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - struct mtk_drm_private *priv = crtc->dev->dev_private; - -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - if (!priv->data->shadow_register && !mtk_crtc->cmdq_client.chan) - mtk_crtc_ddp_config(crtc, NULL); - else if (mtk_crtc->cmdq_vblank_cnt > 0 && --mtk_crtc->cmdq_vblank_cnt == 0) - DRM_ERROR("mtk_crtc %d CMDQ execute command timeout!\n", - drm_crtc_index(&mtk_crtc->base)); -#else - if (!priv->data->shadow_register) - mtk_crtc_ddp_config(crtc, NULL); -#endif - mtk_drm_finish_page_flip(mtk_crtc); -} - -static int mtk_drm_crtc_enable_vblank(struct drm_crtc *crtc) -{ - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; - - mtk_ddp_comp_enable_vblank(comp); - - return 0; -} - -static void mtk_drm_crtc_disable_vblank(struct drm_crtc *crtc) -{ - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; - - mtk_ddp_comp_disable_vblank(comp); -} - -static void mtk_drm_crtc_update_output(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - int crtc_index = drm_crtc_index(crtc); - int i; - struct device *dev; - struct drm_crtc_state *crtc_state = state->crtcs[crtc_index].new_state; - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - struct mtk_drm_private *priv; - unsigned int encoder_mask = crtc_state->encoder_mask; - - if (!crtc_state->connectors_changed) - return; - - if (!mtk_crtc->num_conn_routes) - return; - - priv = ((struct mtk_drm_private *)crtc->dev->dev_private)->all_drm_private[crtc_index]; - dev = priv->dev; - - dev_dbg(dev, "connector change:%d, encoder mask:0x%x for crtc:%d\n", - crtc_state->connectors_changed, encoder_mask, crtc_index); - - for (i = 0; i < mtk_crtc->num_conn_routes; i++) { - unsigned int comp_id = mtk_crtc->conn_routes[i].route_ddp; - struct mtk_ddp_comp *comp = &priv->ddp_comp[comp_id]; - - if (comp->encoder_index >= 0 && - (encoder_mask & BIT(comp->encoder_index))) { - mtk_crtc->ddp_comp[mtk_crtc->ddp_comp_nr - 1] = comp; - dev_dbg(dev, "Add comp_id: %d at path index %d\n", - comp->id, mtk_crtc->ddp_comp_nr - 1); - break; - } - } -} - -int mtk_drm_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane, - struct mtk_plane_state *state) -{ - unsigned int local_layer; - struct mtk_ddp_comp *comp; - - comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer); - if (comp) - return mtk_ddp_comp_layer_check(comp, local_layer, state); - return 0; -} - -void mtk_drm_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - - if (!mtk_crtc->enabled) - return; - - mtk_drm_crtc_update_config(mtk_crtc, false); -} - -static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; - int ret; - - DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id); - - ret = mtk_ddp_comp_power_on(comp); - if (ret < 0) { - DRM_DEV_ERROR(comp->dev, "Failed to enable power domain: %d\n", ret); - return; - } - - mtk_drm_crtc_update_output(crtc, state); - - ret = mtk_crtc_ddp_hw_init(mtk_crtc); - if (ret) { - mtk_ddp_comp_power_off(comp); - return; - } - - drm_crtc_vblank_on(crtc); - mtk_crtc->enabled = true; -} - -static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; - int i; - - DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id); - if (!mtk_crtc->enabled) - return; - - /* Set all pending plane state to disabled */ - for (i = 0; i < mtk_crtc->layer_nr; i++) { - struct drm_plane *plane = &mtk_crtc->planes[i]; - struct mtk_plane_state *plane_state; - - plane_state = to_mtk_plane_state(plane->state); - plane_state->pending.enable = false; - plane_state->pending.config = true; - } - mtk_crtc->pending_planes = true; - - mtk_drm_crtc_update_config(mtk_crtc, false); -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - /* Wait for planes to be disabled by cmdq */ - if (mtk_crtc->cmdq_client.chan) - wait_event_timeout(mtk_crtc->cb_blocking_queue, - mtk_crtc->cmdq_vblank_cnt == 0, - msecs_to_jiffies(500)); -#endif - /* Wait for planes to be disabled */ - drm_crtc_wait_one_vblank(crtc); - - drm_crtc_vblank_off(crtc); - mtk_crtc_ddp_hw_fini(mtk_crtc); - mtk_ddp_comp_power_off(comp); - - mtk_crtc->enabled = false; -} - -static void mtk_drm_crtc_atomic_begin(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, - crtc); - struct mtk_crtc_state *mtk_crtc_state = to_mtk_crtc_state(crtc_state); - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - unsigned long flags; - - if (mtk_crtc->event && mtk_crtc_state->base.event) - DRM_ERROR("new event while there is still a pending event\n"); - - if (mtk_crtc_state->base.event) { - mtk_crtc_state->base.event->pipe = drm_crtc_index(crtc); - WARN_ON(drm_crtc_vblank_get(crtc) != 0); - - spin_lock_irqsave(&crtc->dev->event_lock, flags); - mtk_crtc->event = mtk_crtc_state->base.event; - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); - - mtk_crtc_state->base.event = NULL; - } -} - -static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); - int i; - - if (crtc->state->color_mgmt_changed) - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { - mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state); - mtk_ddp_ctm_set(mtk_crtc->ddp_comp[i], crtc->state); - } - mtk_drm_crtc_update_config(mtk_crtc, !!mtk_crtc->event); -} - -static const struct drm_crtc_funcs mtk_crtc_funcs = { - .set_config = drm_atomic_helper_set_config, - .page_flip = drm_atomic_helper_page_flip, - .destroy = mtk_drm_crtc_destroy, - .reset = mtk_drm_crtc_reset, - .atomic_duplicate_state = mtk_drm_crtc_duplicate_state, - .atomic_destroy_state = mtk_drm_crtc_destroy_state, - .enable_vblank = mtk_drm_crtc_enable_vblank, - .disable_vblank = mtk_drm_crtc_disable_vblank, -}; - -static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = { - .mode_fixup = mtk_drm_crtc_mode_fixup, - .mode_set_nofb = mtk_drm_crtc_mode_set_nofb, - .mode_valid = mtk_drm_crtc_mode_valid, - .atomic_begin = mtk_drm_crtc_atomic_begin, - .atomic_flush = mtk_drm_crtc_atomic_flush, - .atomic_enable = mtk_drm_crtc_atomic_enable, - .atomic_disable = mtk_drm_crtc_atomic_disable, -}; - -static int mtk_drm_crtc_init(struct drm_device *drm, - struct mtk_drm_crtc *mtk_crtc, - unsigned int pipe) -{ - struct drm_plane *primary = NULL; - struct drm_plane *cursor = NULL; - int i, ret; - - for (i = 0; i < mtk_crtc->layer_nr; i++) { - if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_PRIMARY) - primary = &mtk_crtc->planes[i]; - else if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_CURSOR) - cursor = &mtk_crtc->planes[i]; - } - - ret = drm_crtc_init_with_planes(drm, &mtk_crtc->base, primary, cursor, - &mtk_crtc_funcs, NULL); - if (ret) - goto err_cleanup_crtc; - - drm_crtc_helper_add(&mtk_crtc->base, &mtk_crtc_helper_funcs); - - return 0; - -err_cleanup_crtc: - drm_crtc_cleanup(&mtk_crtc->base); - return ret; -} - -static int mtk_drm_crtc_num_comp_planes(struct mtk_drm_crtc *mtk_crtc, - int comp_idx) -{ - struct mtk_ddp_comp *comp; - - if (comp_idx > 1) - return 0; - - comp = mtk_crtc->ddp_comp[comp_idx]; - if (!comp->funcs) - return 0; - - if (comp_idx == 1 && !comp->funcs->bgclr_in_on) - return 0; - - return mtk_ddp_comp_layer_nr(comp); -} - -static inline -enum drm_plane_type mtk_drm_crtc_plane_type(unsigned int plane_idx, - unsigned int num_planes) -{ - if (plane_idx == 0) - return DRM_PLANE_TYPE_PRIMARY; - else if (plane_idx == (num_planes - 1)) - return DRM_PLANE_TYPE_CURSOR; - else - return DRM_PLANE_TYPE_OVERLAY; - -} - -static int mtk_drm_crtc_init_comp_planes(struct drm_device *drm_dev, - struct mtk_drm_crtc *mtk_crtc, - int comp_idx, int pipe) -{ - int num_planes = mtk_drm_crtc_num_comp_planes(mtk_crtc, comp_idx); - struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[comp_idx]; - int i, ret; - - for (i = 0; i < num_planes; i++) { - ret = mtk_plane_init(drm_dev, - &mtk_crtc->planes[mtk_crtc->layer_nr], - BIT(pipe), - mtk_drm_crtc_plane_type(mtk_crtc->layer_nr, - num_planes), - mtk_ddp_comp_supported_rotations(comp), - mtk_ddp_comp_get_formats(comp), - mtk_ddp_comp_get_num_formats(comp)); - if (ret) - return ret; - - mtk_crtc->layer_nr++; - } - return 0; -} - -struct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc *crtc) -{ - struct mtk_drm_crtc *mtk_crtc = NULL; - - if (!crtc) - return NULL; - - mtk_crtc = to_mtk_crtc(crtc); - if (!mtk_crtc) - return NULL; - - return mtk_crtc->dma_dev; -} - -int mtk_drm_crtc_create(struct drm_device *drm_dev, - const unsigned int *path, unsigned int path_len, - int priv_data_index, const struct mtk_drm_route *conn_routes, - unsigned int num_conn_routes) -{ - struct mtk_drm_private *priv = drm_dev->dev_private; - struct device *dev = drm_dev->dev; - struct mtk_drm_crtc *mtk_crtc; - unsigned int num_comp_planes = 0; - int ret; - int i; - bool has_ctm = false; - uint gamma_lut_size = 0; - struct drm_crtc *tmp; - int crtc_i = 0; - - if (!path) - return 0; - - priv = priv->all_drm_private[priv_data_index]; - - drm_for_each_crtc(tmp, drm_dev) - crtc_i++; - - for (i = 0; i < path_len; i++) { - enum mtk_ddp_comp_id comp_id = path[i]; - struct device_node *node; - struct mtk_ddp_comp *comp; - - node = priv->comp_node[comp_id]; - comp = &priv->ddp_comp[comp_id]; - - /* Not all drm components have a DTS device node, such as ovl_adaptor, - * which is the drm bring up sub driver - */ - if (!node && comp_id != DDP_COMPONENT_DRM_OVL_ADAPTOR) { - dev_info(dev, - "Not creating crtc %d because component %d is disabled or missing\n", - crtc_i, comp_id); - return 0; - } - - if (!comp->dev) { - dev_err(dev, "Component %pOF not initialized\n", node); - return -ENODEV; - } - } - - mtk_crtc = devm_kzalloc(dev, sizeof(*mtk_crtc), GFP_KERNEL); - if (!mtk_crtc) - return -ENOMEM; - - mtk_crtc->mmsys_dev = priv->mmsys_dev; - mtk_crtc->ddp_comp_nr = path_len; - mtk_crtc->ddp_comp = devm_kcalloc(dev, - mtk_crtc->ddp_comp_nr + (conn_routes ? 1 : 0), - sizeof(*mtk_crtc->ddp_comp), - GFP_KERNEL); - if (!mtk_crtc->ddp_comp) - return -ENOMEM; - - mtk_crtc->mutex = mtk_mutex_get(priv->mutex_dev); - if (IS_ERR(mtk_crtc->mutex)) { - ret = PTR_ERR(mtk_crtc->mutex); - dev_err(dev, "Failed to get mutex: %d\n", ret); - return ret; - } - - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { - unsigned int comp_id = path[i]; - struct mtk_ddp_comp *comp; - - comp = &priv->ddp_comp[comp_id]; - mtk_crtc->ddp_comp[i] = comp; - - if (comp->funcs) { - if (comp->funcs->gamma_set && comp->funcs->gamma_get_lut_size) { - unsigned int lut_sz = mtk_ddp_gamma_get_lut_size(comp); - - if (lut_sz) - gamma_lut_size = lut_sz; - } - - if (comp->funcs->ctm_set) - has_ctm = true; - } - - mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq, - &mtk_crtc->base); - } - - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) - num_comp_planes += mtk_drm_crtc_num_comp_planes(mtk_crtc, i); - - mtk_crtc->planes = devm_kcalloc(dev, num_comp_planes, - sizeof(struct drm_plane), GFP_KERNEL); - if (!mtk_crtc->planes) - return -ENOMEM; - - for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { - ret = mtk_drm_crtc_init_comp_planes(drm_dev, mtk_crtc, i, - crtc_i); - if (ret) - return ret; - } - - /* - * Default to use the first component as the dma dev. - * In the case of ovl_adaptor sub driver, it needs to use the - * dma_dev_get function to get representative dma dev. - */ - mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(&priv->ddp_comp[path[0]]); - - ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, crtc_i); - if (ret < 0) - return ret; - - if (gamma_lut_size) - drm_mode_crtc_set_gamma_size(&mtk_crtc->base, gamma_lut_size); - drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, has_ctm, gamma_lut_size); - mutex_init(&mtk_crtc->hw_lock); - -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - i = priv->mbox_index++; - mtk_crtc->cmdq_client.client.dev = mtk_crtc->mmsys_dev; - mtk_crtc->cmdq_client.client.tx_block = false; - mtk_crtc->cmdq_client.client.knows_txdone = true; - mtk_crtc->cmdq_client.client.rx_callback = ddp_cmdq_cb; - mtk_crtc->cmdq_client.chan = - mbox_request_channel(&mtk_crtc->cmdq_client.client, i); - if (IS_ERR(mtk_crtc->cmdq_client.chan)) { - dev_dbg(dev, "mtk_crtc %d failed to create mailbox client, writing register by CPU now\n", - drm_crtc_index(&mtk_crtc->base)); - mtk_crtc->cmdq_client.chan = NULL; - } - - if (mtk_crtc->cmdq_client.chan) { - ret = of_property_read_u32_index(priv->mutex_node, - "mediatek,gce-events", - i, - &mtk_crtc->cmdq_event); - if (ret) { - dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n", - drm_crtc_index(&mtk_crtc->base)); - mbox_free_channel(mtk_crtc->cmdq_client.chan); - mtk_crtc->cmdq_client.chan = NULL; - } else { - ret = mtk_drm_cmdq_pkt_create(&mtk_crtc->cmdq_client, - &mtk_crtc->cmdq_handle, - PAGE_SIZE); - if (ret) { - dev_dbg(dev, "mtk_crtc %d failed to create cmdq packet\n", - drm_crtc_index(&mtk_crtc->base)); - mbox_free_channel(mtk_crtc->cmdq_client.chan); - mtk_crtc->cmdq_client.chan = NULL; - } - } - - /* for sending blocking cmd in crtc disable */ - init_waitqueue_head(&mtk_crtc->cb_blocking_queue); - } -#endif - - if (conn_routes) { - for (i = 0; i < num_conn_routes; i++) { - unsigned int comp_id = conn_routes[i].route_ddp; - struct device_node *node = priv->comp_node[comp_id]; - struct mtk_ddp_comp *comp = &priv->ddp_comp[comp_id]; - - if (!comp->dev) { - dev_dbg(dev, "comp_id:%d, Component %pOF not initialized\n", - comp_id, node); - /* mark encoder_index to -1, if route comp device is not enabled */ - comp->encoder_index = -1; - continue; - } - - mtk_ddp_comp_encoder_index_set(&priv->ddp_comp[comp_id]); - } - - mtk_crtc->num_conn_routes = num_conn_routes; - mtk_crtc->conn_routes = conn_routes; - - /* increase ddp_comp_nr at the end of mtk_drm_crtc_create */ - mtk_crtc->ddp_comp_nr++; - } - - return 0; -} diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h deleted file mode 100644 index 1f988ff1bf..0000000000 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2015 MediaTek Inc. - */ - -#ifndef MTK_DRM_CRTC_H -#define MTK_DRM_CRTC_H - -#include -#include "mtk_drm_ddp_comp.h" -#include "mtk_drm_drv.h" -#include "mtk_drm_plane.h" - -#define MTK_MAX_BPC 10 -#define MTK_MIN_BPC 3 - -void mtk_drm_crtc_commit(struct drm_crtc *crtc); -int mtk_drm_crtc_create(struct drm_device *drm_dev, - const unsigned int *path, - unsigned int path_len, - int priv_data_index, - const struct mtk_drm_route *conn_routes, - unsigned int num_conn_routes); -int mtk_drm_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane, - struct mtk_plane_state *state); -void mtk_drm_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane, - struct drm_atomic_state *plane_state); -struct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc *crtc); - -#endif /* MTK_DRM_CRTC_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c deleted file mode 100644 index a515e96cfe..0000000000 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ /dev/null @@ -1,644 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2015 MediaTek Inc. - * Authors: - * YT Shen - * CK Hu - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "mtk_disp_drv.h" -#include "mtk_drm_drv.h" -#include "mtk_drm_plane.h" -#include "mtk_drm_ddp_comp.h" -#include "mtk_drm_crtc.h" - - -#define DISP_REG_DITHER_EN 0x0000 -#define DITHER_EN BIT(0) -#define DISP_REG_DITHER_CFG 0x0020 -#define DITHER_RELAY_MODE BIT(0) -#define DITHER_ENGINE_EN BIT(1) -#define DISP_DITHERING BIT(2) -#define DISP_REG_DITHER_SIZE 0x0030 -#define DISP_REG_DITHER_5 0x0114 -#define DISP_REG_DITHER_7 0x011c -#define DISP_REG_DITHER_15 0x013c -#define DITHER_LSB_ERR_SHIFT_R(x) (((x) & 0x7) << 28) -#define DITHER_ADD_LSHIFT_R(x) (((x) & 0x7) << 20) -#define DITHER_NEW_BIT_MODE BIT(0) -#define DISP_REG_DITHER_16 0x0140 -#define DITHER_LSB_ERR_SHIFT_B(x) (((x) & 0x7) << 28) -#define DITHER_ADD_LSHIFT_B(x) (((x) & 0x7) << 20) -#define DITHER_LSB_ERR_SHIFT_G(x) (((x) & 0x7) << 12) -#define DITHER_ADD_LSHIFT_G(x) (((x) & 0x7) << 4) - -#define DISP_REG_DSC_CON 0x0000 -#define DSC_EN BIT(0) -#define DSC_DUAL_INOUT BIT(2) -#define DSC_BYPASS BIT(4) -#define DSC_UFOE_SEL BIT(16) - -#define DISP_REG_OD_EN 0x0000 -#define DISP_REG_OD_CFG 0x0020 -#define OD_RELAYMODE BIT(0) -#define DISP_REG_OD_SIZE 0x0030 - -#define DISP_REG_POSTMASK_EN 0x0000 -#define POSTMASK_EN BIT(0) -#define DISP_REG_POSTMASK_CFG 0x0020 -#define POSTMASK_RELAY_MODE BIT(0) -#define DISP_REG_POSTMASK_SIZE 0x0030 - -#define DISP_REG_UFO_START 0x0000 -#define UFO_BYPASS BIT(2) - -struct mtk_ddp_comp_dev { - struct clk *clk; - void __iomem *regs; - struct cmdq_client_reg cmdq_reg; -}; - -void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value, - struct cmdq_client_reg *cmdq_reg, void __iomem *regs, - unsigned int offset) -{ -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - if (cmdq_pkt) - cmdq_pkt_write(cmdq_pkt, cmdq_reg->subsys, - cmdq_reg->offset + offset, value); - else -#endif - writel(value, regs + offset); -} - -void mtk_ddp_write_relaxed(struct cmdq_pkt *cmdq_pkt, unsigned int value, - struct cmdq_client_reg *cmdq_reg, void __iomem *regs, - unsigned int offset) -{ -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - if (cmdq_pkt) - cmdq_pkt_write(cmdq_pkt, cmdq_reg->subsys, - cmdq_reg->offset + offset, value); - else -#endif - writel_relaxed(value, regs + offset); -} - -void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, unsigned int value, - struct cmdq_client_reg *cmdq_reg, void __iomem *regs, - unsigned int offset, unsigned int mask) -{ -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - if (cmdq_pkt) { - cmdq_pkt_write_mask(cmdq_pkt, cmdq_reg->subsys, - cmdq_reg->offset + offset, value, mask); - } else { -#endif - u32 tmp = readl(regs + offset); - - tmp = (tmp & ~mask) | (value & mask); - writel(tmp, regs + offset); -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - } -#endif -} - -static int mtk_ddp_clk_enable(struct device *dev) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - return clk_prepare_enable(priv->clk); -} - -static void mtk_ddp_clk_disable(struct device *dev) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - clk_disable_unprepare(priv->clk); -} - -void mtk_dither_set_common(void __iomem *regs, struct cmdq_client_reg *cmdq_reg, - unsigned int bpc, unsigned int cfg, - unsigned int dither_en, struct cmdq_pkt *cmdq_pkt) -{ - /* If bpc equal to 0, the dithering function didn't be enabled */ - if (bpc == 0) - return; - - if (bpc >= MTK_MIN_BPC) { - mtk_ddp_write(cmdq_pkt, 0, cmdq_reg, regs, DISP_REG_DITHER_5); - mtk_ddp_write(cmdq_pkt, 0, cmdq_reg, regs, DISP_REG_DITHER_7); - mtk_ddp_write(cmdq_pkt, - DITHER_LSB_ERR_SHIFT_R(MTK_MAX_BPC - bpc) | - DITHER_ADD_LSHIFT_R(MTK_MAX_BPC - bpc) | - DITHER_NEW_BIT_MODE, - cmdq_reg, regs, DISP_REG_DITHER_15); - mtk_ddp_write(cmdq_pkt, - DITHER_LSB_ERR_SHIFT_B(MTK_MAX_BPC - bpc) | - DITHER_ADD_LSHIFT_B(MTK_MAX_BPC - bpc) | - DITHER_LSB_ERR_SHIFT_G(MTK_MAX_BPC - bpc) | - DITHER_ADD_LSHIFT_G(MTK_MAX_BPC - bpc), - cmdq_reg, regs, DISP_REG_DITHER_16); - mtk_ddp_write(cmdq_pkt, dither_en, cmdq_reg, regs, cfg); - } -} - -static void mtk_dither_config(struct device *dev, unsigned int w, - unsigned int h, unsigned int vrefresh, - unsigned int bpc, struct cmdq_pkt *cmdq_pkt) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, DISP_REG_DITHER_SIZE); - mtk_ddp_write(cmdq_pkt, DITHER_RELAY_MODE, &priv->cmdq_reg, priv->regs, - DISP_REG_DITHER_CFG); - mtk_dither_set_common(priv->regs, &priv->cmdq_reg, bpc, DISP_REG_DITHER_CFG, - DITHER_ENGINE_EN, cmdq_pkt); -} - -static void mtk_dither_start(struct device *dev) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - writel(DITHER_EN, priv->regs + DISP_REG_DITHER_EN); -} - -static void mtk_dither_stop(struct device *dev) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - writel_relaxed(0x0, priv->regs + DISP_REG_DITHER_EN); -} - -static void mtk_dither_set(struct device *dev, unsigned int bpc, - unsigned int cfg, struct cmdq_pkt *cmdq_pkt) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - mtk_dither_set_common(priv->regs, &priv->cmdq_reg, bpc, cfg, - DISP_DITHERING, cmdq_pkt); -} - -static void mtk_dsc_config(struct device *dev, unsigned int w, - unsigned int h, unsigned int vrefresh, - unsigned int bpc, struct cmdq_pkt *cmdq_pkt) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - /* dsc bypass mode */ - mtk_ddp_write_mask(cmdq_pkt, DSC_BYPASS, &priv->cmdq_reg, priv->regs, - DISP_REG_DSC_CON, DSC_BYPASS); - mtk_ddp_write_mask(cmdq_pkt, DSC_UFOE_SEL, &priv->cmdq_reg, priv->regs, - DISP_REG_DSC_CON, DSC_UFOE_SEL); - mtk_ddp_write_mask(cmdq_pkt, DSC_DUAL_INOUT, &priv->cmdq_reg, priv->regs, - DISP_REG_DSC_CON, DSC_DUAL_INOUT); -} - -static void mtk_dsc_start(struct device *dev) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - /* write with mask to reserve the value set in mtk_dsc_config */ - mtk_ddp_write_mask(NULL, DSC_EN, &priv->cmdq_reg, priv->regs, DISP_REG_DSC_CON, DSC_EN); -} - -static void mtk_dsc_stop(struct device *dev) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - writel_relaxed(0x0, priv->regs + DISP_REG_DSC_CON); -} - -static void mtk_od_config(struct device *dev, unsigned int w, - unsigned int h, unsigned int vrefresh, - unsigned int bpc, struct cmdq_pkt *cmdq_pkt) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, DISP_REG_OD_SIZE); - mtk_ddp_write(cmdq_pkt, OD_RELAYMODE, &priv->cmdq_reg, priv->regs, DISP_REG_OD_CFG); - mtk_dither_set(dev, bpc, DISP_REG_OD_CFG, cmdq_pkt); -} - -static void mtk_od_start(struct device *dev) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - writel(1, priv->regs + DISP_REG_OD_EN); -} - -static void mtk_postmask_config(struct device *dev, unsigned int w, - unsigned int h, unsigned int vrefresh, - unsigned int bpc, struct cmdq_pkt *cmdq_pkt) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, - DISP_REG_POSTMASK_SIZE); - mtk_ddp_write(cmdq_pkt, POSTMASK_RELAY_MODE, &priv->cmdq_reg, - priv->regs, DISP_REG_POSTMASK_CFG); -} - -static void mtk_postmask_start(struct device *dev) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - writel(POSTMASK_EN, priv->regs + DISP_REG_POSTMASK_EN); -} - -static void mtk_postmask_stop(struct device *dev) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - writel_relaxed(0x0, priv->regs + DISP_REG_POSTMASK_EN); -} - -static void mtk_ufoe_start(struct device *dev) -{ - struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); - - writel(UFO_BYPASS, priv->regs + DISP_REG_UFO_START); -} - -static const struct mtk_ddp_comp_funcs ddp_aal = { - .clk_enable = mtk_aal_clk_enable, - .clk_disable = mtk_aal_clk_disable, - .gamma_get_lut_size = mtk_aal_gamma_get_lut_size, - .gamma_set = mtk_aal_gamma_set, - .config = mtk_aal_config, - .start = mtk_aal_start, - .stop = mtk_aal_stop, -}; - -static const struct mtk_ddp_comp_funcs ddp_ccorr = { - .clk_enable = mtk_ccorr_clk_enable, - .clk_disable = mtk_ccorr_clk_disable, - .config = mtk_ccorr_config, - .start = mtk_ccorr_start, - .stop = mtk_ccorr_stop, - .ctm_set = mtk_ccorr_ctm_set, -}; - -static const struct mtk_ddp_comp_funcs ddp_color = { - .clk_enable = mtk_color_clk_enable, - .clk_disable = mtk_color_clk_disable, - .config = mtk_color_config, - .start = mtk_color_start, -}; - -static const struct mtk_ddp_comp_funcs ddp_dither = { - .clk_enable = mtk_ddp_clk_enable, - .clk_disable = mtk_ddp_clk_disable, - .config = mtk_dither_config, - .start = mtk_dither_start, - .stop = mtk_dither_stop, -}; - -static const struct mtk_ddp_comp_funcs ddp_dpi = { - .start = mtk_dpi_start, - .stop = mtk_dpi_stop, - .encoder_index = mtk_dpi_encoder_index, -}; - -static const struct mtk_ddp_comp_funcs ddp_dsc = { - .clk_enable = mtk_ddp_clk_enable, - .clk_disable = mtk_ddp_clk_disable, - .config = mtk_dsc_config, - .start = mtk_dsc_start, - .stop = mtk_dsc_stop, -}; - -static const struct mtk_ddp_comp_funcs ddp_dsi = { - .start = mtk_dsi_ddp_start, - .stop = mtk_dsi_ddp_stop, - .encoder_index = mtk_dsi_encoder_index, -}; - -static const struct mtk_ddp_comp_funcs ddp_gamma = { - .clk_enable = mtk_gamma_clk_enable, - .clk_disable = mtk_gamma_clk_disable, - .gamma_get_lut_size = mtk_gamma_get_lut_size, - .gamma_set = mtk_gamma_set, - .config = mtk_gamma_config, - .start = mtk_gamma_start, - .stop = mtk_gamma_stop, -}; - -static const struct mtk_ddp_comp_funcs ddp_merge = { - .clk_enable = mtk_merge_clk_enable, - .clk_disable = mtk_merge_clk_disable, - .start = mtk_merge_start, - .stop = mtk_merge_stop, - .config = mtk_merge_config, -}; - -static const struct mtk_ddp_comp_funcs ddp_od = { - .clk_enable = mtk_ddp_clk_enable, - .clk_disable = mtk_ddp_clk_disable, - .config = mtk_od_config, - .start = mtk_od_start, -}; - -static const struct mtk_ddp_comp_funcs ddp_ovl = { - .clk_enable = mtk_ovl_clk_enable, - .clk_disable = mtk_ovl_clk_disable, - .config = mtk_ovl_config, - .start = mtk_ovl_start, - .stop = mtk_ovl_stop, - .register_vblank_cb = mtk_ovl_register_vblank_cb, - .unregister_vblank_cb = mtk_ovl_unregister_vblank_cb, - .enable_vblank = mtk_ovl_enable_vblank, - .disable_vblank = mtk_ovl_disable_vblank, - .supported_rotations = mtk_ovl_supported_rotations, - .layer_nr = mtk_ovl_layer_nr, - .layer_check = mtk_ovl_layer_check, - .layer_config = mtk_ovl_layer_config, - .bgclr_in_on = mtk_ovl_bgclr_in_on, - .bgclr_in_off = mtk_ovl_bgclr_in_off, - .get_formats = mtk_ovl_get_formats, - .get_num_formats = mtk_ovl_get_num_formats, -}; - -static const struct mtk_ddp_comp_funcs ddp_postmask = { - .clk_enable = mtk_ddp_clk_enable, - .clk_disable = mtk_ddp_clk_disable, - .config = mtk_postmask_config, - .start = mtk_postmask_start, - .stop = mtk_postmask_stop, -}; - -static const struct mtk_ddp_comp_funcs ddp_rdma = { - .clk_enable = mtk_rdma_clk_enable, - .clk_disable = mtk_rdma_clk_disable, - .config = mtk_rdma_config, - .start = mtk_rdma_start, - .stop = mtk_rdma_stop, - .register_vblank_cb = mtk_rdma_register_vblank_cb, - .unregister_vblank_cb = mtk_rdma_unregister_vblank_cb, - .enable_vblank = mtk_rdma_enable_vblank, - .disable_vblank = mtk_rdma_disable_vblank, - .layer_nr = mtk_rdma_layer_nr, - .layer_config = mtk_rdma_layer_config, - .get_formats = mtk_rdma_get_formats, - .get_num_formats = mtk_rdma_get_num_formats, -}; - -static const struct mtk_ddp_comp_funcs ddp_ufoe = { - .clk_enable = mtk_ddp_clk_enable, - .clk_disable = mtk_ddp_clk_disable, - .start = mtk_ufoe_start, -}; - -static const struct mtk_ddp_comp_funcs ddp_ovl_adaptor = { - .power_on = mtk_ovl_adaptor_power_on, - .power_off = mtk_ovl_adaptor_power_off, - .clk_enable = mtk_ovl_adaptor_clk_enable, - .clk_disable = mtk_ovl_adaptor_clk_disable, - .config = mtk_ovl_adaptor_config, - .start = mtk_ovl_adaptor_start, - .stop = mtk_ovl_adaptor_stop, - .layer_nr = mtk_ovl_adaptor_layer_nr, - .layer_config = mtk_ovl_adaptor_layer_config, - .register_vblank_cb = mtk_ovl_adaptor_register_vblank_cb, - .unregister_vblank_cb = mtk_ovl_adaptor_unregister_vblank_cb, - .enable_vblank = mtk_ovl_adaptor_enable_vblank, - .disable_vblank = mtk_ovl_adaptor_disable_vblank, - .dma_dev_get = mtk_ovl_adaptor_dma_dev_get, - .connect = mtk_ovl_adaptor_connect, - .disconnect = mtk_ovl_adaptor_disconnect, - .add = mtk_ovl_adaptor_add_comp, - .remove = mtk_ovl_adaptor_remove_comp, - .get_formats = mtk_ovl_adaptor_get_formats, - .get_num_formats = mtk_ovl_adaptor_get_num_formats, - .mode_valid = mtk_ovl_adaptor_mode_valid, -}; - -static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = { - [MTK_DISP_AAL] = "aal", - [MTK_DISP_BLS] = "bls", - [MTK_DISP_CCORR] = "ccorr", - [MTK_DISP_COLOR] = "color", - [MTK_DISP_DITHER] = "dither", - [MTK_DISP_DSC] = "dsc", - [MTK_DISP_GAMMA] = "gamma", - [MTK_DISP_MERGE] = "merge", - [MTK_DISP_MUTEX] = "mutex", - [MTK_DISP_OD] = "od", - [MTK_DISP_OVL] = "ovl", - [MTK_DISP_OVL_2L] = "ovl-2l", - [MTK_DISP_OVL_ADAPTOR] = "ovl_adaptor", - [MTK_DISP_POSTMASK] = "postmask", - [MTK_DISP_PWM] = "pwm", - [MTK_DISP_RDMA] = "rdma", - [MTK_DISP_UFOE] = "ufoe", - [MTK_DISP_WDMA] = "wdma", - [MTK_DP_INTF] = "dp-intf", - [MTK_DPI] = "dpi", - [MTK_DSI] = "dsi", -}; - -struct mtk_ddp_comp_match { - enum mtk_ddp_comp_type type; - int alias_id; - const struct mtk_ddp_comp_funcs *funcs; -}; - -static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_DRM_ID_MAX] = { - [DDP_COMPONENT_AAL0] = { MTK_DISP_AAL, 0, &ddp_aal }, - [DDP_COMPONENT_AAL1] = { MTK_DISP_AAL, 1, &ddp_aal }, - [DDP_COMPONENT_BLS] = { MTK_DISP_BLS, 0, NULL }, - [DDP_COMPONENT_CCORR] = { MTK_DISP_CCORR, 0, &ddp_ccorr }, - [DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, &ddp_color }, - [DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, &ddp_color }, - [DDP_COMPONENT_DITHER0] = { MTK_DISP_DITHER, 0, &ddp_dither }, - [DDP_COMPONENT_DP_INTF0] = { MTK_DP_INTF, 0, &ddp_dpi }, - [DDP_COMPONENT_DP_INTF1] = { MTK_DP_INTF, 1, &ddp_dpi }, - [DDP_COMPONENT_DPI0] = { MTK_DPI, 0, &ddp_dpi }, - [DDP_COMPONENT_DPI1] = { MTK_DPI, 1, &ddp_dpi }, - [DDP_COMPONENT_DRM_OVL_ADAPTOR] = { MTK_DISP_OVL_ADAPTOR, 0, &ddp_ovl_adaptor }, - [DDP_COMPONENT_DSC0] = { MTK_DISP_DSC, 0, &ddp_dsc }, - [DDP_COMPONENT_DSC1] = { MTK_DISP_DSC, 1, &ddp_dsc }, - [DDP_COMPONENT_DSI0] = { MTK_DSI, 0, &ddp_dsi }, - [DDP_COMPONENT_DSI1] = { MTK_DSI, 1, &ddp_dsi }, - [DDP_COMPONENT_DSI2] = { MTK_DSI, 2, &ddp_dsi }, - [DDP_COMPONENT_DSI3] = { MTK_DSI, 3, &ddp_dsi }, - [DDP_COMPONENT_GAMMA] = { MTK_DISP_GAMMA, 0, &ddp_gamma }, - [DDP_COMPONENT_MERGE0] = { MTK_DISP_MERGE, 0, &ddp_merge }, - [DDP_COMPONENT_MERGE1] = { MTK_DISP_MERGE, 1, &ddp_merge }, - [DDP_COMPONENT_MERGE2] = { MTK_DISP_MERGE, 2, &ddp_merge }, - [DDP_COMPONENT_MERGE3] = { MTK_DISP_MERGE, 3, &ddp_merge }, - [DDP_COMPONENT_MERGE4] = { MTK_DISP_MERGE, 4, &ddp_merge }, - [DDP_COMPONENT_MERGE5] = { MTK_DISP_MERGE, 5, &ddp_merge }, - [DDP_COMPONENT_OD0] = { MTK_DISP_OD, 0, &ddp_od }, - [DDP_COMPONENT_OD1] = { MTK_DISP_OD, 1, &ddp_od }, - [DDP_COMPONENT_OVL0] = { MTK_DISP_OVL, 0, &ddp_ovl }, - [DDP_COMPONENT_OVL1] = { MTK_DISP_OVL, 1, &ddp_ovl }, - [DDP_COMPONENT_OVL_2L0] = { MTK_DISP_OVL_2L, 0, &ddp_ovl }, - [DDP_COMPONENT_OVL_2L1] = { MTK_DISP_OVL_2L, 1, &ddp_ovl }, - [DDP_COMPONENT_OVL_2L2] = { MTK_DISP_OVL_2L, 2, &ddp_ovl }, - [DDP_COMPONENT_POSTMASK0] = { MTK_DISP_POSTMASK, 0, &ddp_postmask }, - [DDP_COMPONENT_PWM0] = { MTK_DISP_PWM, 0, NULL }, - [DDP_COMPONENT_PWM1] = { MTK_DISP_PWM, 1, NULL }, - [DDP_COMPONENT_PWM2] = { MTK_DISP_PWM, 2, NULL }, - [DDP_COMPONENT_RDMA0] = { MTK_DISP_RDMA, 0, &ddp_rdma }, - [DDP_COMPONENT_RDMA1] = { MTK_DISP_RDMA, 1, &ddp_rdma }, - [DDP_COMPONENT_RDMA2] = { MTK_DISP_RDMA, 2, &ddp_rdma }, - [DDP_COMPONENT_RDMA4] = { MTK_DISP_RDMA, 4, &ddp_rdma }, - [DDP_COMPONENT_UFOE] = { MTK_DISP_UFOE, 0, &ddp_ufoe }, - [DDP_COMPONENT_WDMA0] = { MTK_DISP_WDMA, 0, NULL }, - [DDP_COMPONENT_WDMA1] = { MTK_DISP_WDMA, 1, NULL }, -}; - -static bool mtk_drm_find_comp_in_ddp(struct device *dev, - const unsigned int *path, - unsigned int path_len, - struct mtk_ddp_comp *ddp_comp) -{ - unsigned int i; - - if (path == NULL) - return false; - - for (i = 0U; i < path_len; i++) - if (dev == ddp_comp[path[i]].dev) - return true; - - return false; -} - -static unsigned int mtk_drm_find_comp_in_ddp_conn_path(struct device *dev, - const struct mtk_drm_route *routes, - unsigned int num_routes, - struct mtk_ddp_comp *ddp_comp) -{ - int ret; - unsigned int i; - - if (!routes) { - ret = -EINVAL; - goto err; - } - - for (i = 0; i < num_routes; i++) - if (dev == ddp_comp[routes[i].route_ddp].dev) - return BIT(routes[i].crtc_id); - - ret = -ENODEV; -err: - - DRM_INFO("Failed to find comp in ddp table, ret = %d\n", ret); - - return 0; -} - -int mtk_ddp_comp_get_id(struct device_node *node, - enum mtk_ddp_comp_type comp_type) -{ - int id = of_alias_get_id(node, mtk_ddp_comp_stem[comp_type]); - int i; - - for (i = 0; i < ARRAY_SIZE(mtk_ddp_matches); i++) { - if (comp_type == mtk_ddp_matches[i].type && - (id < 0 || id == mtk_ddp_matches[i].alias_id)) - return i; - } - - return -EINVAL; -} - -unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm, - struct device *dev) -{ - struct mtk_drm_private *private = drm->dev_private; - unsigned int ret = 0; - - if (mtk_drm_find_comp_in_ddp(dev, private->data->main_path, private->data->main_len, - private->ddp_comp)) - ret = BIT(0); - else if (mtk_drm_find_comp_in_ddp(dev, private->data->ext_path, - private->data->ext_len, private->ddp_comp)) - ret = BIT(1); - else if (mtk_drm_find_comp_in_ddp(dev, private->data->third_path, - private->data->third_len, private->ddp_comp)) - ret = BIT(2); - else - ret = mtk_drm_find_comp_in_ddp_conn_path(dev, - private->data->conn_routes, - private->data->num_conn_routes, - private->ddp_comp); - - return ret; -} - -int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp, - unsigned int comp_id) -{ - struct platform_device *comp_pdev; - enum mtk_ddp_comp_type type; - struct mtk_ddp_comp_dev *priv; -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - int ret; -#endif - - if (comp_id < 0 || comp_id >= DDP_COMPONENT_DRM_ID_MAX) - return -EINVAL; - - type = mtk_ddp_matches[comp_id].type; - - comp->id = comp_id; - comp->funcs = mtk_ddp_matches[comp_id].funcs; - /* Not all drm components have a DTS device node, such as ovl_adaptor, - * which is the drm bring up sub driver - */ - if (!node) - return 0; - - comp_pdev = of_find_device_by_node(node); - if (!comp_pdev) { - DRM_INFO("Waiting for device %s\n", node->full_name); - return -EPROBE_DEFER; - } - comp->dev = &comp_pdev->dev; - - if (type == MTK_DISP_AAL || - type == MTK_DISP_BLS || - type == MTK_DISP_CCORR || - type == MTK_DISP_COLOR || - type == MTK_DISP_GAMMA || - type == MTK_DISP_MERGE || - type == MTK_DISP_OVL || - type == MTK_DISP_OVL_2L || - type == MTK_DISP_PWM || - type == MTK_DISP_RDMA || - type == MTK_DPI || - type == MTK_DP_INTF || - type == MTK_DSI) - return 0; - - priv = devm_kzalloc(comp->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->regs = of_iomap(node, 0); - priv->clk = of_clk_get(node, 0); - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); - -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - ret = cmdq_dev_get_client_reg(comp->dev, &priv->cmdq_reg, 0); - if (ret) - dev_dbg(comp->dev, "get mediatek,gce-client-reg fail!\n"); -#endif - - platform_set_drvdata(comp_pdev, priv); - - return 0; -} diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h deleted file mode 100644 index 93d79a1366..0000000000 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ /dev/null @@ -1,343 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2015 MediaTek Inc. - */ - -#ifndef MTK_DRM_DDP_COMP_H -#define MTK_DRM_DDP_COMP_H - -#include -#include -#include -#include -#include - -#include - -struct device; -struct device_node; -struct drm_crtc; -struct drm_device; -struct mtk_plane_state; -struct drm_crtc_state; - -enum mtk_ddp_comp_type { - MTK_DISP_AAL, - MTK_DISP_BLS, - MTK_DISP_CCORR, - MTK_DISP_COLOR, - MTK_DISP_DITHER, - MTK_DISP_DSC, - MTK_DISP_GAMMA, - MTK_DISP_MERGE, - MTK_DISP_MUTEX, - MTK_DISP_OD, - MTK_DISP_OVL, - MTK_DISP_OVL_2L, - MTK_DISP_OVL_ADAPTOR, - MTK_DISP_POSTMASK, - MTK_DISP_PWM, - MTK_DISP_RDMA, - MTK_DISP_UFOE, - MTK_DISP_WDMA, - MTK_DPI, - MTK_DP_INTF, - MTK_DSI, - MTK_DDP_COMP_TYPE_MAX, -}; - -struct mtk_ddp_comp; -struct cmdq_pkt; -struct mtk_ddp_comp_funcs { - int (*power_on)(struct device *dev); - void (*power_off)(struct device *dev); - int (*clk_enable)(struct device *dev); - void (*clk_disable)(struct device *dev); - void (*config)(struct device *dev, unsigned int w, - unsigned int h, unsigned int vrefresh, - unsigned int bpc, struct cmdq_pkt *cmdq_pkt); - void (*start)(struct device *dev); - void (*stop)(struct device *dev); - void (*register_vblank_cb)(struct device *dev, - void (*vblank_cb)(void *), - void *vblank_cb_data); - void (*unregister_vblank_cb)(struct device *dev); - void (*enable_vblank)(struct device *dev); - void (*disable_vblank)(struct device *dev); - unsigned int (*supported_rotations)(struct device *dev); - unsigned int (*layer_nr)(struct device *dev); - int (*layer_check)(struct device *dev, - unsigned int idx, - struct mtk_plane_state *state); - void (*layer_config)(struct device *dev, unsigned int idx, - struct mtk_plane_state *state, - struct cmdq_pkt *cmdq_pkt); - unsigned int (*gamma_get_lut_size)(struct device *dev); - void (*gamma_set)(struct device *dev, - struct drm_crtc_state *state); - void (*bgclr_in_on)(struct device *dev); - void (*bgclr_in_off)(struct device *dev); - void (*ctm_set)(struct device *dev, - struct drm_crtc_state *state); - struct device * (*dma_dev_get)(struct device *dev); - const u32 *(*get_formats)(struct device *dev); - size_t (*get_num_formats)(struct device *dev); - void (*connect)(struct device *dev, struct device *mmsys_dev, unsigned int next); - void (*disconnect)(struct device *dev, struct device *mmsys_dev, unsigned int next); - void (*add)(struct device *dev, struct mtk_mutex *mutex); - void (*remove)(struct device *dev, struct mtk_mutex *mutex); - unsigned int (*encoder_index)(struct device *dev); - enum drm_mode_status (*mode_valid)(struct device *dev, const struct drm_display_mode *mode); -}; - -struct mtk_ddp_comp { - struct device *dev; - int irq; - unsigned int id; - int encoder_index; - const struct mtk_ddp_comp_funcs *funcs; -}; - -static inline int mtk_ddp_comp_power_on(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->power_on) - return comp->funcs->power_on(comp->dev); - else - return pm_runtime_resume_and_get(comp->dev); - return 0; -} - -static inline void mtk_ddp_comp_power_off(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->power_off) - comp->funcs->power_off(comp->dev); - else - pm_runtime_put(comp->dev); -} - -static inline int mtk_ddp_comp_clk_enable(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->clk_enable) - return comp->funcs->clk_enable(comp->dev); - - return 0; -} - -static inline void mtk_ddp_comp_clk_disable(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->clk_disable) - comp->funcs->clk_disable(comp->dev); -} - -static inline -enum drm_mode_status mtk_ddp_comp_mode_valid(struct mtk_ddp_comp *comp, - const struct drm_display_mode *mode) -{ - if (comp && comp->funcs && comp->funcs->mode_valid) - return comp->funcs->mode_valid(comp->dev, mode); - return MODE_OK; -} - -static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp, - unsigned int w, unsigned int h, - unsigned int vrefresh, unsigned int bpc, - struct cmdq_pkt *cmdq_pkt) -{ - if (comp->funcs && comp->funcs->config) - comp->funcs->config(comp->dev, w, h, vrefresh, bpc, cmdq_pkt); -} - -static inline void mtk_ddp_comp_start(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->start) - comp->funcs->start(comp->dev); -} - -static inline void mtk_ddp_comp_stop(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->stop) - comp->funcs->stop(comp->dev); -} - -static inline void mtk_ddp_comp_register_vblank_cb(struct mtk_ddp_comp *comp, - void (*vblank_cb)(void *), - void *vblank_cb_data) -{ - if (comp->funcs && comp->funcs->register_vblank_cb) - comp->funcs->register_vblank_cb(comp->dev, vblank_cb, - vblank_cb_data); -} - -static inline void mtk_ddp_comp_unregister_vblank_cb(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->unregister_vblank_cb) - comp->funcs->unregister_vblank_cb(comp->dev); -} - -static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->enable_vblank) - comp->funcs->enable_vblank(comp->dev); -} - -static inline void mtk_ddp_comp_disable_vblank(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->disable_vblank) - comp->funcs->disable_vblank(comp->dev); -} - -static inline -unsigned int mtk_ddp_comp_supported_rotations(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->supported_rotations) - return comp->funcs->supported_rotations(comp->dev); - - return 0; -} - -static inline unsigned int mtk_ddp_comp_layer_nr(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->layer_nr) - return comp->funcs->layer_nr(comp->dev); - - return 0; -} - -static inline int mtk_ddp_comp_layer_check(struct mtk_ddp_comp *comp, - unsigned int idx, - struct mtk_plane_state *state) -{ - if (comp->funcs && comp->funcs->layer_check) - return comp->funcs->layer_check(comp->dev, idx, state); - return 0; -} - -static inline void mtk_ddp_comp_layer_config(struct mtk_ddp_comp *comp, - unsigned int idx, - struct mtk_plane_state *state, - struct cmdq_pkt *cmdq_pkt) -{ - if (comp->funcs && comp->funcs->layer_config) - comp->funcs->layer_config(comp->dev, idx, state, cmdq_pkt); -} - -static inline unsigned int mtk_ddp_gamma_get_lut_size(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->gamma_get_lut_size) - return comp->funcs->gamma_get_lut_size(comp->dev); - - return 0; -} - -static inline void mtk_ddp_gamma_set(struct mtk_ddp_comp *comp, - struct drm_crtc_state *state) -{ - if (comp->funcs && comp->funcs->gamma_set) - comp->funcs->gamma_set(comp->dev, state); -} - -static inline void mtk_ddp_comp_bgclr_in_on(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->bgclr_in_on) - comp->funcs->bgclr_in_on(comp->dev); -} - -static inline void mtk_ddp_comp_bgclr_in_off(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->bgclr_in_off) - comp->funcs->bgclr_in_off(comp->dev); -} - -static inline void mtk_ddp_ctm_set(struct mtk_ddp_comp *comp, - struct drm_crtc_state *state) -{ - if (comp->funcs && comp->funcs->ctm_set) - comp->funcs->ctm_set(comp->dev, state); -} - -static inline struct device *mtk_ddp_comp_dma_dev_get(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->dma_dev_get) - return comp->funcs->dma_dev_get(comp->dev); - return comp->dev; -} - -static inline -const u32 *mtk_ddp_comp_get_formats(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->get_formats) - return comp->funcs->get_formats(comp->dev); - - return NULL; -} - -static inline -size_t mtk_ddp_comp_get_num_formats(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->get_num_formats) - return comp->funcs->get_num_formats(comp->dev); - - return 0; -} - -static inline bool mtk_ddp_comp_add(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex) -{ - if (comp->funcs && comp->funcs->add) { - comp->funcs->add(comp->dev, mutex); - return true; - } - return false; -} - -static inline bool mtk_ddp_comp_remove(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex) -{ - if (comp->funcs && comp->funcs->remove) { - comp->funcs->remove(comp->dev, mutex); - return true; - } - return false; -} - -static inline bool mtk_ddp_comp_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev, - unsigned int next) -{ - if (comp->funcs && comp->funcs->connect) { - comp->funcs->connect(comp->dev, mmsys_dev, next); - return true; - } - return false; -} - -static inline bool mtk_ddp_comp_disconnect(struct mtk_ddp_comp *comp, struct device *mmsys_dev, - unsigned int next) -{ - if (comp->funcs && comp->funcs->disconnect) { - comp->funcs->disconnect(comp->dev, mmsys_dev, next); - return true; - } - return false; -} - -static inline void mtk_ddp_comp_encoder_index_set(struct mtk_ddp_comp *comp) -{ - if (comp->funcs && comp->funcs->encoder_index) - comp->encoder_index = (int)comp->funcs->encoder_index(comp->dev); -} - -int mtk_ddp_comp_get_id(struct device_node *node, - enum mtk_ddp_comp_type comp_type); -unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm, - struct device *dev); -int mtk_ddp_comp_init(struct device_node *comp_node, struct mtk_ddp_comp *comp, - unsigned int comp_id); -enum mtk_ddp_comp_type mtk_ddp_comp_get_type(unsigned int comp_id); -void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value, - struct cmdq_client_reg *cmdq_reg, void __iomem *regs, - unsigned int offset); -void mtk_ddp_write_relaxed(struct cmdq_pkt *cmdq_pkt, unsigned int value, - struct cmdq_client_reg *cmdq_reg, void __iomem *regs, - unsigned int offset); -void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, unsigned int value, - struct cmdq_client_reg *cmdq_reg, void __iomem *regs, - unsigned int offset, unsigned int mask); -#endif /* MTK_DRM_DDP_COMP_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 0b570e1940..56f409ad7f 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -24,10 +24,10 @@ #include #include -#include "mtk_drm_crtc.h" -#include "mtk_drm_ddp_comp.h" +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" #include "mtk_drm_drv.h" -#include "mtk_drm_gem.h" +#include "mtk_gem.h" #define DRIVER_NAME "mediatek" #define DRIVER_DESC "Mediatek SoC DRM" @@ -294,6 +294,9 @@ static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = { .conn_routes = mt8188_mtk_ddp_main_routes, .num_conn_routes = ARRAY_SIZE(mt8188_mtk_ddp_main_routes), .mmsys_dev_num = 2, + .max_width = 8191, + .min_width = 1, + .min_height = 1, }; static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = { @@ -308,6 +311,9 @@ static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = { .main_path = mt8195_mtk_ddp_main, .main_len = ARRAY_SIZE(mt8195_mtk_ddp_main), .mmsys_dev_num = 2, + .max_width = 8191, + .min_width = 1, + .min_height = 1, }; static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = { @@ -315,6 +321,9 @@ static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = { .ext_len = ARRAY_SIZE(mt8195_mtk_ddp_ext), .mmsys_id = 1, .mmsys_dev_num = 2, + .max_width = 8191, + .min_width = 2, /* 2-pixel align when ethdr is bypassed */ + .min_height = 1, }; static const struct of_device_id mtk_drm_of_ids[] = { @@ -493,25 +502,34 @@ static int mtk_drm_kms_init(struct drm_device *drm) for (j = 0; j < private->data->mmsys_dev_num; j++) { priv_n = private->all_drm_private[j]; + if (priv_n->data->max_width) + drm->mode_config.max_width = priv_n->data->max_width; + + if (priv_n->data->min_width) + drm->mode_config.min_width = priv_n->data->min_width; + + if (priv_n->data->min_height) + drm->mode_config.min_height = priv_n->data->min_height; + if (i == CRTC_MAIN && priv_n->data->main_len) { - ret = mtk_drm_crtc_create(drm, priv_n->data->main_path, - priv_n->data->main_len, j, - priv_n->data->conn_routes, - priv_n->data->num_conn_routes); + ret = mtk_crtc_create(drm, priv_n->data->main_path, + priv_n->data->main_len, j, + priv_n->data->conn_routes, + priv_n->data->num_conn_routes); if (ret) goto err_component_unbind; continue; } else if (i == CRTC_EXT && priv_n->data->ext_len) { - ret = mtk_drm_crtc_create(drm, priv_n->data->ext_path, - priv_n->data->ext_len, j, NULL, 0); + ret = mtk_crtc_create(drm, priv_n->data->ext_path, + priv_n->data->ext_len, j, NULL, 0); if (ret) goto err_component_unbind; continue; } else if (i == CRTC_THIRD && priv_n->data->third_len) { - ret = mtk_drm_crtc_create(drm, priv_n->data->third_path, - priv_n->data->third_len, j, NULL, 0); + ret = mtk_crtc_create(drm, priv_n->data->third_path, + priv_n->data->third_len, j, NULL, 0); if (ret) goto err_component_unbind; @@ -520,10 +538,14 @@ static int mtk_drm_kms_init(struct drm_device *drm) } } + /* IGT will check if the cursor size is configured */ + drm->mode_config.cursor_width = drm->mode_config.max_width; + drm->mode_config.cursor_height = drm->mode_config.max_height; + /* Use OVL device for all DMA memory allocations */ crtc = drm_crtc_from_index(drm, 0); if (crtc) - dma_dev = mtk_drm_crtc_dma_dev_get(crtc); + dma_dev = mtk_crtc_dma_dev_get(crtc); if (!dma_dev) { ret = -ENODEV; dev_err(drm->dev, "Need at least one OVL device\n"); @@ -576,8 +598,8 @@ DEFINE_DRM_GEM_FOPS(mtk_drm_fops); * We need to override this because the device used to import the memory is * not dev->dev, as drm_gem_prime_import() expects. */ -static struct drm_gem_object *mtk_drm_gem_prime_import(struct drm_device *dev, - struct dma_buf *dma_buf) +static struct drm_gem_object *mtk_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf) { struct mtk_drm_private *private = dev->dev_private; @@ -587,9 +609,9 @@ static struct drm_gem_object *mtk_drm_gem_prime_import(struct drm_device *dev, static const struct drm_driver mtk_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, - .dumb_create = mtk_drm_gem_dumb_create, + .dumb_create = mtk_gem_dumb_create, - .gem_prime_import = mtk_drm_gem_prime_import, + .gem_prime_import = mtk_gem_prime_import, .gem_prime_import_sg_table = mtk_gem_prime_import_sg_table, .fops = &mtk_drm_fops, @@ -709,6 +731,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { .data = (void *)MTK_DISP_GAMMA, }, { .compatible = "mediatek,mt8183-disp-gamma", .data = (void *)MTK_DISP_GAMMA, }, + { .compatible = "mediatek,mt8195-disp-gamma", + .data = (void *)MTK_DISP_GAMMA, }, { .compatible = "mediatek,mt8195-disp-merge", .data = (void *)MTK_DISP_MERGE }, { .compatible = "mediatek,mt2701-disp-mutex", @@ -741,6 +765,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { .data = (void *)MTK_DISP_OVL }, { .compatible = "mediatek,mt8192-disp-ovl", .data = (void *)MTK_DISP_OVL }, + { .compatible = "mediatek,mt8195-disp-ovl", + .data = (void *)MTK_DISP_OVL }, { .compatible = "mediatek,mt8183-disp-ovl-2l", .data = (void *)MTK_DISP_OVL_2L }, { .compatible = "mediatek,mt8192-disp-ovl-2l", diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h index 33fadb08dc..ce897984de 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h @@ -7,13 +7,13 @@ #define MTK_DRM_DRV_H #include -#include "mtk_drm_ddp_comp.h" +#include "mtk_ddp_comp.h" #define MAX_CONNECTOR 2 #define DDP_COMPONENT_DRM_OVL_ADAPTOR (DDP_COMPONENT_ID_MAX + 1) #define DDP_COMPONENT_DRM_ID_MAX (DDP_COMPONENT_DRM_OVL_ADAPTOR + 1) -enum mtk_drm_crtc_path { +enum mtk_crtc_path { CRTC_MAIN, CRTC_EXT, CRTC_THIRD, @@ -46,6 +46,10 @@ struct mtk_mmsys_driver_data { bool shadow_register; unsigned int mmsys_id; unsigned int mmsys_dev_num; + + u16 max_width; + u16 min_width; + u16 min_height; }; struct mtk_drm_private { diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c b/drivers/gpu/drm/mediatek/mtk_drm_gem.c deleted file mode 100644 index 1bf229615b..0000000000 --- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c +++ /dev/null @@ -1,288 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2015 MediaTek Inc. - */ - -#include - -#include -#include -#include -#include -#include - -#include "mtk_drm_drv.h" -#include "mtk_drm_gem.h" - -static int mtk_drm_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); - -static const struct vm_operations_struct vm_ops = { - .open = drm_gem_vm_open, - .close = drm_gem_vm_close, -}; - -static const struct drm_gem_object_funcs mtk_drm_gem_object_funcs = { - .free = mtk_drm_gem_free_object, - .get_sg_table = mtk_gem_prime_get_sg_table, - .vmap = mtk_drm_gem_prime_vmap, - .vunmap = mtk_drm_gem_prime_vunmap, - .mmap = mtk_drm_gem_object_mmap, - .vm_ops = &vm_ops, -}; - -static struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev, - unsigned long size) -{ - struct mtk_drm_gem_obj *mtk_gem_obj; - int ret; - - size = round_up(size, PAGE_SIZE); - - if (size == 0) - return ERR_PTR(-EINVAL); - - mtk_gem_obj = kzalloc(sizeof(*mtk_gem_obj), GFP_KERNEL); - if (!mtk_gem_obj) - return ERR_PTR(-ENOMEM); - - mtk_gem_obj->base.funcs = &mtk_drm_gem_object_funcs; - - ret = drm_gem_object_init(dev, &mtk_gem_obj->base, size); - if (ret < 0) { - DRM_ERROR("failed to initialize gem object\n"); - kfree(mtk_gem_obj); - return ERR_PTR(ret); - } - - return mtk_gem_obj; -} - -struct mtk_drm_gem_obj *mtk_drm_gem_create(struct drm_device *dev, - size_t size, bool alloc_kmap) -{ - struct mtk_drm_private *priv = dev->dev_private; - struct mtk_drm_gem_obj *mtk_gem; - struct drm_gem_object *obj; - int ret; - - mtk_gem = mtk_drm_gem_init(dev, size); - if (IS_ERR(mtk_gem)) - return ERR_CAST(mtk_gem); - - obj = &mtk_gem->base; - - mtk_gem->dma_attrs = DMA_ATTR_WRITE_COMBINE; - - if (!alloc_kmap) - mtk_gem->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING; - - mtk_gem->cookie = dma_alloc_attrs(priv->dma_dev, obj->size, - &mtk_gem->dma_addr, GFP_KERNEL, - mtk_gem->dma_attrs); - if (!mtk_gem->cookie) { - DRM_ERROR("failed to allocate %zx byte dma buffer", obj->size); - ret = -ENOMEM; - goto err_gem_free; - } - - if (alloc_kmap) - mtk_gem->kvaddr = mtk_gem->cookie; - - DRM_DEBUG_DRIVER("cookie = %p dma_addr = %pad size = %zu\n", - mtk_gem->cookie, &mtk_gem->dma_addr, - size); - - return mtk_gem; - -err_gem_free: - drm_gem_object_release(obj); - kfree(mtk_gem); - return ERR_PTR(ret); -} - -void mtk_drm_gem_free_object(struct drm_gem_object *obj) -{ - struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj); - struct mtk_drm_private *priv = obj->dev->dev_private; - - if (mtk_gem->sg) - drm_prime_gem_destroy(obj, mtk_gem->sg); - else - dma_free_attrs(priv->dma_dev, obj->size, mtk_gem->cookie, - mtk_gem->dma_addr, mtk_gem->dma_attrs); - - /* release file pointer to gem object. */ - drm_gem_object_release(obj); - - kfree(mtk_gem); -} - -int mtk_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, - struct drm_mode_create_dumb *args) -{ - struct mtk_drm_gem_obj *mtk_gem; - int ret; - - args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8); - - /* - * Multiply 2 variables of different types, - * for example: args->size = args->spacing * args->height; - * may cause coverity issue with unintentional overflow. - */ - args->size = args->pitch; - args->size *= args->height; - - mtk_gem = mtk_drm_gem_create(dev, args->size, false); - if (IS_ERR(mtk_gem)) - return PTR_ERR(mtk_gem); - - /* - * allocate a id of idr table where the obj is registered - * and handle has the id what user can see. - */ - ret = drm_gem_handle_create(file_priv, &mtk_gem->base, &args->handle); - if (ret) - goto err_handle_create; - - /* drop reference from allocate - handle holds it now. */ - drm_gem_object_put(&mtk_gem->base); - - return 0; - -err_handle_create: - mtk_drm_gem_free_object(&mtk_gem->base); - return ret; -} - -static int mtk_drm_gem_object_mmap(struct drm_gem_object *obj, - struct vm_area_struct *vma) - -{ - int ret; - struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj); - struct mtk_drm_private *priv = obj->dev->dev_private; - - /* - * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the - * whole buffer from the start. - */ - vma->vm_pgoff = 0; - - /* - * dma_alloc_attrs() allocated a struct page table for mtk_gem, so clear - * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap(). - */ - vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP); - vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); - vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); - - ret = dma_mmap_attrs(priv->dma_dev, vma, mtk_gem->cookie, - mtk_gem->dma_addr, obj->size, mtk_gem->dma_attrs); - - return ret; -} - -/* - * Allocate a sg_table for this GEM object. - * Note: Both the table's contents, and the sg_table itself must be freed by - * the caller. - * Returns a pointer to the newly allocated sg_table, or an ERR_PTR() error. - */ -struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj) -{ - struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj); - struct mtk_drm_private *priv = obj->dev->dev_private; - struct sg_table *sgt; - int ret; - - sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); - if (!sgt) - return ERR_PTR(-ENOMEM); - - ret = dma_get_sgtable_attrs(priv->dma_dev, sgt, mtk_gem->cookie, - mtk_gem->dma_addr, obj->size, - mtk_gem->dma_attrs); - if (ret) { - DRM_ERROR("failed to allocate sgt, %d\n", ret); - kfree(sgt); - return ERR_PTR(ret); - } - - return sgt; -} - -struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev, - struct dma_buf_attachment *attach, struct sg_table *sg) -{ - struct mtk_drm_gem_obj *mtk_gem; - - /* check if the entries in the sg_table are contiguous */ - if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) { - DRM_ERROR("sg_table is not contiguous"); - return ERR_PTR(-EINVAL); - } - - mtk_gem = mtk_drm_gem_init(dev, attach->dmabuf->size); - if (IS_ERR(mtk_gem)) - return ERR_CAST(mtk_gem); - - mtk_gem->dma_addr = sg_dma_address(sg->sgl); - mtk_gem->sg = sg; - - return &mtk_gem->base; -} - -int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) -{ - struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj); - struct sg_table *sgt = NULL; - unsigned int npages; - - if (mtk_gem->kvaddr) - goto out; - - sgt = mtk_gem_prime_get_sg_table(obj); - if (IS_ERR(sgt)) - return PTR_ERR(sgt); - - npages = obj->size >> PAGE_SHIFT; - mtk_gem->pages = kcalloc(npages, sizeof(*mtk_gem->pages), GFP_KERNEL); - if (!mtk_gem->pages) { - sg_free_table(sgt); - kfree(sgt); - return -ENOMEM; - } - - drm_prime_sg_to_page_array(sgt, mtk_gem->pages, npages); - - mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP, - pgprot_writecombine(PAGE_KERNEL)); - if (!mtk_gem->kvaddr) { - sg_free_table(sgt); - kfree(sgt); - kfree(mtk_gem->pages); - return -ENOMEM; - } - sg_free_table(sgt); - kfree(sgt); - -out: - iosys_map_set_vaddr(map, mtk_gem->kvaddr); - - return 0; -} - -void mtk_drm_gem_prime_vunmap(struct drm_gem_object *obj, - struct iosys_map *map) -{ - struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj); - void *vaddr = map->vaddr; - - if (!mtk_gem->pages) - return; - - vunmap(vaddr); - mtk_gem->kvaddr = NULL; - kfree(mtk_gem->pages); -} diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.h b/drivers/gpu/drm/mediatek/mtk_drm_gem.h deleted file mode 100644 index 78f23b07a0..0000000000 --- a/drivers/gpu/drm/mediatek/mtk_drm_gem.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2015 MediaTek Inc. - */ - -#ifndef _MTK_DRM_GEM_H_ -#define _MTK_DRM_GEM_H_ - -#include - -/* - * mtk drm buffer structure. - * - * @base: a gem object. - * - a new handle to this gem object would be created - * by drm_gem_handle_create(). - * @cookie: the return value of dma_alloc_attrs(), keep it for dma_free_attrs() - * @kvaddr: kernel virtual address of gem buffer. - * @dma_addr: dma address of gem buffer. - * @dma_attrs: dma attributes of gem buffer. - * - * P.S. this object would be transferred to user as kms_bo.handle so - * user can access the buffer through kms_bo.handle. - */ -struct mtk_drm_gem_obj { - struct drm_gem_object base; - void *cookie; - void *kvaddr; - dma_addr_t dma_addr; - unsigned long dma_attrs; - struct sg_table *sg; - struct page **pages; -}; - -#define to_mtk_gem_obj(x) container_of(x, struct mtk_drm_gem_obj, base) - -void mtk_drm_gem_free_object(struct drm_gem_object *gem); -struct mtk_drm_gem_obj *mtk_drm_gem_create(struct drm_device *dev, size_t size, - bool alloc_kmap); -int mtk_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, - struct drm_mode_create_dumb *args); -struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj); -struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev, - struct dma_buf_attachment *attach, struct sg_table *sg); -int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map); -void mtk_drm_gem_prime_vunmap(struct drm_gem_object *obj, - struct iosys_map *map); - -#endif diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c deleted file mode 100644 index ddc9355b06..0000000000 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ /dev/null @@ -1,350 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2015 MediaTek Inc. - * Author: CK Hu - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mtk_drm_crtc.h" -#include "mtk_drm_ddp_comp.h" -#include "mtk_drm_drv.h" -#include "mtk_drm_gem.h" -#include "mtk_drm_plane.h" - -static const u64 modifiers[] = { - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | - AFBC_FORMAT_MOD_SPLIT | - AFBC_FORMAT_MOD_SPARSE), - DRM_FORMAT_MOD_INVALID, -}; - -static void mtk_plane_reset(struct drm_plane *plane) -{ - struct mtk_plane_state *state; - - if (plane->state) { - __drm_atomic_helper_plane_destroy_state(plane->state); - - state = to_mtk_plane_state(plane->state); - memset(state, 0, sizeof(*state)); - } else { - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) - return; - } - - __drm_atomic_helper_plane_reset(plane, &state->base); - - state->base.plane = plane; - state->pending.format = DRM_FORMAT_RGB565; - state->pending.modifier = DRM_FORMAT_MOD_LINEAR; -} - -static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane) -{ - struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state); - struct mtk_plane_state *state; - - state = kmalloc(sizeof(*state), GFP_KERNEL); - if (!state) - return NULL; - - __drm_atomic_helper_plane_duplicate_state(plane, &state->base); - - WARN_ON(state->base.plane != plane); - - state->pending = old_state->pending; - - return &state->base; -} - -static bool mtk_plane_format_mod_supported(struct drm_plane *plane, - uint32_t format, - uint64_t modifier) -{ - if (modifier == DRM_FORMAT_MOD_LINEAR) - return true; - - if (modifier != DRM_FORMAT_MOD_ARM_AFBC( - AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | - AFBC_FORMAT_MOD_SPLIT | - AFBC_FORMAT_MOD_SPARSE)) - return false; - - if (format != DRM_FORMAT_XRGB8888 && - format != DRM_FORMAT_ARGB8888 && - format != DRM_FORMAT_BGRX8888 && - format != DRM_FORMAT_BGRA8888 && - format != DRM_FORMAT_ABGR8888 && - format != DRM_FORMAT_XBGR8888 && - format != DRM_FORMAT_RGB888 && - format != DRM_FORMAT_BGR888) - return false; - - return true; -} - -static void mtk_drm_plane_destroy_state(struct drm_plane *plane, - struct drm_plane_state *state) -{ - __drm_atomic_helper_plane_destroy_state(state); - kfree(to_mtk_plane_state(state)); -} - -static int mtk_plane_atomic_async_check(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, - plane); - struct drm_crtc_state *crtc_state; - int ret; - - if (plane != new_plane_state->crtc->cursor) - return -EINVAL; - - if (!plane->state) - return -EINVAL; - - if (!plane->state->fb) - return -EINVAL; - - ret = mtk_drm_crtc_plane_check(new_plane_state->crtc, plane, - to_mtk_plane_state(new_plane_state)); - if (ret) - return ret; - - crtc_state = drm_atomic_get_existing_crtc_state(state, new_plane_state->crtc); - - return drm_atomic_helper_check_plane_state(plane->state, crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - true, true); -} - -static void mtk_plane_update_new_state(struct drm_plane_state *new_state, - struct mtk_plane_state *mtk_plane_state) -{ - struct drm_framebuffer *fb = new_state->fb; - struct drm_gem_object *gem; - struct mtk_drm_gem_obj *mtk_gem; - unsigned int pitch, format; - u64 modifier; - dma_addr_t addr; - dma_addr_t hdr_addr = 0; - unsigned int hdr_pitch = 0; - int offset; - - gem = fb->obj[0]; - mtk_gem = to_mtk_gem_obj(gem); - addr = mtk_gem->dma_addr; - pitch = fb->pitches[0]; - format = fb->format->format; - modifier = fb->modifier; - - if (modifier == DRM_FORMAT_MOD_LINEAR) { - /* - * Using dma_addr_t variable to calculate with multiplier of different types, - * for example: addr += (new_state->src.x1 >> 16) * fb->format->cpp[0]; - * may cause coverity issue with unintentional overflow. - */ - offset = (new_state->src.x1 >> 16) * fb->format->cpp[0]; - addr += offset; - offset = (new_state->src.y1 >> 16) * pitch; - addr += offset; - } else { - int width_in_blocks = ALIGN(fb->width, AFBC_DATA_BLOCK_WIDTH) - / AFBC_DATA_BLOCK_WIDTH; - int height_in_blocks = ALIGN(fb->height, AFBC_DATA_BLOCK_HEIGHT) - / AFBC_DATA_BLOCK_HEIGHT; - int x_offset_in_blocks = (new_state->src.x1 >> 16) / AFBC_DATA_BLOCK_WIDTH; - int y_offset_in_blocks = (new_state->src.y1 >> 16) / AFBC_DATA_BLOCK_HEIGHT; - int hdr_size, hdr_offset; - - hdr_pitch = width_in_blocks * AFBC_HEADER_BLOCK_SIZE; - pitch = width_in_blocks * AFBC_DATA_BLOCK_WIDTH * - AFBC_DATA_BLOCK_HEIGHT * fb->format->cpp[0]; - - hdr_size = ALIGN(hdr_pitch * height_in_blocks, AFBC_HEADER_ALIGNMENT); - hdr_offset = hdr_pitch * y_offset_in_blocks + - AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks; - - /* - * Using dma_addr_t variable to calculate with multiplier of different types, - * for example: addr += hdr_pitch * y_offset_in_blocks; - * may cause coverity issue with unintentional overflow. - */ - hdr_addr = addr + hdr_offset; - - /* The data plane is offset by 1 additional block. */ - offset = pitch * y_offset_in_blocks + - AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT * - fb->format->cpp[0] * (x_offset_in_blocks + 1); - - /* - * Using dma_addr_t variable to calculate with multiplier of different types, - * for example: addr += pitch * y_offset_in_blocks; - * may cause coverity issue with unintentional overflow. - */ - addr = addr + hdr_size + offset; - } - - mtk_plane_state->pending.enable = true; - mtk_plane_state->pending.pitch = pitch; - mtk_plane_state->pending.hdr_pitch = hdr_pitch; - mtk_plane_state->pending.format = format; - mtk_plane_state->pending.modifier = modifier; - mtk_plane_state->pending.addr = addr; - mtk_plane_state->pending.hdr_addr = hdr_addr; - mtk_plane_state->pending.x = new_state->dst.x1; - mtk_plane_state->pending.y = new_state->dst.y1; - mtk_plane_state->pending.width = drm_rect_width(&new_state->dst); - mtk_plane_state->pending.height = drm_rect_height(&new_state->dst); - mtk_plane_state->pending.rotation = new_state->rotation; - mtk_plane_state->pending.color_encoding = new_state->color_encoding; -} - -static void mtk_plane_atomic_async_update(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, - plane); - struct mtk_plane_state *new_plane_state = to_mtk_plane_state(plane->state); - - plane->state->crtc_x = new_state->crtc_x; - plane->state->crtc_y = new_state->crtc_y; - plane->state->crtc_h = new_state->crtc_h; - plane->state->crtc_w = new_state->crtc_w; - plane->state->src_x = new_state->src_x; - plane->state->src_y = new_state->src_y; - plane->state->src_h = new_state->src_h; - plane->state->src_w = new_state->src_w; - - mtk_plane_update_new_state(new_state, new_plane_state); - swap(plane->state->fb, new_state->fb); - wmb(); /* Make sure the above parameters are set before update */ - new_plane_state->pending.async_dirty = true; - mtk_drm_crtc_async_update(new_state->crtc, plane, state); -} - -static const struct drm_plane_funcs mtk_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = drm_plane_cleanup, - .reset = mtk_plane_reset, - .atomic_duplicate_state = mtk_plane_duplicate_state, - .atomic_destroy_state = mtk_drm_plane_destroy_state, - .format_mod_supported = mtk_plane_format_mod_supported, -}; - -static int mtk_plane_atomic_check(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, - plane); - struct drm_framebuffer *fb = new_plane_state->fb; - struct drm_crtc_state *crtc_state; - int ret; - - if (!fb) - return 0; - - if (WARN_ON(!new_plane_state->crtc)) - return 0; - - ret = mtk_drm_crtc_plane_check(new_plane_state->crtc, plane, - to_mtk_plane_state(new_plane_state)); - if (ret) - return ret; - - crtc_state = drm_atomic_get_crtc_state(state, - new_plane_state->crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - - return drm_atomic_helper_check_plane_state(new_plane_state, - crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - true, true); -} - -static void mtk_plane_atomic_disable(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, - plane); - struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state); - mtk_plane_state->pending.enable = false; - wmb(); /* Make sure the above parameter is set before update */ - mtk_plane_state->pending.dirty = true; -} - -static void mtk_plane_atomic_update(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, - plane); - struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state); - - if (!new_state->crtc || WARN_ON(!new_state->fb)) - return; - - if (!new_state->visible) { - mtk_plane_atomic_disable(plane, state); - return; - } - - mtk_plane_update_new_state(new_state, mtk_plane_state); - wmb(); /* Make sure the above parameters are set before update */ - mtk_plane_state->pending.dirty = true; -} - -static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = { - .atomic_check = mtk_plane_atomic_check, - .atomic_update = mtk_plane_atomic_update, - .atomic_disable = mtk_plane_atomic_disable, - .atomic_async_update = mtk_plane_atomic_async_update, - .atomic_async_check = mtk_plane_atomic_async_check, -}; - -int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane, - unsigned long possible_crtcs, enum drm_plane_type type, - unsigned int supported_rotations, const u32 *formats, - size_t num_formats) -{ - int err; - - if (!formats || !num_formats) { - DRM_ERROR("no formats for plane\n"); - return -EINVAL; - } - - err = drm_universal_plane_init(dev, plane, possible_crtcs, - &mtk_plane_funcs, formats, - num_formats, modifiers, type, NULL); - if (err) { - DRM_ERROR("failed to initialize plane\n"); - return err; - } - - if (supported_rotations & ~DRM_MODE_ROTATE_0) { - err = drm_plane_create_rotation_property(plane, - DRM_MODE_ROTATE_0, - supported_rotations); - if (err) - DRM_INFO("Create rotation property failed\n"); - } - - drm_plane_helper_add(plane, &mtk_plane_helper_funcs); - - return 0; -} diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.h b/drivers/gpu/drm/mediatek/mtk_drm_plane.h deleted file mode 100644 index 99aff7da08..0000000000 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.h +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2015 MediaTek Inc. - * Author: CK Hu - */ - -#ifndef _MTK_DRM_PLANE_H_ -#define _MTK_DRM_PLANE_H_ - -#include -#include - -#define AFBC_DATA_BLOCK_WIDTH 32 -#define AFBC_DATA_BLOCK_HEIGHT 8 -#define AFBC_HEADER_BLOCK_SIZE 16 -#define AFBC_HEADER_ALIGNMENT 1024 - -struct mtk_plane_pending_state { - bool config; - bool enable; - dma_addr_t addr; - dma_addr_t hdr_addr; - unsigned int pitch; - unsigned int hdr_pitch; - unsigned int format; - unsigned long long modifier; - unsigned int x; - unsigned int y; - unsigned int width; - unsigned int height; - unsigned int rotation; - bool dirty; - bool async_dirty; - bool async_config; - enum drm_color_encoding color_encoding; -}; - -struct mtk_plane_state { - struct drm_plane_state base; - struct mtk_plane_pending_state pending; -}; - -static inline struct mtk_plane_state * -to_mtk_plane_state(struct drm_plane_state *state) -{ - return container_of(state, struct mtk_plane_state, base); -} - -int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane, - unsigned long possible_crtcs, enum drm_plane_type type, - unsigned int supported_rotations, const u32 *formats, - size_t num_formats); - -#endif diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 9501f40191..b6e3c011a1 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -28,8 +28,8 @@ #include #include +#include "mtk_ddp_comp.h" #include "mtk_disp_drv.h" -#include "mtk_drm_ddp_comp.h" #include "mtk_drm_drv.h" #define DSI_START 0x00 @@ -242,22 +242,23 @@ static void mtk_dsi_phy_timconfig(struct mtk_dsi *dsi) u32 data_rate_mhz = DIV_ROUND_UP(dsi->data_rate, HZ_PER_MHZ); struct mtk_phy_timing *timing = &dsi->phy_timing; - timing->lpx = (60 * data_rate_mhz / (8 * 1000)) + 1; - timing->da_hs_prepare = (80 * data_rate_mhz + 4 * 1000) / 8000; - timing->da_hs_zero = (170 * data_rate_mhz + 10 * 1000) / 8000 + 1 - + timing->lpx = (80 * data_rate_mhz / (8 * 1000)) + 1; + timing->da_hs_prepare = (59 * data_rate_mhz + 4 * 1000) / 8000 + 1; + timing->da_hs_zero = (163 * data_rate_mhz + 11 * 1000) / 8000 + 1 - timing->da_hs_prepare; - timing->da_hs_trail = timing->da_hs_prepare + 1; + timing->da_hs_trail = (78 * data_rate_mhz + 7 * 1000) / 8000 + 1; - timing->ta_go = 4 * timing->lpx - 2; - timing->ta_sure = timing->lpx + 2; - timing->ta_get = 4 * timing->lpx; - timing->da_hs_exit = 2 * timing->lpx + 1; + timing->ta_go = 4 * timing->lpx; + timing->ta_sure = 3 * timing->lpx / 2; + timing->ta_get = 5 * timing->lpx; + timing->da_hs_exit = (118 * data_rate_mhz / (8 * 1000)) + 1; - timing->clk_hs_prepare = 70 * data_rate_mhz / (8 * 1000); - timing->clk_hs_post = timing->clk_hs_prepare + 8; - timing->clk_hs_trail = timing->clk_hs_prepare; - timing->clk_hs_zero = timing->clk_hs_trail * 4; - timing->clk_hs_exit = 2 * timing->clk_hs_trail; + timing->clk_hs_prepare = (57 * data_rate_mhz / (8 * 1000)) + 1; + timing->clk_hs_post = (65 * data_rate_mhz + 53 * 1000) / 8000 + 1; + timing->clk_hs_trail = (78 * data_rate_mhz + 7 * 1000) / 8000 + 1; + timing->clk_hs_zero = (330 * data_rate_mhz / (8 * 1000)) + 1 - + timing->clk_hs_prepare; + timing->clk_hs_exit = (118 * data_rate_mhz / (8 * 1000)) + 1; timcon0 = FIELD_PREP(LPX, timing->lpx) | FIELD_PREP(HS_PREP, timing->da_hs_prepare) | @@ -662,7 +663,7 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) /* * mtk_dsi_stop() and mtk_dsi_start() is asymmetric, since - * mtk_dsi_stop() should be called after mtk_drm_crtc_atomic_disable(), + * mtk_dsi_stop() should be called after mtk_crtc_atomic_disable(), * which needs irq for vblank, and mtk_dsi_stop() will disable irq. * mtk_dsi_start() needs to be called in mtk_output_dsi_enable(), * after dsi is fully set. @@ -836,7 +837,10 @@ static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi) return ret; } - dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev); + ret = mtk_find_possible_crtcs(drm, dsi->host.dev); + if (ret < 0) + goto err_cleanup_encoder; + dsi->encoder.possible_crtcs = ret; ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); diff --git a/drivers/gpu/drm/mediatek/mtk_ethdr.c b/drivers/gpu/drm/mediatek/mtk_ethdr.c index 6a5d0c345a..bf5826b7e7 100644 --- a/drivers/gpu/drm/mediatek/mtk_ethdr.c +++ b/drivers/gpu/drm/mediatek/mtk_ethdr.c @@ -14,8 +14,8 @@ #include #include -#include "mtk_drm_crtc.h" -#include "mtk_drm_ddp_comp.h" +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" #include "mtk_drm_drv.h" #include "mtk_ethdr.h" @@ -50,7 +50,6 @@ #define MIXER_INX_MODE_BYPASS 0 #define MIXER_INX_MODE_EVEN_EXTEND 1 -#define DEFAULT_9BIT_ALPHA 0x100 #define MIXER_ALPHA_AEN BIT(8) #define MIXER_ALPHA 0xff #define ETHDR_CLK_NUM 13 @@ -154,13 +153,19 @@ void mtk_ethdr_layer_config(struct device *dev, unsigned int idx, unsigned int offset = (pending->x & 1) << 31 | pending->y << 16 | pending->x; unsigned int align_width = ALIGN_DOWN(pending->width, 2); unsigned int alpha_con = 0; + bool replace_src_a = false; dev_dbg(dev, "%s+ idx:%d", __func__, idx); if (idx >= 4) return; - if (!pending->enable) { + if (!pending->enable || !pending->width || !pending->height) { + /* + * instead of disabling layer with MIX_SRC_CON directly + * set the size to 0 to avoid screen shift due to mixer + * mode switch (hardware behavior) + */ mtk_ddp_write(cmdq_pkt, 0, &mixer->cmdq_base, mixer->regs, MIX_L_SRC_SIZE(idx)); return; } @@ -168,8 +173,16 @@ void mtk_ethdr_layer_config(struct device *dev, unsigned int idx, if (state->base.fb && state->base.fb->format->has_alpha) alpha_con = MIXER_ALPHA_AEN | MIXER_ALPHA; - mtk_mmsys_mixer_in_config(priv->mmsys_dev, idx + 1, alpha_con ? false : true, - DEFAULT_9BIT_ALPHA, + if (state->base.fb && !state->base.fb->format->has_alpha) { + /* + * Mixer doesn't support CONST_BLD mode, + * use a trick to make the output equivalent + */ + replace_src_a = true; + } + + mtk_mmsys_mixer_in_config(priv->mmsys_dev, idx + 1, replace_src_a, + MIXER_ALPHA, pending->x & 1 ? MIXER_INX_MODE_EVEN_EXTEND : MIXER_INX_MODE_BYPASS, align_width / 2 - 1, cmdq_pkt); @@ -363,7 +376,6 @@ struct platform_driver mtk_ethdr_driver = { .remove_new = mtk_ethdr_remove, .driver = { .name = "mediatek-disp-ethdr", - .owner = THIS_MODULE, .of_match_table = mtk_ethdr_driver_dt_match, }, }; diff --git a/drivers/gpu/drm/mediatek/mtk_gem.c b/drivers/gpu/drm/mediatek/mtk_gem.c new file mode 100644 index 0000000000..a172456d1d --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_gem.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015 MediaTek Inc. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "mtk_drm_drv.h" +#include "mtk_gem.h" + +static int mtk_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); + +static const struct vm_operations_struct vm_ops = { + .open = drm_gem_vm_open, + .close = drm_gem_vm_close, +}; + +static const struct drm_gem_object_funcs mtk_gem_object_funcs = { + .free = mtk_gem_free_object, + .get_sg_table = mtk_gem_prime_get_sg_table, + .vmap = mtk_gem_prime_vmap, + .vunmap = mtk_gem_prime_vunmap, + .mmap = mtk_gem_object_mmap, + .vm_ops = &vm_ops, +}; + +static struct mtk_gem_obj *mtk_gem_init(struct drm_device *dev, + unsigned long size) +{ + struct mtk_gem_obj *mtk_gem_obj; + int ret; + + size = round_up(size, PAGE_SIZE); + + if (size == 0) + return ERR_PTR(-EINVAL); + + mtk_gem_obj = kzalloc(sizeof(*mtk_gem_obj), GFP_KERNEL); + if (!mtk_gem_obj) + return ERR_PTR(-ENOMEM); + + mtk_gem_obj->base.funcs = &mtk_gem_object_funcs; + + ret = drm_gem_object_init(dev, &mtk_gem_obj->base, size); + if (ret < 0) { + DRM_ERROR("failed to initialize gem object\n"); + kfree(mtk_gem_obj); + return ERR_PTR(ret); + } + + return mtk_gem_obj; +} + +struct mtk_gem_obj *mtk_gem_create(struct drm_device *dev, + size_t size, bool alloc_kmap) +{ + struct mtk_drm_private *priv = dev->dev_private; + struct mtk_gem_obj *mtk_gem; + struct drm_gem_object *obj; + int ret; + + mtk_gem = mtk_gem_init(dev, size); + if (IS_ERR(mtk_gem)) + return ERR_CAST(mtk_gem); + + obj = &mtk_gem->base; + + mtk_gem->dma_attrs = DMA_ATTR_WRITE_COMBINE; + + if (!alloc_kmap) + mtk_gem->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING; + + mtk_gem->cookie = dma_alloc_attrs(priv->dma_dev, obj->size, + &mtk_gem->dma_addr, GFP_KERNEL, + mtk_gem->dma_attrs); + if (!mtk_gem->cookie) { + DRM_ERROR("failed to allocate %zx byte dma buffer", obj->size); + ret = -ENOMEM; + goto err_gem_free; + } + + if (alloc_kmap) + mtk_gem->kvaddr = mtk_gem->cookie; + + DRM_DEBUG_DRIVER("cookie = %p dma_addr = %pad size = %zu\n", + mtk_gem->cookie, &mtk_gem->dma_addr, + size); + + return mtk_gem; + +err_gem_free: + drm_gem_object_release(obj); + kfree(mtk_gem); + return ERR_PTR(ret); +} + +void mtk_gem_free_object(struct drm_gem_object *obj) +{ + struct mtk_gem_obj *mtk_gem = to_mtk_gem_obj(obj); + struct mtk_drm_private *priv = obj->dev->dev_private; + + if (mtk_gem->sg) + drm_prime_gem_destroy(obj, mtk_gem->sg); + else + dma_free_attrs(priv->dma_dev, obj->size, mtk_gem->cookie, + mtk_gem->dma_addr, mtk_gem->dma_attrs); + + /* release file pointer to gem object. */ + drm_gem_object_release(obj); + + kfree(mtk_gem); +} + +int mtk_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + struct mtk_gem_obj *mtk_gem; + int ret; + + args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + + /* + * Multiply 2 variables of different types, + * for example: args->size = args->spacing * args->height; + * may cause coverity issue with unintentional overflow. + */ + args->size = args->pitch; + args->size *= args->height; + + mtk_gem = mtk_gem_create(dev, args->size, false); + if (IS_ERR(mtk_gem)) + return PTR_ERR(mtk_gem); + + /* + * allocate a id of idr table where the obj is registered + * and handle has the id what user can see. + */ + ret = drm_gem_handle_create(file_priv, &mtk_gem->base, &args->handle); + if (ret) + goto err_handle_create; + + /* drop reference from allocate - handle holds it now. */ + drm_gem_object_put(&mtk_gem->base); + + return 0; + +err_handle_create: + mtk_gem_free_object(&mtk_gem->base); + return ret; +} + +static int mtk_gem_object_mmap(struct drm_gem_object *obj, + struct vm_area_struct *vma) + +{ + int ret; + struct mtk_gem_obj *mtk_gem = to_mtk_gem_obj(obj); + struct mtk_drm_private *priv = obj->dev->dev_private; + + /* + * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the + * whole buffer from the start. + */ + vma->vm_pgoff = 0; + + /* + * dma_alloc_attrs() allocated a struct page table for mtk_gem, so clear + * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap(). + */ + vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP); + vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + + ret = dma_mmap_attrs(priv->dma_dev, vma, mtk_gem->cookie, + mtk_gem->dma_addr, obj->size, mtk_gem->dma_attrs); + + return ret; +} + +/* + * Allocate a sg_table for this GEM object. + * Note: Both the table's contents, and the sg_table itself must be freed by + * the caller. + * Returns a pointer to the newly allocated sg_table, or an ERR_PTR() error. + */ +struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj) +{ + struct mtk_gem_obj *mtk_gem = to_mtk_gem_obj(obj); + struct mtk_drm_private *priv = obj->dev->dev_private; + struct sg_table *sgt; + int ret; + + sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) + return ERR_PTR(-ENOMEM); + + ret = dma_get_sgtable_attrs(priv->dma_dev, sgt, mtk_gem->cookie, + mtk_gem->dma_addr, obj->size, + mtk_gem->dma_attrs); + if (ret) { + DRM_ERROR("failed to allocate sgt, %d\n", ret); + kfree(sgt); + return ERR_PTR(ret); + } + + return sgt; +} + +struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev, + struct dma_buf_attachment *attach, struct sg_table *sg) +{ + struct mtk_gem_obj *mtk_gem; + + /* check if the entries in the sg_table are contiguous */ + if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) { + DRM_ERROR("sg_table is not contiguous"); + return ERR_PTR(-EINVAL); + } + + mtk_gem = mtk_gem_init(dev, attach->dmabuf->size); + if (IS_ERR(mtk_gem)) + return ERR_CAST(mtk_gem); + + mtk_gem->dma_addr = sg_dma_address(sg->sgl); + mtk_gem->sg = sg; + + return &mtk_gem->base; +} + +int mtk_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) +{ + struct mtk_gem_obj *mtk_gem = to_mtk_gem_obj(obj); + struct sg_table *sgt = NULL; + unsigned int npages; + + if (mtk_gem->kvaddr) + goto out; + + sgt = mtk_gem_prime_get_sg_table(obj); + if (IS_ERR(sgt)) + return PTR_ERR(sgt); + + npages = obj->size >> PAGE_SHIFT; + mtk_gem->pages = kcalloc(npages, sizeof(*mtk_gem->pages), GFP_KERNEL); + if (!mtk_gem->pages) { + sg_free_table(sgt); + kfree(sgt); + return -ENOMEM; + } + + drm_prime_sg_to_page_array(sgt, mtk_gem->pages, npages); + + mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); + if (!mtk_gem->kvaddr) { + sg_free_table(sgt); + kfree(sgt); + kfree(mtk_gem->pages); + return -ENOMEM; + } + sg_free_table(sgt); + kfree(sgt); + +out: + iosys_map_set_vaddr(map, mtk_gem->kvaddr); + + return 0; +} + +void mtk_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map) +{ + struct mtk_gem_obj *mtk_gem = to_mtk_gem_obj(obj); + void *vaddr = map->vaddr; + + if (!mtk_gem->pages) + return; + + vunmap(vaddr); + mtk_gem->kvaddr = NULL; + kfree(mtk_gem->pages); +} diff --git a/drivers/gpu/drm/mediatek/mtk_gem.h b/drivers/gpu/drm/mediatek/mtk_gem.h new file mode 100644 index 0000000000..66e5f154f6 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_gem.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015 MediaTek Inc. + */ + +#ifndef _MTK_GEM_H_ +#define _MTK_GEM_H_ + +#include + +/* + * mtk drm buffer structure. + * + * @base: a gem object. + * - a new handle to this gem object would be created + * by drm_gem_handle_create(). + * @cookie: the return value of dma_alloc_attrs(), keep it for dma_free_attrs() + * @kvaddr: kernel virtual address of gem buffer. + * @dma_addr: dma address of gem buffer. + * @dma_attrs: dma attributes of gem buffer. + * + * P.S. this object would be transferred to user as kms_bo.handle so + * user can access the buffer through kms_bo.handle. + */ +struct mtk_gem_obj { + struct drm_gem_object base; + void *cookie; + void *kvaddr; + dma_addr_t dma_addr; + unsigned long dma_attrs; + struct sg_table *sg; + struct page **pages; +}; + +#define to_mtk_gem_obj(x) container_of(x, struct mtk_gem_obj, base) + +void mtk_gem_free_object(struct drm_gem_object *gem); +struct mtk_gem_obj *mtk_gem_create(struct drm_device *dev, size_t size, + bool alloc_kmap); +int mtk_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, + struct drm_mode_create_dumb *args); +struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj); +struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev, + struct dma_buf_attachment *attach, struct sg_table *sg); +int mtk_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map); +void mtk_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map); + +#endif diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index c6bdc565e4..6e1cca97a6 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1695,7 +1695,7 @@ static int mtk_hdmi_register_audio_driver(struct device *dev) return 0; } -static int mtk_drm_hdmi_probe(struct platform_device *pdev) +static int mtk_hdmi_probe(struct platform_device *pdev) { struct mtk_hdmi *hdmi; struct device *dev = &pdev->dev; @@ -1754,7 +1754,7 @@ err_bridge_remove: return ret; } -static void mtk_drm_hdmi_remove(struct platform_device *pdev) +static void mtk_hdmi_remove(struct platform_device *pdev) { struct mtk_hdmi *hdmi = platform_get_drvdata(pdev); @@ -1798,7 +1798,7 @@ static const struct mtk_hdmi_conf mtk_hdmi_conf_mt8167 = { .cea_modes_only = true, }; -static const struct of_device_id mtk_drm_hdmi_of_ids[] = { +static const struct of_device_id mtk_hdmi_of_ids[] = { { .compatible = "mediatek,mt2701-hdmi", .data = &mtk_hdmi_conf_mt2701, }, @@ -1809,14 +1809,14 @@ static const struct of_device_id mtk_drm_hdmi_of_ids[] = { }, {} }; -MODULE_DEVICE_TABLE(of, mtk_drm_hdmi_of_ids); +MODULE_DEVICE_TABLE(of, mtk_hdmi_of_ids); static struct platform_driver mtk_hdmi_driver = { - .probe = mtk_drm_hdmi_probe, - .remove_new = mtk_drm_hdmi_remove, + .probe = mtk_hdmi_probe, + .remove_new = mtk_hdmi_remove, .driver = { .name = "mediatek-drm-hdmi", - .of_match_table = mtk_drm_hdmi_of_ids, + .of_match_table = mtk_hdmi_of_ids, .pm = &mtk_hdmi_pm_ops, }, }; diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c index 54e46e440e..52d55861f9 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c @@ -284,8 +284,7 @@ static int mtk_hdmi_ddc_probe(struct platform_device *pdev) return PTR_ERR(ddc->clk); } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ddc->regs = devm_ioremap_resource(&pdev->dev, mem); + ddc->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(ddc->regs)) return PTR_ERR(ddc->regs); diff --git a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c index ee9ce9b6d0..925cbb7471 100644 --- a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c +++ b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c @@ -346,7 +346,6 @@ struct platform_driver mtk_mdp_rdma_driver = { .remove_new = mtk_mdp_rdma_remove, .driver = { .name = "mediatek-mdp-rdma", - .owner = THIS_MODULE, .of_match_table = mtk_mdp_rdma_driver_dt_match, }, }; diff --git a/drivers/gpu/drm/mediatek/mtk_padding.c b/drivers/gpu/drm/mediatek/mtk_padding.c index 0d6451c149..85bc6768b6 100644 --- a/drivers/gpu/drm/mediatek/mtk_padding.c +++ b/drivers/gpu/drm/mediatek/mtk_padding.c @@ -11,9 +11,9 @@ #include #include +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" #include "mtk_disp_drv.h" -#include "mtk_drm_crtc.h" -#include "mtk_drm_ddp_comp.h" #define PADDING_CONTROL_REG 0x00 #define PADDING_BYPASS BIT(0) @@ -154,7 +154,6 @@ struct platform_driver mtk_padding_driver = { .remove = mtk_padding_remove, .driver = { .name = "mediatek-disp-padding", - .owner = THIS_MODULE, .of_match_table = mtk_padding_driver_dt_match, }, }; diff --git a/drivers/gpu/drm/mediatek/mtk_plane.c b/drivers/gpu/drm/mediatek/mtk_plane.c new file mode 100644 index 0000000000..1723d4333f --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_plane.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015 MediaTek Inc. + * Author: CK Hu + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_crtc.h" +#include "mtk_ddp_comp.h" +#include "mtk_drm_drv.h" +#include "mtk_gem.h" +#include "mtk_plane.h" + +static const u64 modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_SPLIT | + AFBC_FORMAT_MOD_SPARSE), + DRM_FORMAT_MOD_INVALID, +}; + +static void mtk_plane_reset(struct drm_plane *plane) +{ + struct mtk_plane_state *state; + + if (plane->state) { + __drm_atomic_helper_plane_destroy_state(plane->state); + + state = to_mtk_plane_state(plane->state); + memset(state, 0, sizeof(*state)); + } else { + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return; + } + + __drm_atomic_helper_plane_reset(plane, &state->base); + + state->base.plane = plane; + state->pending.format = DRM_FORMAT_RGB565; + state->pending.modifier = DRM_FORMAT_MOD_LINEAR; +} + +static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane) +{ + struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state); + struct mtk_plane_state *state; + + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_plane_duplicate_state(plane, &state->base); + + WARN_ON(state->base.plane != plane); + + state->pending = old_state->pending; + + return &state->base; +} + +static bool mtk_plane_format_mod_supported(struct drm_plane *plane, + uint32_t format, + uint64_t modifier) +{ + if (modifier == DRM_FORMAT_MOD_LINEAR) + return true; + + if (modifier != DRM_FORMAT_MOD_ARM_AFBC( + AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_SPLIT | + AFBC_FORMAT_MOD_SPARSE)) + return false; + + if (format != DRM_FORMAT_XRGB8888 && + format != DRM_FORMAT_ARGB8888 && + format != DRM_FORMAT_BGRX8888 && + format != DRM_FORMAT_BGRA8888 && + format != DRM_FORMAT_ABGR8888 && + format != DRM_FORMAT_XBGR8888 && + format != DRM_FORMAT_RGB888 && + format != DRM_FORMAT_BGR888) + return false; + + return true; +} + +static void mtk_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + __drm_atomic_helper_plane_destroy_state(state); + kfree(to_mtk_plane_state(state)); +} + +static int mtk_plane_atomic_async_check(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, + plane); + struct drm_crtc_state *crtc_state; + int ret; + + if (plane != new_plane_state->crtc->cursor) + return -EINVAL; + + if (!plane->state) + return -EINVAL; + + if (!plane->state->fb) + return -EINVAL; + + ret = mtk_crtc_plane_check(new_plane_state->crtc, plane, + to_mtk_plane_state(new_plane_state)); + if (ret) + return ret; + + crtc_state = drm_atomic_get_existing_crtc_state(state, new_plane_state->crtc); + + return drm_atomic_helper_check_plane_state(plane->state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + true, true); +} + +static void mtk_plane_update_new_state(struct drm_plane_state *new_state, + struct mtk_plane_state *mtk_plane_state) +{ + struct drm_framebuffer *fb = new_state->fb; + struct drm_gem_object *gem; + struct mtk_gem_obj *mtk_gem; + unsigned int pitch, format; + u64 modifier; + dma_addr_t addr; + dma_addr_t hdr_addr = 0; + unsigned int hdr_pitch = 0; + int offset; + + gem = fb->obj[0]; + mtk_gem = to_mtk_gem_obj(gem); + addr = mtk_gem->dma_addr; + pitch = fb->pitches[0]; + format = fb->format->format; + modifier = fb->modifier; + + if (modifier == DRM_FORMAT_MOD_LINEAR) { + /* + * Using dma_addr_t variable to calculate with multiplier of different types, + * for example: addr += (new_state->src.x1 >> 16) * fb->format->cpp[0]; + * may cause coverity issue with unintentional overflow. + */ + offset = (new_state->src.x1 >> 16) * fb->format->cpp[0]; + addr += offset; + offset = (new_state->src.y1 >> 16) * pitch; + addr += offset; + } else { + int width_in_blocks = ALIGN(fb->width, AFBC_DATA_BLOCK_WIDTH) + / AFBC_DATA_BLOCK_WIDTH; + int height_in_blocks = ALIGN(fb->height, AFBC_DATA_BLOCK_HEIGHT) + / AFBC_DATA_BLOCK_HEIGHT; + int x_offset_in_blocks = (new_state->src.x1 >> 16) / AFBC_DATA_BLOCK_WIDTH; + int y_offset_in_blocks = (new_state->src.y1 >> 16) / AFBC_DATA_BLOCK_HEIGHT; + int hdr_size, hdr_offset; + + hdr_pitch = width_in_blocks * AFBC_HEADER_BLOCK_SIZE; + pitch = width_in_blocks * AFBC_DATA_BLOCK_WIDTH * + AFBC_DATA_BLOCK_HEIGHT * fb->format->cpp[0]; + + hdr_size = ALIGN(hdr_pitch * height_in_blocks, AFBC_HEADER_ALIGNMENT); + hdr_offset = hdr_pitch * y_offset_in_blocks + + AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks; + + /* + * Using dma_addr_t variable to calculate with multiplier of different types, + * for example: addr += hdr_pitch * y_offset_in_blocks; + * may cause coverity issue with unintentional overflow. + */ + hdr_addr = addr + hdr_offset; + + /* The data plane is offset by 1 additional block. */ + offset = pitch * y_offset_in_blocks + + AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT * + fb->format->cpp[0] * (x_offset_in_blocks + 1); + + /* + * Using dma_addr_t variable to calculate with multiplier of different types, + * for example: addr += pitch * y_offset_in_blocks; + * may cause coverity issue with unintentional overflow. + */ + addr = addr + hdr_size + offset; + } + + mtk_plane_state->pending.enable = true; + mtk_plane_state->pending.pitch = pitch; + mtk_plane_state->pending.hdr_pitch = hdr_pitch; + mtk_plane_state->pending.format = format; + mtk_plane_state->pending.modifier = modifier; + mtk_plane_state->pending.addr = addr; + mtk_plane_state->pending.hdr_addr = hdr_addr; + mtk_plane_state->pending.x = new_state->dst.x1; + mtk_plane_state->pending.y = new_state->dst.y1; + mtk_plane_state->pending.width = drm_rect_width(&new_state->dst); + mtk_plane_state->pending.height = drm_rect_height(&new_state->dst); + mtk_plane_state->pending.rotation = new_state->rotation; + mtk_plane_state->pending.color_encoding = new_state->color_encoding; +} + +static void mtk_plane_atomic_async_update(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, + plane); + struct mtk_plane_state *new_plane_state = to_mtk_plane_state(plane->state); + + plane->state->crtc_x = new_state->crtc_x; + plane->state->crtc_y = new_state->crtc_y; + plane->state->crtc_h = new_state->crtc_h; + plane->state->crtc_w = new_state->crtc_w; + plane->state->src_x = new_state->src_x; + plane->state->src_y = new_state->src_y; + plane->state->src_h = new_state->src_h; + plane->state->src_w = new_state->src_w; + plane->state->dst.x1 = new_state->dst.x1; + plane->state->dst.y1 = new_state->dst.y1; + + mtk_plane_update_new_state(new_state, new_plane_state); + swap(plane->state->fb, new_state->fb); + wmb(); /* Make sure the above parameters are set before update */ + new_plane_state->pending.async_dirty = true; + mtk_crtc_async_update(new_state->crtc, plane, state); +} + +static const struct drm_plane_funcs mtk_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = mtk_plane_reset, + .atomic_duplicate_state = mtk_plane_duplicate_state, + .atomic_destroy_state = mtk_plane_destroy_state, + .format_mod_supported = mtk_plane_format_mod_supported, +}; + +static int mtk_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, + plane); + struct drm_framebuffer *fb = new_plane_state->fb; + struct drm_crtc_state *crtc_state; + int ret; + + if (!fb) + return 0; + + if (WARN_ON(!new_plane_state->crtc)) + return 0; + + ret = mtk_crtc_plane_check(new_plane_state->crtc, plane, + to_mtk_plane_state(new_plane_state)); + if (ret) + return ret; + + crtc_state = drm_atomic_get_crtc_state(state, + new_plane_state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + return drm_atomic_helper_check_plane_state(new_plane_state, + crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + true, true); +} + +static void mtk_plane_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, + plane); + struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state); + mtk_plane_state->pending.enable = false; + wmb(); /* Make sure the above parameter is set before update */ + mtk_plane_state->pending.dirty = true; +} + +static void mtk_plane_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, + plane); + struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state); + + if (!new_state->crtc || WARN_ON(!new_state->fb)) + return; + + if (!new_state->visible) { + mtk_plane_atomic_disable(plane, state); + return; + } + + mtk_plane_update_new_state(new_state, mtk_plane_state); + wmb(); /* Make sure the above parameters are set before update */ + mtk_plane_state->pending.dirty = true; +} + +static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = { + .atomic_check = mtk_plane_atomic_check, + .atomic_update = mtk_plane_atomic_update, + .atomic_disable = mtk_plane_atomic_disable, + .atomic_async_update = mtk_plane_atomic_async_update, + .atomic_async_check = mtk_plane_atomic_async_check, +}; + +int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane, + unsigned long possible_crtcs, enum drm_plane_type type, + unsigned int supported_rotations, const u32 *formats, + size_t num_formats) +{ + int err; + + if (!formats || !num_formats) { + DRM_ERROR("no formats for plane\n"); + return -EINVAL; + } + + err = drm_universal_plane_init(dev, plane, possible_crtcs, + &mtk_plane_funcs, formats, + num_formats, modifiers, type, NULL); + if (err) { + DRM_ERROR("failed to initialize plane\n"); + return err; + } + + if (supported_rotations) { + err = drm_plane_create_rotation_property(plane, + DRM_MODE_ROTATE_0, + supported_rotations); + if (err) + DRM_INFO("Create rotation property failed\n"); + } + + drm_plane_helper_add(plane, &mtk_plane_helper_funcs); + + return 0; +} diff --git a/drivers/gpu/drm/mediatek/mtk_plane.h b/drivers/gpu/drm/mediatek/mtk_plane.h new file mode 100644 index 0000000000..231bb7aac9 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_plane.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015 MediaTek Inc. + * Author: CK Hu + */ + +#ifndef _MTK_PLANE_H_ +#define _MTK_PLANE_H_ + +#include +#include + +#define AFBC_DATA_BLOCK_WIDTH 32 +#define AFBC_DATA_BLOCK_HEIGHT 8 +#define AFBC_HEADER_BLOCK_SIZE 16 +#define AFBC_HEADER_ALIGNMENT 1024 + +struct mtk_plane_pending_state { + bool config; + bool enable; + dma_addr_t addr; + dma_addr_t hdr_addr; + unsigned int pitch; + unsigned int hdr_pitch; + unsigned int format; + unsigned long long modifier; + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + unsigned int rotation; + bool dirty; + bool async_dirty; + bool async_config; + enum drm_color_encoding color_encoding; +}; + +struct mtk_plane_state { + struct drm_plane_state base; + struct mtk_plane_pending_state pending; +}; + +static inline struct mtk_plane_state * +to_mtk_plane_state(struct drm_plane_state *state) +{ + return container_of(state, struct mtk_plane_state, base); +} + +int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane, + unsigned long possible_crtcs, enum drm_plane_type type, + unsigned int supported_rotations, const u32 *formats, + size_t num_formats); + +#endif -- cgit v1.2.3