Commit 017da39e authored by Dave Airlie's avatar Dave Airlie

Merge tag 'mediatek-drm-next-6.9' of...

Merge tag 'mediatek-drm-next-6.9' of https://git.kernel.org/pub/scm/linux/kernel/git/chunkuang.hu/linux into drm-next

Mediatek DRM Next for Linux 6.9

1. Add display driver for MT8188 VDOSYS1
2. DSI driver cleanups
3. Filter modes according to hardware capability
4. Fix a null pointer crash in mtk_drm_crtc_finish_page_flip
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Chun-Kuang Hu <chunkuang.hu@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20240229162143.28957-1-chunkuang.hu@kernel.org
parents 1752f138 c958e86e
......@@ -73,6 +73,8 @@ void mtk_merge_advance_config(struct device *dev, unsigned int l_w, unsigned int
struct cmdq_pkt *cmdq_pkt);
void mtk_merge_start_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt);
void mtk_merge_stop_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt);
enum drm_mode_status mtk_merge_mode_valid(struct device *dev,
const struct drm_display_mode *mode);
void mtk_ovl_bgclr_in_on(struct device *dev);
void mtk_ovl_bgclr_in_off(struct device *dev);
......@@ -131,6 +133,8 @@ unsigned int mtk_ovl_adaptor_layer_nr(struct device *dev);
struct device *mtk_ovl_adaptor_dma_dev_get(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,
const struct drm_display_mode *mode);
void mtk_rdma_bypass_shadow(struct device *dev);
int mtk_rdma_clk_enable(struct device *dev);
......
......@@ -222,6 +222,71 @@ void mtk_merge_clk_disable(struct device *dev)
clk_disable_unprepare(priv->clk);
}
enum drm_mode_status mtk_merge_mode_valid(struct device *dev,
const struct drm_display_mode *mode)
{
struct mtk_disp_merge *priv = dev_get_drvdata(dev);
unsigned long rate;
rate = clk_get_rate(priv->clk);
/* Convert to KHz and round the number */
rate = (rate + 500) / 1000;
if (rate && mode->clock > rate) {
dev_dbg(dev, "invalid clock: %d (>%lu)\n", mode->clock, rate);
return MODE_CLOCK_HIGH;
}
/*
* Measure the bandwidth requirement of hardware prefetch (per frame)
*
* let N = prefetch buffer size in lines
* (ex. N=3, then prefetch buffer size = 3 lines)
*
* prefetch size = htotal * N (pixels)
* time per line = 1 / fps / vtotal (seconds)
* duration = vbp * time per line
* = vbp / fps / vtotal
*
* data rate = prefetch size / duration
* = htotal * N / (vbp / fps / vtotal)
* = htotal * vtotal * fps * N / vbp
* = clk * N / vbp (pixels per second)
*
* Say 4K60 (CEA-861) is the maximum mode supported by the SoC
* data rate = 594000K * N / 72 = 8250 (standard)
* (remove K * N due to the same unit)
*
* For 2560x1440@144 (clk=583600K, vbp=17):
* data rate = 583600 / 17 ~= 34329 > 8250 (NG)
*
* For 2560x1440@120 (clk=497760K, vbp=77):
* data rate = 497760 / 77 ~= 6464 < 8250 (OK)
*
* A non-standard 4K60 timing (clk=521280K, vbp=54)
* data rate = 521280 / 54 ~= 9653 > 8250 (NG)
*
* Bandwidth requirement of hardware prefetch increases significantly
* when the VBP decreases (more than 4x in this example).
*
* The proposed formula is only one way to estimate whether our SoC
* supports the mode setting. The basic idea behind it is just to check
* if the data rate requirement is too high (directly proportional to
* pixel clock, inversely proportional to vbp). Please adjust the
* function if it doesn't fit your situation in the future.
*/
rate = mode->clock / (mode->vtotal - mode->vsync_end);
if (rate > 8250) {
dev_dbg(dev, "invalid rate: %lu (>8250): " DRM_MODE_FMT "\n",
rate, DRM_MODE_ARG(mode));
return MODE_BAD;
}
return MODE_OK;
}
static int mtk_disp_merge_bind(struct device *dev, struct device *master,
void *data)
{
......
......@@ -30,6 +30,7 @@ enum mtk_ovl_adaptor_comp_type {
OVL_ADAPTOR_TYPE_ETHDR,
OVL_ADAPTOR_TYPE_MDP_RDMA,
OVL_ADAPTOR_TYPE_MERGE,
OVL_ADAPTOR_TYPE_PADDING,
OVL_ADAPTOR_TYPE_NUM,
};
......@@ -47,6 +48,14 @@ enum mtk_ovl_adaptor_comp_id {
OVL_ADAPTOR_MERGE1,
OVL_ADAPTOR_MERGE2,
OVL_ADAPTOR_MERGE3,
OVL_ADAPTOR_PADDING0,
OVL_ADAPTOR_PADDING1,
OVL_ADAPTOR_PADDING2,
OVL_ADAPTOR_PADDING3,
OVL_ADAPTOR_PADDING4,
OVL_ADAPTOR_PADDING5,
OVL_ADAPTOR_PADDING6,
OVL_ADAPTOR_PADDING7,
OVL_ADAPTOR_ID_MAX
};
......@@ -67,6 +76,7 @@ static const char * const private_comp_stem[OVL_ADAPTOR_TYPE_NUM] = {
[OVL_ADAPTOR_TYPE_ETHDR] = "ethdr",
[OVL_ADAPTOR_TYPE_MDP_RDMA] = "vdo1-rdma",
[OVL_ADAPTOR_TYPE_MERGE] = "merge",
[OVL_ADAPTOR_TYPE_PADDING] = "padding",
};
static const struct mtk_ddp_comp_funcs ethdr = {
......@@ -79,6 +89,14 @@ static const struct mtk_ddp_comp_funcs ethdr = {
static const struct mtk_ddp_comp_funcs merge = {
.clk_enable = mtk_merge_clk_enable,
.clk_disable = mtk_merge_clk_disable,
.mode_valid = mtk_merge_mode_valid,
};
static const struct mtk_ddp_comp_funcs padding = {
.clk_enable = mtk_padding_clk_enable,
.clk_disable = mtk_padding_clk_disable,
.start = mtk_padding_start,
.stop = mtk_padding_stop,
};
static const struct mtk_ddp_comp_funcs rdma = {
......@@ -102,6 +120,14 @@ static const struct ovl_adaptor_comp_match comp_matches[OVL_ADAPTOR_ID_MAX] = {
[OVL_ADAPTOR_MERGE1] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE2, 2, &merge },
[OVL_ADAPTOR_MERGE2] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE3, 3, &merge },
[OVL_ADAPTOR_MERGE3] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE4, 4, &merge },
[OVL_ADAPTOR_PADDING0] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING0, 0, &padding },
[OVL_ADAPTOR_PADDING1] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING1, 1, &padding },
[OVL_ADAPTOR_PADDING2] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING2, 2, &padding },
[OVL_ADAPTOR_PADDING3] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING3, 3, &padding },
[OVL_ADAPTOR_PADDING4] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING4, 4, &padding },
[OVL_ADAPTOR_PADDING5] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING5, 5, &padding },
[OVL_ADAPTOR_PADDING6] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING6, 6, &padding },
[OVL_ADAPTOR_PADDING7] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING7, 7, &padding },
};
void mtk_ovl_adaptor_layer_config(struct device *dev, unsigned int idx,
......@@ -317,6 +343,22 @@ void mtk_ovl_adaptor_clk_disable(struct device *dev)
}
}
enum drm_mode_status mtk_ovl_adaptor_mode_valid(struct device *dev,
const struct drm_display_mode *mode)
{
int i;
struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
dev = ovl_adaptor->ovl_adaptor_comp[i];
if (!dev || !comp_matches[i].funcs->mode_valid)
continue;
return comp_matches[i].funcs->mode_valid(dev, mode);
}
return MODE_OK;
}
unsigned int mtk_ovl_adaptor_layer_nr(struct device *dev)
{
return MTK_OVL_ADAPTOR_LAYER_NUM;
......@@ -437,6 +479,7 @@ static int ovl_adaptor_comp_get_id(struct device *dev, struct device_node *node,
}
static const struct of_device_id mtk_ovl_adaptor_comp_dt_ids[] = {
{ .compatible = "mediatek,mt8188-disp-padding", .data = (void *)OVL_ADAPTOR_TYPE_PADDING },
{ .compatible = "mediatek,mt8195-disp-ethdr", .data = (void *)OVL_ADAPTOR_TYPE_ETHDR },
{ .compatible = "mediatek,mt8195-disp-merge", .data = (void *)OVL_ADAPTOR_TYPE_MERGE },
{ .compatible = "mediatek,mt8195-vdo1-rdma", .data = (void *)OVL_ADAPTOR_TYPE_MDP_RDMA },
......
......@@ -95,11 +95,13 @@ static void mtk_drm_crtc_finish_page_flip(struct mtk_drm_crtc *mtk_crtc)
struct drm_crtc *crtc = &mtk_crtc->base;
unsigned long flags;
spin_lock_irqsave(&crtc->dev->event_lock, flags);
drm_crtc_send_vblank_event(crtc, mtk_crtc->event);
drm_crtc_vblank_put(crtc);
mtk_crtc->event = NULL;
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
if (mtk_crtc->event) {
spin_lock_irqsave(&crtc->dev->event_lock, flags);
drm_crtc_send_vblank_event(crtc, mtk_crtc->event);
drm_crtc_vblank_put(crtc);
mtk_crtc->event = NULL;
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
}
}
static void mtk_drm_finish_page_flip(struct mtk_drm_crtc *mtk_crtc)
......@@ -213,6 +215,22 @@ static void mtk_drm_crtc_destroy_state(struct drm_crtc *crtc,
kfree(to_mtk_crtc_state(state));
}
static enum drm_mode_status
mtk_drm_crtc_mode_valid(struct drm_crtc *crtc,
const struct drm_display_mode *mode)
{
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
enum drm_mode_status status = MODE_OK;
int i;
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
status = mtk_ddp_comp_mode_valid(mtk_crtc->ddp_comp[i], mode);
if (status != MODE_OK)
break;
}
return status;
}
static bool mtk_drm_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
......@@ -831,6 +849,7 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = {
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,
......
......@@ -418,6 +418,7 @@ static const struct mtk_ddp_comp_funcs ddp_ovl_adaptor = {
.remove = mtk_ovl_adaptor_remove_comp,
.get_formats = mtk_ovl_adaptor_get_formats,
.get_num_formats = mtk_ovl_adaptor_get_num_formats,
.mode_valid = mtk_ovl_adaptor_mode_valid,
};
static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
......
......@@ -12,6 +12,8 @@
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/soc/mediatek/mtk-mutex.h>
#include <drm/drm_modes.h>
struct device;
struct device_node;
struct drm_crtc;
......@@ -85,6 +87,7 @@ struct mtk_ddp_comp_funcs {
void (*add)(struct device *dev, struct mtk_mutex *mutex);
void (*remove)(struct device *dev, struct mtk_mutex *mutex);
unsigned int (*encoder_index)(struct device *dev);
enum drm_mode_status (*mode_valid)(struct device *dev, const struct drm_display_mode *mode);
};
struct mtk_ddp_comp {
......@@ -126,6 +129,15 @@ static inline void mtk_ddp_comp_clk_disable(struct mtk_ddp_comp *comp)
comp->funcs->clk_disable(comp->dev);
}
static inline
enum drm_mode_status mtk_ddp_comp_mode_valid(struct mtk_ddp_comp *comp,
const struct drm_display_mode *mode)
{
if (comp && comp->funcs && comp->funcs->mode_valid)
return comp->funcs->mode_valid(comp->dev, mode);
return MODE_OK;
}
static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp,
unsigned int w, unsigned int h,
unsigned int vrefresh, unsigned int bpc,
......
......@@ -293,7 +293,7 @@ static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = {
.main_len = ARRAY_SIZE(mt8188_mtk_ddp_main),
.conn_routes = mt8188_mtk_ddp_main_routes,
.num_conn_routes = ARRAY_SIZE(mt8188_mtk_ddp_main_routes),
.mmsys_dev_num = 1,
.mmsys_dev_num = 2,
};
static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
......@@ -334,6 +334,8 @@ static const struct of_device_id mtk_drm_of_ids[] = {
.data = &mt8186_mmsys_driver_data},
{ .compatible = "mediatek,mt8188-vdosys0",
.data = &mt8188_vdosys0_driver_data},
{ .compatible = "mediatek,mt8188-vdosys1",
.data = &mt8195_vdosys1_driver_data},
{ .compatible = "mediatek,mt8192-mmsys",
.data = &mt8192_mmsys_driver_data},
{ .compatible = "mediatek,mt8195-mmsys",
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment