summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/mediatek
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/mediatek')
-rw-r--r--drivers/gpu/drm/mediatek/Kconfig15
-rw-r--r--drivers/gpu/drm/mediatek/Makefile20
-rw-r--r--drivers/gpu/drm/mediatek/mtk_cec.c37
-rw-r--r--drivers/gpu/drm/mediatek/mtk_crtc.c (renamed from drivers/gpu/drm/mediatek/mtk_drm_crtc.c)316
-rw-r--r--drivers/gpu/drm/mediatek/mtk_crtc.h28
-rw-r--r--drivers/gpu/drm/mediatek/mtk_ddp_comp.c (renamed from drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c)120
-rw-r--r--drivers/gpu/drm/mediatek/mtk_ddp_comp.h (renamed from drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h)25
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_aal.c25
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_ccorr.c25
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_color.c31
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_drv.h5
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_gamma.c29
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_merge.c34
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_ovl.c290
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c67
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_rdma.c51
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dp.c207
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dp_reg.h1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dpi.c469
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dpi_regs.h9
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_crtc.h30
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_drv.c384
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_drv.h10
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dsi.c174
-rw-r--r--drivers/gpu/drm/mediatek/mtk_ethdr.c71
-rw-r--r--drivers/gpu/drm/mediatek/mtk_ethdr.h1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_gem.c (renamed from drivers/gpu/drm/mediatek/mtk_drm_gem.c)69
-rw-r--r--drivers/gpu/drm/mediatek/mtk_gem.h (renamed from drivers/gpu/drm/mediatek/mtk_drm_gem.h)23
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi.c572
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi.h14
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c28
-rw-r--r--drivers/gpu/drm/mediatek/mtk_mdp_rdma.c25
-rw-r--r--drivers/gpu/drm/mediatek/mtk_padding.c28
-rw-r--r--drivers/gpu/drm/mediatek/mtk_plane.c (renamed from drivers/gpu/drm/mediatek/mtk_drm_plane.c)62
-rw-r--r--drivers/gpu/drm/mediatek/mtk_plane.h (renamed from drivers/gpu/drm/mediatek/mtk_drm_plane.h)9
35 files changed, 2082 insertions, 1222 deletions
diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig
index 76cab28e010c..e47debd60619 100644
--- a/drivers/gpu/drm/mediatek/Kconfig
+++ b/drivers/gpu/drm/mediatek/Kconfig
@@ -2,17 +2,18 @@
config DRM_MEDIATEK
tristate "DRM Support for Mediatek SoCs"
depends on DRM
- depends on ARCH_MEDIATEK || (ARM && COMPILE_TEST)
+ depends on ARCH_MEDIATEK || COMPILE_TEST
depends on COMMON_CLK
- depends on HAVE_ARM_SMCCC
+ depends on HAVE_ARM_SMCCC || COMPILE_TEST
depends on OF
depends on MTK_MMSYS
+ select DRM_CLIENT_SELECTION
+ select DRM_GEM_DMA_HELPER if DRM_FBDEV_EMULATION
select DRM_KMS_HELPER
+ select DRM_DISPLAY_HELPER
+ select DRM_BRIDGE_CONNECTOR
select DRM_MIPI_DSI
select DRM_PANEL
- select MEMORY
- select MTK_SMI
- select PHY_MTK_MIPI_DSI
select VIDEOMODE_HELPERS
help
Choose this option if you have a Mediatek SoCs.
@@ -23,10 +24,9 @@ config DRM_MEDIATEK
config DRM_MEDIATEK_DP
tristate "DRM DPTX Support for MediaTek SoCs"
depends on DRM_MEDIATEK
- 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.
@@ -34,6 +34,5 @@ config DRM_MEDIATEK_HDMI
tristate "DRM HDMI Support for Mediatek SoCs"
depends on DRM_MEDIATEK
select SND_SOC_HDMI_CODEC if SND_SOC
- select PHY_MTK_HDMI
help
DRM/KMS HDMI driver for Mediatek SoCs
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index 5e4436403b8d..43afd0a26d14 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,23 +10,19 @@ 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
-mediatek-drm-hdmi-objs := mtk_cec.o \
- mtk_hdmi.o \
- mtk_hdmi_ddc.o
-
-obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
+obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mtk_cec.o
+obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mtk_hdmi.o
+obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mtk_hdmi_ddc.o
obj-$(CONFIG_DRM_MEDIATEK_DP) += mtk_dp.o
diff --git a/drivers/gpu/drm/mediatek/mtk_cec.c b/drivers/gpu/drm/mediatek/mtk_cec.c
index 8519e9bade36..c7be530ca041 100644
--- a/drivers/gpu/drm/mediatek/mtk_cec.c
+++ b/drivers/gpu/drm/mediatek/mtk_cec.c
@@ -12,7 +12,6 @@
#include <linux/platform_device.h>
#include "mtk_cec.h"
-#include "mtk_hdmi.h"
#include "mtk_drm_drv.h"
#define TR_CONFIG 0x00
@@ -102,6 +101,7 @@ void mtk_cec_set_hpd_event(struct device *dev,
cec->hpd_event = hpd_event;
spin_unlock_irqrestore(&cec->lock, flags);
}
+EXPORT_SYMBOL_NS_GPL(mtk_cec_set_hpd_event, "DRM_MTK_HDMI_V1");
bool mtk_cec_hpd_high(struct device *dev)
{
@@ -112,6 +112,7 @@ bool mtk_cec_hpd_high(struct device *dev)
return (status & (HDMI_PORD | HDMI_HTPLG)) == (HDMI_PORD | HDMI_HTPLG);
}
+EXPORT_SYMBOL_NS_GPL(mtk_cec_hpd_high, "DRM_MTK_HDMI_V1");
static void mtk_cec_htplg_irq_init(struct mtk_cec *cec)
{
@@ -195,18 +196,14 @@ static int mtk_cec_probe(struct platform_device *pdev)
spin_lock_init(&cec->lock);
cec->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(cec->regs)) {
- ret = PTR_ERR(cec->regs);
- dev_err(dev, "Failed to ioremap cec: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(cec->regs))
+ return dev_err_probe(dev, PTR_ERR(cec->regs),
+ "Failed to ioremap cec\n");
cec->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(cec->clk)) {
- ret = PTR_ERR(cec->clk);
- dev_err(dev, "Failed to get cec clock: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(cec->clk))
+ return dev_err_probe(dev, PTR_ERR(cec->clk),
+ "Failed to get cec clock\n");
cec->irq = platform_get_irq(pdev, 0);
if (cec->irq < 0)
@@ -216,16 +213,12 @@ static int mtk_cec_probe(struct platform_device *pdev)
mtk_cec_htplg_isr_thread,
IRQF_SHARED | IRQF_TRIGGER_LOW |
IRQF_ONESHOT, "hdmi hpd", dev);
- if (ret) {
- dev_err(dev, "Failed to register cec irq: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register cec irq\n");
ret = clk_prepare_enable(cec->clk);
- if (ret) {
- dev_err(dev, "Failed to enable cec clock: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable cec clock\n");
mtk_cec_htplg_irq_init(cec);
mtk_cec_htplg_irq_enable(cec);
@@ -249,9 +242,13 @@ MODULE_DEVICE_TABLE(of, mtk_cec_of_ids);
struct platform_driver mtk_cec_driver = {
.probe = mtk_cec_probe,
- .remove_new = mtk_cec_remove,
+ .remove = mtk_cec_remove,
.driver = {
.name = "mediatek-cec",
.of_match_table = mtk_cec_of_ids,
},
};
+module_platform_driver(mtk_cec_driver);
+
+MODULE_DESCRIPTION("MediaTek HDMI CEC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index a04499c4f9ca..8f6fba4217ec 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -19,14 +19,14 @@
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
+#include "mtk_crtc.h"
+#include "mtk_ddp_comp.h"
#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"
+#include "mtk_gem.h"
+#include "mtk_plane.h"
/*
- * struct mtk_drm_crtc - MediaTek specific crtc structure.
+ * 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
@@ -38,7 +38,7 @@
*
* TODO: Needs update: this header is missing a bunch of member descriptions.
*/
-struct mtk_drm_crtc {
+struct mtk_crtc {
struct drm_crtc base;
bool enabled;
@@ -69,6 +69,8 @@ struct mtk_drm_crtc {
/* lock for display hardware access */
struct mutex hw_lock;
bool config_updating;
+ /* lock for config_updating to cmd buffer */
+ spinlock_t config_lock;
};
struct mtk_crtc_state {
@@ -80,9 +82,9 @@ struct mtk_crtc_state {
unsigned int pending_vrefresh;
};
-static inline struct mtk_drm_crtc *to_mtk_crtc(struct drm_crtc *c)
+static inline struct mtk_crtc *to_mtk_crtc(struct drm_crtc *c)
{
- return container_of(c, struct mtk_drm_crtc, base);
+ return container_of(c, struct mtk_crtc, base);
}
static inline struct mtk_crtc_state *to_mtk_crtc_state(struct drm_crtc_state *s)
@@ -90,7 +92,7 @@ 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)
+static void mtk_crtc_finish_page_flip(struct mtk_crtc *mtk_crtc)
{
struct drm_crtc *crtc = &mtk_crtc->base;
unsigned long flags;
@@ -104,63 +106,34 @@ static void mtk_drm_crtc_finish_page_flip(struct mtk_drm_crtc *mtk_crtc)
}
}
-static void mtk_drm_finish_page_flip(struct mtk_drm_crtc *mtk_crtc)
+static void mtk_drm_finish_page_flip(struct mtk_crtc *mtk_crtc)
{
+ unsigned long flags;
+
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;
+ if (mtk_crtc->cmdq_client.chan)
+ return;
+#endif
- 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;
+ spin_lock_irqsave(&mtk_crtc->config_lock, flags);
+ if (!mtk_crtc->config_updating && mtk_crtc->pending_needs_vblank) {
+ mtk_crtc_finish_page_flip(mtk_crtc);
+ mtk_crtc->pending_needs_vblank = false;
}
-
- pkt->pa_base = dma_addr;
-
- return 0;
+ spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
}
-static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
+static void mtk_crtc_destroy(struct drm_crtc *crtc)
{
- 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);
+ 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) {
+ cmdq_pkt_destroy(&mtk_crtc->cmdq_client, &mtk_crtc->cmdq_handle);
mbox_free_channel(mtk_crtc->cmdq_client.chan);
mtk_crtc->cmdq_client.chan = NULL;
}
@@ -176,7 +149,7 @@ static void mtk_drm_crtc_destroy(struct drm_crtc *crtc)
drm_crtc_cleanup(crtc);
}
-static void mtk_drm_crtc_reset(struct drm_crtc *crtc)
+static void mtk_crtc_reset(struct drm_crtc *crtc)
{
struct mtk_crtc_state *state;
@@ -191,7 +164,7 @@ static void mtk_drm_crtc_reset(struct drm_crtc *crtc)
__drm_atomic_helper_crtc_reset(crtc, &state->base);
}
-static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc)
+static struct drm_crtc_state *mtk_crtc_duplicate_state(struct drm_crtc *crtc)
{
struct mtk_crtc_state *state;
@@ -208,18 +181,17 @@ static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc
return &state->base;
}
-static void mtk_drm_crtc_destroy_state(struct drm_crtc *crtc,
- struct drm_crtc_state *state)
+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_drm_crtc_mode_valid(struct drm_crtc *crtc,
- const struct drm_display_mode *mode)
+mtk_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
{
- struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+ struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
enum drm_mode_status status = MODE_OK;
int i;
@@ -231,15 +203,15 @@ mtk_drm_crtc_mode_valid(struct drm_crtc *crtc,
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)
+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_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
+static void mtk_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
struct mtk_crtc_state *state = to_mtk_crtc_state(crtc->state);
@@ -250,7 +222,7 @@ static void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
state->pending_config = true;
}
-static int mtk_crtc_ddp_clk_enable(struct mtk_drm_crtc *mtk_crtc)
+static int mtk_crtc_ddp_clk_enable(struct mtk_crtc *mtk_crtc)
{
int ret;
int i;
@@ -270,7 +242,7 @@ err:
return ret;
}
-static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc)
+static void mtk_crtc_ddp_clk_disable(struct mtk_crtc *mtk_crtc)
{
int i;
@@ -279,11 +251,11 @@ static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc)
}
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_ddp_comp *mtk_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_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_ddp_comp *comp;
int i, count = 0;
unsigned int local_index = plane - mtk_crtc->planes;
@@ -306,15 +278,20 @@ 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 *mtk_crtc = container_of(cmdq_cl, struct mtk_crtc, cmdq_client);
struct mtk_crtc_state *state;
unsigned int i;
+ unsigned long flags;
if (data->sta < 0)
return;
state = to_mtk_crtc_state(mtk_crtc->base.state);
+ spin_lock_irqsave(&mtk_crtc->config_lock, flags);
+ if (mtk_crtc->config_updating)
+ goto ddp_cmdq_cb_out;
+
state->pending_config = false;
if (mtk_crtc->pending_planes) {
@@ -341,12 +318,21 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
mtk_crtc->pending_async_planes = false;
}
+ddp_cmdq_cb_out:
+
+ if (mtk_crtc->pending_needs_vblank) {
+ mtk_crtc_finish_page_flip(mtk_crtc);
+ mtk_crtc->pending_needs_vblank = false;
+ }
+
+ spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
+
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)
+static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
{
struct drm_crtc *crtc = &mtk_crtc->base;
struct drm_connector *connector;
@@ -431,7 +417,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
/* should not enable layer before crtc enabled */
plane_state->pending.enable = false;
- comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer);
+ comp = mtk_ddp_comp_for_plane(crtc, plane, &local_layer);
if (comp)
mtk_ddp_comp_layer_config(comp, local_layer,
plane_state, NULL);
@@ -446,10 +432,11 @@ err_pm_runtime_put:
return ret;
}
-static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc)
+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;
+ unsigned long flags;
int i;
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
@@ -481,17 +468,17 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc)
pm_runtime_put(drm->dev);
if (crtc->state->event && !crtc->state->active) {
- spin_lock_irq(&crtc->dev->event_lock);
+ spin_lock_irqsave(&crtc->dev->event_lock, flags);
drm_crtc_send_vblank_event(crtc, crtc->state->event);
crtc->state->event = NULL;
- spin_unlock_irq(&crtc->dev->event_lock);
+ spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
}
}
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 *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;
@@ -522,8 +509,7 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,
if (!plane_state->pending.config)
continue;
- comp = mtk_drm_ddp_comp_for_plane(crtc, plane,
- &local_layer);
+ comp = mtk_ddp_comp_for_plane(crtc, plane, &local_layer);
if (comp)
mtk_ddp_comp_layer_config(comp, local_layer,
@@ -547,8 +533,7 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,
if (!plane_state->pending.async_config)
continue;
- comp = mtk_drm_ddp_comp_for_plane(crtc, plane,
- &local_layer);
+ comp = mtk_ddp_comp_for_plane(crtc, plane, &local_layer);
if (comp)
mtk_ddp_comp_layer_config(comp, local_layer,
@@ -563,8 +548,7 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,
}
}
-static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,
- bool needs_vblank)
+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;
@@ -573,9 +557,14 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,
struct mtk_drm_private *priv = crtc->dev->dev_private;
unsigned int pending_planes = 0, pending_async_planes = 0;
int i;
+ unsigned long flags;
mutex_lock(&mtk_crtc->hw_lock);
+
+ spin_lock_irqsave(&mtk_crtc->config_lock, flags);
mtk_crtc->config_updating = true;
+ spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
+
if (needs_vblank)
mtk_crtc->pending_needs_vblank = true;
@@ -611,7 +600,7 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,
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);
+ cmdq_pkt_eoc(cmdq_handle);
dma_sync_single_for_device(mtk_crtc->cmdq_client.chan->mbox->dev,
cmdq_handle->pa_base,
cmdq_handle->cmd_buf_size,
@@ -625,18 +614,29 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,
*/
mtk_crtc->cmdq_vblank_cnt = 3;
+ spin_lock_irqsave(&mtk_crtc->config_lock, flags);
+ mtk_crtc->config_updating = false;
+ spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
+
mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle);
mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0);
+ goto update_config_out;
}
#endif
+ spin_lock_irqsave(&mtk_crtc->config_lock, flags);
mtk_crtc->config_updating = false;
+ spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+update_config_out:
+#endif
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_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_drm_private *priv = crtc->dev->dev_private;
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
@@ -652,9 +652,9 @@ static void mtk_crtc_ddp_irq(void *data)
mtk_drm_finish_page_flip(mtk_crtc);
}
-static int mtk_drm_crtc_enable_vblank(struct drm_crtc *crtc)
+static int mtk_crtc_enable_vblank(struct drm_crtc *crtc)
{
- struct mtk_drm_crtc *mtk_crtc = to_mtk_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);
@@ -662,22 +662,22 @@ static int mtk_drm_crtc_enable_vblank(struct drm_crtc *crtc)
return 0;
}
-static void mtk_drm_crtc_disable_vblank(struct drm_crtc *crtc)
+static void mtk_crtc_disable_vblank(struct drm_crtc *crtc)
{
- struct mtk_drm_crtc *mtk_crtc = to_mtk_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_drm_crtc_update_output(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+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_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+ struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_drm_private *priv;
unsigned int encoder_mask = crtc_state->encoder_mask;
@@ -707,33 +707,33 @@ static void mtk_drm_crtc_update_output(struct drm_crtc *crtc,
}
}
-int mtk_drm_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane,
- struct mtk_plane_state *state)
+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_drm_ddp_comp_for_plane(crtc, plane, &local_layer);
+ 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_drm_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane,
- struct drm_atomic_state *state)
+void mtk_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);
+ struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
if (!mtk_crtc->enabled)
return;
- mtk_drm_crtc_update_config(mtk_crtc, false);
+ mtk_crtc_update_config(mtk_crtc, false);
}
-static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+static void mtk_crtc_atomic_enable(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
{
- struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+ struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
int ret;
@@ -745,7 +745,7 @@ static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc,
return;
}
- mtk_drm_crtc_update_output(crtc, state);
+ mtk_crtc_update_output(crtc, state);
ret = mtk_crtc_ddp_hw_init(mtk_crtc);
if (ret) {
@@ -757,10 +757,10 @@ static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc,
mtk_crtc->enabled = true;
}
-static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+static void mtk_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
{
- struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+ struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
int i;
@@ -779,7 +779,7 @@ static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc,
}
mtk_crtc->pending_planes = true;
- mtk_drm_crtc_update_config(mtk_crtc, false);
+ 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)
@@ -797,13 +797,13 @@ static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc,
mtk_crtc->enabled = false;
}
-static void mtk_drm_crtc_atomic_begin(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+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_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+ struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
unsigned long flags;
if (mtk_crtc->event && mtk_crtc_state->base.event)
@@ -821,10 +821,10 @@ static void mtk_drm_crtc_atomic_begin(struct drm_crtc *crtc,
}
}
-static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+static void mtk_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
{
- struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+ struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
int i;
if (crtc->state->color_mgmt_changed)
@@ -832,33 +832,32 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
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);
+ 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_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,
+ .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_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,
+ .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_drm_crtc_init(struct drm_device *drm,
- struct mtk_drm_crtc *mtk_crtc,
- unsigned int pipe)
+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;
@@ -885,8 +884,7 @@ err_cleanup_crtc:
return ret;
}
-static int mtk_drm_crtc_num_comp_planes(struct mtk_drm_crtc *mtk_crtc,
- int comp_idx)
+static int mtk_crtc_num_comp_planes(struct mtk_crtc *mtk_crtc, int comp_idx)
{
struct mtk_ddp_comp *comp;
@@ -904,8 +902,8 @@ static int mtk_drm_crtc_num_comp_planes(struct mtk_drm_crtc *mtk_crtc,
}
static inline
-enum drm_plane_type mtk_drm_crtc_plane_type(unsigned int plane_idx,
- unsigned int num_planes)
+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;
@@ -916,11 +914,11 @@ enum drm_plane_type mtk_drm_crtc_plane_type(unsigned int plane_idx,
}
-static int mtk_drm_crtc_init_comp_planes(struct drm_device *drm_dev,
- struct mtk_drm_crtc *mtk_crtc,
- int comp_idx, int pipe)
+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_drm_crtc_num_comp_planes(mtk_crtc, comp_idx);
+ 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;
@@ -928,11 +926,11 @@ static int mtk_drm_crtc_init_comp_planes(struct drm_device *drm_dev,
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_crtc_plane_type(mtk_crtc->layer_nr, num_planes),
mtk_ddp_comp_supported_rotations(comp),
+ mtk_ddp_comp_get_blend_modes(comp),
mtk_ddp_comp_get_formats(comp),
- mtk_ddp_comp_get_num_formats(comp));
+ mtk_ddp_comp_get_num_formats(comp), i);
if (ret)
return ret;
@@ -941,9 +939,9 @@ static int mtk_drm_crtc_init_comp_planes(struct drm_device *drm_dev,
return 0;
}
-struct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc *crtc)
+struct device *mtk_crtc_dma_dev_get(struct drm_crtc *crtc)
{
- struct mtk_drm_crtc *mtk_crtc = NULL;
+ struct mtk_crtc *mtk_crtc = NULL;
if (!crtc)
return NULL;
@@ -955,14 +953,14 @@ struct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc *crtc)
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)
+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_drm_crtc *mtk_crtc;
+ struct mtk_crtc *mtk_crtc;
unsigned int num_comp_planes = 0;
int ret;
int i;
@@ -1009,10 +1007,10 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
mtk_crtc->mmsys_dev = priv->mmsys_dev;
mtk_crtc->ddp_comp_nr = path_len;
- mtk_crtc->ddp_comp = devm_kmalloc_array(dev,
- mtk_crtc->ddp_comp_nr + (conn_routes ? 1 : 0),
- sizeof(*mtk_crtc->ddp_comp),
- GFP_KERNEL);
+ 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;
@@ -1047,7 +1045,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
}
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
- num_comp_planes += mtk_drm_crtc_num_comp_planes(mtk_crtc, 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);
@@ -1055,8 +1053,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
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);
+ ret = mtk_crtc_init_comp_planes(drm_dev, mtk_crtc, i, crtc_i);
if (ret)
return ret;
}
@@ -1068,7 +1065,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_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);
+ ret = mtk_crtc_init(drm_dev, mtk_crtc, crtc_i);
if (ret < 0)
return ret;
@@ -1076,6 +1073,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
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);
+ spin_lock_init(&mtk_crtc->config_lock);
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
i = priv->mbox_index++;
@@ -1102,9 +1100,9 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
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);
+ ret = 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));
@@ -1138,7 +1136,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
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 */
+ /* increase ddp_comp_nr at the end of mtk_crtc_create */
mtk_crtc->ddp_comp_nr++;
}
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.h b/drivers/gpu/drm/mediatek/mtk_crtc.h
new file mode 100644
index 000000000000..388e900b6f4d
--- /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 <drm/drm_crtc.h>
+#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_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index a515e96cfefc..edc6417639e6 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -14,11 +14,11 @@
#include <linux/soc/mediatek/mtk-cmdq.h>
#include <drm/drm_print.h>
+#include "mtk_crtc.h"
+#include "mtk_ddp_comp.h"
#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"
+#include "mtk_plane.h"
#define DISP_REG_DITHER_EN 0x0000
@@ -363,6 +363,7 @@ static const struct mtk_ddp_comp_funcs ddp_ovl = {
.layer_config = mtk_ovl_layer_config,
.bgclr_in_on = mtk_ovl_bgclr_in_on,
.bgclr_in_off = mtk_ovl_bgclr_in_off,
+ .get_blend_modes = mtk_ovl_get_blend_modes,
.get_formats = mtk_ovl_get_formats,
.get_num_formats = mtk_ovl_get_num_formats,
};
@@ -416,6 +417,7 @@ static const struct mtk_ddp_comp_funcs ddp_ovl_adaptor = {
.disconnect = mtk_ovl_adaptor_disconnect,
.add = mtk_ovl_adaptor_add_comp,
.remove = mtk_ovl_adaptor_remove_comp,
+ .get_blend_modes = mtk_ovl_adaptor_get_blend_modes,
.get_formats = mtk_ovl_adaptor_get_formats,
.get_num_formats = mtk_ovl_adaptor_get_num_formats,
.mode_valid = mtk_ovl_adaptor_mode_valid,
@@ -497,10 +499,10 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_DRM_ID_MAX]
[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)
+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;
@@ -514,29 +516,42 @@ static bool mtk_drm_find_comp_in_ddp(struct device *dev,
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)
+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)
{
- int ret;
unsigned int i;
- if (!routes) {
- ret = -EINVAL;
- goto err;
- }
+ 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);
- ret = -ENODEV;
-err:
+ return -ENODEV;
+}
- DRM_INFO("Failed to find comp in ddp table, ret = %d\n", ret);
+static bool mtk_ddp_path_available(const unsigned int *path,
+ unsigned int path_len,
+ struct device_node **comp_node)
+{
+ unsigned int i;
- return 0;
+ 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,
@@ -554,26 +569,53 @@ int mtk_ddp_comp_get_id(struct device_node *node,
return -EINVAL;
}
-unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm,
- struct device *dev)
+int mtk_find_possible_crtcs(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);
+ 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;
}
@@ -588,7 +630,7 @@ int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp,
int ret;
#endif
- if (comp_id < 0 || comp_id >= DDP_COMPONENT_DRM_ID_MAX)
+ if (comp_id >= DDP_COMPONENT_DRM_ID_MAX)
return -EINVAL;
type = mtk_ddp_matches[comp_id].type;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index 93d79a1366e9..39720b27f4e9 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -3,8 +3,8 @@
* Copyright (c) 2015 MediaTek Inc.
*/
-#ifndef MTK_DRM_DDP_COMP_H
-#define MTK_DRM_DDP_COMP_H
+#ifndef MTK_DDP_COMP_H
+#define MTK_DDP_COMP_H
#include <linux/io.h>
#include <linux/pm_runtime.h>
@@ -80,6 +80,7 @@ struct mtk_ddp_comp_funcs {
void (*ctm_set)(struct device *dev,
struct drm_crtc_state *state);
struct device * (*dma_dev_get)(struct device *dev);
+ u32 (*get_blend_modes)(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);
@@ -192,7 +193,11 @@ 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;
+ /*
+ * 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)
@@ -263,6 +268,15 @@ static inline struct device *mtk_ddp_comp_dma_dev_get(struct mtk_ddp_comp *comp)
}
static inline
+u32 mtk_ddp_comp_get_blend_modes(struct mtk_ddp_comp *comp)
+{
+ if (comp->funcs && comp->funcs->get_blend_modes)
+ return comp->funcs->get_blend_modes(comp->dev);
+
+ return 0;
+}
+
+static inline
const u32 *mtk_ddp_comp_get_formats(struct mtk_ddp_comp *comp)
{
if (comp->funcs && comp->funcs->get_formats)
@@ -326,8 +340,7 @@ static inline void mtk_ddp_comp_encoder_index_set(struct mtk_ddp_comp *comp)
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_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);
@@ -340,4 +353,4 @@ void mtk_ddp_write_relaxed(struct cmdq_pkt *cmdq_pkt, unsigned int value,
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 */
+#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 40fe403086c3..abc9e5525d03 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
@@ -11,9 +11,9 @@
#include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
+#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
@@ -175,16 +175,14 @@ static int mtk_disp_aal_probe(struct platform_device *pdev)
return -ENOMEM;
priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "failed to get aal clk\n");
- return PTR_ERR(priv->clk);
- }
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "failed to get aal clk\n");
priv->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(priv->regs)) {
- dev_err(dev, "failed to ioremap aal\n");
- return PTR_ERR(priv->regs);
- }
+ if (IS_ERR(priv->regs))
+ return dev_err_probe(dev, PTR_ERR(priv->regs),
+ "failed to ioremap aal\n");
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
@@ -197,9 +195,9 @@ static int mtk_disp_aal_probe(struct platform_device *pdev)
ret = component_add(dev, &mtk_disp_aal_component_ops);
if (ret)
- dev_err(dev, "Failed to add component: %d\n", ret);
+ return dev_err_probe(dev, ret, "Failed to add component\n");
- return ret;
+ return 0;
}
static void mtk_disp_aal_remove(struct platform_device *pdev)
@@ -220,10 +218,9 @@ MODULE_DEVICE_TABLE(of, mtk_disp_aal_driver_dt_match);
struct platform_driver mtk_disp_aal_driver = {
.probe = mtk_disp_aal_probe,
- .remove_new = mtk_disp_aal_remove,
+ .remove = 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 465cddce0d32..10d60d2c2a56 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
@@ -10,9 +10,9 @@
#include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
+#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
@@ -160,16 +160,14 @@ static int mtk_disp_ccorr_probe(struct platform_device *pdev)
return -ENOMEM;
priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "failed to get ccorr clk\n");
- return PTR_ERR(priv->clk);
- }
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "failed to get ccorr clk\n");
priv->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(priv->regs)) {
- dev_err(dev, "failed to ioremap ccorr\n");
- return PTR_ERR(priv->regs);
- }
+ if (IS_ERR(priv->regs))
+ return dev_err_probe(dev, PTR_ERR(priv->regs),
+ "failed to ioremap ccorr\n");
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
@@ -182,9 +180,9 @@ static int mtk_disp_ccorr_probe(struct platform_device *pdev)
ret = component_add(dev, &mtk_disp_ccorr_component_ops);
if (ret)
- dev_err(dev, "Failed to add component: %d\n", ret);
+ return dev_err_probe(dev, ret, "Failed to add component\n");
- return ret;
+ return 0;
}
static void mtk_disp_ccorr_remove(struct platform_device *pdev)
@@ -211,10 +209,9 @@ MODULE_DEVICE_TABLE(of, mtk_disp_ccorr_driver_dt_match);
struct platform_driver mtk_disp_ccorr_driver = {
.probe = mtk_disp_ccorr_probe,
- .remove_new = mtk_disp_ccorr_remove,
+ .remove = 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 78ea99f1444f..39c7de4cdcc1 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_color.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_color.c
@@ -10,9 +10,9 @@
#include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
+#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
@@ -96,7 +96,6 @@ static int mtk_disp_color_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_disp_color *priv;
- struct resource *res;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -104,17 +103,14 @@ static int mtk_disp_color_probe(struct platform_device *pdev)
return -ENOMEM;
priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "failed to get color clk\n");
- return PTR_ERR(priv->clk);
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(priv->regs)) {
- dev_err(dev, "failed to ioremap color\n");
- return PTR_ERR(priv->regs);
- }
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "failed to get color clk\n");
+
+ priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->regs))
+ return dev_err_probe(dev, PTR_ERR(priv->regs),
+ "failed to ioremap color\n");
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
if (ret)
@@ -126,9 +122,9 @@ static int mtk_disp_color_probe(struct platform_device *pdev)
ret = component_add(dev, &mtk_disp_color_component_ops);
if (ret)
- dev_err(dev, "Failed to add component: %d\n", ret);
+ return dev_err_probe(dev, ret, "Failed to add component\n");
- return ret;
+ return 0;
}
static void mtk_disp_color_remove(struct platform_device *pdev)
@@ -161,10 +157,9 @@ MODULE_DEVICE_TABLE(of, mtk_disp_color_driver_dt_match);
struct platform_driver mtk_disp_color_driver = {
.probe = mtk_disp_color_probe,
- .remove_new = mtk_disp_color_remove,
+ .remove = 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 90e64467ea8f..04217a36939c 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -9,8 +9,8 @@
#include <linux/soc/mediatek/mtk-cmdq.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/soc/mediatek/mtk-mutex.h>
-#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);
@@ -103,11 +103,13 @@ void mtk_ovl_register_vblank_cb(struct device *dev,
void mtk_ovl_unregister_vblank_cb(struct device *dev);
void mtk_ovl_enable_vblank(struct device *dev);
void mtk_ovl_disable_vblank(struct device *dev);
+u32 mtk_ovl_get_blend_modes(struct device *dev);
const u32 *mtk_ovl_get_formats(struct device *dev);
size_t mtk_ovl_get_num_formats(struct device *dev);
void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex);
void mtk_ovl_adaptor_remove_comp(struct device *dev, struct mtk_mutex *mutex);
+bool mtk_ovl_adaptor_is_comp_present(struct device_node *node);
void mtk_ovl_adaptor_connect(struct device *dev, struct device *mmsys_dev,
unsigned int next);
void mtk_ovl_adaptor_disconnect(struct device *dev, struct device *mmsys_dev,
@@ -131,6 +133,7 @@ void mtk_ovl_adaptor_start(struct device *dev);
void mtk_ovl_adaptor_stop(struct device *dev);
unsigned int mtk_ovl_adaptor_layer_nr(struct device *dev);
struct device *mtk_ovl_adaptor_dma_dev_get(struct device *dev);
+u32 mtk_ovl_adaptor_get_blend_modes(struct device *dev);
const u32 *mtk_ovl_adaptor_get_formats(struct device *dev);
size_t mtk_ovl_adaptor_get_num_formats(struct device *dev);
enum drm_mode_status mtk_ovl_adaptor_mode_valid(struct device *dev,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index c1bc8b00d938..8afd15006df2 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -11,9 +11,9 @@
#include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
+#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
@@ -256,7 +256,6 @@ static int mtk_disp_gamma_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_disp_gamma *priv;
- struct resource *res;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -264,17 +263,14 @@ static int mtk_disp_gamma_probe(struct platform_device *pdev)
return -ENOMEM;
priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "failed to get gamma clk\n");
- return PTR_ERR(priv->clk);
- }
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "failed to get gamma clk\n");
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(priv->regs)) {
- dev_err(dev, "failed to ioremap gamma\n");
- return PTR_ERR(priv->regs);
- }
+ priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->regs))
+ return dev_err_probe(dev, PTR_ERR(priv->regs),
+ "failed to ioremap gamma\n");
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
@@ -287,9 +283,9 @@ static int mtk_disp_gamma_probe(struct platform_device *pdev)
ret = component_add(dev, &mtk_disp_gamma_component_ops);
if (ret)
- dev_err(dev, "Failed to add component: %d\n", ret);
+ return dev_err_probe(dev, ret, "Failed to add component\n");
- return ret;
+ return 0;
}
static void mtk_disp_gamma_remove(struct platform_device *pdev)
@@ -331,10 +327,9 @@ MODULE_DEVICE_TABLE(of, mtk_disp_gamma_driver_dt_match);
struct platform_driver mtk_disp_gamma_driver = {
.probe = mtk_disp_gamma_probe,
- .remove_new = mtk_disp_gamma_remove,
+ .remove = 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 32a29924bd54..b174dda091d3 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_merge.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_merge.c
@@ -10,7 +10,7 @@
#include <linux/reset.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
-#include "mtk_drm_ddp_comp.h"
+#include "mtk_ddp_comp.h"
#include "mtk_drm_drv.h"
#include "mtk_disp_drv.h"
@@ -306,7 +306,6 @@ static const struct component_ops mtk_disp_merge_component_ops = {
static int mtk_disp_merge_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct resource *res;
struct mtk_disp_merge *priv;
int ret;
@@ -314,24 +313,20 @@ static int mtk_disp_merge_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(priv->regs)) {
- dev_err(dev, "failed to ioremap merge\n");
- return PTR_ERR(priv->regs);
- }
+ priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->regs))
+ return dev_err_probe(dev, PTR_ERR(priv->regs),
+ "failed to ioremap merge\n");
priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "failed to get merge clk\n");
- return PTR_ERR(priv->clk);
- }
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "failed to get merge clk\n");
priv->async_clk = devm_clk_get_optional(dev, "merge_async");
- if (IS_ERR(priv->async_clk)) {
- dev_err(dev, "failed to get merge async clock\n");
- return PTR_ERR(priv->async_clk);
- }
+ if (IS_ERR(priv->async_clk))
+ return dev_err_probe(dev, PTR_ERR(priv->async_clk),
+ "failed to get merge async clock\n");
if (priv->async_clk) {
priv->reset_ctl = devm_reset_control_get_optional_exclusive(dev, NULL);
@@ -354,9 +349,9 @@ static int mtk_disp_merge_probe(struct platform_device *pdev)
ret = component_add(dev, &mtk_disp_merge_component_ops);
if (ret != 0)
- dev_err(dev, "Failed to add component: %d\n", ret);
+ return dev_err_probe(dev, ret, "Failed to add component\n");
- return ret;
+ return 0;
}
static void mtk_disp_merge_remove(struct platform_device *pdev)
@@ -373,10 +368,9 @@ MODULE_DEVICE_TABLE(of, mtk_disp_merge_driver_dt_match);
struct platform_driver mtk_disp_merge_driver = {
.probe = mtk_disp_merge_probe,
- .remove_new = mtk_disp_merge_remove,
+ .remove = 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 2bffe4245466..d0581c4e3c99 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -15,9 +15,9 @@
#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
+#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,10 +38,15 @@
#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
-#define DISP_REG_OVL_CLRFMT_EXT 0x02D0
+#define DISP_REG_OVL_CLRFMT_EXT 0x02d0
+#define OVL_CON_CLRFMT_BIT_DEPTH_MASK(n) (GENMASK(1, 0) << (4 * (n)))
+#define OVL_CON_CLRFMT_BIT_DEPTH(depth, n) ((depth) << (4 * (n)))
+#define OVL_CON_CLRFMT_8_BIT (0)
+#define OVL_CON_CLRFMT_10_BIT (1)
#define DISP_REG_OVL_ADDR_MT8173 0x0f40
#define DISP_REG_OVL_ADDR(ovl, n) ((ovl)->data->addr + 0x20 * (n))
#define DISP_REG_OVL_HDR_ADDR(ovl, n) ((ovl)->data->addr + 0x20 * (n) + 0x04)
@@ -51,26 +56,51 @@
#define GMC_THRESHOLD_HIGH ((1 << GMC_THRESHOLD_BITS) / 4)
#define GMC_THRESHOLD_LOW ((1 << GMC_THRESHOLD_BITS) / 8)
+#define OVL_CON_CLRFMT_MAN BIT(23)
#define OVL_CON_BYTE_SWAP BIT(24)
-#define OVL_CON_MTX_YUV_TO_RGB (6 << 16)
+
+/* OVL_CON_RGB_SWAP works only if OVL_CON_CLRFMT_MAN is enabled */
+#define OVL_CON_RGB_SWAP BIT(25)
+
#define OVL_CON_CLRFMT_RGB (1 << 12)
-#define OVL_CON_CLRFMT_RGBA8888 (2 << 12)
-#define OVL_CON_CLRFMT_ARGB8888 (3 << 12)
+#define OVL_CON_CLRFMT_ARGB8888 (2 << 12)
+#define OVL_CON_CLRFMT_RGBA8888 (3 << 12)
+#define OVL_CON_CLRFMT_ABGR8888 (OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP)
+#define OVL_CON_CLRFMT_BGRA8888 (OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP)
#define OVL_CON_CLRFMT_UYVY (4 << 12)
#define OVL_CON_CLRFMT_YUYV (5 << 12)
+#define OVL_CON_MTX_YUV_TO_RGB (6 << 16)
+#define OVL_CON_CLRFMT_PARGB8888 ((3 << 12) | OVL_CON_CLRFMT_MAN)
+#define OVL_CON_CLRFMT_PABGR8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_RGB_SWAP)
+#define OVL_CON_CLRFMT_PBGRA8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_BYTE_SWAP)
+#define OVL_CON_CLRFMT_PRGBA8888 (OVL_CON_CLRFMT_PABGR8888 | OVL_CON_BYTE_SWAP)
#define OVL_CON_CLRFMT_RGB565(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
0 : OVL_CON_CLRFMT_RGB)
#define OVL_CON_CLRFMT_RGB888(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
OVL_CON_CLRFMT_RGB : 0)
-#define OVL_CON_CLRFMT_BIT_DEPTH_MASK(ovl) (0xFF << 4 * (ovl))
-#define OVL_CON_CLRFMT_BIT_DEPTH(depth, ovl) (depth << 4 * (ovl))
-#define OVL_CON_CLRFMT_8_BIT 0x00
-#define OVL_CON_CLRFMT_10_BIT 0x01
#define OVL_CON_AEN BIT(8)
#define OVL_CON_ALPHA 0xff
#define OVL_CON_VIRT_FLIP BIT(9)
#define OVL_CON_HORZ_FLIP BIT(10)
+#define OVL_COLOR_ALPHA GENMASK(31, 24)
+
+static inline bool is_10bit_rgb(u32 fmt)
+{
+ switch (fmt) {
+ case DRM_FORMAT_XRGB2101010:
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_RGBX1010102:
+ case DRM_FORMAT_RGBA1010102:
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_BGRX1010102:
+ case DRM_FORMAT_BGRA1010102:
+ return true;
+ }
+ return false;
+}
+
static const u32 mt8173_formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
@@ -88,12 +118,20 @@ static const u32 mt8173_formats[] = {
static const u32 mt8195_formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_XRGB2101010,
DRM_FORMAT_ARGB2101010,
DRM_FORMAT_BGRX8888,
DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_BGRX1010102,
DRM_FORMAT_BGRA1010102,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_XBGR2101010,
+ DRM_FORMAT_ABGR2101010,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_RGBX1010102,
+ DRM_FORMAT_RGBA1010102,
DRM_FORMAT_RGB888,
DRM_FORMAT_BGR888,
DRM_FORMAT_RGB565,
@@ -108,6 +146,7 @@ struct mtk_disp_ovl_data {
bool fmt_rgb565_is_0;
bool smi_id_en;
bool supports_afbc;
+ const u32 blend_modes;
const u32 *formats;
size_t num_formats;
bool supports_clrfmt_ext;
@@ -176,6 +215,13 @@ void mtk_ovl_disable_vblank(struct device *dev)
writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN);
}
+u32 mtk_ovl_get_blend_modes(struct device *dev)
+{
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+
+ return ovl->data->blend_modes;
+}
+
const u32 *mtk_ovl_get_formats(struct device *dev)
{
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
@@ -244,24 +290,17 @@ static void mtk_ovl_set_bit_depth(struct device *dev, int idx, u32 format,
struct cmdq_pkt *cmdq_pkt)
{
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
- unsigned int reg;
unsigned int bit_depth = OVL_CON_CLRFMT_8_BIT;
if (!ovl->data->supports_clrfmt_ext)
return;
- reg = readl(ovl->regs + DISP_REG_OVL_CLRFMT_EXT);
- reg &= ~OVL_CON_CLRFMT_BIT_DEPTH_MASK(idx);
-
- if (format == DRM_FORMAT_RGBA1010102 ||
- format == DRM_FORMAT_BGRA1010102 ||
- format == DRM_FORMAT_ARGB2101010)
+ if (is_10bit_rgb(format))
bit_depth = OVL_CON_CLRFMT_10_BIT;
- reg |= OVL_CON_CLRFMT_BIT_DEPTH(bit_depth, idx);
-
- mtk_ddp_write(cmdq_pkt, reg, &ovl->cmdq_reg,
- ovl->regs, DISP_REG_OVL_CLRFMT_EXT);
+ mtk_ddp_write_mask(cmdq_pkt, OVL_CON_CLRFMT_BIT_DEPTH(bit_depth, idx),
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_CLRFMT_EXT,
+ OVL_CON_CLRFMT_BIT_DEPTH_MASK(idx));
}
void mtk_ovl_config(struct device *dev, unsigned int w,
@@ -273,7 +312,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 +341,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;
}
@@ -356,13 +394,27 @@ void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
DISP_REG_OVL_RDMA_CTRL(idx));
}
-static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
+static unsigned int mtk_ovl_fmt_convert(struct mtk_disp_ovl *ovl,
+ struct mtk_plane_state *state)
{
- /* The return value in switch "MEM_MODE_INPUT_FORMAT_XXX"
- * is defined in mediatek HW data sheet.
- * The alphabet order in XXX is no relation to data
- * arrangement in memory.
+ unsigned int fmt = state->pending.format;
+ unsigned int blend_mode = DRM_MODE_BLEND_COVERAGE;
+
+ /*
+ * For the platforms where OVL_CON_CLRFMT_MAN is defined in the hardware data sheet
+ * and supports premultiplied color formats, such as OVL_CON_CLRFMT_PARGB8888.
+ *
+ * Check blend_modes in the driver data to see if premultiplied mode is supported.
+ * If not, use coverage mode instead to set it to the supported color formats.
+ *
+ * Current DRM assumption is that alpha is default premultiplied, so the bitmask of
+ * blend_modes must include BIT(DRM_MODE_BLEND_PREMULTI). Otherwise, mtk_plane_init()
+ * will get an error return from drm_plane_create_blend_mode_property() and
+ * state->base.pixel_blend_mode should not be used.
*/
+ if (ovl->data->blend_modes & BIT(DRM_MODE_BLEND_PREMULTI))
+ blend_mode = state->base.pixel_blend_mode;
+
switch (fmt) {
default:
case DRM_FORMAT_RGB565:
@@ -375,18 +427,32 @@ static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
return OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP;
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_RGBA8888:
- return OVL_CON_CLRFMT_ARGB8888;
+ case DRM_FORMAT_RGBX1010102:
+ case DRM_FORMAT_RGBA1010102:
+ return blend_mode == DRM_MODE_BLEND_COVERAGE ?
+ OVL_CON_CLRFMT_RGBA8888 :
+ OVL_CON_CLRFMT_PRGBA8888;
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_BGRA8888:
+ case DRM_FORMAT_BGRX1010102:
case DRM_FORMAT_BGRA1010102:
- return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP;
+ return blend_mode == DRM_MODE_BLEND_COVERAGE ?
+ OVL_CON_CLRFMT_BGRA8888 :
+ OVL_CON_CLRFMT_PBGRA8888;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_ARGB2101010:
- return OVL_CON_CLRFMT_RGBA8888;
+ return blend_mode == DRM_MODE_BLEND_COVERAGE ?
+ OVL_CON_CLRFMT_ARGB8888 :
+ OVL_CON_CLRFMT_PARGB8888;
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ABGR8888:
- return OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP;
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_ABGR2101010:
+ return blend_mode == DRM_MODE_BLEND_COVERAGE ?
+ OVL_CON_CLRFMT_ABGR8888 :
+ OVL_CON_CLRFMT_PABGR8888;
case DRM_FORMAT_UYVY:
return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB;
case DRM_FORMAT_YUYV:
@@ -394,6 +460,29 @@ static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
}
}
+static void mtk_ovl_afbc_layer_config(struct mtk_disp_ovl *ovl,
+ unsigned int idx,
+ struct mtk_plane_pending_state *pending,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ unsigned int pitch_msb = pending->pitch >> 16;
+ unsigned int hdr_pitch = pending->hdr_pitch;
+ unsigned int hdr_addr = pending->hdr_addr;
+
+ if (pending->modifier != DRM_FORMAT_MOD_LINEAR) {
+ mtk_ddp_write_relaxed(cmdq_pkt, hdr_addr, &ovl->cmdq_reg, ovl->regs,
+ DISP_REG_OVL_HDR_ADDR(ovl, idx));
+ mtk_ddp_write_relaxed(cmdq_pkt,
+ OVL_PITCH_MSB_2ND_SUBBUF | pitch_msb,
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH_MSB(idx));
+ mtk_ddp_write_relaxed(cmdq_pkt, hdr_pitch, &ovl->cmdq_reg, ovl->regs,
+ DISP_REG_OVL_HDR_PITCH(ovl, idx));
+ } else {
+ mtk_ddp_write_relaxed(cmdq_pkt, pitch_msb,
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH_MSB(idx));
+ }
+}
+
void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt)
@@ -401,50 +490,66 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
struct mtk_plane_pending_state *pending = &state->pending;
unsigned int addr = pending->addr;
- unsigned int hdr_addr = pending->hdr_addr;
- unsigned int pitch = pending->pitch;
- unsigned int hdr_pitch = pending->hdr_pitch;
+ unsigned int pitch_lsb = pending->pitch & GENMASK(15, 0);
unsigned int fmt = pending->format;
+ unsigned int rotation = pending->rotation;
unsigned int offset = (pending->y << 16) | pending->x;
unsigned int src_size = (pending->height << 16) | pending->width;
+ unsigned int blend_mode = state->base.pixel_blend_mode;
+ unsigned int ignore_pixel_alpha = 0;
unsigned int con;
- bool is_afbc = pending->modifier != DRM_FORMAT_MOD_LINEAR;
- union overlay_pitch {
- struct split_pitch {
- u16 lsb;
- u16 msb;
- } split_pitch;
- u32 pitch;
- } overlay_pitch;
-
- overlay_pitch.pitch = pitch;
if (!pending->enable) {
mtk_ovl_layer_off(dev, idx, cmdq_pkt);
return;
}
- con = ovl_fmt_convert(ovl, fmt);
- if (state->base.fb && state->base.fb->format->has_alpha)
- con |= OVL_CON_AEN | OVL_CON_ALPHA;
+ con = mtk_ovl_fmt_convert(ovl, state);
+ if (state->base.fb) {
+ con |= state->base.alpha & OVL_CON_ALPHA;
+
+ /*
+ * For blend_modes supported SoCs, always enable alpha blending.
+ * For blend_modes unsupported SoCs, enable alpha blending when has_alpha is set.
+ */
+ if (blend_mode || state->base.fb->format->has_alpha)
+ con |= OVL_CON_AEN;
+
+ /*
+ * Although the alpha channel can be ignored, CONST_BLD must be enabled
+ * for XRGB format, otherwise 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 (blend_mode == DRM_MODE_BLEND_PIXEL_NONE || !state->base.fb->format->has_alpha)
+ ignore_pixel_alpha = OVL_CONST_BLEND;
+ }
+
+ /*
+ * Treat rotate 180 as flip x + flip y, and XOR the original rotation value
+ * to flip x + flip y to support both in the same time.
+ */
+ if (rotation & DRM_MODE_ROTATE_180)
+ rotation ^= DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y;
- if (pending->rotation & DRM_MODE_REFLECT_Y) {
+ if (rotation & DRM_MODE_REFLECT_Y) {
con |= OVL_CON_VIRT_FLIP;
addr += (pending->height - 1) * pending->pitch;
}
- if (pending->rotation & DRM_MODE_REFLECT_X) {
+ if (rotation & DRM_MODE_REFLECT_X) {
con |= OVL_CON_HORZ_FLIP;
addr += pending->pitch - 1;
}
if (ovl->data->supports_afbc)
- mtk_ovl_set_afbc(ovl, cmdq_pkt, idx, is_afbc);
+ mtk_ovl_set_afbc(ovl, cmdq_pkt, idx,
+ pending->modifier != DRM_FORMAT_MOD_LINEAR);
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, 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,
@@ -452,19 +557,8 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_ADDR(ovl, idx));
- if (is_afbc) {
- mtk_ddp_write_relaxed(cmdq_pkt, hdr_addr, &ovl->cmdq_reg, ovl->regs,
- DISP_REG_OVL_HDR_ADDR(ovl, idx));
- mtk_ddp_write_relaxed(cmdq_pkt,
- OVL_PITCH_MSB_2ND_SUBBUF | overlay_pitch.split_pitch.msb,
- &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH_MSB(idx));
- mtk_ddp_write_relaxed(cmdq_pkt, hdr_pitch, &ovl->cmdq_reg, ovl->regs,
- DISP_REG_OVL_HDR_PITCH(ovl, idx));
- } else {
- mtk_ddp_write_relaxed(cmdq_pkt,
- overlay_pitch.split_pitch.msb,
- &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH_MSB(idx));
- }
+ if (ovl->data->supports_afbc)
+ mtk_ovl_afbc_layer_config(ovl, idx, pending, cmdq_pkt);
mtk_ovl_set_bit_depth(dev, idx, fmt, cmdq_pkt);
mtk_ovl_layer_on(dev, idx, cmdq_pkt);
@@ -510,7 +604,6 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_disp_ovl *priv;
- struct resource *res;
int irq;
int ret;
@@ -523,17 +616,14 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
return irq;
priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "failed to get ovl clk\n");
- return PTR_ERR(priv->clk);
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(priv->regs)) {
- dev_err(dev, "failed to ioremap ovl\n");
- return PTR_ERR(priv->regs);
- }
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "failed to get ovl clk\n");
+
+ priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->regs))
+ return dev_err_probe(dev, PTR_ERR(priv->regs),
+ "failed to ioremap ovl\n");
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
if (ret)
@@ -545,20 +635,18 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler,
IRQF_TRIGGER_NONE, dev_name(dev), priv);
- if (ret < 0) {
- dev_err(dev, "Failed to request irq %d: %d\n", irq, ret);
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to request irq %d\n", irq);
pm_runtime_enable(dev);
ret = component_add(dev, &mtk_disp_ovl_component_ops);
if (ret) {
pm_runtime_disable(dev);
- dev_err(dev, "Failed to add component: %d\n", ret);
+ return dev_err_probe(dev, ret, "Failed to add component\n");
}
- return ret;
+ return 0;
}
static void mtk_disp_ovl_remove(struct platform_device *pdev)
@@ -609,6 +697,9 @@ static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = {
.layer_nr = 4,
.fmt_rgb565_is_0 = true,
.smi_id_en = true,
+ .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE) |
+ BIT(DRM_MODE_BLEND_PIXEL_NONE),
.formats = mt8173_formats,
.num_formats = ARRAY_SIZE(mt8173_formats),
};
@@ -619,6 +710,9 @@ static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
.layer_nr = 2,
.fmt_rgb565_is_0 = true,
.smi_id_en = true,
+ .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE) |
+ BIT(DRM_MODE_BLEND_PIXEL_NONE),
.formats = mt8173_formats,
.num_formats = ARRAY_SIZE(mt8173_formats),
};
@@ -630,6 +724,9 @@ static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
.fmt_rgb565_is_0 = true,
.smi_id_en = true,
.supports_afbc = true,
+ .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE) |
+ BIT(DRM_MODE_BLEND_PIXEL_NONE),
.formats = mt8195_formats,
.num_formats = ARRAY_SIZE(mt8195_formats),
.supports_clrfmt_ext = true,
@@ -656,10 +753,9 @@ MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match);
struct platform_driver mtk_disp_ovl_driver = {
.probe = mtk_disp_ovl_probe,
- .remove_new = mtk_disp_ovl_remove,
+ .remove = 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 034d31824d4d..fe97bb97e004 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
@@ -17,9 +17,8 @@
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/soc/mediatek/mtk-mutex.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 +157,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);
@@ -401,6 +400,13 @@ void mtk_ovl_adaptor_disable_vblank(struct device *dev)
mtk_ethdr_disable_vblank(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0]);
}
+u32 mtk_ovl_adaptor_get_blend_modes(struct device *dev)
+{
+ struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
+
+ return mtk_ethdr_get_blend_modes(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0]);
+}
+
const u32 *mtk_ovl_adaptor_get_formats(struct device *dev)
{
struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
@@ -486,26 +492,55 @@ static const struct of_device_id mtk_ovl_adaptor_comp_dt_ids[] = {
{ /* sentinel */ }
};
-static int compare_of(struct device *dev, void *data)
+static int ovl_adaptor_of_get_ddp_comp_type(struct device_node *node,
+ enum mtk_ovl_adaptor_comp_type *ctype)
{
- return dev->of_node == data;
+ const struct of_device_id *of_id = of_match_node(mtk_ovl_adaptor_comp_dt_ids, node);
+
+ if (!of_id)
+ return -EINVAL;
+
+ *ctype = (enum mtk_ovl_adaptor_comp_type)((uintptr_t)of_id->data);
+
+ return 0;
+}
+
+bool mtk_ovl_adaptor_is_comp_present(struct device_node *node)
+{
+ enum mtk_ovl_adaptor_comp_type type;
+ int ret;
+
+ ret = ovl_adaptor_of_get_ddp_comp_type(node, &type);
+ if (ret)
+ return false;
+
+ if (type >= OVL_ADAPTOR_TYPE_NUM)
+ return false;
+
+ /*
+ * In the context of mediatek-drm, ETHDR, MDP_RDMA and Padding are
+ * used exclusively by OVL Adaptor: if this component is not one of
+ * those, it's likely not an OVL Adaptor path.
+ */
+ return type == OVL_ADAPTOR_TYPE_ETHDR ||
+ type == OVL_ADAPTOR_TYPE_MDP_RDMA ||
+ type == OVL_ADAPTOR_TYPE_PADDING;
}
static int ovl_adaptor_comp_init(struct device *dev, struct component_match **match)
{
struct mtk_disp_ovl_adaptor *priv = dev_get_drvdata(dev);
- struct device_node *node, *parent;
+ struct device_node *parent;
struct platform_device *comp_pdev;
parent = dev->parent->parent->of_node->parent;
- for_each_child_of_node(parent, node) {
- const struct of_device_id *of_id;
+ for_each_child_of_node_scoped(parent, node) {
enum mtk_ovl_adaptor_comp_type type;
- int id;
+ int id, ret;
- of_id = of_match_node(mtk_ovl_adaptor_comp_dt_ids, node);
- if (!of_id)
+ ret = ovl_adaptor_of_get_ddp_comp_type(node, &type);
+ if (ret)
continue;
if (!of_device_is_available(node)) {
@@ -514,7 +549,6 @@ static int ovl_adaptor_comp_init(struct device *dev, struct component_match **ma
continue;
}
- type = (enum mtk_ovl_adaptor_comp_type)(uintptr_t)of_id->data;
id = ovl_adaptor_comp_get_id(dev, node, type);
if (id < 0) {
dev_warn(dev, "Skipping unknown component %pOF\n",
@@ -528,7 +562,7 @@ static int ovl_adaptor_comp_init(struct device *dev, struct component_match **ma
priv->ovl_adaptor_comp[id] = &comp_pdev->dev;
- drm_of_component_match_add(dev, match, compare_of, node);
+ drm_of_component_match_add(dev, match, component_compare_of, node);
dev_dbg(dev, "Adding component match for %pOF\n", node);
}
@@ -612,10 +646,10 @@ static int mtk_disp_ovl_adaptor_probe(struct platform_device *pdev)
ret = component_add(dev, &mtk_disp_ovl_adaptor_comp_ops);
if (ret != 0) {
pm_runtime_disable(dev);
- dev_err(dev, "Failed to add component: %d\n", ret);
+ return dev_err_probe(dev, ret, "Failed to add component\n");
}
- return ret;
+ return 0;
}
static void mtk_disp_ovl_adaptor_remove(struct platform_device *pdev)
@@ -626,9 +660,8 @@ static void mtk_disp_ovl_adaptor_remove(struct platform_device *pdev)
struct platform_driver mtk_disp_ovl_adaptor_driver = {
.probe = mtk_disp_ovl_adaptor_probe,
- .remove_new = mtk_disp_ovl_adaptor_remove,
+ .remove = 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 faa907f2f443..c9d41d75e7f2 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -13,9 +13,9 @@
#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
+#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
@@ -313,7 +313,6 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_disp_rdma *priv;
- struct resource *res;
int irq;
int ret;
@@ -326,32 +325,25 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
return irq;
priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "failed to get rdma clk\n");
- return PTR_ERR(priv->clk);
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(priv->regs)) {
- dev_err(dev, "failed to ioremap rdma\n");
- return PTR_ERR(priv->regs);
- }
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "failed to get rdma clk\n");
+
+ priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->regs))
+ return dev_err_probe(dev, PTR_ERR(priv->regs),
+ "failed to ioremap rdma\n");
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
if (ret)
dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
#endif
- if (of_find_property(dev->of_node, "mediatek,rdma-fifo-size", &ret)) {
- ret = of_property_read_u32(dev->of_node,
- "mediatek,rdma-fifo-size",
- &priv->fifo_size);
- if (ret) {
- dev_err(dev, "Failed to get rdma fifo size\n");
- return ret;
- }
- }
+ ret = of_property_read_u32(dev->of_node,
+ "mediatek,rdma-fifo-size",
+ &priv->fifo_size);
+ if (ret && (ret != -EINVAL))
+ return dev_err_probe(dev, ret, "Failed to get rdma fifo size\n");
/* Disable and clear pending interrupts */
writel(0x0, priv->regs + DISP_REG_RDMA_INT_ENABLE);
@@ -359,10 +351,8 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, mtk_disp_rdma_irq_handler,
IRQF_TRIGGER_NONE, dev_name(dev), priv);
- if (ret < 0) {
- dev_err(dev, "Failed to request irq %d: %d\n", irq, ret);
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to request irq %d\n", irq);
priv->data = of_device_get_match_data(dev);
@@ -373,10 +363,10 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
ret = component_add(dev, &mtk_disp_rdma_component_ops);
if (ret) {
pm_runtime_disable(dev);
- dev_err(dev, "Failed to add component: %d\n", ret);
+ return dev_err_probe(dev, ret, "Failed to add component\n");
}
- return ret;
+ return 0;
}
static void mtk_disp_rdma_remove(struct platform_device *pdev)
@@ -425,10 +415,9 @@ MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match);
struct platform_driver mtk_disp_rdma_driver = {
.probe = mtk_disp_rdma_probe,
- .remove_new = mtk_disp_rdma_remove,
+ .remove = 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 0ba72102636a..b2408abb9d49 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -145,6 +145,89 @@ struct mtk_dp_data {
u16 audio_m_div2_bit;
};
+static const struct mtk_dp_efuse_fmt mt8188_dp_efuse_fmt[MTK_DP_CAL_MAX] = {
+ [MTK_DP_CAL_GLB_BIAS_TRIM] = {
+ .idx = 0,
+ .shift = 10,
+ .mask = 0x1f,
+ .min_val = 1,
+ .max_val = 0x1e,
+ .default_val = 0xf,
+ },
+ [MTK_DP_CAL_CLKTX_IMPSE] = {
+ .idx = 0,
+ .shift = 15,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_0] = {
+ .idx = 1,
+ .shift = 0,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_1] = {
+ .idx = 1,
+ .shift = 8,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_2] = {
+ .idx = 1,
+ .shift = 16,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_3] = {
+ .idx = 1,
+ .shift = 24,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_0] = {
+ .idx = 1,
+ .shift = 4,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_1] = {
+ .idx = 1,
+ .shift = 12,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_2] = {
+ .idx = 1,
+ .shift = 20,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_3] = {
+ .idx = 1,
+ .shift = 28,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+};
+
static const struct mtk_dp_efuse_fmt mt8195_edp_efuse_fmt[MTK_DP_CAL_MAX] = {
[MTK_DP_CAL_GLB_BIAS_TRIM] = {
.idx = 3,
@@ -311,7 +394,7 @@ static const struct mtk_dp_efuse_fmt mt8195_dp_efuse_fmt[MTK_DP_CAL_MAX] = {
},
};
-static struct regmap_config mtk_dp_regmap_config = {
+static const struct regmap_config mtk_dp_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
@@ -460,18 +543,16 @@ static int mtk_dp_set_color_format(struct mtk_dp *mtk_dp,
enum dp_pixelformat color_format)
{
u32 val;
-
- /* update MISC0 */
- mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
- color_format << DP_TEST_COLOR_FORMAT_SHIFT,
- DP_TEST_COLOR_FORMAT_MASK);
+ u32 misc0_color;
switch (color_format) {
case DP_PIXELFORMAT_YUV422:
val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422;
+ misc0_color = DP_COLOR_FORMAT_YCbCr422;
break;
case DP_PIXELFORMAT_RGB:
val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB;
+ misc0_color = DP_COLOR_FORMAT_RGB;
break;
default:
drm_warn(mtk_dp->drm_dev, "Unsupported color format: %d\n",
@@ -479,6 +560,11 @@ static int mtk_dp_set_color_format(struct mtk_dp *mtk_dp,
return -EINVAL;
}
+ /* update MISC0 */
+ mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
+ misc0_color,
+ DP_TEST_COLOR_FORMAT_MASK);
+
mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
val, PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK);
return 0;
@@ -1052,6 +1138,18 @@ static void mtk_dp_digital_sw_reset(struct mtk_dp *mtk_dp)
0, DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0);
}
+static void mtk_dp_sdp_path_reset(struct mtk_dp *mtk_dp)
+{
+ mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004,
+ SDP_RESET_SW_DP_ENC0_P0,
+ SDP_RESET_SW_DP_ENC0_P0);
+
+ /* Wait for sdp path reset to complete */
+ usleep_range(1000, 5000);
+ mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004,
+ 0, SDP_RESET_SW_DP_ENC0_P0);
+}
+
static void mtk_dp_set_lanes(struct mtk_dp *mtk_dp, int lanes)
{
mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_35F0,
@@ -1082,17 +1180,25 @@ static void mtk_dp_get_calibration_data(struct mtk_dp *mtk_dp)
buf = (u32 *)nvmem_cell_read(cell, &len);
nvmem_cell_put(cell);
- if (IS_ERR(buf) || ((len / sizeof(u32)) != 4)) {
+ if (IS_ERR(buf)) {
dev_warn(dev, "Failed to read nvmem_cell_read\n");
-
- if (!IS_ERR(buf))
- kfree(buf);
-
goto use_default_val;
}
+ /* The cell length is in bytes. Convert it to be compatible with u32 buffer. */
+ len /= sizeof(u32);
+
for (i = 0; i < MTK_DP_CAL_MAX; i++) {
fmt = &mtk_dp->data->efuse_fmt[i];
+
+ if (fmt->idx >= len) {
+ dev_warn(mtk_dp->dev,
+ "Out-of-bound efuse data access, fmt idx = %d, buf len = %zu\n",
+ fmt->idx, len);
+ kfree(buf);
+ goto use_default_val;
+ }
+
cal_data[i] = (buf[fmt->idx] >> fmt->shift) & fmt->mask;
if (cal_data[i] < fmt->min_val || cal_data[i] > fmt->max_val) {
@@ -1660,7 +1766,7 @@ static int mtk_dp_parse_capabilities(struct mtk_dp *mtk_dp)
ret = drm_dp_dpcd_readb(&mtk_dp->aux, DP_MSTM_CAP, &val);
if (ret < 1) {
- drm_err(mtk_dp->drm_dev, "Read mstm cap failed\n");
+ dev_err(mtk_dp->dev, "Read mstm cap failed: %zd\n", ret);
return ret == 0 ? -EIO : ret;
}
@@ -1670,7 +1776,7 @@ static int mtk_dp_parse_capabilities(struct mtk_dp *mtk_dp)
DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0,
&val);
if (ret < 1) {
- drm_err(mtk_dp->drm_dev, "Read irq vector failed\n");
+ dev_err(mtk_dp->dev, "Read irq vector failed: %zd\n", ret);
return ret == 0 ? -EIO : ret;
}
@@ -1953,7 +2059,7 @@ static int mtk_dp_wait_hpd_asserted(struct drm_dp_aux *mtk_aux, unsigned long wa
ret = mtk_dp_parse_capabilities(mtk_dp);
if (ret) {
- drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n");
+ dev_err(mtk_dp->dev, "Can't parse capabilities: %d\n", ret);
return ret;
}
@@ -2017,7 +2123,6 @@ static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge)
struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
enum drm_connector_status ret = connector_status_disconnected;
bool enabled = mtk_dp->enabled;
- u8 sink_count = 0;
if (!mtk_dp->train_info.cable_plugged_in)
return ret;
@@ -2032,8 +2137,8 @@ static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge)
* function, we just need to check the HPD connection to check
* whether we connect to a sink device.
*/
- drm_dp_dpcd_readb(&mtk_dp->aux, DP_SINK_COUNT, &sink_count);
- if (DP_GET_SINK_COUNT(sink_count))
+
+ if (drm_dp_read_sink_count(&mtk_dp->aux) > 0)
ret = connector_status_connected;
if (!enabled)
@@ -2073,9 +2178,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
@@ -2104,7 +2215,7 @@ static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux,
if (mtk_dp->bridge.type != DRM_MODE_CONNECTOR_eDP &&
!mtk_dp->train_info.cable_plugged_in) {
- ret = -EAGAIN;
+ ret = -EIO;
goto err;
}
@@ -2176,6 +2287,7 @@ static void mtk_dp_poweroff(struct mtk_dp *mtk_dp)
}
static int mtk_dp_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
@@ -2199,7 +2311,7 @@ static int mtk_dp_bridge_attach(struct drm_bridge *bridge,
goto err_aux_register;
if (mtk_dp->next_bridge) {
- ret = drm_bridge_attach(bridge->encoder, mtk_dp->next_bridge,
+ ret = drm_bridge_attach(encoder, mtk_dp->next_bridge,
&mtk_dp->bridge, flags);
if (ret) {
drm_warn(mtk_dp->drm_dev,
@@ -2239,12 +2351,12 @@ static void mtk_dp_bridge_detach(struct drm_bridge *bridge)
}
static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_state)
+ struct drm_atomic_state *state)
{
struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
int ret;
- mtk_dp->conn = drm_atomic_get_new_connector_for_encoder(old_state->base.state,
+ mtk_dp->conn = drm_atomic_get_new_connector_for_encoder(state,
bridge->encoder);
if (!mtk_dp->conn) {
drm_err(mtk_dp->drm_dev,
@@ -2289,7 +2401,7 @@ power_off_aux:
}
static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_state)
+ struct drm_atomic_state *state)
{
struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
@@ -2308,6 +2420,9 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
DP_PWR_STATE_BANDGAP_TPLL,
DP_PWR_STATE_MASK);
+ /* SDP path reset sw*/
+ mtk_dp_sdp_path_reset(mtk_dp);
+
/* Ensure the sink is muted */
msleep(20);
}
@@ -2319,12 +2434,19 @@ mtk_dp_bridge_mode_valid(struct drm_bridge *bridge,
{
struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
u32 bpp = info->color_formats & DRM_COLOR_FORMAT_YCBCR422 ? 16 : 24;
- u32 rate = min_t(u32, drm_dp_max_link_rate(mtk_dp->rx_cap) *
- drm_dp_max_lane_count(mtk_dp->rx_cap),
- drm_dp_bw_code_to_link_rate(mtk_dp->max_linkrate) *
- mtk_dp->max_lanes);
+ u32 lane_count_min = mtk_dp->train_info.lane_count;
+ u32 rate = drm_dp_bw_code_to_link_rate(mtk_dp->train_info.link_rate) *
+ lane_count_min;
- if (rate < mode->clock * bpp / 8)
+ /*
+ *FEC overhead is approximately 2.4% from DP 1.4a spec 2.2.1.4.2.
+ *The down-spread amplitude shall either be disabled (0.0%) or up
+ *to 0.5% from 1.4a 3.5.2.6. Add up to approximately 3% total overhead.
+ *
+ *Because rate is already divided by 10,
+ *mode->clock does not need to be multiplied by 10
+ */
+ if ((rate * 97 / 100) < (mode->clock * bpp / 8))
return MODE_CLOCK_HIGH;
return MODE_OK;
@@ -2365,10 +2487,9 @@ static u32 *mtk_dp_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
struct drm_display_mode *mode = &crtc_state->adjusted_mode;
struct drm_display_info *display_info =
&conn_state->connector->display_info;
- u32 rate = min_t(u32, drm_dp_max_link_rate(mtk_dp->rx_cap) *
- drm_dp_max_lane_count(mtk_dp->rx_cap),
- drm_dp_bw_code_to_link_rate(mtk_dp->max_linkrate) *
- mtk_dp->max_lanes);
+ u32 lane_count_min = mtk_dp->train_info.lane_count;
+ u32 rate = drm_dp_bw_code_to_link_rate(mtk_dp->train_info.link_rate) *
+ lane_count_min;
*num_input_fmts = 0;
@@ -2377,8 +2498,8 @@ static u32 *mtk_dp_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
* datarate of YUV422 and sink device supports YUV422, we output YUV422
* format. Use this condition, we can support more resolution.
*/
- if ((rate < (mode->clock * 24 / 8)) &&
- (rate > (mode->clock * 16 / 8)) &&
+ if (((rate * 97 / 100) < (mode->clock * 24 / 8)) &&
+ ((rate * 97 / 100) > (mode->clock * 16 / 8)) &&
(display_info->color_formats & DRM_COLOR_FORMAT_YCBCR422)) {
input_fmts = kcalloc(1, sizeof(*input_fmts), GFP_KERNEL);
if (!input_fmts)
@@ -2526,7 +2647,6 @@ static const struct hdmi_codec_ops mtk_dp_audio_codec_ops = {
.audio_shutdown = mtk_dp_audio_shutdown,
.get_eld = mtk_dp_audio_get_eld,
.hook_plugged_cb = mtk_dp_audio_hook_plugged_cb,
- .no_capture_mute = 1,
};
static int mtk_dp_register_audio_driver(struct device *dev)
@@ -2537,6 +2657,7 @@ static int mtk_dp_register_audio_driver(struct device *dev)
.max_i2s_channels = 8,
.i2s = 1,
.data = mtk_dp,
+ .no_capture_mute = 1,
};
mtk_dp->audio_pdev = platform_device_register_data(dev,
@@ -2655,11 +2776,9 @@ static int mtk_dp_probe(struct platform_device *pdev)
mutex_init(&mtk_dp->update_plugged_status_lock);
ret = mtk_dp_register_audio_driver(dev);
- if (ret) {
- dev_err(dev, "Failed to register audio driver: %d\n",
- ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to register audio driver\n");
}
ret = mtk_dp_register_phy(mtk_dp);
@@ -2729,7 +2848,7 @@ static void mtk_dp_remove(struct platform_device *pdev)
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
if (mtk_dp->data->bridge_type != DRM_MODE_CONNECTOR_eDP)
- del_timer_sync(&mtk_dp->debounce_timer);
+ timer_delete_sync(&mtk_dp->debounce_timer);
platform_device_unregister(mtk_dp->phy_dev);
if (mtk_dp->audio_pdev)
platform_device_unregister(mtk_dp->audio_pdev);
@@ -2767,7 +2886,7 @@ static SIMPLE_DEV_PM_OPS(mtk_dp_pm_ops, mtk_dp_suspend, mtk_dp_resume);
static const struct mtk_dp_data mt8188_dp_data = {
.bridge_type = DRM_MODE_CONNECTOR_DisplayPort,
.smc_cmd = MTK_DP_SIP_ATF_VIDEO_UNMUTE,
- .efuse_fmt = mt8195_dp_efuse_fmt,
+ .efuse_fmt = mt8188_dp_efuse_fmt,
.audio_supported = true,
.audio_pkt_in_hblank_area = true,
.audio_m_div2_bit = MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
@@ -2812,7 +2931,7 @@ MODULE_DEVICE_TABLE(of, mtk_dp_of_match);
static struct platform_driver mtk_dp_driver = {
.probe = mtk_dp_probe,
- .remove_new = mtk_dp_remove,
+ .remove = mtk_dp_remove,
.driver = {
.name = "mediatek-drm-dp",
.of_match_table = mtk_dp_of_match,
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
index 709b79480693..8ad7a9cc259e 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
+++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
@@ -86,6 +86,7 @@
#define MTK_DP_ENC0_P0_3004 0x3004
#define VIDEO_M_CODE_SEL_DP_ENC0_P0_MASK BIT(8)
#define DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0 BIT(9)
+#define SDP_RESET_SW_DP_ENC0_P0 BIT(13)
#define MTK_DP_ENC0_P0_3010 0x3010
#define HTOTAL_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
#define MTK_DP_ENC0_P0_3014 0x3014
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index beb7d9d08e97..6fb85bc6487a 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -4,8 +4,10 @@
* Author: Jie Qiu <jie.qiu@mediatek.com>
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/component.h>
+#include <linux/debugfs.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/media-bus-format.h>
@@ -26,9 +28,9 @@
#include <drm/drm_of.h>
#include <drm/drm_simple_kms_helper.h>
+#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 {
@@ -57,7 +59,8 @@ enum mtk_dpi_out_channel_swap {
enum mtk_dpi_out_color_format {
MTK_DPI_COLOR_FORMAT_RGB,
- MTK_DPI_COLOR_FORMAT_YCBCR_422
+ MTK_DPI_COLOR_FORMAT_YCBCR_422,
+ MTK_DPI_COLOR_FORMAT_YCBCR_444
};
struct mtk_dpi {
@@ -116,9 +119,15 @@ struct mtk_dpi_yc_limit {
u16 c_bottom;
};
+struct mtk_dpi_factor {
+ u32 clock;
+ u8 factor;
+};
+
/**
* struct mtk_dpi_conf - Configuration of mediatek dpi.
- * @cal_factor: Callback function to calculate factor value.
+ * @dpi_factor: SoC-specific pixel clock PLL factor values.
+ * @num_dpi_factor: Number of pixel clock PLL factor values.
* @reg_h_fre_con: Register address of frequency control.
* @max_clock_khz: Max clock frequency supported for this SoCs in khz units.
* @edge_sel_en: Enable of edge selection.
@@ -127,19 +136,24 @@ struct mtk_dpi_yc_limit {
* @is_ck_de_pol: Support CK/DE polarity.
* @swap_input_support: Support input swap function.
* @support_direct_pin: IP supports direct connection to dpi panels.
- * @input_2pixel: Input pixel of dp_intf is 2 pixel per round, so enable this
- * config to enable this feature.
* @dimension_mask: Mask used for HWIDTH, HPORCH, VSYNC_WIDTH and VSYNC_PORCH
* (no shift).
* @hvsize_mask: Mask of HSIZE and VSIZE mask (no shift).
* @channel_swap_shift: Shift value of channel swap.
* @yuv422_en_bit: Enable bit of yuv422.
* @csc_enable_bit: Enable bit of CSC.
+ * @input_2p_en_bit: Enable bit for input two pixel per round feature.
+ * If present, implies that the feature must be enabled.
* @pixels_per_iter: Quantity of transferred pixels per iteration.
* @edge_cfg_in_mmsys: If the edge configuration for DPI's output needs to be set in MMSYS.
+ * @clocked_by_hdmi: HDMI IP outputs clock to dpi_pixel_clk input clock, needed
+ * for DPI registers access.
+ * @output_1pixel: Enable outputting one pixel per round; if the input is two pixel per
+ * round, the DPI hardware will internally transform it to 1T1P.
*/
struct mtk_dpi_conf {
- unsigned int (*cal_factor)(int clock);
+ const struct mtk_dpi_factor *dpi_factor;
+ const u8 num_dpi_factor;
u32 reg_h_fre_con;
u32 max_clock_khz;
bool edge_sel_en;
@@ -148,14 +162,16 @@ struct mtk_dpi_conf {
bool is_ck_de_pol;
bool swap_input_support;
bool support_direct_pin;
- bool input_2pixel;
u32 dimension_mask;
u32 hvsize_mask;
u32 channel_swap_shift;
u32 yuv422_en_bit;
u32 csc_enable_bit;
+ u32 input_2p_en_bit;
u32 pixels_per_iter;
bool edge_cfg_in_mmsys;
+ bool clocked_by_hdmi;
+ bool output_1pixel;
};
static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
@@ -166,6 +182,18 @@ static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
writel(tmp, dpi->regs + offset);
}
+static void mtk_dpi_test_pattern_en(struct mtk_dpi *dpi, u8 type, bool enable)
+{
+ u32 val;
+
+ if (enable)
+ val = FIELD_PREP(DPI_PAT_SEL, type) | DPI_PAT_EN;
+ else
+ val = 0;
+
+ mtk_dpi_mask(dpi, DPI_PATTERN0, val, DPI_PAT_SEL | DPI_PAT_EN);
+}
+
static void mtk_dpi_sw_reset(struct mtk_dpi *dpi, bool reset)
{
mtk_dpi_mask(dpi, DPI_RET, reset ? RST : 0, RST);
@@ -410,21 +438,29 @@ static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable)
static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi)
{
- mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N);
+ if (dpi->conf->reg_h_fre_con)
+ mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N);
}
static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi)
{
- if (dpi->conf->edge_sel_en)
+ if (dpi->conf->edge_sel_en && dpi->conf->reg_h_fre_con)
mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, 0, EDGE_SEL_EN);
}
static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
enum mtk_dpi_out_color_format format)
{
- mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
+ mtk_dpi_config_channel_swap(dpi, dpi->channel_swap);
- if (format == MTK_DPI_COLOR_FORMAT_YCBCR_422) {
+ switch (format) {
+ case MTK_DPI_COLOR_FORMAT_YCBCR_444:
+ mtk_dpi_config_yuv422_enable(dpi, false);
+ mtk_dpi_config_csc_enable(dpi, true);
+ if (dpi->conf->swap_input_support)
+ mtk_dpi_config_swap_input(dpi, false);
+ break;
+ case MTK_DPI_COLOR_FORMAT_YCBCR_422:
mtk_dpi_config_yuv422_enable(dpi, true);
mtk_dpi_config_csc_enable(dpi, true);
@@ -435,11 +471,14 @@ static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
mtk_dpi_mask(dpi, DPI_MATRIX_SET, dpi->mode.hdisplay <= 720 ?
MATRIX_SEL_RGB_TO_BT601 : MATRIX_SEL_RGB_TO_JPEG,
INT_MATRIX_SEL_MASK);
- } else {
+ break;
+ default:
+ case MTK_DPI_COLOR_FORMAT_RGB:
mtk_dpi_config_yuv422_enable(dpi, false);
mtk_dpi_config_csc_enable(dpi, false);
if (dpi->conf->swap_input_support)
mtk_dpi_config_swap_input(dpi, false);
+ break;
}
}
@@ -471,6 +510,7 @@ static void mtk_dpi_power_off(struct mtk_dpi *dpi)
mtk_dpi_disable(dpi);
clk_disable_unprepare(dpi->pixel_clk);
+ clk_disable_unprepare(dpi->tvd_clk);
clk_disable_unprepare(dpi->engine_clk);
}
@@ -487,6 +527,12 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi)
goto err_refcount;
}
+ ret = clk_prepare_enable(dpi->tvd_clk);
+ if (ret) {
+ dev_err(dpi->dev, "Failed to enable tvd pll: %d\n", ret);
+ goto err_engine;
+ }
+
ret = clk_prepare_enable(dpi->pixel_clk);
if (ret) {
dev_err(dpi->dev, "Failed to enable pixel clock: %d\n", ret);
@@ -496,32 +542,39 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi)
return 0;
err_pixel:
+ clk_disable_unprepare(dpi->tvd_clk);
+err_engine:
clk_disable_unprepare(dpi->engine_clk);
err_refcount:
dpi->refcount--;
return ret;
}
-static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
- struct drm_display_mode *mode)
+static unsigned int mtk_dpi_calculate_factor(struct mtk_dpi *dpi, int mode_clk)
+{
+ const struct mtk_dpi_factor *dpi_factor = dpi->conf->dpi_factor;
+ int i;
+
+ for (i = 0; i < dpi->conf->num_dpi_factor; i++) {
+ if (mode_clk <= dpi_factor[i].clock)
+ return dpi_factor[i].factor;
+ }
+
+ /* If no match try the lowest possible factor */
+ return dpi_factor[dpi->conf->num_dpi_factor - 1].factor;
+}
+
+static void mtk_dpi_set_pixel_clk(struct mtk_dpi *dpi, struct videomode *vm, int mode_clk)
{
- struct mtk_dpi_polarities dpi_pol;
- struct mtk_dpi_sync_param hsync;
- struct mtk_dpi_sync_param vsync_lodd = { 0 };
- struct mtk_dpi_sync_param vsync_leven = { 0 };
- struct mtk_dpi_sync_param vsync_rodd = { 0 };
- struct mtk_dpi_sync_param vsync_reven = { 0 };
- struct videomode vm = { 0 };
unsigned long pll_rate;
unsigned int factor;
/* let pll_rate can fix the valid range of tvdpll (1G~2GHz) */
- factor = dpi->conf->cal_factor(mode->clock);
- drm_display_mode_to_videomode(mode, &vm);
- pll_rate = vm.pixelclock * factor;
+ factor = mtk_dpi_calculate_factor(dpi, mode_clk);
+ pll_rate = vm->pixelclock * factor;
dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
- pll_rate, vm.pixelclock);
+ pll_rate, vm->pixelclock);
clk_set_rate(dpi->tvd_clk, pll_rate);
pll_rate = clk_get_rate(dpi->tvd_clk);
@@ -531,20 +584,36 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
* pixels for each iteration: divide the clock by this number and
* adjust the display porches accordingly.
*/
- vm.pixelclock = pll_rate / factor;
- vm.pixelclock /= dpi->conf->pixels_per_iter;
+ vm->pixelclock = pll_rate / factor;
+ vm->pixelclock /= dpi->conf->pixels_per_iter;
if ((dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE) ||
(dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE))
- clk_set_rate(dpi->pixel_clk, vm.pixelclock * 2);
+ clk_set_rate(dpi->pixel_clk, vm->pixelclock * 2);
else
- clk_set_rate(dpi->pixel_clk, vm.pixelclock);
+ clk_set_rate(dpi->pixel_clk, vm->pixelclock);
-
- vm.pixelclock = clk_get_rate(dpi->pixel_clk);
+ vm->pixelclock = clk_get_rate(dpi->pixel_clk);
dev_dbg(dpi->dev, "Got PLL %lu Hz, pixel clock %lu Hz\n",
- pll_rate, vm.pixelclock);
+ pll_rate, vm->pixelclock);
+}
+
+static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
+ struct drm_display_mode *mode)
+{
+ struct mtk_dpi_polarities dpi_pol;
+ struct mtk_dpi_sync_param hsync;
+ struct mtk_dpi_sync_param vsync_lodd = { 0 };
+ struct mtk_dpi_sync_param vsync_leven = { 0 };
+ struct mtk_dpi_sync_param vsync_rodd = { 0 };
+ struct mtk_dpi_sync_param vsync_reven = { 0 };
+ struct videomode vm = { 0 };
+
+ drm_display_mode_to_videomode(mode, &vm);
+
+ if (!dpi->conf->clocked_by_hdmi)
+ mtk_dpi_set_pixel_clk(dpi, &vm, mode->clock);
dpi_pol.ck_pol = MTK_DPI_POLARITY_FALLING;
dpi_pol.de_pol = MTK_DPI_POLARITY_RISING;
@@ -607,12 +676,18 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
if (dpi->conf->support_direct_pin) {
mtk_dpi_config_yc_map(dpi, dpi->yc_map);
mtk_dpi_config_2n_h_fre(dpi);
- mtk_dpi_dual_edge(dpi);
+
+ /* DPI can connect to either an external bridge or the internal HDMI encoder */
+ if (dpi->conf->output_1pixel)
+ mtk_dpi_mask(dpi, DPI_CON, DPI_OUTPUT_1T1P_EN, DPI_OUTPUT_1T1P_EN);
+ else
+ mtk_dpi_dual_edge(dpi);
+
mtk_dpi_config_disable_edge(dpi);
}
- if (dpi->conf->input_2pixel) {
- mtk_dpi_mask(dpi, DPI_CON, DPINTF_INPUT_2P_EN,
- DPINTF_INPUT_2P_EN);
+ if (dpi->conf->input_2p_en_bit) {
+ mtk_dpi_mask(dpi, DPI_CON, dpi->conf->input_2p_en_bit,
+ dpi->conf->input_2p_en_bit);
}
mtk_dpi_sw_reset(dpi, false);
@@ -670,6 +745,65 @@ static u32 *mtk_dpi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
return input_fmts;
}
+static unsigned int mtk_dpi_bus_fmt_bit_num(unsigned int out_bus_format)
+{
+ switch (out_bus_format) {
+ default:
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_BGR888_1X24:
+ case MEDIA_BUS_FMT_RGB888_2X12_LE:
+ case MEDIA_BUS_FMT_RGB888_2X12_BE:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ return MTK_DPI_OUT_BIT_NUM_8BITS;
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ return MTK_DPI_OUT_BIT_NUM_10BITS;
+ case MEDIA_BUS_FMT_YUYV12_1X24:
+ return MTK_DPI_OUT_BIT_NUM_12BITS;
+ }
+}
+
+static unsigned int mtk_dpi_bus_fmt_channel_swap(unsigned int out_bus_format)
+{
+ switch (out_bus_format) {
+ default:
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_RGB888_2X12_LE:
+ case MEDIA_BUS_FMT_RGB888_2X12_BE:
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUYV12_1X24:
+ return MTK_DPI_OUT_CHANNEL_SWAP_RGB;
+ case MEDIA_BUS_FMT_BGR888_1X24:
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ return MTK_DPI_OUT_CHANNEL_SWAP_BGR;
+ }
+}
+
+static unsigned int mtk_dpi_bus_fmt_color_format(unsigned int out_bus_format)
+{
+ switch (out_bus_format) {
+ default:
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_BGR888_1X24:
+ case MEDIA_BUS_FMT_RGB888_2X12_LE:
+ case MEDIA_BUS_FMT_RGB888_2X12_BE:
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ return MTK_DPI_COLOR_FORMAT_RGB;
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUYV12_1X24:
+ return MTK_DPI_COLOR_FORMAT_YCBCR_422;
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ return MTK_DPI_COLOR_FORMAT_YCBCR_444;
+ }
+}
+
static int mtk_dpi_bridge_atomic_check(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
@@ -689,23 +823,35 @@ static int mtk_dpi_bridge_atomic_check(struct drm_bridge *bridge,
bridge_state->output_bus_cfg.format);
dpi->output_fmt = out_bus_format;
- dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS;
- dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB;
+ dpi->bit_num = mtk_dpi_bus_fmt_bit_num(out_bus_format);
+ dpi->channel_swap = mtk_dpi_bus_fmt_channel_swap(out_bus_format);
dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
- if (out_bus_format == MEDIA_BUS_FMT_YUYV8_1X16)
- dpi->color_format = MTK_DPI_COLOR_FORMAT_YCBCR_422;
- else
- dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
+ dpi->color_format = mtk_dpi_bus_fmt_color_format(out_bus_format);
return 0;
}
static int mtk_dpi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+ int ret;
+
+ dpi->next_bridge = devm_drm_of_get_bridge(dpi->dev, dpi->dev->of_node, 1, -1);
+ if (IS_ERR(dpi->next_bridge)) {
+ ret = PTR_ERR(dpi->next_bridge);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ /* Old devicetree has only one endpoint */
+ dpi->next_bridge = devm_drm_of_get_bridge(dpi->dev, dpi->dev->of_node, 0, 0);
+ if (IS_ERR(dpi->next_bridge))
+ return dev_err_probe(dpi->dev, PTR_ERR(dpi->next_bridge),
+ "Failed to get bridge\n");
+ }
- return drm_bridge_attach(bridge->encoder, dpi->next_bridge,
+ return drm_bridge_attach(encoder, dpi->next_bridge,
&dpi->bridge, flags);
}
@@ -753,6 +899,99 @@ mtk_dpi_bridge_mode_valid(struct drm_bridge *bridge,
return MODE_OK;
}
+static int mtk_dpi_debug_tp_show(struct seq_file *m, void *arg)
+{
+ struct mtk_dpi *dpi = m->private;
+ bool en;
+ u32 val;
+
+ if (!dpi)
+ return -EINVAL;
+
+ val = readl(dpi->regs + DPI_PATTERN0);
+ en = val & DPI_PAT_EN;
+ val = FIELD_GET(DPI_PAT_SEL, val);
+
+ seq_printf(m, "DPI Test Pattern: %s\n", en ? "Enabled" : "Disabled");
+
+ if (en) {
+ seq_printf(m, "Internal pattern %d: ", val);
+ switch (val) {
+ case 0:
+ seq_puts(m, "256 Vertical Gray\n");
+ break;
+ case 1:
+ seq_puts(m, "1024 Vertical Gray\n");
+ break;
+ case 2:
+ seq_puts(m, "256 Horizontal Gray\n");
+ break;
+ case 3:
+ seq_puts(m, "1024 Horizontal Gray\n");
+ break;
+ case 4:
+ seq_puts(m, "Vertical Color bars\n");
+ break;
+ case 6:
+ seq_puts(m, "Frame border\n");
+ break;
+ case 7:
+ seq_puts(m, "Dot moire\n");
+ break;
+ default:
+ seq_puts(m, "Invalid selection\n");
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t mtk_dpi_debug_tp_write(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *offp)
+{
+ struct seq_file *m = file->private_data;
+ u32 en, type;
+ char buf[6];
+
+ if (!m || !m->private || *offp || len > sizeof(buf) - 1)
+ return -EINVAL;
+
+ memset(buf, 0, sizeof(buf));
+ if (copy_from_user(buf, ubuf, len))
+ return -EFAULT;
+
+ if (sscanf(buf, "%u %u", &en, &type) != 2)
+ return -EINVAL;
+
+ if (en < 0 || en > 1 || type < 0 || type > 7)
+ return -EINVAL;
+
+ mtk_dpi_test_pattern_en((struct mtk_dpi *)m->private, type, en);
+ return len;
+}
+
+static int mtk_dpi_debug_tp_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mtk_dpi_debug_tp_show, inode->i_private);
+}
+
+static const struct file_operations mtk_dpi_debug_tp_fops = {
+ .owner = THIS_MODULE,
+ .open = mtk_dpi_debug_tp_open,
+ .read = seq_read,
+ .write = mtk_dpi_debug_tp_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void mtk_dpi_debugfs_init(struct drm_bridge *bridge, struct dentry *root)
+{
+ struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+
+ debugfs_create_file("dpi_test_pattern", 0640, root, dpi, &mtk_dpi_debug_tp_fops);
+}
+
static const struct drm_bridge_funcs mtk_dpi_bridge_funcs = {
.attach = mtk_dpi_bridge_attach,
.mode_set = mtk_dpi_bridge_mode_set,
@@ -765,20 +1004,23 @@ static const struct drm_bridge_funcs mtk_dpi_bridge_funcs = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
+ .debugfs_init = mtk_dpi_debugfs_init,
};
void mtk_dpi_start(struct device *dev)
{
struct mtk_dpi *dpi = dev_get_drvdata(dev);
- mtk_dpi_power_on(dpi);
+ if (!dpi->conf->clocked_by_hdmi)
+ mtk_dpi_power_on(dpi);
}
void mtk_dpi_stop(struct device *dev)
{
struct mtk_dpi *dpi = dev_get_drvdata(dev);
- mtk_dpi_power_off(dpi);
+ if (!dpi->conf->clocked_by_hdmi)
+ mtk_dpi_power_off(dpi);
}
unsigned int mtk_dpi_encoder_index(struct device *dev)
@@ -805,7 +1047,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);
@@ -840,48 +1085,6 @@ static const struct component_ops mtk_dpi_component_ops = {
.unbind = mtk_dpi_unbind,
};
-static unsigned int mt8173_calculate_factor(int clock)
-{
- if (clock <= 27000)
- return 3 << 4;
- else if (clock <= 84000)
- return 3 << 3;
- else if (clock <= 167000)
- return 3 << 2;
- else
- return 3 << 1;
-}
-
-static unsigned int mt2701_calculate_factor(int clock)
-{
- if (clock <= 64000)
- return 4;
- else if (clock <= 128000)
- return 2;
- else
- return 1;
-}
-
-static unsigned int mt8183_calculate_factor(int clock)
-{
- if (clock <= 27000)
- return 8;
- else if (clock <= 167000)
- return 4;
- else
- return 2;
-}
-
-static unsigned int mt8195_dpintf_calculate_factor(int clock)
-{
- if (clock < 70000)
- return 4;
- else if (clock < 200000)
- return 2;
- else
- return 1;
-}
-
static const u32 mt8173_output_fmts[] = {
MEDIA_BUS_FMT_RGB888_1X24,
};
@@ -891,13 +1094,50 @@ static const u32 mt8183_output_fmts[] = {
MEDIA_BUS_FMT_RGB888_2X12_BE,
};
-static const u32 mt8195_output_fmts[] = {
+static const u32 mt8195_dpi_output_fmts[] = {
+ MEDIA_BUS_FMT_BGR888_1X24,
MEDIA_BUS_FMT_RGB888_1X24,
+ MEDIA_BUS_FMT_RGB888_2X12_LE,
+ MEDIA_BUS_FMT_RGB888_2X12_BE,
+ MEDIA_BUS_FMT_RGB101010_1X30,
MEDIA_BUS_FMT_YUYV8_1X16,
+ MEDIA_BUS_FMT_YUYV10_1X20,
+ MEDIA_BUS_FMT_YUYV12_1X24,
+ MEDIA_BUS_FMT_YUV8_1X24,
+ MEDIA_BUS_FMT_YUV10_1X30,
+};
+
+static const u32 mt8195_dp_intf_output_fmts[] = {
+ MEDIA_BUS_FMT_BGR888_1X24,
+ MEDIA_BUS_FMT_RGB888_1X24,
+ MEDIA_BUS_FMT_RGB888_2X12_LE,
+ MEDIA_BUS_FMT_RGB888_2X12_BE,
+ MEDIA_BUS_FMT_RGB101010_1X30,
+ MEDIA_BUS_FMT_YUYV8_1X16,
+ MEDIA_BUS_FMT_YUYV10_1X20,
+ MEDIA_BUS_FMT_YUV8_1X24,
+ MEDIA_BUS_FMT_YUV10_1X30,
+};
+
+static const struct mtk_dpi_factor dpi_factor_mt2701[] = {
+ { 64000, 4 }, { 128000, 2 }, { U32_MAX, 1 }
+};
+
+static const struct mtk_dpi_factor dpi_factor_mt8173[] = {
+ { 27000, 48 }, { 84000, 24 }, { 167000, 12 }, { U32_MAX, 6 }
+};
+
+static const struct mtk_dpi_factor dpi_factor_mt8183[] = {
+ { 27000, 8 }, { 167000, 4 }, { U32_MAX, 2 }
+};
+
+static const struct mtk_dpi_factor dpi_factor_mt8195_dp_intf[] = {
+ { 70000 - 1, 4 }, { 200000 - 1, 2 }, { U32_MAX, 1 }
};
static const struct mtk_dpi_conf mt8173_conf = {
- .cal_factor = mt8173_calculate_factor,
+ .dpi_factor = dpi_factor_mt8173,
+ .num_dpi_factor = ARRAY_SIZE(dpi_factor_mt8173),
.reg_h_fre_con = 0xe0,
.max_clock_khz = 300000,
.output_fmts = mt8173_output_fmts,
@@ -914,7 +1154,8 @@ static const struct mtk_dpi_conf mt8173_conf = {
};
static const struct mtk_dpi_conf mt2701_conf = {
- .cal_factor = mt2701_calculate_factor,
+ .dpi_factor = dpi_factor_mt2701,
+ .num_dpi_factor = ARRAY_SIZE(dpi_factor_mt2701),
.reg_h_fre_con = 0xb0,
.edge_sel_en = true,
.max_clock_khz = 150000,
@@ -932,7 +1173,8 @@ static const struct mtk_dpi_conf mt2701_conf = {
};
static const struct mtk_dpi_conf mt8183_conf = {
- .cal_factor = mt8183_calculate_factor,
+ .dpi_factor = dpi_factor_mt8183,
+ .num_dpi_factor = ARRAY_SIZE(dpi_factor_mt8183),
.reg_h_fre_con = 0xe0,
.max_clock_khz = 100000,
.output_fmts = mt8183_output_fmts,
@@ -949,7 +1191,8 @@ static const struct mtk_dpi_conf mt8183_conf = {
};
static const struct mtk_dpi_conf mt8186_conf = {
- .cal_factor = mt8183_calculate_factor,
+ .dpi_factor = dpi_factor_mt8183,
+ .num_dpi_factor = ARRAY_SIZE(dpi_factor_mt8183),
.reg_h_fre_con = 0xe0,
.max_clock_khz = 150000,
.output_fmts = mt8183_output_fmts,
@@ -967,7 +1210,8 @@ static const struct mtk_dpi_conf mt8186_conf = {
};
static const struct mtk_dpi_conf mt8192_conf = {
- .cal_factor = mt8183_calculate_factor,
+ .dpi_factor = dpi_factor_mt8183,
+ .num_dpi_factor = ARRAY_SIZE(dpi_factor_mt8183),
.reg_h_fre_con = 0xe0,
.max_clock_khz = 150000,
.output_fmts = mt8183_output_fmts,
@@ -983,18 +1227,37 @@ static const struct mtk_dpi_conf mt8192_conf = {
.csc_enable_bit = CSC_ENABLE,
};
+static const struct mtk_dpi_conf mt8195_conf = {
+ .max_clock_khz = 594000,
+ .output_fmts = mt8195_dpi_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8195_dpi_output_fmts),
+ .pixels_per_iter = 1,
+ .is_ck_de_pol = true,
+ .swap_input_support = true,
+ .support_direct_pin = true,
+ .dimension_mask = HPW_MASK,
+ .hvsize_mask = HSIZE_MASK,
+ .channel_swap_shift = CH_SWAP,
+ .yuv422_en_bit = YUV422_EN,
+ .csc_enable_bit = CSC_ENABLE,
+ .input_2p_en_bit = DPI_INPUT_2P_EN,
+ .clocked_by_hdmi = true,
+ .output_1pixel = true,
+};
+
static const struct mtk_dpi_conf mt8195_dpintf_conf = {
- .cal_factor = mt8195_dpintf_calculate_factor,
+ .dpi_factor = dpi_factor_mt8195_dp_intf,
+ .num_dpi_factor = ARRAY_SIZE(dpi_factor_mt8195_dp_intf),
.max_clock_khz = 600000,
- .output_fmts = mt8195_output_fmts,
- .num_output_fmts = ARRAY_SIZE(mt8195_output_fmts),
+ .output_fmts = mt8195_dp_intf_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8195_dp_intf_output_fmts),
.pixels_per_iter = 4,
- .input_2pixel = true,
.dimension_mask = DPINTF_HPW_MASK,
.hvsize_mask = DPINTF_HSIZE_MASK,
.channel_swap_shift = DPINTF_CH_SWAP,
.yuv422_en_bit = DPINTF_YUV422_EN,
.csc_enable_bit = DPINTF_CSC_ENABLE,
+ .input_2p_en_bit = DPINTF_INPUT_2P_EN,
};
static int mtk_dpi_probe(struct platform_device *pdev)
@@ -1055,13 +1318,6 @@ static int mtk_dpi_probe(struct platform_device *pdev)
if (dpi->irq < 0)
return dpi->irq;
- dpi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
- if (IS_ERR(dpi->next_bridge))
- return dev_err_probe(dev, PTR_ERR(dpi->next_bridge),
- "Failed to get bridge\n");
-
- dev_info(dev, "Found bridge node: %pOF\n", dpi->next_bridge->of_node);
-
platform_set_drvdata(pdev, dpi);
dpi->bridge.funcs = &mtk_dpi_bridge_funcs;
@@ -1092,13 +1348,14 @@ static const struct of_device_id mtk_dpi_of_ids[] = {
{ .compatible = "mediatek,mt8188-dp-intf", .data = &mt8195_dpintf_conf },
{ .compatible = "mediatek,mt8192-dpi", .data = &mt8192_conf },
{ .compatible = "mediatek,mt8195-dp-intf", .data = &mt8195_dpintf_conf },
+ { .compatible = "mediatek,mt8195-dpi", .data = &mt8195_conf },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mtk_dpi_of_ids);
struct platform_driver mtk_dpi_driver = {
.probe = mtk_dpi_probe,
- .remove_new = mtk_dpi_remove,
+ .remove = mtk_dpi_remove,
.driver = {
.name = "mediatek-dpi",
.of_match_table = mtk_dpi_of_ids,
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
index 62bd4931b344..23eeefce8fd2 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
+++ b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
@@ -40,6 +40,11 @@
#define FAKE_DE_LEVEN BIT(21)
#define FAKE_DE_RODD BIT(22)
#define FAKE_DE_REVEN BIT(23)
+
+/* DPI_CON: DPI instances */
+#define DPI_OUTPUT_1T1P_EN BIT(24)
+#define DPI_INPUT_2P_EN BIT(25)
+/* DPI_CON: DPINTF instances */
#define DPINTF_YUV422_EN BIT(24)
#define DPINTF_CSC_ENABLE BIT(26)
#define DPINTF_INPUT_2P_EN BIT(29)
@@ -235,4 +240,8 @@
#define MATRIX_SEL_RGB_TO_JPEG 0
#define MATRIX_SEL_RGB_TO_BT601 2
+#define DPI_PATTERN0 0xf00
+#define DPI_PAT_EN BIT(0)
+#define DPI_PAT_SEL GENMASK(6, 4)
+
#endif /* __MTK_DPI_REGS_H */
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 1f988ff1bf9f..000000000000
--- 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 <drm/drm_crtc.h>
-#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_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 74832c213092..7c0c12dde488 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -12,10 +12,11 @@
#include <linux/pm_runtime.h>
#include <linux/dma-mapping.h>
+#include <drm/clients/drm_client_setup.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fbdev_generic.h>
+#include <drm/drm_fbdev_dma.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_framebuffer_helper.h>
@@ -24,14 +25,14 @@
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
-#include "mtk_drm_crtc.h"
-#include "mtk_drm_ddp_comp.h"
+#include "mtk_crtc.h"
+#include "mtk_ddp_comp.h"
+#include "mtk_disp_drv.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"
-#define DRIVER_DATE "20150513"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
@@ -294,6 +295,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 +312,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 +322,13 @@ 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 mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
+ .mmsys_dev_num = 1,
};
static const struct of_device_id mtk_drm_of_ids[] = {
@@ -344,11 +358,13 @@ static const struct of_device_id mtk_drm_of_ids[] = {
.data = &mt8195_vdosys0_driver_data},
{ .compatible = "mediatek,mt8195-vdosys1",
.data = &mt8195_vdosys1_driver_data},
+ { .compatible = "mediatek,mt8365-mmsys",
+ .data = &mt8365_mmsys_driver_data},
{ }
};
MODULE_DEVICE_TABLE(of, mtk_drm_of_ids);
-static int mtk_drm_match(struct device *dev, void *data)
+static int mtk_drm_match(struct device *dev, const void *data)
{
if (!strncmp(dev_name(dev), "mediatek-drm", sizeof("mediatek-drm") - 1))
return true;
@@ -396,8 +412,10 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
if (temp_drm_priv->mtk_drm_bound)
cnt++;
- if (cnt == MAX_CRTC)
+ if (cnt == MAX_CRTC) {
+ of_node_put(node);
break;
+ }
}
if (drm_priv->data->mmsys_dev_num == cnt) {
@@ -452,7 +470,7 @@ static int mtk_drm_kms_init(struct drm_device *drm)
ret = drmm_mode_config_init(drm);
if (ret)
- goto put_mutex_dev;
+ return ret;
drm->mode_config.min_width = 64;
drm->mode_config.min_height = 64;
@@ -470,8 +488,11 @@ static int mtk_drm_kms_init(struct drm_device *drm)
for (i = 0; i < private->data->mmsys_dev_num; i++) {
drm->dev_private = private->all_drm_private[i];
ret = component_bind_all(private->all_drm_private[i]->dev, drm);
- if (ret)
- goto put_mutex_dev;
+ if (ret) {
+ while (--i >= 0)
+ component_unbind_all(private->all_drm_private[i]->dev, drm);
+ return ret;
+ }
}
/*
@@ -493,25 +514,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 +550,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 = 512;
+ drm->mode_config.cursor_height = 512;
+
/* 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");
@@ -537,11 +571,7 @@ static int mtk_drm_kms_init(struct drm_device *drm)
* Configure the DMA segment size to make sure we get contiguous IOVA
* when importing PRIME buffers.
*/
- ret = dma_set_max_seg_size(dma_dev, UINT_MAX);
- if (ret) {
- dev_err(dma_dev, "Failed to set DMA segment size\n");
- goto err_component_unbind;
- }
+ dma_set_max_seg_size(dma_dev, UINT_MAX);
ret = drm_vblank_init(drm, MAX_CRTC);
if (ret < 0)
@@ -555,9 +585,6 @@ static int mtk_drm_kms_init(struct drm_device *drm)
err_component_unbind:
for (i = 0; i < private->data->mmsys_dev_num; i++)
component_unbind_all(private->all_drm_private[i]->dev, drm);
-put_mutex_dev:
- for (i = 0; i < private->data->mmsys_dev_num; i++)
- put_device(private->all_drm_private[i]->mutex_dev);
return ret;
}
@@ -576,8 +603,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,15 +614,15 @@ 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,
+ DRM_FBDEV_DMA_DRIVER_OPS,
- .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,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
- .date = DRIVER_DATE,
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
};
@@ -628,8 +655,10 @@ static int mtk_drm_bind(struct device *dev)
return 0;
drm = drm_dev_alloc(&mtk_drm_driver, dev);
- if (IS_ERR(drm))
- return PTR_ERR(drm);
+ if (IS_ERR(drm)) {
+ ret = PTR_ERR(drm);
+ goto err_put_dev;
+ }
private->drm_master = true;
drm->dev_private = private;
@@ -644,7 +673,7 @@ static int mtk_drm_bind(struct device *dev)
if (ret < 0)
goto err_deinit;
- drm_fbdev_generic_setup(drm, 32);
+ drm_client_setup(drm, NULL);
return 0;
@@ -653,18 +682,33 @@ err_deinit:
err_free:
private->drm = NULL;
drm_dev_put(drm);
+ for (i = 0; i < private->data->mmsys_dev_num; i++)
+ private->all_drm_private[i]->drm = NULL;
+err_put_dev:
+ for (i = 0; i < private->data->mmsys_dev_num; i++) {
+ /* For device_find_child in mtk_drm_get_all_priv() */
+ put_device(private->all_drm_private[i]->dev);
+ }
+ put_device(private->mutex_dev);
return ret;
}
static void mtk_drm_unbind(struct device *dev)
{
struct mtk_drm_private *private = dev_get_drvdata(dev);
+ int i;
/* for multi mmsys dev, unregister drm dev in mmsys master */
if (private->drm_master) {
drm_dev_unregister(private->drm);
mtk_drm_kms_deinit(private->drm);
drm_dev_put(private->drm);
+
+ for (i = 0; i < private->data->mmsys_dev_num; i++) {
+ /* For device_find_child in mtk_drm_get_all_priv() */
+ put_device(private->all_drm_private[i]->dev);
+ }
+ put_device(private->mutex_dev);
}
private->mtk_drm_bound = false;
private->drm_master = false;
@@ -709,6 +753,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",
@@ -729,6 +775,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt8195-disp-mutex",
.data = (void *)MTK_DISP_MUTEX },
+ { .compatible = "mediatek,mt8365-disp-mutex",
+ .data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt8173-disp-od",
.data = (void *)MTK_DISP_OD },
{ .compatible = "mediatek,mt2701-disp-ovl",
@@ -741,6 +789,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",
@@ -783,6 +833,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt8195-dp-intf",
.data = (void *)MTK_DP_INTF },
+ { .compatible = "mediatek,mt8195-dpi",
+ .data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt2701-dsi",
.data = (void *)MTK_DSI },
{ .compatible = "mediatek,mt8173-dsi",
@@ -796,12 +848,235 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
{ }
};
+static int mtk_drm_of_get_ddp_comp_type(struct device_node *node, enum mtk_ddp_comp_type *ctype)
+{
+ const struct of_device_id *of_id = of_match_node(mtk_ddp_comp_dt_ids, node);
+
+ if (!of_id)
+ return -EINVAL;
+
+ *ctype = (enum mtk_ddp_comp_type)((uintptr_t)of_id->data);
+
+ return 0;
+}
+
+static int mtk_drm_of_get_ddp_ep_cid(struct device_node *node,
+ int output_port, enum mtk_crtc_path crtc_path,
+ struct device_node **next, unsigned int *cid)
+{
+ struct device_node *ep_dev_node, *ep_out;
+ enum mtk_ddp_comp_type comp_type;
+ int ret;
+
+ ep_out = of_graph_get_endpoint_by_regs(node, output_port, crtc_path);
+ if (!ep_out)
+ return -ENOENT;
+
+ ep_dev_node = of_graph_get_remote_port_parent(ep_out);
+ of_node_put(ep_out);
+ if (!ep_dev_node)
+ return -EINVAL;
+
+ /*
+ * Pass the next node pointer regardless of failures in the later code
+ * so that if this function is called in a loop it will walk through all
+ * of the subsequent endpoints anyway.
+ */
+ *next = ep_dev_node;
+
+ if (!of_device_is_available(ep_dev_node))
+ return -ENODEV;
+
+ ret = mtk_drm_of_get_ddp_comp_type(ep_dev_node, &comp_type);
+ if (ret) {
+ if (mtk_ovl_adaptor_is_comp_present(ep_dev_node)) {
+ *cid = (unsigned int)DDP_COMPONENT_DRM_OVL_ADAPTOR;
+ return 0;
+ }
+ return ret;
+ }
+
+ ret = mtk_ddp_comp_get_id(ep_dev_node, comp_type);
+ if (ret < 0)
+ return ret;
+
+ /* All ok! Pass the Component ID to the caller. */
+ *cid = (unsigned int)ret;
+
+ return 0;
+}
+
+/**
+ * mtk_drm_of_ddp_path_build_one - Build a Display HW Pipeline for a CRTC Path
+ * @dev: The mediatek-drm device
+ * @cpath: CRTC Path relative to a VDO or MMSYS
+ * @out_path: Pointer to an array that will contain the new pipeline
+ * @out_path_len: Number of entries in the pipeline array
+ *
+ * MediaTek SoCs can use different DDP hardware pipelines (or paths) depending
+ * on the board-specific desired display configuration; this function walks
+ * through all of the output endpoints starting from a VDO or MMSYS hardware
+ * instance and builds the right pipeline as specified in device trees.
+ *
+ * Return:
+ * * %0 - Display HW Pipeline successfully built and validated
+ * * %-ENOENT - Display pipeline was not specified in device tree
+ * * %-EINVAL - Display pipeline built but validation failed
+ * * %-ENOMEM - Failure to allocate pipeline array to pass to the caller
+ */
+static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path cpath,
+ const unsigned int **out_path,
+ unsigned int *out_path_len)
+{
+ struct device_node *next = NULL, *prev, *vdo = dev->parent->of_node;
+ unsigned int temp_path[DDP_COMPONENT_DRM_ID_MAX] = { 0 };
+ unsigned int *final_ddp_path;
+ unsigned short int idx = 0;
+ bool ovl_adaptor_comp_added = false;
+ int ret;
+
+ /* Get the first entry for the temp_path array */
+ ret = mtk_drm_of_get_ddp_ep_cid(vdo, 0, cpath, &next, &temp_path[idx]);
+ if (ret) {
+ if (next && temp_path[idx] == DDP_COMPONENT_DRM_OVL_ADAPTOR) {
+ dev_dbg(dev, "Adding OVL Adaptor for %pOF\n", next);
+ ovl_adaptor_comp_added = true;
+ } else {
+ if (next)
+ dev_err(dev, "Invalid component %pOF\n", next);
+ else
+ dev_err(dev, "Cannot find first endpoint for path %d\n", cpath);
+
+ return ret;
+ }
+ }
+ idx++;
+
+ /*
+ * Walk through port outputs until we reach the last valid mediatek-drm component.
+ * To be valid, this must end with an "invalid" component that is a display node.
+ */
+ do {
+ prev = next;
+ ret = mtk_drm_of_get_ddp_ep_cid(next, 1, cpath, &next, &temp_path[idx]);
+ of_node_put(prev);
+ if (ret) {
+ of_node_put(next);
+ break;
+ }
+
+ /*
+ * If this is an OVL adaptor exclusive component and one of those
+ * was already added, don't add another instance of the generic
+ * DDP_COMPONENT_OVL_ADAPTOR, as this is used only to decide whether
+ * to probe that component master driver of which only one instance
+ * is needed and possible.
+ */
+ if (temp_path[idx] == DDP_COMPONENT_DRM_OVL_ADAPTOR) {
+ if (!ovl_adaptor_comp_added)
+ ovl_adaptor_comp_added = true;
+ else
+ idx--;
+ }
+ } while (++idx < DDP_COMPONENT_DRM_ID_MAX);
+
+ /*
+ * The device component might not be enabled: in that case, don't
+ * check the last entry and just report that the device is missing.
+ */
+ if (ret == -ENODEV)
+ return ret;
+
+ /* If the last entry is not a final display output, the configuration is wrong */
+ switch (temp_path[idx - 1]) {
+ case DDP_COMPONENT_DP_INTF0:
+ case DDP_COMPONENT_DP_INTF1:
+ case DDP_COMPONENT_DPI0:
+ case DDP_COMPONENT_DPI1:
+ case DDP_COMPONENT_DSI0:
+ case DDP_COMPONENT_DSI1:
+ case DDP_COMPONENT_DSI2:
+ case DDP_COMPONENT_DSI3:
+ break;
+ default:
+ dev_err(dev, "Invalid display hw pipeline. Last component: %d (ret=%d)\n",
+ temp_path[idx - 1], ret);
+ return -EINVAL;
+ }
+
+ final_ddp_path = devm_kmemdup(dev, temp_path, idx * sizeof(temp_path[0]), GFP_KERNEL);
+ if (!final_ddp_path)
+ return -ENOMEM;
+
+ dev_dbg(dev, "Display HW Pipeline built with %d components.\n", idx);
+
+ /* Pipeline built! */
+ *out_path = final_ddp_path;
+ *out_path_len = idx;
+
+ return 0;
+}
+
+static int mtk_drm_of_ddp_path_build(struct device *dev, struct device_node *node,
+ struct mtk_mmsys_driver_data *data)
+{
+ struct device_node *ep_node;
+ struct of_endpoint of_ep;
+ bool output_present[MAX_CRTC] = { false };
+ int ret;
+
+ for_each_endpoint_of_node(node, ep_node) {
+ ret = of_graph_parse_endpoint(ep_node, &of_ep);
+ if (ret) {
+ dev_err_probe(dev, ret, "Cannot parse endpoint\n");
+ break;
+ }
+
+ if (of_ep.id >= MAX_CRTC) {
+ ret = dev_err_probe(dev, -EINVAL,
+ "Invalid endpoint%u number\n", of_ep.port);
+ break;
+ }
+
+ output_present[of_ep.id] = true;
+ }
+
+ if (ret) {
+ of_node_put(ep_node);
+ return ret;
+ }
+
+ if (output_present[CRTC_MAIN]) {
+ ret = mtk_drm_of_ddp_path_build_one(dev, CRTC_MAIN,
+ &data->main_path, &data->main_len);
+ if (ret && ret != -ENODEV)
+ return ret;
+ }
+
+ if (output_present[CRTC_EXT]) {
+ ret = mtk_drm_of_ddp_path_build_one(dev, CRTC_EXT,
+ &data->ext_path, &data->ext_len);
+ if (ret && ret != -ENODEV)
+ return ret;
+ }
+
+ if (output_present[CRTC_THIRD]) {
+ ret = mtk_drm_of_ddp_path_build_one(dev, CRTC_THIRD,
+ &data->third_path, &data->third_len);
+ if (ret && ret != -ENODEV)
+ return ret;
+ }
+
+ return 0;
+}
+
static int mtk_drm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *phandle = dev->parent->of_node;
const struct of_device_id *of_id;
struct mtk_drm_private *private;
+ struct mtk_mmsys_driver_data *mtk_drm_data;
struct device_node *node;
struct component_match *match = NULL;
struct platform_device *ovl_adaptor;
@@ -822,7 +1097,27 @@ static int mtk_drm_probe(struct platform_device *pdev)
if (!of_id)
return -ENODEV;
- private->data = of_id->data;
+ mtk_drm_data = (struct mtk_mmsys_driver_data *)of_id->data;
+ if (!mtk_drm_data)
+ return -EINVAL;
+
+ /* Try to build the display pipeline from devicetree graphs */
+ if (of_graph_is_present(phandle)) {
+ dev_dbg(dev, "Building display pipeline for MMSYS %u\n",
+ mtk_drm_data->mmsys_id);
+ private->data = devm_kmemdup(dev, mtk_drm_data,
+ sizeof(*mtk_drm_data), GFP_KERNEL);
+ if (!private->data)
+ return -ENOMEM;
+
+ ret = mtk_drm_of_ddp_path_build(dev, phandle, private->data);
+ if (ret)
+ return ret;
+ } else {
+ /* No devicetree graphs support: go with hardcoded paths if present */
+ dev_dbg(dev, "Using hardcoded paths for MMSYS %u\n", mtk_drm_data->mmsys_id);
+ private->data = mtk_drm_data;
+ }
private->all_drm_private = devm_kmalloc_array(dev, private->data->mmsys_dev_num,
sizeof(*private->all_drm_private),
@@ -844,12 +1139,11 @@ static int mtk_drm_probe(struct platform_device *pdev)
/* Iterate over sibling DISP function blocks */
for_each_child_of_node(phandle->parent, node) {
- const struct of_device_id *of_id;
enum mtk_ddp_comp_type comp_type;
int comp_id;
- of_id = of_match_node(mtk_ddp_comp_dt_ids, node);
- if (!of_id)
+ ret = mtk_drm_of_get_ddp_comp_type(node, &comp_type);
+ if (ret)
continue;
if (!of_device_is_available(node)) {
@@ -858,8 +1152,6 @@ static int mtk_drm_probe(struct platform_device *pdev)
continue;
}
- comp_type = (enum mtk_ddp_comp_type)(uintptr_t)of_id->data;
-
if (comp_type == MTK_DISP_MUTEX) {
int id;
@@ -950,6 +1242,13 @@ static void mtk_drm_remove(struct platform_device *pdev)
of_node_put(private->comp_node[i]);
}
+static void mtk_drm_shutdown(struct platform_device *pdev)
+{
+ struct mtk_drm_private *private = platform_get_drvdata(pdev);
+
+ drm_atomic_helper_shutdown(private->drm);
+}
+
static int mtk_drm_sys_prepare(struct device *dev)
{
struct mtk_drm_private *private = dev_get_drvdata(dev);
@@ -980,7 +1279,8 @@ static const struct dev_pm_ops mtk_drm_pm_ops = {
static struct platform_driver mtk_drm_platform_driver = {
.probe = mtk_drm_probe,
- .remove_new = mtk_drm_remove,
+ .remove = mtk_drm_remove,
+ .shutdown = mtk_drm_shutdown,
.driver = {
.name = "mediatek-drm",
.pm = &mtk_drm_pm_ops,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index 33fadb08dc1c..675cdc90a440 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 <linux/io.h>
-#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 {
@@ -59,7 +63,7 @@ struct mtk_drm_private {
struct device *mmsys_dev;
struct device_node *comp_node[DDP_COMPONENT_DRM_ID_MAX];
struct mtk_ddp_comp ddp_comp[DDP_COMPONENT_DRM_ID_MAX];
- const struct mtk_mmsys_driver_data *data;
+ struct mtk_mmsys_driver_data *data;
struct drm_atomic_state *suspend_state;
unsigned int mbox_index;
struct mtk_drm_private **all_drm_private;
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 9501f4019199..4fe1f38a3c4b 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -28,8 +28,8 @@
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
+#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
@@ -88,12 +88,15 @@
#define DSI_HSA_WC 0x50
#define DSI_HBP_WC 0x54
#define DSI_HFP_WC 0x58
+#define HFP_HS_VB_PS_WC GENMASK(30, 16)
+#define HFP_HS_EN BIT(31)
#define DSI_CMDQ_SIZE 0x60
#define CMDQ_SIZE 0x3f
#define CMDQ_SIZE_SEL BIT(15)
#define DSI_HSTX_CKL_WC 0x64
+#define HSTX_CKL_WC GENMASK(15, 2)
#define DSI_RX_DATA0 0x74
#define DSI_RX_DATA1 0x78
@@ -136,11 +139,11 @@
#define CLK_HS_POST GENMASK(15, 8)
#define CLK_HS_EXIT GENMASK(23, 16)
-#define DSI_VM_CMD_CON 0x130
+/* DSI_VM_CMD_CON */
#define VM_CMD_EN BIT(0)
#define TS_VFP_EN BIT(5)
-#define DSI_SHADOW_DEBUG 0x190U
+/* DSI_SHADOW_DEBUG */
#define FORCE_COMMIT BIT(0)
#define BYPASS_SHADOW BIT(1)
@@ -184,9 +187,12 @@ struct phy;
struct mtk_dsi_driver_data {
const u32 reg_cmdq_off;
+ const u32 reg_vm_cmd_off;
+ const u32 reg_shadow_dbg_off;
bool has_shadow_ctl;
bool has_size_ctl;
bool cmdq_long_packet_ctl;
+ bool support_per_frame_lp;
};
struct mtk_dsi {
@@ -362,8 +368,8 @@ static void mtk_dsi_set_mode(struct mtk_dsi *dsi)
static void mtk_dsi_set_vm_cmd(struct mtk_dsi *dsi)
{
- mtk_dsi_mask(dsi, DSI_VM_CMD_CON, VM_CMD_EN, VM_CMD_EN);
- mtk_dsi_mask(dsi, DSI_VM_CMD_CON, TS_VFP_EN, TS_VFP_EN);
+ mtk_dsi_mask(dsi, dsi->driver_data->reg_vm_cmd_off, VM_CMD_EN, VM_CMD_EN);
+ mtk_dsi_mask(dsi, dsi->driver_data->reg_vm_cmd_off, TS_VFP_EN, TS_VFP_EN);
}
static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)
@@ -425,7 +431,75 @@ static void mtk_dsi_ps_control(struct mtk_dsi *dsi, bool config_vact)
writel(ps_val, dsi->regs + DSI_PSCTRL);
}
-static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
+static void mtk_dsi_config_vdo_timing_per_frame_lp(struct mtk_dsi *dsi)
+{
+ u32 horizontal_sync_active_byte;
+ u32 horizontal_backporch_byte;
+ u32 horizontal_frontporch_byte;
+ u32 hfp_byte_adjust, v_active_adjust;
+ u32 cklp_wc_min_adjust, cklp_wc_max_adjust;
+ u32 dsi_tmp_buf_bpp;
+ unsigned int da_hs_trail;
+ unsigned int ps_wc, hs_vb_ps_wc;
+ u32 v_active_roundup, hstx_cklp_wc;
+ u32 hstx_cklp_wc_max, hstx_cklp_wc_min;
+ struct videomode *vm = &dsi->vm;
+
+ if (dsi->format == MIPI_DSI_FMT_RGB565)
+ dsi_tmp_buf_bpp = 2;
+ else
+ dsi_tmp_buf_bpp = 3;
+
+ da_hs_trail = dsi->phy_timing.da_hs_trail;
+ ps_wc = vm->hactive * dsi_tmp_buf_bpp;
+
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
+ horizontal_sync_active_byte =
+ vm->hsync_len * dsi_tmp_buf_bpp - 10;
+ horizontal_backporch_byte =
+ vm->hback_porch * dsi_tmp_buf_bpp - 10;
+ hfp_byte_adjust = 12;
+ v_active_adjust = 32 + horizontal_sync_active_byte;
+ cklp_wc_min_adjust = 12 + 2 + 4 + horizontal_sync_active_byte;
+ cklp_wc_max_adjust = 20 + 6 + 4 + horizontal_sync_active_byte;
+ } else {
+ horizontal_sync_active_byte = vm->hsync_len * dsi_tmp_buf_bpp - 4;
+ horizontal_backporch_byte = (vm->hback_porch + vm->hsync_len) *
+ dsi_tmp_buf_bpp - 10;
+ cklp_wc_min_adjust = 4;
+ cklp_wc_max_adjust = 12 + 4 + 4;
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {
+ hfp_byte_adjust = 18;
+ v_active_adjust = 28;
+ } else {
+ hfp_byte_adjust = 12;
+ v_active_adjust = 22;
+ }
+ }
+ horizontal_frontporch_byte = vm->hfront_porch * dsi_tmp_buf_bpp - hfp_byte_adjust;
+ v_active_roundup = (v_active_adjust + horizontal_backporch_byte + ps_wc +
+ horizontal_frontporch_byte) % dsi->lanes;
+ if (v_active_roundup)
+ horizontal_backporch_byte += dsi->lanes - v_active_roundup;
+ hstx_cklp_wc_min = (DIV_ROUND_UP(cklp_wc_min_adjust, dsi->lanes) + da_hs_trail + 1)
+ * dsi->lanes / 6 - 1;
+ hstx_cklp_wc_max = (DIV_ROUND_UP((cklp_wc_max_adjust + horizontal_backporch_byte +
+ ps_wc), dsi->lanes) + da_hs_trail + 1) * dsi->lanes / 6 - 1;
+
+ hstx_cklp_wc = FIELD_PREP(HSTX_CKL_WC, (hstx_cklp_wc_min + hstx_cklp_wc_max) / 2);
+ writel(hstx_cklp_wc, dsi->regs + DSI_HSTX_CKL_WC);
+
+ hs_vb_ps_wc = ps_wc - (dsi->phy_timing.lpx + dsi->phy_timing.da_hs_exit +
+ dsi->phy_timing.da_hs_prepare + dsi->phy_timing.da_hs_zero + 2) * dsi->lanes;
+ horizontal_frontporch_byte |= FIELD_PREP(HFP_HS_EN, 1) |
+ FIELD_PREP(HFP_HS_VB_PS_WC, hs_vb_ps_wc);
+
+ writel(horizontal_sync_active_byte, dsi->regs + DSI_HSA_WC);
+ writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC);
+ writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC);
+}
+
+static void mtk_dsi_config_vdo_timing_per_line_lp(struct mtk_dsi *dsi)
{
u32 horizontal_sync_active_byte;
u32 horizontal_backporch_byte;
@@ -435,7 +509,6 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
u32 dsi_tmp_buf_bpp, data_phy_cycles;
u32 delta;
struct mtk_phy_timing *timing = &dsi->phy_timing;
-
struct videomode *vm = &dsi->vm;
if (dsi->format == MIPI_DSI_FMT_RGB565)
@@ -443,16 +516,6 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
else
dsi_tmp_buf_bpp = 3;
- writel(vm->vsync_len, dsi->regs + DSI_VSA_NL);
- writel(vm->vback_porch, dsi->regs + DSI_VBP_NL);
- writel(vm->vfront_porch, dsi->regs + DSI_VFP_NL);
- writel(vm->vactive, dsi->regs + DSI_VACT_NL);
-
- if (dsi->driver_data->has_size_ctl)
- writel(FIELD_PREP(DSI_HEIGHT, vm->vactive) |
- FIELD_PREP(DSI_WIDTH, vm->hactive),
- dsi->regs + DSI_SIZE_CON);
-
horizontal_sync_active_byte = (vm->hsync_len * dsi_tmp_buf_bpp - 10);
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
@@ -498,6 +561,26 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
writel(horizontal_sync_active_byte, dsi->regs + DSI_HSA_WC);
writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC);
writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC);
+}
+
+static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
+{
+ struct videomode *vm = &dsi->vm;
+
+ writel(vm->vsync_len, dsi->regs + DSI_VSA_NL);
+ writel(vm->vback_porch, dsi->regs + DSI_VBP_NL);
+ writel(vm->vfront_porch, dsi->regs + DSI_VFP_NL);
+ writel(vm->vactive, dsi->regs + DSI_VACT_NL);
+
+ if (dsi->driver_data->has_size_ctl)
+ writel(FIELD_PREP(DSI_HEIGHT, vm->vactive) |
+ FIELD_PREP(DSI_WIDTH, vm->hactive),
+ dsi->regs + DSI_SIZE_CON);
+
+ if (dsi->driver_data->support_per_frame_lp)
+ mtk_dsi_config_vdo_timing_per_frame_lp(dsi);
+ else
+ mtk_dsi_config_vdo_timing_per_line_lp(dsi);
mtk_dsi_ps_control(dsi, false);
}
@@ -632,7 +715,7 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
if (dsi->driver_data->has_shadow_ctl)
writel(FORCE_COMMIT | BYPASS_SHADOW,
- dsi->regs + DSI_SHADOW_DEBUG);
+ dsi->regs + dsi->driver_data->reg_shadow_dbg_off);
mtk_dsi_reset_engine(dsi);
mtk_dsi_phy_timconfig(dsi);
@@ -662,7 +745,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.
@@ -724,12 +807,13 @@ static void mtk_output_dsi_disable(struct mtk_dsi *dsi)
}
static int mtk_dsi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct mtk_dsi *dsi = bridge_to_dsi(bridge);
/* Attach the panel or bridge to the dsi bridge */
- return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
+ return drm_bridge_attach(encoder, dsi->next_bridge,
&dsi->bridge, flags);
}
@@ -743,7 +827,7 @@ static void mtk_dsi_bridge_mode_set(struct drm_bridge *bridge,
}
static void mtk_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
struct mtk_dsi *dsi = bridge_to_dsi(bridge);
@@ -751,7 +835,7 @@ static void mtk_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
}
static void mtk_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
struct mtk_dsi *dsi = bridge_to_dsi(bridge);
@@ -762,7 +846,7 @@ static void mtk_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
}
static void mtk_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
struct mtk_dsi *dsi = bridge_to_dsi(bridge);
int ret;
@@ -773,7 +857,7 @@ static void mtk_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
}
static void mtk_dsi_bridge_atomic_post_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
struct mtk_dsi *dsi = bridge_to_dsi(bridge);
@@ -836,7 +920,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);
@@ -903,9 +990,17 @@ static int mtk_dsi_host_attach(struct mipi_dsi_host *host,
dsi->lanes = device->lanes;
dsi->format = device->format;
dsi->mode_flags = device->mode_flags;
- dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
- if (IS_ERR(dsi->next_bridge))
- return PTR_ERR(dsi->next_bridge);
+ dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
+ if (IS_ERR(dsi->next_bridge)) {
+ ret = PTR_ERR(dsi->next_bridge);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ /* Old devicetree has only one endpoint */
+ dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
+ if (IS_ERR(dsi->next_bridge))
+ return PTR_ERR(dsi->next_bridge);
+ }
drm_bridge_add(&dsi->bridge);
@@ -1022,12 +1117,12 @@ static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg)
{
struct mtk_dsi *dsi = host_to_dsi(host);
- u32 recv_cnt, i;
+ ssize_t recv_cnt;
u8 read_data[16];
void *src_addr;
u8 irq_flag = CMD_DONE_INT_FLAG;
u32 dsi_mode;
- int ret;
+ int ret, i;
dsi_mode = readl(dsi->regs + DSI_MODE_CTRL);
if (dsi_mode & MODE) {
@@ -1076,7 +1171,7 @@ static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host,
if (recv_cnt)
memcpy(msg->rx_buf, src_addr, recv_cnt);
- DRM_INFO("dsi get %d byte data from the panel address(0x%x)\n",
+ DRM_INFO("dsi get %zd byte data from the panel address(0x%x)\n",
recv_cnt, *((u8 *)(msg->tx_buf)));
restore_dsi_mode:
@@ -1098,7 +1193,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
{
struct mtk_dsi *dsi;
struct device *dev = &pdev->dev;
- struct resource *regs;
int irq_num;
int ret;
@@ -1123,8 +1217,7 @@ static int mtk_dsi_probe(struct platform_device *pdev)
if (IS_ERR(dsi->hs_clk))
return dev_err_probe(dev, PTR_ERR(dsi->hs_clk), "Failed to get hs clock\n");
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dsi->regs = devm_ioremap_resource(dev, regs);
+ dsi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dsi->regs))
return dev_err_probe(dev, PTR_ERR(dsi->regs), "Failed to ioremap memory\n");
@@ -1170,29 +1263,40 @@ static void mtk_dsi_remove(struct platform_device *pdev)
static const struct mtk_dsi_driver_data mt8173_dsi_driver_data = {
.reg_cmdq_off = 0x200,
+ .reg_vm_cmd_off = 0x130,
+ .reg_shadow_dbg_off = 0x190
};
static const struct mtk_dsi_driver_data mt2701_dsi_driver_data = {
.reg_cmdq_off = 0x180,
+ .reg_vm_cmd_off = 0x130,
+ .reg_shadow_dbg_off = 0x190
};
static const struct mtk_dsi_driver_data mt8183_dsi_driver_data = {
.reg_cmdq_off = 0x200,
+ .reg_vm_cmd_off = 0x130,
+ .reg_shadow_dbg_off = 0x190,
.has_shadow_ctl = true,
.has_size_ctl = true,
};
static const struct mtk_dsi_driver_data mt8186_dsi_driver_data = {
.reg_cmdq_off = 0xd00,
+ .reg_vm_cmd_off = 0x200,
+ .reg_shadow_dbg_off = 0xc00,
.has_shadow_ctl = true,
.has_size_ctl = true,
};
static const struct mtk_dsi_driver_data mt8188_dsi_driver_data = {
.reg_cmdq_off = 0xd00,
+ .reg_vm_cmd_off = 0x200,
+ .reg_shadow_dbg_off = 0xc00,
.has_shadow_ctl = true,
.has_size_ctl = true,
.cmdq_long_packet_ctl = true,
+ .support_per_frame_lp = true,
};
static const struct of_device_id mtk_dsi_of_match[] = {
@@ -1207,7 +1311,7 @@ MODULE_DEVICE_TABLE(of, mtk_dsi_of_match);
struct platform_driver mtk_dsi_driver = {
.probe = mtk_dsi_probe,
- .remove_new = mtk_dsi_remove,
+ .remove = mtk_dsi_remove,
.driver = {
.name = "mtk-dsi",
.of_match_table = mtk_dsi_of_match,
diff --git a/drivers/gpu/drm/mediatek/mtk_ethdr.c b/drivers/gpu/drm/mediatek/mtk_ethdr.c
index 6a5d0c345aab..96832d0cca37 100644
--- a/drivers/gpu/drm/mediatek/mtk_ethdr.c
+++ b/drivers/gpu/drm/mediatek/mtk_ethdr.c
@@ -3,6 +3,7 @@
* Copyright (c) 2021 MediaTek Inc.
*/
+#include <drm/drm_blend.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <linux/clk.h>
@@ -14,8 +15,8 @@
#include <linux/soc/mediatek/mtk-cmdq.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
-#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"
@@ -35,6 +36,7 @@
#define MIX_SRC_L0_EN BIT(0)
#define MIX_L_SRC_CON(n) (0x28 + 0x18 * (n))
#define NON_PREMULTI_SOURCE (2 << 12)
+#define PREMULTI_SOURCE (3 << 12)
#define MIX_L_SRC_SIZE(n) (0x30 + 0x18 * (n))
#define MIX_L_SRC_OFFSET(n) (0x34 + 0x18 * (n))
#define MIX_FUNC_DCM0 0x120
@@ -50,7 +52,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
@@ -144,6 +145,13 @@ static irqreturn_t mtk_ethdr_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+u32 mtk_ethdr_get_blend_modes(struct device *dev)
+{
+ return BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE) |
+ BIT(DRM_MODE_BLEND_PIXEL_NONE);
+}
+
void mtk_ethdr_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt)
@@ -154,30 +162,51 @@ 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;
}
- if (state->base.fb && state->base.fb->format->has_alpha)
- alpha_con = MIXER_ALPHA_AEN | MIXER_ALPHA;
+ if (state->base.fb) {
+ alpha_con |= MIXER_ALPHA_AEN;
+ alpha_con |= state->base.alpha & MIXER_ALPHA;
+ }
- mtk_mmsys_mixer_in_config(priv->mmsys_dev, idx + 1, alpha_con ? false : true,
- DEFAULT_9BIT_ALPHA,
+ if (state->base.pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
+ alpha_con |= PREMULTI_SOURCE;
+ else
+ alpha_con |= NON_PREMULTI_SOURCE;
+
+ if ((state->base.fb && !state->base.fb->format->has_alpha) ||
+ state->base.pixel_blend_mode == DRM_MODE_BLEND_PIXEL_NONE) {
+ /*
+ * 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);
mtk_ddp_write(cmdq_pkt, pending->height << 16 | align_width, &mixer->cmdq_base,
mixer->regs, MIX_L_SRC_SIZE(idx));
mtk_ddp_write(cmdq_pkt, offset, &mixer->cmdq_base, mixer->regs, MIX_L_SRC_OFFSET(idx));
- mtk_ddp_write_mask(cmdq_pkt, alpha_con, &mixer->cmdq_base, mixer->regs, MIX_L_SRC_CON(idx),
- 0x1ff);
+ mtk_ddp_write(cmdq_pkt, alpha_con, &mixer->cmdq_base, mixer->regs, MIX_L_SRC_CON(idx));
mtk_ddp_write_mask(cmdq_pkt, BIT(idx), &mixer->cmdq_base, mixer->regs, MIX_SRC_CON,
BIT(idx));
}
@@ -325,25 +354,24 @@ static int mtk_ethdr_probe(struct platform_device *pdev)
if (priv->irq) {
ret = devm_request_irq(dev, priv->irq, mtk_ethdr_irq_handler,
IRQF_TRIGGER_NONE, dev_name(dev), priv);
- if (ret < 0) {
- dev_err(dev, "Failed to request irq %d: %d\n", priv->irq, ret);
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to request irq %d\n",
+ priv->irq);
}
priv->reset_ctl = devm_reset_control_array_get_optional_exclusive(dev);
- if (IS_ERR(priv->reset_ctl)) {
- dev_err_probe(dev, PTR_ERR(priv->reset_ctl), "cannot get ethdr reset control\n");
- return PTR_ERR(priv->reset_ctl);
- }
+ if (IS_ERR(priv->reset_ctl))
+ return dev_err_probe(dev, PTR_ERR(priv->reset_ctl),
+ "cannot get ethdr reset control\n");
platform_set_drvdata(pdev, priv);
ret = component_add(dev, &mtk_ethdr_component_ops);
if (ret)
- dev_notice(dev, "Failed to add component: %d\n", ret);
+ return dev_err_probe(dev, ret, "Failed to add component\n");
- return ret;
+ return 0;
}
static void mtk_ethdr_remove(struct platform_device *pdev)
@@ -360,10 +388,9 @@ MODULE_DEVICE_TABLE(of, mtk_ethdr_driver_dt_match);
struct platform_driver mtk_ethdr_driver = {
.probe = mtk_ethdr_probe,
- .remove_new = mtk_ethdr_remove,
+ .remove = 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_ethdr.h b/drivers/gpu/drm/mediatek/mtk_ethdr.h
index 81af9edea3f7..a72aeee46829 100644
--- a/drivers/gpu/drm/mediatek/mtk_ethdr.h
+++ b/drivers/gpu/drm/mediatek/mtk_ethdr.h
@@ -13,6 +13,7 @@ void mtk_ethdr_clk_disable(struct device *dev);
void mtk_ethdr_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+u32 mtk_ethdr_get_blend_modes(struct device *dev);
void mtk_ethdr_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c b/drivers/gpu/drm/mediatek/mtk_gem.c
index 4f2e3feabc0f..a172456d1d7b 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
+++ b/drivers/gpu/drm/mediatek/mtk_gem.c
@@ -4,6 +4,7 @@
*/
#include <linux/dma-buf.h>
+#include <linux/vmalloc.h>
#include <drm/drm.h>
#include <drm/drm_device.h>
@@ -12,37 +13,40 @@
#include <drm/drm_prime.h>
#include "mtk_drm_drv.h"
-#include "mtk_drm_gem.h"
+#include "mtk_gem.h"
-static int mtk_drm_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
+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_drm_gem_object_funcs = {
- .free = mtk_drm_gem_free_object,
+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_drm_gem_prime_vmap,
- .vunmap = mtk_drm_gem_prime_vunmap,
- .mmap = mtk_drm_gem_object_mmap,
+ .vmap = mtk_gem_prime_vmap,
+ .vunmap = mtk_gem_prime_vunmap,
+ .mmap = mtk_gem_object_mmap,
.vm_ops = &vm_ops,
};
-static struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev,
- unsigned long size)
+static struct mtk_gem_obj *mtk_gem_init(struct drm_device *dev,
+ unsigned long size)
{
- struct mtk_drm_gem_obj *mtk_gem_obj;
+ 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_drm_gem_object_funcs;
+ mtk_gem_obj->base.funcs = &mtk_gem_object_funcs;
ret = drm_gem_object_init(dev, &mtk_gem_obj->base, size);
if (ret < 0) {
@@ -54,15 +58,15 @@ static struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev,
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_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_drm_gem_obj *mtk_gem;
+ struct mtk_gem_obj *mtk_gem;
struct drm_gem_object *obj;
int ret;
- mtk_gem = mtk_drm_gem_init(dev, size);
+ mtk_gem = mtk_gem_init(dev, size);
if (IS_ERR(mtk_gem))
return ERR_CAST(mtk_gem);
@@ -97,9 +101,9 @@ err_gem_free:
return ERR_PTR(ret);
}
-void mtk_drm_gem_free_object(struct drm_gem_object *obj)
+void mtk_gem_free_object(struct drm_gem_object *obj)
{
- struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(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)
@@ -114,10 +118,10 @@ void mtk_drm_gem_free_object(struct drm_gem_object *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)
+int mtk_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;
+ struct mtk_gem_obj *mtk_gem;
int ret;
args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
@@ -130,7 +134,7 @@ int mtk_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
args->size = args->pitch;
args->size *= args->height;
- mtk_gem = mtk_drm_gem_create(dev, args->size, false);
+ mtk_gem = mtk_gem_create(dev, args->size, false);
if (IS_ERR(mtk_gem))
return PTR_ERR(mtk_gem);
@@ -148,16 +152,16 @@ int mtk_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
return 0;
err_handle_create:
- mtk_drm_gem_free_object(&mtk_gem->base);
+ mtk_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)
+static int mtk_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_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
struct mtk_drm_private *priv = obj->dev->dev_private;
/*
@@ -188,7 +192,7 @@ static int mtk_drm_gem_object_mmap(struct drm_gem_object *obj,
*/
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_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
struct mtk_drm_private *priv = obj->dev->dev_private;
struct sg_table *sgt;
int ret;
@@ -212,7 +216,7 @@ 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)
{
- struct mtk_drm_gem_obj *mtk_gem;
+ 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) {
@@ -220,7 +224,7 @@ struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev,
return ERR_PTR(-EINVAL);
}
- mtk_gem = mtk_drm_gem_init(dev, attach->dmabuf->size);
+ mtk_gem = mtk_gem_init(dev, attach->dmabuf->size);
if (IS_ERR(mtk_gem))
return ERR_CAST(mtk_gem);
@@ -230,9 +234,9 @@ struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev,
return &mtk_gem->base;
}
-int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
+int mtk_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 mtk_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
struct sg_table *sgt = NULL;
unsigned int npages;
@@ -270,10 +274,9 @@ out:
return 0;
}
-void mtk_drm_gem_prime_vunmap(struct drm_gem_object *obj,
- struct iosys_map *map)
+void mtk_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
{
- struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
+ struct mtk_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
void *vaddr = map->vaddr;
if (!mtk_gem->pages)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.h b/drivers/gpu/drm/mediatek/mtk_gem.h
index 78f23b07a02e..66e5f154f698 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.h
+++ b/drivers/gpu/drm/mediatek/mtk_gem.h
@@ -3,8 +3,8 @@
* Copyright (c) 2015 MediaTek Inc.
*/
-#ifndef _MTK_DRM_GEM_H_
-#define _MTK_DRM_GEM_H_
+#ifndef _MTK_GEM_H_
+#define _MTK_GEM_H_
#include <drm/drm_gem.h>
@@ -22,7 +22,7 @@
* 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 mtk_gem_obj {
struct drm_gem_object base;
void *cookie;
void *kvaddr;
@@ -32,18 +32,17 @@ struct mtk_drm_gem_obj {
struct page **pages;
};
-#define to_mtk_gem_obj(x) container_of(x, struct mtk_drm_gem_obj, base)
+#define to_mtk_gem_obj(x) container_of(x, struct mtk_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);
+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_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);
+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 c6bdc565e4a9..8803cd4a8bc9 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -31,7 +31,6 @@
#include <drm/drm_probe_helper.h>
#include "mtk_cec.h"
-#include "mtk_hdmi.h"
#include "mtk_hdmi_regs.h"
#define NCTS_BYTES 7
@@ -137,7 +136,7 @@ enum hdmi_aud_channel_swap_type {
struct hdmi_audio_param {
enum hdmi_audio_coding_type aud_codec;
- enum hdmi_audio_sample_size aud_sampe_size;
+ enum hdmi_audio_sample_size aud_sample_size;
enum hdmi_aud_input_type aud_input_type;
enum hdmi_aud_i2s_fmt aud_i2s_fmt;
enum hdmi_aud_mclk aud_mclk;
@@ -163,16 +162,10 @@ struct mtk_hdmi {
struct clk *clk[MTK_HDMI_CLK_COUNT];
struct drm_display_mode mode;
bool dvi_mode;
- u32 min_clock;
- u32 max_clock;
- u32 max_hdisplay;
- u32 max_vdisplay;
- u32 ibias;
- u32 ibias_up;
struct regmap *sys_regmap;
unsigned int sys_offset;
- void __iomem *regs;
- enum hdmi_colorspace csp;
+ struct regmap *regs;
+ struct platform_device *audio_pdev;
struct hdmi_audio_param aud_param;
bool audio_enable;
bool powered;
@@ -187,50 +180,10 @@ static inline struct mtk_hdmi *hdmi_ctx_from_bridge(struct drm_bridge *b)
return container_of(b, struct mtk_hdmi, bridge);
}
-static u32 mtk_hdmi_read(struct mtk_hdmi *hdmi, u32 offset)
-{
- return readl(hdmi->regs + offset);
-}
-
-static void mtk_hdmi_write(struct mtk_hdmi *hdmi, u32 offset, u32 val)
-{
- writel(val, hdmi->regs + offset);
-}
-
-static void mtk_hdmi_clear_bits(struct mtk_hdmi *hdmi, u32 offset, u32 bits)
-{
- void __iomem *reg = hdmi->regs + offset;
- u32 tmp;
-
- tmp = readl(reg);
- tmp &= ~bits;
- writel(tmp, reg);
-}
-
-static void mtk_hdmi_set_bits(struct mtk_hdmi *hdmi, u32 offset, u32 bits)
-{
- void __iomem *reg = hdmi->regs + offset;
- u32 tmp;
-
- tmp = readl(reg);
- tmp |= bits;
- writel(tmp, reg);
-}
-
-static void mtk_hdmi_mask(struct mtk_hdmi *hdmi, u32 offset, u32 val, u32 mask)
-{
- void __iomem *reg = hdmi->regs + offset;
- u32 tmp;
-
- tmp = readl(reg);
- tmp = (tmp & ~mask) | (val & mask);
- writel(tmp, reg);
-}
-
static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdmi, bool black)
{
- mtk_hdmi_mask(hdmi, VIDEO_CFG_4, black ? GEN_RGB : NORMAL_PATH,
- VIDEO_SOURCE_SEL);
+ regmap_update_bits(hdmi->regs, VIDEO_SOURCE_SEL,
+ VIDEO_CFG_4, black ? GEN_RGB : NORMAL_PATH);
}
static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable)
@@ -265,12 +218,12 @@ static void mtk_hdmi_hw_1p4_version_enable(struct mtk_hdmi *hdmi, bool enable)
static void mtk_hdmi_hw_aud_mute(struct mtk_hdmi *hdmi)
{
- mtk_hdmi_set_bits(hdmi, GRL_AUDIO_CFG, AUDIO_ZERO);
+ regmap_set_bits(hdmi->regs, GRL_AUDIO_CFG, AUDIO_ZERO);
}
static void mtk_hdmi_hw_aud_unmute(struct mtk_hdmi *hdmi)
{
- mtk_hdmi_clear_bits(hdmi, GRL_AUDIO_CFG, AUDIO_ZERO);
+ regmap_clear_bits(hdmi->regs, GRL_AUDIO_CFG, AUDIO_ZERO);
}
static void mtk_hdmi_hw_reset(struct mtk_hdmi *hdmi)
@@ -279,25 +232,25 @@ static void mtk_hdmi_hw_reset(struct mtk_hdmi *hdmi)
HDMI_RST, HDMI_RST);
regmap_update_bits(hdmi->sys_regmap, hdmi->sys_offset + HDMI_SYS_CFG1C,
HDMI_RST, 0);
- mtk_hdmi_clear_bits(hdmi, GRL_CFG3, CFG3_CONTROL_PACKET_DELAY);
+ regmap_clear_bits(hdmi->regs, GRL_CFG3, CFG3_CONTROL_PACKET_DELAY);
regmap_update_bits(hdmi->sys_regmap, hdmi->sys_offset + HDMI_SYS_CFG1C,
ANLG_ON, ANLG_ON);
}
static void mtk_hdmi_hw_enable_notice(struct mtk_hdmi *hdmi, bool enable_notice)
{
- mtk_hdmi_mask(hdmi, GRL_CFG2, enable_notice ? CFG2_NOTICE_EN : 0,
- CFG2_NOTICE_EN);
+ regmap_update_bits(hdmi->regs, GRL_CFG2, CFG2_NOTICE_EN,
+ enable_notice ? CFG2_NOTICE_EN : 0);
}
static void mtk_hdmi_hw_write_int_mask(struct mtk_hdmi *hdmi, u32 int_mask)
{
- mtk_hdmi_write(hdmi, GRL_INT_MASK, int_mask);
+ regmap_write(hdmi->regs, GRL_INT_MASK, int_mask);
}
static void mtk_hdmi_hw_enable_dvi_mode(struct mtk_hdmi *hdmi, bool enable)
{
- mtk_hdmi_mask(hdmi, GRL_CFG1, enable ? CFG1_DVI : 0, CFG1_DVI);
+ regmap_update_bits(hdmi->regs, GRL_CFG1, CFG1_DVI, enable ? CFG1_DVI : 0);
}
static void mtk_hdmi_hw_send_info_frame(struct mtk_hdmi *hdmi, u8 *buffer,
@@ -343,22 +296,22 @@ static void mtk_hdmi_hw_send_info_frame(struct mtk_hdmi *hdmi, u8 *buffer,
dev_err(hdmi->dev, "Unknown infoframe type %d\n", frame_type);
return;
}
- mtk_hdmi_clear_bits(hdmi, ctrl_reg, ctrl_frame_en);
- mtk_hdmi_write(hdmi, GRL_INFOFRM_TYPE, frame_type);
- mtk_hdmi_write(hdmi, GRL_INFOFRM_VER, frame_ver);
- mtk_hdmi_write(hdmi, GRL_INFOFRM_LNG, frame_len);
+ regmap_clear_bits(hdmi->regs, ctrl_reg, ctrl_frame_en);
+ regmap_write(hdmi->regs, GRL_INFOFRM_TYPE, frame_type);
+ regmap_write(hdmi->regs, GRL_INFOFRM_VER, frame_ver);
+ regmap_write(hdmi->regs, GRL_INFOFRM_LNG, frame_len);
- mtk_hdmi_write(hdmi, GRL_IFM_PORT, checksum);
+ regmap_write(hdmi->regs, GRL_IFM_PORT, checksum);
for (i = 0; i < frame_len; i++)
- mtk_hdmi_write(hdmi, GRL_IFM_PORT, frame_data[i]);
+ regmap_write(hdmi->regs, GRL_IFM_PORT, frame_data[i]);
- mtk_hdmi_set_bits(hdmi, ctrl_reg, ctrl_frame_en);
+ regmap_set_bits(hdmi->regs, ctrl_reg, ctrl_frame_en);
}
static void mtk_hdmi_hw_send_aud_packet(struct mtk_hdmi *hdmi, bool enable)
{
- mtk_hdmi_mask(hdmi, GRL_SHIFT_R2, enable ? 0 : AUDIO_PACKET_OFF,
- AUDIO_PACKET_OFF);
+ regmap_update_bits(hdmi->regs, AUDIO_PACKET_OFF,
+ GRL_SHIFT_R2, enable ? 0 : AUDIO_PACKET_OFF);
}
static void mtk_hdmi_hw_config_sys(struct mtk_hdmi *hdmi)
@@ -379,44 +332,44 @@ static void mtk_hdmi_hw_set_deep_color_mode(struct mtk_hdmi *hdmi)
static void mtk_hdmi_hw_send_av_mute(struct mtk_hdmi *hdmi)
{
- mtk_hdmi_clear_bits(hdmi, GRL_CFG4, CTRL_AVMUTE);
+ regmap_clear_bits(hdmi->regs, GRL_CFG4, CTRL_AVMUTE);
usleep_range(2000, 4000);
- mtk_hdmi_set_bits(hdmi, GRL_CFG4, CTRL_AVMUTE);
+ regmap_set_bits(hdmi->regs, GRL_CFG4, CTRL_AVMUTE);
}
static void mtk_hdmi_hw_send_av_unmute(struct mtk_hdmi *hdmi)
{
- mtk_hdmi_mask(hdmi, GRL_CFG4, CFG4_AV_UNMUTE_EN,
- CFG4_AV_UNMUTE_EN | CFG4_AV_UNMUTE_SET);
+ regmap_update_bits(hdmi->regs, GRL_CFG4, CFG4_AV_UNMUTE_EN | CFG4_AV_UNMUTE_SET,
+ CFG4_AV_UNMUTE_EN);
usleep_range(2000, 4000);
- mtk_hdmi_mask(hdmi, GRL_CFG4, CFG4_AV_UNMUTE_SET,
- CFG4_AV_UNMUTE_EN | CFG4_AV_UNMUTE_SET);
+ regmap_update_bits(hdmi->regs, GRL_CFG4, CFG4_AV_UNMUTE_EN | CFG4_AV_UNMUTE_SET,
+ CFG4_AV_UNMUTE_SET);
}
static void mtk_hdmi_hw_ncts_enable(struct mtk_hdmi *hdmi, bool on)
{
- mtk_hdmi_mask(hdmi, GRL_CTS_CTRL, on ? 0 : CTS_CTRL_SOFT,
- CTS_CTRL_SOFT);
+ regmap_update_bits(hdmi->regs, GRL_CTS_CTRL, CTS_CTRL_SOFT,
+ on ? 0 : CTS_CTRL_SOFT);
}
static void mtk_hdmi_hw_ncts_auto_write_enable(struct mtk_hdmi *hdmi,
bool enable)
{
- mtk_hdmi_mask(hdmi, GRL_CTS_CTRL, enable ? NCTS_WRI_ANYTIME : 0,
- NCTS_WRI_ANYTIME);
+ regmap_update_bits(hdmi->regs, GRL_CTS_CTRL, NCTS_WRI_ANYTIME,
+ enable ? NCTS_WRI_ANYTIME : 0);
}
static void mtk_hdmi_hw_msic_setting(struct mtk_hdmi *hdmi,
struct drm_display_mode *mode)
{
- mtk_hdmi_clear_bits(hdmi, GRL_CFG4, CFG4_MHL_MODE);
+ regmap_clear_bits(hdmi->regs, GRL_CFG4, CFG4_MHL_MODE);
if (mode->flags & DRM_MODE_FLAG_INTERLACE &&
mode->clock == 74250 &&
mode->vdisplay == 1080)
- mtk_hdmi_clear_bits(hdmi, GRL_CFG2, CFG2_MHL_DE_SEL);
+ regmap_clear_bits(hdmi->regs, GRL_CFG2, CFG2_MHL_DE_SEL);
else
- mtk_hdmi_set_bits(hdmi, GRL_CFG2, CFG2_MHL_DE_SEL);
+ regmap_set_bits(hdmi->regs, GRL_CFG2, CFG2_MHL_DE_SEL);
}
static void mtk_hdmi_hw_aud_set_channel_swap(struct mtk_hdmi *hdmi,
@@ -444,7 +397,7 @@ static void mtk_hdmi_hw_aud_set_channel_swap(struct mtk_hdmi *hdmi,
swap_bit = LFE_CC_SWAP;
break;
}
- mtk_hdmi_mask(hdmi, GRL_CH_SWAP, swap_bit, 0xff);
+ regmap_update_bits(hdmi->regs, GRL_CH_SWAP, 0xff, swap_bit);
}
static void mtk_hdmi_hw_aud_set_bit_num(struct mtk_hdmi *hdmi,
@@ -465,7 +418,7 @@ static void mtk_hdmi_hw_aud_set_bit_num(struct mtk_hdmi *hdmi,
break;
}
- mtk_hdmi_mask(hdmi, GRL_AOUT_CFG, val, AOUT_BNUM_SEL_MASK);
+ regmap_update_bits(hdmi->regs, GRL_AOUT_CFG, AOUT_BNUM_SEL_MASK, val);
}
static void mtk_hdmi_hw_aud_set_i2s_fmt(struct mtk_hdmi *hdmi,
@@ -473,7 +426,7 @@ static void mtk_hdmi_hw_aud_set_i2s_fmt(struct mtk_hdmi *hdmi,
{
u32 val;
- val = mtk_hdmi_read(hdmi, GRL_CFG0);
+ regmap_read(hdmi->regs, GRL_CFG0, &val);
val &= ~(CFG0_W_LENGTH_MASK | CFG0_I2S_MODE_MASK);
switch (i2s_fmt) {
@@ -497,7 +450,7 @@ static void mtk_hdmi_hw_aud_set_i2s_fmt(struct mtk_hdmi *hdmi,
val |= CFG0_I2S_MODE_I2S | CFG0_W_LENGTH_16BIT;
break;
}
- mtk_hdmi_write(hdmi, GRL_CFG0, val);
+ regmap_write(hdmi->regs, GRL_CFG0, val);
}
static void mtk_hdmi_hw_audio_config(struct mtk_hdmi *hdmi, bool dst)
@@ -506,14 +459,14 @@ static void mtk_hdmi_hw_audio_config(struct mtk_hdmi *hdmi, bool dst)
u8 val;
/* Disable high bitrate, set DST packet normal/double */
- mtk_hdmi_clear_bits(hdmi, GRL_AOUT_CFG, HIGH_BIT_RATE_PACKET_ALIGN);
+ regmap_clear_bits(hdmi->regs, GRL_AOUT_CFG, HIGH_BIT_RATE_PACKET_ALIGN);
if (dst)
val = DST_NORMAL_DOUBLE | SACD_DST;
else
val = 0;
- mtk_hdmi_mask(hdmi, GRL_AUDIO_CFG, val, mask);
+ regmap_update_bits(hdmi->regs, GRL_AUDIO_CFG, mask, val);
}
static void mtk_hdmi_hw_aud_set_i2s_chan_num(struct mtk_hdmi *hdmi,
@@ -554,10 +507,10 @@ static void mtk_hdmi_hw_aud_set_i2s_chan_num(struct mtk_hdmi *hdmi,
i2s_uv = I2S_UV_CH_EN(0);
}
- mtk_hdmi_write(hdmi, GRL_CH_SW0, ch_switch & 0xff);
- mtk_hdmi_write(hdmi, GRL_CH_SW1, (ch_switch >> 8) & 0xff);
- mtk_hdmi_write(hdmi, GRL_CH_SW2, (ch_switch >> 16) & 0xff);
- mtk_hdmi_write(hdmi, GRL_I2S_UV, i2s_uv);
+ regmap_write(hdmi->regs, GRL_CH_SW0, ch_switch & 0xff);
+ regmap_write(hdmi->regs, GRL_CH_SW1, (ch_switch >> 8) & 0xff);
+ regmap_write(hdmi->regs, GRL_CH_SW2, (ch_switch >> 16) & 0xff);
+ regmap_write(hdmi->regs, GRL_I2S_UV, i2s_uv);
}
static void mtk_hdmi_hw_aud_set_input_type(struct mtk_hdmi *hdmi,
@@ -565,7 +518,7 @@ static void mtk_hdmi_hw_aud_set_input_type(struct mtk_hdmi *hdmi,
{
u32 val;
- val = mtk_hdmi_read(hdmi, GRL_CFG1);
+ regmap_read(hdmi->regs, GRL_CFG1, &val);
if (input_type == HDMI_AUD_INPUT_I2S &&
(val & CFG1_SPDIF) == CFG1_SPDIF) {
val &= ~CFG1_SPDIF;
@@ -573,7 +526,7 @@ static void mtk_hdmi_hw_aud_set_input_type(struct mtk_hdmi *hdmi,
(val & CFG1_SPDIF) == 0) {
val |= CFG1_SPDIF;
}
- mtk_hdmi_write(hdmi, GRL_CFG1, val);
+ regmap_write(hdmi->regs, GRL_CFG1, val);
}
static void mtk_hdmi_hw_aud_set_channel_status(struct mtk_hdmi *hdmi,
@@ -582,13 +535,13 @@ static void mtk_hdmi_hw_aud_set_channel_status(struct mtk_hdmi *hdmi,
int i;
for (i = 0; i < 5; i++) {
- mtk_hdmi_write(hdmi, GRL_I2S_C_STA0 + i * 4, channel_status[i]);
- mtk_hdmi_write(hdmi, GRL_L_STATUS_0 + i * 4, channel_status[i]);
- mtk_hdmi_write(hdmi, GRL_R_STATUS_0 + i * 4, channel_status[i]);
+ regmap_write(hdmi->regs, GRL_I2S_C_STA0 + i * 4, channel_status[i]);
+ regmap_write(hdmi->regs, GRL_L_STATUS_0 + i * 4, channel_status[i]);
+ regmap_write(hdmi->regs, GRL_R_STATUS_0 + i * 4, channel_status[i]);
}
for (; i < 24; i++) {
- mtk_hdmi_write(hdmi, GRL_L_STATUS_0 + i * 4, 0);
- mtk_hdmi_write(hdmi, GRL_R_STATUS_0 + i * 4, 0);
+ regmap_write(hdmi->regs, GRL_L_STATUS_0 + i * 4, 0);
+ regmap_write(hdmi->regs, GRL_R_STATUS_0 + i * 4, 0);
}
}
@@ -596,13 +549,13 @@ static void mtk_hdmi_hw_aud_src_reenable(struct mtk_hdmi *hdmi)
{
u32 val;
- val = mtk_hdmi_read(hdmi, GRL_MIX_CTRL);
+ regmap_read(hdmi->regs, GRL_MIX_CTRL, &val);
if (val & MIX_CTRL_SRC_EN) {
val &= ~MIX_CTRL_SRC_EN;
- mtk_hdmi_write(hdmi, GRL_MIX_CTRL, val);
+ regmap_write(hdmi->regs, GRL_MIX_CTRL, val);
usleep_range(255, 512);
val |= MIX_CTRL_SRC_EN;
- mtk_hdmi_write(hdmi, GRL_MIX_CTRL, val);
+ regmap_write(hdmi->regs, GRL_MIX_CTRL, val);
}
}
@@ -610,10 +563,10 @@ static void mtk_hdmi_hw_aud_src_disable(struct mtk_hdmi *hdmi)
{
u32 val;
- val = mtk_hdmi_read(hdmi, GRL_MIX_CTRL);
+ regmap_read(hdmi->regs, GRL_MIX_CTRL, &val);
val &= ~MIX_CTRL_SRC_EN;
- mtk_hdmi_write(hdmi, GRL_MIX_CTRL, val);
- mtk_hdmi_write(hdmi, GRL_SHIFT_L1, 0x00);
+ regmap_write(hdmi->regs, GRL_MIX_CTRL, val);
+ regmap_write(hdmi->regs, GRL_SHIFT_L1, 0x00);
}
static void mtk_hdmi_hw_aud_set_mclk(struct mtk_hdmi *hdmi,
@@ -621,7 +574,7 @@ static void mtk_hdmi_hw_aud_set_mclk(struct mtk_hdmi *hdmi,
{
u32 val;
- val = mtk_hdmi_read(hdmi, GRL_CFG5);
+ regmap_read(hdmi->regs, GRL_CFG5, &val);
val &= CFG5_CD_RATIO_MASK;
switch (mclk) {
@@ -644,7 +597,7 @@ static void mtk_hdmi_hw_aud_set_mclk(struct mtk_hdmi *hdmi,
val |= CFG5_FS256;
break;
}
- mtk_hdmi_write(hdmi, GRL_CFG5, val);
+ regmap_write(hdmi->regs, GRL_CFG5, val);
}
struct hdmi_acr_n {
@@ -722,15 +675,22 @@ static unsigned int hdmi_expected_cts(unsigned int audio_sample_rate,
128 * audio_sample_rate);
}
+static void mtk_hdmi_get_ncts(unsigned int sample_rate, unsigned int clock,
+ unsigned int *n, unsigned int *cts)
+{
+ *n = hdmi_recommended_n(sample_rate, clock);
+ *cts = hdmi_expected_cts(sample_rate, clock, *n);
+}
+
static void do_hdmi_hw_aud_set_ncts(struct mtk_hdmi *hdmi, unsigned int n,
unsigned int cts)
{
unsigned char val[NCTS_BYTES];
int i;
- mtk_hdmi_write(hdmi, GRL_NCTS, 0);
- mtk_hdmi_write(hdmi, GRL_NCTS, 0);
- mtk_hdmi_write(hdmi, GRL_NCTS, 0);
+ regmap_write(hdmi->regs, GRL_NCTS, 0);
+ regmap_write(hdmi->regs, GRL_NCTS, 0);
+ regmap_write(hdmi->regs, GRL_NCTS, 0);
memset(val, 0, sizeof(val));
val[0] = (cts >> 24) & 0xff;
@@ -743,7 +703,7 @@ static void do_hdmi_hw_aud_set_ncts(struct mtk_hdmi *hdmi, unsigned int n,
val[6] = n & 0xff;
for (i = 0; i < NCTS_BYTES; i++)
- mtk_hdmi_write(hdmi, GRL_NCTS, val[i]);
+ regmap_write(hdmi->regs, GRL_NCTS, val[i]);
}
static void mtk_hdmi_hw_aud_set_ncts(struct mtk_hdmi *hdmi,
@@ -752,14 +712,12 @@ static void mtk_hdmi_hw_aud_set_ncts(struct mtk_hdmi *hdmi,
{
unsigned int n, cts;
- n = hdmi_recommended_n(sample_rate, clock);
- cts = hdmi_expected_cts(sample_rate, clock, n);
+ mtk_hdmi_get_ncts(sample_rate, clock, &n, &cts);
dev_dbg(hdmi->dev, "%s: sample_rate=%u, clock=%d, cts=%u, n=%u\n",
__func__, sample_rate, clock, n, cts);
- mtk_hdmi_mask(hdmi, DUMMY_304, AUDIO_I2S_NCTS_SEL_64,
- AUDIO_I2S_NCTS_SEL);
+ regmap_update_bits(hdmi->regs, DUMMY_304, AUDIO_I2S_NCTS_SEL, AUDIO_I2S_NCTS_SEL_64);
do_hdmi_hw_aud_set_ncts(hdmi, n, cts);
}
@@ -879,7 +837,7 @@ static void mtk_hdmi_aud_set_input(struct mtk_hdmi *hdmi)
bool dst;
mtk_hdmi_hw_aud_set_channel_swap(hdmi, HDMI_AUD_SWAP_LFE_CC);
- mtk_hdmi_set_bits(hdmi, GRL_MIX_CTRL, MIX_CTRL_FLAT);
+ regmap_set_bits(hdmi->regs, GRL_MIX_CTRL, MIX_CTRL_FLAT);
if (hdmi->aud_param.aud_input_type == HDMI_AUD_INPUT_SPDIF &&
hdmi->aud_param.aud_codec == HDMI_AUDIO_CODING_TYPE_DST) {
@@ -911,7 +869,7 @@ static int mtk_hdmi_aud_set_src(struct mtk_hdmi *hdmi,
mtk_hdmi_hw_ncts_enable(hdmi, false);
mtk_hdmi_hw_aud_src_disable(hdmi);
- mtk_hdmi_clear_bits(hdmi, GRL_CFG2, CFG2_ACLK_INV);
+ regmap_clear_bits(hdmi->regs, GRL_CFG2, CFG2_ACLK_INV);
if (hdmi->aud_param.aud_input_type == HDMI_AUD_INPUT_I2S) {
switch (sample_rate) {
@@ -987,15 +945,14 @@ static int mtk_hdmi_setup_avi_infoframe(struct mtk_hdmi *hdmi,
return 0;
}
-static int mtk_hdmi_setup_spd_infoframe(struct mtk_hdmi *hdmi,
- const char *vendor,
- const char *product)
+static int mtk_hdmi_setup_spd_infoframe(struct mtk_hdmi *hdmi)
{
+ struct drm_bridge *bridge = &hdmi->bridge;
struct hdmi_spd_infoframe frame;
u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_SPD_INFOFRAME_SIZE];
ssize_t err;
- err = hdmi_spd_infoframe_init(&frame, vendor, product);
+ err = hdmi_spd_infoframe_init(&frame, bridge->vendor, bridge->product);
if (err < 0) {
dev_err(hdmi->dev, "Failed to initialize SPD infoframe: %zd\n",
err);
@@ -1068,21 +1025,6 @@ static int mtk_hdmi_setup_vendor_specific_infoframe(struct mtk_hdmi *hdmi,
return 0;
}
-static int mtk_hdmi_output_init(struct mtk_hdmi *hdmi)
-{
- struct hdmi_audio_param *aud_param = &hdmi->aud_param;
-
- hdmi->csp = HDMI_COLORSPACE_RGB;
- aud_param->aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
- aud_param->aud_sampe_size = HDMI_AUDIO_SAMPLE_SIZE_16;
- aud_param->aud_input_type = HDMI_AUD_INPUT_I2S;
- aud_param->aud_i2s_fmt = HDMI_I2S_MODE_I2S_24BIT;
- aud_param->aud_mclk = HDMI_AUD_MCLK_128FS;
- aud_param->aud_input_chan_type = HDMI_AUD_CHAN_TYPE_2_0;
-
- return 0;
-}
-
static void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi)
{
mtk_hdmi_hw_send_aud_packet(hdmi, true);
@@ -1095,20 +1037,6 @@ static void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi)
hdmi->audio_enable = false;
}
-static int mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi,
- struct hdmi_audio_param *param)
-{
- if (!hdmi->audio_enable) {
- dev_err(hdmi->dev, "hdmi audio is in disable state!\n");
- return -EINVAL;
- }
- dev_dbg(hdmi->dev, "codec:%d, input:%d, channel:%d, fs:%d\n",
- param->aud_codec, param->aud_input_type,
- param->aud_input_chan_type, param->codec_params.sample_rate);
- memcpy(&hdmi->aud_param, param, sizeof(*param));
- return mtk_hdmi_aud_output_config(hdmi, &hdmi->mode);
-}
-
static int mtk_hdmi_output_set_display_mode(struct mtk_hdmi *hdmi,
struct drm_display_mode *mode)
{
@@ -1167,13 +1095,12 @@ static int mtk_hdmi_clk_enable_audio(struct mtk_hdmi *hdmi)
return ret;
ret = clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_AUD_SPDIF]);
- if (ret)
- goto err;
+ if (ret) {
+ clk_disable_unprepare(hdmi->clk[MTK_HDMI_CLK_AUD_BCLK]);
+ return ret;
+ }
return 0;
-err:
- clk_disable_unprepare(hdmi->clk[MTK_HDMI_CLK_AUD_BCLK]);
- return ret;
}
static void mtk_hdmi_clk_disable_audio(struct mtk_hdmi *hdmi)
@@ -1208,22 +1135,11 @@ mtk_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_mode *mode)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
- struct drm_bridge *next_bridge;
dev_dbg(hdmi->dev, "xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode),
!!(mode->flags & DRM_MODE_FLAG_INTERLACE), mode->clock * 1000);
- next_bridge = drm_bridge_get_next_bridge(&hdmi->bridge);
- if (next_bridge) {
- struct drm_display_mode adjusted_mode;
-
- drm_mode_init(&adjusted_mode, mode);
- if (!drm_bridge_chain_mode_fixup(next_bridge, mode,
- &adjusted_mode))
- return MODE_BAD;
- }
-
if (hdmi->conf) {
if (hdmi->conf->cea_modes_only && !drm_match_cea_mode(mode))
return MODE_BAD;
@@ -1289,6 +1205,7 @@ static const struct drm_edid *mtk_hdmi_bridge_edid_read(struct drm_bridge *bridg
}
static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
@@ -1301,7 +1218,7 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge,
}
if (hdmi->next_bridge) {
- ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
+ ret = drm_bridge_attach(encoder, hdmi->next_bridge,
bridge, flags);
if (ret)
return ret;
@@ -1320,7 +1237,7 @@ static bool mtk_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
}
static void mtk_hdmi_bridge_atomic_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
@@ -1337,7 +1254,7 @@ static void mtk_hdmi_bridge_atomic_disable(struct drm_bridge *bridge,
}
static void mtk_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_state)
+ struct drm_atomic_state *state)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
@@ -1373,7 +1290,7 @@ static void mtk_hdmi_bridge_mode_set(struct drm_bridge *bridge,
}
static void mtk_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_state)
+ struct drm_atomic_state *state)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
@@ -1388,15 +1305,14 @@ static void mtk_hdmi_send_infoframe(struct mtk_hdmi *hdmi,
{
mtk_hdmi_setup_audio_infoframe(hdmi);
mtk_hdmi_setup_avi_infoframe(hdmi, mode);
- mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI");
+ mtk_hdmi_setup_spd_infoframe(hdmi);
if (mode->flags & DRM_MODE_FLAG_3D_MASK)
mtk_hdmi_setup_vendor_specific_infoframe(hdmi, mode);
}
static void mtk_hdmi_bridge_atomic_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_state)
+ struct drm_atomic_state *state)
{
- struct drm_atomic_state *state = old_state->base.state;
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
/* Retrieve the connector through the atomic state. */
@@ -1428,31 +1344,20 @@ static const struct drm_bridge_funcs mtk_hdmi_bridge_funcs = {
.edid_read = mtk_hdmi_bridge_edid_read,
};
-static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
- struct platform_device *pdev)
+static int mtk_hdmi_get_cec_dev(struct mtk_hdmi *hdmi, struct device *dev, struct device_node *np)
{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- struct device_node *cec_np, *remote, *i2c_np;
struct platform_device *cec_pdev;
- struct regmap *regmap;
- struct resource *mem;
+ struct device_node *cec_np;
int ret;
ret = mtk_hdmi_get_all_clk(hdmi, np);
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Failed to get clocks: %d\n", ret);
-
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get clocks\n");
/* The CEC module handles HDMI hotplug detection */
cec_np = of_get_compatible_child(np->parent, "mediatek,mt8173-cec");
- if (!cec_np) {
- dev_err(dev, "Failed to find CEC node\n");
- return -EINVAL;
- }
+ if (!cec_np)
+ return dev_err_probe(dev, -EINVAL, "Failed to find CEC node\n");
cec_pdev = of_find_device_by_node(cec_np);
if (!cec_pdev) {
@@ -1462,83 +1367,77 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
return -EPROBE_DEFER;
}
of_node_put(cec_np);
- hdmi->cec_dev = &cec_pdev->dev;
/*
* The mediatek,syscon-hdmi property contains a phandle link to the
* MMSYS_CONFIG device and the register offset of the HDMI_SYS_CFG
* registers it contains.
*/
- regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,syscon-hdmi");
- ret = of_property_read_u32_index(np, "mediatek,syscon-hdmi", 1,
- &hdmi->sys_offset);
- if (IS_ERR(regmap))
- ret = PTR_ERR(regmap);
- if (ret) {
- dev_err(dev,
- "Failed to get system configuration registers: %d\n",
- ret);
- goto put_device;
- }
- hdmi->sys_regmap = regmap;
+ hdmi->sys_regmap = syscon_regmap_lookup_by_phandle_args(np, "mediatek,syscon-hdmi",
+ 1, &hdmi->sys_offset);
+ if (IS_ERR(hdmi->sys_regmap))
+ return dev_err_probe(dev, PTR_ERR(hdmi->sys_regmap),
+ "Failed to get system configuration registers\n");
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi->regs = devm_ioremap_resource(dev, mem);
- if (IS_ERR(hdmi->regs)) {
- ret = PTR_ERR(hdmi->regs);
- goto put_device;
- }
+ hdmi->cec_dev = &cec_pdev->dev;
+ return 0;
+}
+
+static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *remote, *i2c_np;
+ int ret;
+
+ ret = mtk_hdmi_get_all_clk(hdmi, np);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get clocks\n");
+
+ hdmi->regs = device_node_to_regmap(dev->of_node);
+ if (IS_ERR(hdmi->regs))
+ return PTR_ERR(hdmi->regs);
remote = of_graph_get_remote_node(np, 1, 0);
- if (!remote) {
- ret = -EINVAL;
- goto put_device;
- }
+ if (!remote)
+ return -EINVAL;
if (!of_device_is_compatible(remote, "hdmi-connector")) {
hdmi->next_bridge = of_drm_find_bridge(remote);
if (!hdmi->next_bridge) {
dev_err(dev, "Waiting for external bridge\n");
of_node_put(remote);
- ret = -EPROBE_DEFER;
- goto put_device;
+ return -EPROBE_DEFER;
}
}
i2c_np = of_parse_phandle(remote, "ddc-i2c-bus", 0);
- if (!i2c_np) {
- dev_err(dev, "Failed to find ddc-i2c-bus node in %pOF\n",
- remote);
- of_node_put(remote);
- ret = -EINVAL;
- goto put_device;
- }
of_node_put(remote);
+ if (!i2c_np)
+ return dev_err_probe(dev, -EINVAL, "No ddc-i2c-bus in connector\n");
hdmi->ddc_adpt = of_find_i2c_adapter_by_node(i2c_np);
of_node_put(i2c_np);
- if (!hdmi->ddc_adpt) {
- dev_err(dev, "Failed to get ddc i2c adapter by node\n");
- ret = -EINVAL;
- goto put_device;
- }
+ if (!hdmi->ddc_adpt)
+ return dev_err_probe(dev, -EINVAL, "Failed to get ddc i2c adapter by node\n");
+
+ ret = mtk_hdmi_get_cec_dev(hdmi, dev, np);
+ if (ret)
+ return ret;
return 0;
-put_device:
- put_device(hdmi->cec_dev);
- return ret;
}
/*
* HDMI audio codec callbacks
*/
-static int mtk_hdmi_audio_hw_params(struct device *dev, void *data,
- struct hdmi_codec_daifmt *daifmt,
- struct hdmi_codec_params *params)
+static int mtk_hdmi_audio_params(struct mtk_hdmi *hdmi,
+ struct hdmi_codec_daifmt *daifmt,
+ struct hdmi_codec_params *params)
{
- struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
- struct hdmi_audio_param hdmi_params;
+ struct hdmi_audio_param aud_params = { 0 };
unsigned int chan = params->cea.channels;
dev_dbg(hdmi->dev, "%s: %u Hz, %d bit, %d channels\n", __func__,
@@ -1549,16 +1448,16 @@ static int mtk_hdmi_audio_hw_params(struct device *dev, void *data,
switch (chan) {
case 2:
- hdmi_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_2_0;
+ aud_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_2_0;
break;
case 4:
- hdmi_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_4_0;
+ aud_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_4_0;
break;
case 6:
- hdmi_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_5_1;
+ aud_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_5_1;
break;
case 8:
- hdmi_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_7_1;
+ aud_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_7_1;
break;
default:
dev_err(hdmi->dev, "channel[%d] not supported!\n", chan);
@@ -1582,27 +1481,45 @@ static int mtk_hdmi_audio_hw_params(struct device *dev, void *data,
switch (daifmt->fmt) {
case HDMI_I2S:
- hdmi_params.aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
- hdmi_params.aud_sampe_size = HDMI_AUDIO_SAMPLE_SIZE_16;
- hdmi_params.aud_input_type = HDMI_AUD_INPUT_I2S;
- hdmi_params.aud_i2s_fmt = HDMI_I2S_MODE_I2S_24BIT;
- hdmi_params.aud_mclk = HDMI_AUD_MCLK_128FS;
+ aud_params.aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
+ aud_params.aud_sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
+ aud_params.aud_input_type = HDMI_AUD_INPUT_I2S;
+ aud_params.aud_i2s_fmt = HDMI_I2S_MODE_I2S_24BIT;
+ aud_params.aud_mclk = HDMI_AUD_MCLK_128FS;
break;
case HDMI_SPDIF:
- hdmi_params.aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
- hdmi_params.aud_sampe_size = HDMI_AUDIO_SAMPLE_SIZE_16;
- hdmi_params.aud_input_type = HDMI_AUD_INPUT_SPDIF;
+ aud_params.aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
+ aud_params.aud_sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
+ aud_params.aud_input_type = HDMI_AUD_INPUT_SPDIF;
break;
default:
dev_err(hdmi->dev, "%s: Invalid DAI format %d\n", __func__,
daifmt->fmt);
return -EINVAL;
}
+ memcpy(&aud_params.codec_params, params, sizeof(aud_params.codec_params));
+ memcpy(&hdmi->aud_param, &aud_params, sizeof(aud_params));
+
+ dev_dbg(hdmi->dev, "codec:%d, input:%d, channel:%d, fs:%d\n",
+ aud_params.aud_codec, aud_params.aud_input_type,
+ aud_params.aud_input_chan_type, aud_params.codec_params.sample_rate);
- memcpy(&hdmi_params.codec_params, params,
- sizeof(hdmi_params.codec_params));
+ return 0;
+}
+
+static int mtk_hdmi_audio_hw_params(struct device *dev, void *data,
+ struct hdmi_codec_daifmt *daifmt,
+ struct hdmi_codec_params *params)
+{
+ struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
+
+ if (!hdmi->audio_enable) {
+ dev_err(hdmi->dev, "hdmi audio is in disable state!\n");
+ return -EINVAL;
+ }
- mtk_hdmi_audio_set_param(hdmi, &hdmi_params);
+ mtk_hdmi_audio_params(hdmi, daifmt, params);
+ mtk_hdmi_aud_output_config(hdmi, &hdmi->mode);
return 0;
}
@@ -1648,17 +1565,22 @@ static int mtk_hdmi_audio_get_eld(struct device *dev, void *data, uint8_t *buf,
return 0;
}
-static int mtk_hdmi_audio_hook_plugged_cb(struct device *dev, void *data,
- hdmi_codec_plugged_cb fn,
+static void mtk_hdmi_audio_set_plugged_cb(struct mtk_hdmi *hdmi, hdmi_codec_plugged_cb fn,
struct device *codec_dev)
{
- struct mtk_hdmi *hdmi = data;
-
mutex_lock(&hdmi->update_plugged_status_lock);
hdmi->plugged_cb = fn;
hdmi->codec_dev = codec_dev;
mutex_unlock(&hdmi->update_plugged_status_lock);
+}
+static int mtk_hdmi_audio_hook_plugged_cb(struct device *dev, void *data,
+ hdmi_codec_plugged_cb fn,
+ struct device *codec_dev)
+{
+ struct mtk_hdmi *hdmi = data;
+
+ mtk_hdmi_audio_set_plugged_cb(hdmi, fn, codec_dev);
mtk_hdmi_update_plugged_status(hdmi);
return 0;
@@ -1671,31 +1593,50 @@ static const struct hdmi_codec_ops mtk_hdmi_audio_codec_ops = {
.mute_stream = mtk_hdmi_audio_mute,
.get_eld = mtk_hdmi_audio_get_eld,
.hook_plugged_cb = mtk_hdmi_audio_hook_plugged_cb,
- .no_capture_mute = 1,
};
+static void mtk_hdmi_unregister_audio_driver(void *data)
+{
+ platform_device_unregister(data);
+}
+
static int mtk_hdmi_register_audio_driver(struct device *dev)
{
struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
+ struct hdmi_audio_param *aud_param = &hdmi->aud_param;
struct hdmi_codec_pdata codec_data = {
.ops = &mtk_hdmi_audio_codec_ops,
.max_i2s_channels = 2,
.i2s = 1,
.data = hdmi,
+ .no_capture_mute = 1,
};
- struct platform_device *pdev;
+ int ret;
+
+ aud_param->aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
+ aud_param->aud_sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
+ aud_param->aud_input_type = HDMI_AUD_INPUT_I2S;
+ aud_param->aud_i2s_fmt = HDMI_I2S_MODE_I2S_24BIT;
+ aud_param->aud_mclk = HDMI_AUD_MCLK_128FS;
+ aud_param->aud_input_chan_type = HDMI_AUD_CHAN_TYPE_2_0;
- pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
- PLATFORM_DEVID_AUTO, &codec_data,
- sizeof(codec_data));
- if (IS_ERR(pdev))
- return PTR_ERR(pdev);
+ hdmi->audio_pdev = platform_device_register_data(dev,
+ HDMI_CODEC_DRV_NAME,
+ PLATFORM_DEVID_AUTO,
+ &codec_data,
+ sizeof(codec_data));
+ if (IS_ERR(hdmi->audio_pdev))
+ return PTR_ERR(hdmi->audio_pdev);
+
+ ret = devm_add_action_or_reset(dev, mtk_hdmi_unregister_audio_driver,
+ hdmi->audio_pdev);
+ if (ret)
+ return ret;
- DRM_INFO("%s driver bound to HDMI\n", HDMI_CODEC_DRV_NAME);
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;
@@ -1713,57 +1654,46 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
return ret;
hdmi->phy = devm_phy_get(dev, "hdmi");
- if (IS_ERR(hdmi->phy)) {
- ret = PTR_ERR(hdmi->phy);
- dev_err(dev, "Failed to get HDMI PHY: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(hdmi->phy))
+ return dev_err_probe(dev, PTR_ERR(hdmi->phy),
+ "Failed to get HDMI PHY\n");
mutex_init(&hdmi->update_plugged_status_lock);
platform_set_drvdata(pdev, hdmi);
- ret = mtk_hdmi_output_init(hdmi);
- if (ret) {
- dev_err(dev, "Failed to initialize hdmi output\n");
- return ret;
- }
-
ret = mtk_hdmi_register_audio_driver(dev);
- if (ret) {
- dev_err(dev, "Failed to register audio driver: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to register audio driver\n");
hdmi->bridge.funcs = &mtk_hdmi_bridge_funcs;
hdmi->bridge.of_node = pdev->dev.of_node;
hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID
| DRM_BRIDGE_OP_HPD;
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
- drm_bridge_add(&hdmi->bridge);
+ hdmi->bridge.vendor = "MediaTek";
+ hdmi->bridge.product = "On-Chip HDMI";
+
+ ret = devm_drm_bridge_add(dev, &hdmi->bridge);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add bridge\n");
ret = mtk_hdmi_clk_enable_audio(hdmi);
- if (ret) {
- dev_err(dev, "Failed to enable audio clocks: %d\n", ret);
- goto err_bridge_remove;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable audio clocks\n");
return 0;
-
-err_bridge_remove:
- drm_bridge_remove(&hdmi->bridge);
- 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);
- drm_bridge_remove(&hdmi->bridge);
mtk_hdmi_clk_disable_audio(hdmi);
}
-#ifdef CONFIG_PM_SLEEP
-static int mtk_hdmi_suspend(struct device *dev)
+static __maybe_unused int mtk_hdmi_suspend(struct device *dev)
{
struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
@@ -1772,22 +1702,14 @@ static int mtk_hdmi_suspend(struct device *dev)
return 0;
}
-static int mtk_hdmi_resume(struct device *dev)
+static __maybe_unused int mtk_hdmi_resume(struct device *dev)
{
struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
- int ret = 0;
- ret = mtk_hdmi_clk_enable_audio(hdmi);
- if (ret) {
- dev_err(dev, "hdmi resume failed!\n");
- return ret;
- }
-
- return 0;
+ return mtk_hdmi_clk_enable_audio(hdmi);
}
-#endif
-static SIMPLE_DEV_PM_OPS(mtk_hdmi_pm_ops,
- mtk_hdmi_suspend, mtk_hdmi_resume);
+
+static SIMPLE_DEV_PM_OPS(mtk_hdmi_pm_ops, mtk_hdmi_suspend, mtk_hdmi_resume);
static const struct mtk_hdmi_conf mtk_hdmi_conf_mt2701 = {
.tz_disabled = true,
@@ -1798,50 +1720,26 @@ 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[] = {
- { .compatible = "mediatek,mt2701-hdmi",
- .data = &mtk_hdmi_conf_mt2701,
- },
- { .compatible = "mediatek,mt8167-hdmi",
- .data = &mtk_hdmi_conf_mt8167,
- },
- { .compatible = "mediatek,mt8173-hdmi",
- },
- {}
+static const struct of_device_id mtk_hdmi_of_ids[] = {
+ { .compatible = "mediatek,mt2701-hdmi", .data = &mtk_hdmi_conf_mt2701 },
+ { .compatible = "mediatek,mt8167-hdmi", .data = &mtk_hdmi_conf_mt8167 },
+ { .compatible = "mediatek,mt8173-hdmi" },
+ { /* sentinel */ }
};
-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 = 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,
},
};
-
-static struct platform_driver * const mtk_hdmi_drivers[] = {
- &mtk_hdmi_ddc_driver,
- &mtk_cec_driver,
- &mtk_hdmi_driver,
-};
-
-static int __init mtk_hdmitx_init(void)
-{
- return platform_register_drivers(mtk_hdmi_drivers,
- ARRAY_SIZE(mtk_hdmi_drivers));
-}
-
-static void __exit mtk_hdmitx_exit(void)
-{
- platform_unregister_drivers(mtk_hdmi_drivers,
- ARRAY_SIZE(mtk_hdmi_drivers));
-}
-
-module_init(mtk_hdmitx_init);
-module_exit(mtk_hdmitx_exit);
+module_platform_driver(mtk_hdmi_driver);
MODULE_AUTHOR("Jie Qiu <jie.qiu@mediatek.com>");
MODULE_DESCRIPTION("MediaTek HDMI Driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("DRM_MTK_HDMI_V1");
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.h b/drivers/gpu/drm/mediatek/mtk_hdmi.h
deleted file mode 100644
index 472bf141c92b..000000000000
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2014 MediaTek Inc.
- * Author: Jie Qiu <jie.qiu@mediatek.com>
- */
-#ifndef _MTK_HDMI_CTRL_H
-#define _MTK_HDMI_CTRL_H
-
-struct platform_driver;
-
-extern struct platform_driver mtk_cec_driver;
-extern struct platform_driver mtk_hdmi_ddc_driver;
-
-#endif /* _MTK_HDMI_CTRL_H */
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
index 54e46e440e0f..6358e1af69b4 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
@@ -20,7 +20,6 @@
#include <linux/of_platform.h>
#include "mtk_drm_drv.h"
-#include "mtk_hdmi.h"
#define SIF1_CLOK (288)
#define DDC_DDCMCTL0 (0x0)
@@ -279,21 +278,17 @@ static int mtk_hdmi_ddc_probe(struct platform_device *pdev)
return -ENOMEM;
ddc->clk = devm_clk_get(dev, "ddc-i2c");
- if (IS_ERR(ddc->clk)) {
- dev_err(dev, "get ddc_clk failed: %p ,\n", ddc->clk);
- return PTR_ERR(ddc->clk);
- }
+ if (IS_ERR(ddc->clk))
+ return dev_err_probe(dev, PTR_ERR(ddc->clk),
+ "get ddc_clk failed\n");
- 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);
ret = clk_prepare_enable(ddc->clk);
- if (ret) {
- dev_err(dev, "enable ddc clk failed!\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "enable ddc clk failed!\n");
strscpy(ddc->adap.name, "mediatek-hdmi-ddc", sizeof(ddc->adap.name));
ddc->adap.owner = THIS_MODULE;
@@ -305,8 +300,8 @@ static int mtk_hdmi_ddc_probe(struct platform_device *pdev)
ret = i2c_add_adapter(&ddc->adap);
if (ret < 0) {
- dev_err(dev, "failed to add bus to i2c core\n");
- goto err_clk_disable;
+ clk_disable_unprepare(ddc->clk);
+ return dev_err_probe(dev, ret, "failed to add bus to i2c core\n");
}
platform_set_drvdata(pdev, ddc);
@@ -317,10 +312,6 @@ static int mtk_hdmi_ddc_probe(struct platform_device *pdev)
&mem->end);
return 0;
-
-err_clk_disable:
- clk_disable_unprepare(ddc->clk);
- return ret;
}
static void mtk_hdmi_ddc_remove(struct platform_device *pdev)
@@ -339,12 +330,13 @@ MODULE_DEVICE_TABLE(of, mtk_hdmi_ddc_match);
struct platform_driver mtk_hdmi_ddc_driver = {
.probe = mtk_hdmi_ddc_probe,
- .remove_new = mtk_hdmi_ddc_remove,
+ .remove = mtk_hdmi_ddc_remove,
.driver = {
.name = "mediatek-hdmi-ddc",
.of_match_table = mtk_hdmi_ddc_match,
},
};
+module_platform_driver(mtk_hdmi_ddc_driver);
MODULE_AUTHOR("Jie Qiu <jie.qiu@mediatek.com>");
MODULE_DESCRIPTION("MediaTek HDMI DDC Driver");
diff --git a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c
index ee9ce9b6d078..7982788ae9df 100644
--- a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c
@@ -291,7 +291,6 @@ static const struct component_ops mtk_mdp_rdma_component_ops = {
static int mtk_mdp_rdma_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct resource *res;
struct mtk_mdp_rdma *priv;
int ret = 0;
@@ -299,18 +298,15 @@ static int mtk_mdp_rdma_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(priv->regs)) {
- dev_err(dev, "failed to ioremap rdma\n");
- return PTR_ERR(priv->regs);
- }
+ priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->regs))
+ return dev_err_probe(dev, PTR_ERR(priv->regs),
+ "failed to ioremap rdma\n");
priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "failed to get rdma clk\n");
- return PTR_ERR(priv->clk);
- }
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "failed to get rdma clk\n");
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
@@ -324,9 +320,9 @@ static int mtk_mdp_rdma_probe(struct platform_device *pdev)
ret = component_add(dev, &mtk_mdp_rdma_component_ops);
if (ret != 0) {
pm_runtime_disable(dev);
- dev_err(dev, "Failed to add component: %d\n", ret);
+ return dev_err_probe(dev, ret, "Failed to add component\n");
}
- return ret;
+ return 0;
}
static void mtk_mdp_rdma_remove(struct platform_device *pdev)
@@ -343,10 +339,9 @@ MODULE_DEVICE_TABLE(of, mtk_mdp_rdma_driver_dt_match);
struct platform_driver mtk_mdp_rdma_driver = {
.probe = mtk_mdp_rdma_probe,
- .remove_new = mtk_mdp_rdma_remove,
+ .remove = 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 0d6451c149b6..b4e3e5a3428b 100644
--- a/drivers/gpu/drm/mediatek/mtk_padding.c
+++ b/drivers/gpu/drm/mediatek/mtk_padding.c
@@ -11,9 +11,9 @@
#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
+#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)
@@ -103,23 +103,19 @@ static int mtk_padding_probe(struct platform_device *pdev)
return -ENOMEM;
priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "failed to get clk\n");
- return PTR_ERR(priv->clk);
- }
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "failed to get clk\n");
priv->reg = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
- if (IS_ERR(priv->reg)) {
- dev_err(dev, "failed to do ioremap\n");
- return PTR_ERR(priv->reg);
- }
+ if (IS_ERR(priv->reg))
+ return dev_err_probe(dev, PTR_ERR(priv->reg),
+ "failed to do ioremap\n");
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
- if (ret) {
- dev_err(dev, "failed to get gce client reg\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get gce client reg\n");
#endif
platform_set_drvdata(pdev, priv);
@@ -137,10 +133,9 @@ static int mtk_padding_probe(struct platform_device *pdev)
return 0;
}
-static int mtk_padding_remove(struct platform_device *pdev)
+static void mtk_padding_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &mtk_padding_component_ops);
- return 0;
}
static const struct of_device_id mtk_padding_driver_dt_match[] = {
@@ -154,7 +149,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_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_plane.c
index ddc9355b06d5..655106bbb76d 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_plane.c
@@ -13,11 +13,11 @@
#include <drm/drm_gem_atomic_helper.h>
#include <linux/align.h>
-#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_drm_plane.h"
+#include "mtk_gem.h"
+#include "mtk_plane.h"
static const u64 modifiers[] = {
DRM_FORMAT_MOD_LINEAR,
@@ -93,15 +93,15 @@ static bool mtk_plane_format_mod_supported(struct drm_plane *plane,
return true;
}
-static void mtk_drm_plane_destroy_state(struct drm_plane *plane,
- struct drm_plane_state *state)
+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_atomic_state *state, bool flip)
{
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
plane);
@@ -117,8 +117,8 @@ static int mtk_plane_atomic_async_check(struct drm_plane *plane,
if (!plane->state->fb)
return -EINVAL;
- ret = mtk_drm_crtc_plane_check(new_plane_state->crtc, plane,
- to_mtk_plane_state(new_plane_state));
+ ret = mtk_crtc_plane_check(new_plane_state->crtc, plane,
+ to_mtk_plane_state(new_plane_state));
if (ret)
return ret;
@@ -135,7 +135,7 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state,
{
struct drm_framebuffer *fb = new_state->fb;
struct drm_gem_object *gem;
- struct mtk_drm_gem_obj *mtk_gem;
+ struct mtk_gem_obj *mtk_gem;
unsigned int pitch, format;
u64 modifier;
dma_addr_t addr;
@@ -227,12 +227,14 @@ static void mtk_plane_atomic_async_update(struct drm_plane *plane,
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_drm_crtc_async_update(new_state->crtc, plane, state);
+ mtk_crtc_async_update(new_state->crtc, plane, state);
}
static const struct drm_plane_funcs mtk_plane_funcs = {
@@ -241,7 +243,7 @@ static const struct drm_plane_funcs mtk_plane_funcs = {
.destroy = drm_plane_cleanup,
.reset = mtk_plane_reset,
.atomic_duplicate_state = mtk_plane_duplicate_state,
- .atomic_destroy_state = mtk_drm_plane_destroy_state,
+ .atomic_destroy_state = mtk_plane_destroy_state,
.format_mod_supported = mtk_plane_format_mod_supported,
};
@@ -260,8 +262,8 @@ static int mtk_plane_atomic_check(struct drm_plane *plane,
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));
+ ret = mtk_crtc_plane_check(new_plane_state->crtc, plane,
+ to_mtk_plane_state(new_plane_state));
if (ret)
return ret;
@@ -318,8 +320,8 @@ static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
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)
+ unsigned int supported_rotations, const u32 blend_modes,
+ const u32 *formats, size_t num_formats, unsigned int plane_idx)
{
int err;
@@ -336,7 +338,23 @@ int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
return err;
}
- if (supported_rotations & ~DRM_MODE_ROTATE_0) {
+ /*
+ * The hardware does not support repositioning planes by muxing: their
+ * Z-position is infact fixed and the only way to change the actual
+ * order is to swap the contents of the entire register set of one
+ * overlay with another, which may be more expensive than desired.
+ *
+ * With no repositioning, the caller of this function guarantees that
+ * the plane_idx is correct. This means that, for example, the PRIMARY
+ * plane fed to this function will always have plane_idx zero.
+ */
+ err = drm_plane_create_zpos_immutable_property(plane, plane_idx);
+ if (err) {
+ DRM_ERROR("Failed to create zpos property for plane %u\n", plane_idx);
+ return err;
+ }
+
+ if (supported_rotations) {
err = drm_plane_create_rotation_property(plane,
DRM_MODE_ROTATE_0,
supported_rotations);
@@ -344,6 +362,16 @@ int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
DRM_INFO("Create rotation property failed\n");
}
+ err = drm_plane_create_alpha_property(plane);
+ if (err)
+ DRM_ERROR("failed to create property: alpha\n");
+
+ if (blend_modes) {
+ err = drm_plane_create_blend_mode_property(plane, blend_modes);
+ if (err)
+ DRM_ERROR("failed to create property: blend_mode\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_plane.h
index 99aff7da0831..3b13b89989c7 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.h
+++ b/drivers/gpu/drm/mediatek/mtk_plane.h
@@ -4,8 +4,8 @@
* Author: CK Hu <ck.hu@mediatek.com>
*/
-#ifndef _MTK_DRM_PLANE_H_
-#define _MTK_DRM_PLANE_H_
+#ifndef _MTK_PLANE_H_
+#define _MTK_PLANE_H_
#include <drm/drm_crtc.h>
#include <linux/types.h>
@@ -48,7 +48,6 @@ to_mtk_plane_state(struct drm_plane_state *state)
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);
-
+ unsigned int supported_rotations, const u32 blend_modes,
+ const u32 *formats, size_t num_formats, unsigned int plane_idx);
#endif