From 81d707f32eb913f3296246ab9e2e6edf1a97064b Mon Sep 17 00:00:00 2001 From: Shuijing Li Date: Mon, 11 Sep 2023 20:07:58 +0800 Subject: [PATCH 01/38] dt-bindings: display: mediatek: dsi: Add compatible for MediaTek MT8188 Add dt-binding documentation of dsi for MediaTek MT8188 SoC. Signed-off-by: Shuijing Li Signed-off-by: Jitao Shi Acked-by: Krzysztof Kozlowski Reviewed-by: Matthias Brugger Reviewed-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20230911120800.17369-2-shuijing.li@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- .../devicetree/bindings/display/mediatek/mediatek,dsi.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml index 12441b937684..537e5304b730 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml @@ -30,6 +30,7 @@ properties: - mediatek,mt8173-dsi - mediatek,mt8183-dsi - mediatek,mt8186-dsi + - mediatek,mt8188-dsi - items: - enum: - mediatek,mt6795-dsi From 2ccf6e2580cdc192b6cb034c98485cca6ccc8f58 Mon Sep 17 00:00:00 2001 From: Shuijing Li Date: Mon, 11 Sep 2023 20:07:59 +0800 Subject: [PATCH 02/38] drm/mediatek: dsi: Add dsi cmdq_ctl to send panel initial code For mt8188, add dsi cmdq reg control to send long packets to panel initialization. MT8188 hardware has been changed to automatically set the cmdq_size value by default when sending long packets. In this patch, the cmdq_size value is set manually instead. Remain consistent with previous IC. Signed-off-by: Shuijing Li Reviewed-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20230911120800.17369-3-shuijing.li@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_dsi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index d8bfc2cce54d..623aa829ef6b 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -86,6 +86,7 @@ #define DSI_CMDQ_SIZE 0x60 #define CMDQ_SIZE 0x3f +#define CMDQ_SIZE_SEL BIT(15) #define DSI_HSTX_CKL_WC 0x64 @@ -178,6 +179,7 @@ struct mtk_dsi_driver_data { const u32 reg_cmdq_off; bool has_shadow_ctl; bool has_size_ctl; + bool cmdq_long_packet_ctl; }; struct mtk_dsi { @@ -996,6 +998,10 @@ static void mtk_dsi_cmdq(struct mtk_dsi *dsi, const struct mipi_dsi_msg *msg) mtk_dsi_mask(dsi, reg_cmdq_off, cmdq_mask, reg_val); mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE, cmdq_size); + if (dsi->driver_data->cmdq_long_packet_ctl) { + /* Disable setting cmdq_size automatically for long packets */ + mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE_SEL, CMDQ_SIZE_SEL); + } } static ssize_t mtk_dsi_host_send_cmd(struct mtk_dsi *dsi, From 814d5341f3146a97833c5f7587a349d660e9be4c Mon Sep 17 00:00:00 2001 From: Shuijing Li Date: Mon, 11 Sep 2023 20:08:00 +0800 Subject: [PATCH 03/38] drm/mediatek: Add mt8188 dsi compatible to mtk_dsi.c Add the compatible because there are different definitions for cmdq register bit control in mt8188. Signed-off-by: Shuijing Li Reviewed-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20230911120800.17369-4-shuijing.li@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 2 ++ drivers/gpu/drm/mediatek/mtk_dsi.c | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 93552d76b6e7..034056d0f741 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -765,6 +765,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { .data = (void *)MTK_DSI }, { .compatible = "mediatek,mt8186-dsi", .data = (void *)MTK_DSI }, + { .compatible = "mediatek,mt8188-dsi", + .data = (void *)MTK_DSI }, { } }; diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 623aa829ef6b..49bfc1dd11ae 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -1212,6 +1212,13 @@ static const struct mtk_dsi_driver_data mt8186_dsi_driver_data = { .has_size_ctl = true, }; +static const struct mtk_dsi_driver_data mt8188_dsi_driver_data = { + .reg_cmdq_off = 0xd00, + .has_shadow_ctl = true, + .has_size_ctl = true, + .cmdq_long_packet_ctl = true, +}; + static const struct of_device_id mtk_dsi_of_match[] = { { .compatible = "mediatek,mt2701-dsi", .data = &mt2701_dsi_driver_data }, @@ -1221,6 +1228,8 @@ static const struct of_device_id mtk_dsi_of_match[] = { .data = &mt8183_dsi_driver_data }, { .compatible = "mediatek,mt8186-dsi", .data = &mt8186_dsi_driver_data }, + { .compatible = "mediatek,mt8188-dsi", + .data = &mt8188_dsi_driver_data }, { }, }; MODULE_DEVICE_TABLE(of, mtk_dsi_of_match); From b0b0d811eac6b4c52cb9ad632fa6384cf48869e7 Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Thu, 7 Sep 2023 17:14:25 +0800 Subject: [PATCH 04/38] drm/mediatek: Fix coverity issue with unintentional integer overflow 1. Instead of multiplying 2 variable of different types. Change to assign a value of one variable and then multiply the other variable. 2. Add a int variable for multiplier calculation instead of calculating different types multiplier with dma_addr_t variable directly. Fixes: 1a64a7aff8da ("drm/mediatek: Fix cursor plane no update") Signed-off-by: Jason-JH.Lin Reviewed-by: Alexandre Mergnat Reviewed-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20230907091425.9526-1-jason-jh.lin@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_drm_gem.c | 9 +++++- drivers/gpu/drm/mediatek/mtk_drm_plane.c | 39 ++++++++++++++++++------ 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c b/drivers/gpu/drm/mediatek/mtk_drm_gem.c index 9f364df52478..f6632a0fe509 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c @@ -121,7 +121,14 @@ int mtk_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, int ret; args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8); - args->size = args->pitch * args->height; + + /* + * Multiply 2 variables of different types, + * for example: args->size = args->spacing * args->height; + * may cause coverity issue with unintentional overflow. + */ + args->size = args->pitch; + args->size *= args->height; mtk_gem = mtk_drm_gem_create(dev, args->size, false); if (IS_ERR(mtk_gem)) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index db2f70ae060d..5acb03b7c6fe 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -141,6 +141,7 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state, dma_addr_t addr; dma_addr_t hdr_addr = 0; unsigned int hdr_pitch = 0; + int offset; gem = fb->obj[0]; mtk_gem = to_mtk_gem_obj(gem); @@ -150,8 +151,15 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state, modifier = fb->modifier; if (modifier == DRM_FORMAT_MOD_LINEAR) { - addr += (new_state->src.x1 >> 16) * fb->format->cpp[0]; - addr += (new_state->src.y1 >> 16) * pitch; + /* + * Using dma_addr_t variable to calculate with multiplier of different types, + * for example: addr += (new_state->src.x1 >> 16) * fb->format->cpp[0]; + * may cause coverity issue with unintentional overflow. + */ + offset = (new_state->src.x1 >> 16) * fb->format->cpp[0]; + addr += offset; + offset = (new_state->src.y1 >> 16) * pitch; + addr += offset; } else { int width_in_blocks = ALIGN(fb->width, AFBC_DATA_BLOCK_WIDTH) / AFBC_DATA_BLOCK_WIDTH; @@ -159,21 +167,34 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state, / AFBC_DATA_BLOCK_HEIGHT; int x_offset_in_blocks = (new_state->src.x1 >> 16) / AFBC_DATA_BLOCK_WIDTH; int y_offset_in_blocks = (new_state->src.y1 >> 16) / AFBC_DATA_BLOCK_HEIGHT; - int hdr_size; + int hdr_size, hdr_offset; hdr_pitch = width_in_blocks * AFBC_HEADER_BLOCK_SIZE; pitch = width_in_blocks * AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT * fb->format->cpp[0]; hdr_size = ALIGN(hdr_pitch * height_in_blocks, AFBC_HEADER_ALIGNMENT); + hdr_offset = hdr_pitch * y_offset_in_blocks + + AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks; + + /* + * Using dma_addr_t variable to calculate with multiplier of different types, + * for example: addr += hdr_pitch * y_offset_in_blocks; + * may cause coverity issue with unintentional overflow. + */ + hdr_addr = addr + hdr_offset; - hdr_addr = addr + hdr_pitch * y_offset_in_blocks + - AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks; /* The data plane is offset by 1 additional block. */ - addr = addr + hdr_size + - pitch * y_offset_in_blocks + - AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT * - fb->format->cpp[0] * (x_offset_in_blocks + 1); + offset = pitch * y_offset_in_blocks + + AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT * + fb->format->cpp[0] * (x_offset_in_blocks + 1); + + /* + * Using dma_addr_t variable to calculate with multiplier of different types, + * for example: addr += pitch * y_offset_in_blocks; + * may cause coverity issue with unintentional overflow. + */ + addr = addr + hdr_size + offset; } mtk_plane_state->pending.enable = true; From 579932444fb88cc035d2e0f6cb4aeb0e072b35b9 Mon Sep 17 00:00:00 2001 From: Shuijing Li Date: Tue, 22 Aug 2023 10:41:52 +0800 Subject: [PATCH 05/38] dt-bindings: display: mediatek: dp: Add compatible for MediaTek MT8188 Add dt-binding documentation of dp-tx for MediaTek MT8188 SoC. Signed-off-by: Shuijing Li Signed-off-by: Jitao Shi Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Acked-by: Krzysztof Kozlowski Link: https://patchwork.kernel.org/project/dri-devel/patch/20230822024155.26670-2-shuijing.li@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- .../devicetree/bindings/display/mediatek/mediatek,dp.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml index ff781f2174a0..2aef1eb32e11 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml @@ -21,6 +21,8 @@ description: | properties: compatible: enum: + - mediatek,mt8188-dp-tx + - mediatek,mt8188-edp-tx - mediatek,mt8195-dp-tx - mediatek,mt8195-edp-tx From 2d503773483edb1c0ffc24ad47eef2b60e8c340a Mon Sep 17 00:00:00 2001 From: Shuijing Li Date: Tue, 22 Aug 2023 10:41:53 +0800 Subject: [PATCH 06/38] drm/mediatek: dp: Add the audio packet flag to mtk_dp_data struct The audio packet arrangement function is to only arrange audio packets into the Hblanking area. In order to align with the HW default setting of mt8195, this function needs to be turned off. Signed-off-by: Shuijing Li Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20230822024155.26670-3-shuijing.li@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_dp.c | 14 ++++++++++++++ drivers/gpu/drm/mediatek/mtk_dp_reg.h | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index 2cb47f663756..2f220472a08a 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -141,6 +141,7 @@ struct mtk_dp_data { unsigned int smc_cmd; const struct mtk_dp_efuse_fmt *efuse_fmt; bool audio_supported; + bool audio_pkt_in_hblank_area; }; static const struct mtk_dp_efuse_fmt mt8195_edp_efuse_fmt[MTK_DP_CAL_MAX] = { @@ -1394,6 +1395,18 @@ static void mtk_dp_sdp_set_down_cnt_init_in_hblank(struct mtk_dp *mtk_dp) SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_MASK); } +static void mtk_dp_audio_sample_arrange_disable(struct mtk_dp *mtk_dp) +{ + /* arrange audio packets into the Hblanking and Vblanking area */ + if (!mtk_dp->data->audio_pkt_in_hblank_area) + return; + + mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3374, 0, + SDP_ASP_INSERT_IN_HBLANK_DP_ENC1_P0_MASK); + mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3374, 0, + SDP_DOWN_ASP_CNT_INIT_DP_ENC1_P0_MASK); +} + static void mtk_dp_setup_tu(struct mtk_dp *mtk_dp) { u32 sram_read_start = min_t(u32, MTK_DP_TBC_BUF_READ_START_ADDR, @@ -1403,6 +1416,7 @@ static void mtk_dp_setup_tu(struct mtk_dp *mtk_dp) MTK_DP_PIX_PER_ADDR); mtk_dp_set_sram_read_start(mtk_dp, sram_read_start); mtk_dp_setup_encoder(mtk_dp); + mtk_dp_audio_sample_arrange_disable(mtk_dp); mtk_dp_sdp_set_down_cnt_init_in_hblank(mtk_dp); mtk_dp_sdp_set_down_cnt_init(mtk_dp, sram_read_start); } diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h index 84e38cef03c2..f38d6ff12afe 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h @@ -228,6 +228,11 @@ VIDEO_STABLE_CNT_THRD_DP_ENC1_P0 | \ SDP_DP13_EN_DP_ENC1_P0 | \ BS2BS_MODE_DP_ENC1_P0) + +#define MTK_DP_ENC1_P0_3374 0x3374 +#define SDP_ASP_INSERT_IN_HBLANK_DP_ENC1_P0_MASK BIT(12) +#define SDP_DOWN_ASP_CNT_INIT_DP_ENC1_P0_MASK GENMASK(11, 0) + #define MTK_DP_ENC1_P0_33F4 0x33f4 #define DP_ENC_DUMMY_RW_1_AUDIO_RST_EN BIT(0) #define DP_ENC_DUMMY_RW_1 BIT(9) From d2f7f1ba5cbec030c0011831d9624f6b27b1d71a Mon Sep 17 00:00:00 2001 From: Shuijing Li Date: Tue, 22 Aug 2023 10:41:54 +0800 Subject: [PATCH 07/38] drm/mediatek: dp: Add the audio divider to mtk_dp_data struct Due to the difference of HW, different dividers need to be set. Signed-off-by: Shuijing Li Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20230822024155.26670-4-shuijing.li@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_dp.c | 5 ++++- drivers/gpu/drm/mediatek/mtk_dp_reg.h | 12 ++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index 2f220472a08a..5fd6f3972140 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -142,6 +142,7 @@ struct mtk_dp_data { const struct mtk_dp_efuse_fmt *efuse_fmt; bool audio_supported; bool audio_pkt_in_hblank_area; + u16 audio_m_div2_bit; }; static const struct mtk_dp_efuse_fmt mt8195_edp_efuse_fmt[MTK_DP_CAL_MAX] = { @@ -650,7 +651,7 @@ static void mtk_dp_audio_sdp_asp_set_channels(struct mtk_dp *mtk_dp, static void mtk_dp_audio_set_divider(struct mtk_dp *mtk_dp) { mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_30BC, - AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2, + mtk_dp->data->audio_m_div2_bit, AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MASK); } @@ -2755,6 +2756,7 @@ static const struct mtk_dp_data mt8195_edp_data = { .smc_cmd = MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE, .efuse_fmt = mt8195_edp_efuse_fmt, .audio_supported = false, + .audio_m_div2_bit = MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2, }; static const struct mtk_dp_data mt8195_dp_data = { @@ -2762,6 +2764,7 @@ static const struct mtk_dp_data mt8195_dp_data = { .smc_cmd = MTK_DP_SIP_ATF_VIDEO_UNMUTE, .efuse_fmt = mt8195_dp_efuse_fmt, .audio_supported = true, + .audio_m_div2_bit = MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2, }; static const struct of_device_id 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 f38d6ff12afe..b9859ef067ce 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h @@ -159,12 +159,12 @@ #define MTK_DP_ENC0_P0_30BC 0x30bc #define ISRC_CONT_DP_ENC0_P0 BIT(0) #define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MASK GENMASK(10, 8) -#define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_2 (1 << 8) -#define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_4 (2 << 8) -#define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_8 (3 << 8) -#define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2 (5 << 8) -#define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_4 (6 << 8) -#define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_8 (7 << 8) +#define MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_2 (1 << 8) +#define MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_4 (2 << 8) +#define MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_8 (3 << 8) +#define MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2 (5 << 8) +#define MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_4 (6 << 8) +#define MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_8 (7 << 8) #define MTK_DP_ENC0_P0_30D8 0x30d8 #define MTK_DP_ENC0_P0_312C 0x312c #define ASP_HB2_DP_ENC0_P0_MASK GENMASK(7, 0) From 350c3fe907fbfccb534198d69a580f5fef4ab834 Mon Sep 17 00:00:00 2001 From: Shuijing Li Date: Tue, 22 Aug 2023 10:41:55 +0800 Subject: [PATCH 08/38] drm/mediatek: dp: Add support MT8188 dp/edp function Add support MT8188 dp/edp function Signed-off-by: Shuijing Li Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20230822024155.26670-5-shuijing.li@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_dp.c | 17 +++++++++++++++++ drivers/gpu/drm/mediatek/mtk_dp_reg.h | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index 5fd6f3972140..93f6f8efabd6 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -2751,6 +2751,15 @@ static int mtk_dp_resume(struct device *dev) 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, + .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, +}; + static const struct mtk_dp_data mt8195_edp_data = { .bridge_type = DRM_MODE_CONNECTOR_eDP, .smc_cmd = MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE, @@ -2768,6 +2777,14 @@ static const struct mtk_dp_data mt8195_dp_data = { }; static const struct of_device_id mtk_dp_of_match[] = { + { + .compatible = "mediatek,mt8188-edp-tx", + .data = &mt8195_edp_data, + }, + { + .compatible = "mediatek,mt8188-dp-tx", + .data = &mt8188_dp_data, + }, { .compatible = "mediatek,mt8195-edp-tx", .data = &mt8195_edp_data, diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h index b9859ef067ce..709b79480693 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h @@ -165,6 +165,12 @@ #define MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2 (5 << 8) #define MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_4 (6 << 8) #define MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_8 (7 << 8) +#define MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_2 (1 << 8) +#define MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_4 (2 << 8) +#define MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_8 (3 << 8) +#define MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2 (4 << 8) +#define MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_4 (5 << 8) +#define MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_8 (7 << 8) #define MTK_DP_ENC0_P0_30D8 0x30d8 #define MTK_DP_ENC0_P0_312C 0x312c #define ASP_HB2_DP_ENC0_P0_MASK GENMASK(7, 0) From dab12fa8d2bd3868cf2de485ed15a3feef28a13d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 14 Sep 2023 18:53:17 +0300 Subject: [PATCH 09/38] drm/mediatek/dp: fix memory leak on ->get_edid callback audio detection The sads returned by drm_edid_to_sad() needs to be freed. Fixes: e71a8ebbe086 ("drm/mediatek: dp: Audio support for MT8195") Cc: Guillaume Ranquet Cc: Bo-Chen Chen Cc: AngeloGioacchino Del Regno Cc: Dmitry Osipenko Cc: Chun-Kuang Hu Cc: Philipp Zabel Cc: Matthias Brugger Cc: dri-devel@lists.freedesktop.org Cc: linux-mediatek@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: # v6.1+ Signed-off-by: Jani Nikula Reviewed-by: Chen-Yu Tsai Link: https://patchwork.kernel.org/project/dri-devel/patch/20230914155317.2511876-1-jani.nikula@intel.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_dp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index 93f6f8efabd6..da023de5317a 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -2049,7 +2049,6 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge, bool enabled = mtk_dp->enabled; struct edid *new_edid = NULL; struct mtk_dp_audio_cfg *audio_caps = &mtk_dp->info.audio_cur_cfg; - struct cea_sad *sads; if (!enabled) { drm_atomic_bridge_chain_pre_enable(bridge, connector->state->state); @@ -2068,7 +2067,11 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge, } if (new_edid) { + struct cea_sad *sads; + audio_caps->sad_count = drm_edid_to_sad(new_edid, &sads); + kfree(sads); + audio_caps->detect_monitor = drm_detect_monitor_audio(new_edid); } From fcaf9761fd5884a64eaac48536f8c27ecfd2e6bc Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 14 Sep 2023 16:10:58 +0300 Subject: [PATCH 10/38] drm/mediatek/dp: fix memory leak on ->get_edid callback error path Setting new_edid to NULL leaks the buffer. Fixes: f70ac097a2cf ("drm/mediatek: Add MT8195 Embedded DisplayPort driver") Cc: Markus Schneider-Pargmann Cc: Guillaume Ranquet Cc: Bo-Chen Chen Cc: CK Hu Cc: AngeloGioacchino Del Regno Cc: Dmitry Osipenko Cc: Chun-Kuang Hu Cc: Philipp Zabel Cc: Matthias Brugger Cc: dri-devel@lists.freedesktop.org Cc: linux-mediatek@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: # v6.1+ Signed-off-by: Jani Nikula Reviewed-by: Guillaume Ranquet Link: https://patchwork.kernel.org/project/dri-devel/patch/20230914131058.2472260-1-jani.nikula@intel.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_dp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index da023de5317a..e4c16ba9902d 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -2063,6 +2063,7 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge, */ if (mtk_dp_parse_capabilities(mtk_dp)) { drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n"); + kfree(new_edid); new_edid = NULL; } From 609252ea46643f437febf312fbea1464df60b585 Mon Sep 17 00:00:00 2001 From: Shuijing Li Date: Wed, 23 Aug 2023 17:20:47 +0800 Subject: [PATCH 11/38] drm/mediatek: dsi: Add mode_valid callback to DSI bridge Support IGT (Intel GPU Tools) in Mediatek DSI driver. According to the description of MIPI Alliance Specification for D-PHY Version 1.1, the maximum supported data rate is 1.5Gbps, so add mode_valid callback to dsi bridge to filter out the data rate exceeding the Specification. Signed-off-by: Shuijing Li Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20230823092047.32258-1-shuijing.li@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_dsi.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 49bfc1dd11ae..798611570666 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -808,6 +808,25 @@ static void mtk_dsi_bridge_atomic_post_disable(struct drm_bridge *bridge, mtk_dsi_poweroff(dsi); } +static enum drm_mode_status +mtk_dsi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct mtk_dsi *dsi = bridge_to_dsi(bridge); + u32 bpp; + + if (dsi->format == MIPI_DSI_FMT_RGB565) + bpp = 16; + else + bpp = 24; + + if (mode->clock * bpp / dsi->lanes > 1500000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + static const struct drm_bridge_funcs mtk_dsi_bridge_funcs = { .attach = mtk_dsi_bridge_attach, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, @@ -817,6 +836,7 @@ static const struct drm_bridge_funcs mtk_dsi_bridge_funcs = { .atomic_pre_enable = mtk_dsi_bridge_atomic_pre_enable, .atomic_post_disable = mtk_dsi_bridge_atomic_post_disable, .atomic_reset = drm_atomic_helper_bridge_reset, + .mode_valid = mtk_dsi_bridge_mode_valid, .mode_set = mtk_dsi_bridge_mode_set, }; From ff64e4c31d969cdba20a41969edb3def15f3aaa0 Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Wed, 4 Oct 2023 10:40:05 +0800 Subject: [PATCH 12/38] drm/mediatek: Add mmsys_dev_num to mt8188 vdosys0 driver data Add missing mmsys_dev_num to mt8188 vdosys0 driver data. Fixes: 54b48080278a ("drm/mediatek: Add mediatek-drm of vdosys0 support for mt8188") Signed-off-by: Jason-JH.Lin Reviewed-by: CK Hu Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Fei Shao Tested-by: Fei Shao Link: https://patchwork.kernel.org/project/dri-devel/patch/20231004024013.18956-2-jason-jh.lin@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 034056d0f741..ff4d245dfaba 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -288,6 +288,7 @@ static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = { static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = { .main_path = mt8188_mtk_ddp_main, .main_len = ARRAY_SIZE(mt8188_mtk_ddp_main), + .mmsys_dev_num = 1, }; static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = { From 26c35d1d1646e593e3a82748b19d33b164871ae8 Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Wed, 4 Oct 2023 10:40:06 +0800 Subject: [PATCH 13/38] drm/mediatek: Add crtc path enum for all_drm_priv array Add mtk_drm_crtc_path enum for each display path. Instead of using array index of all_drm_priv in mtk_drm_kms_init(), mtk_drm_crtc_path enum can make code more readable. Signed-off-by: Jason-JH.Lin Reviewed-by: Fei Shao Reviewed-by: CK Hu Reviewed-by: AngeloGioacchino Del Regno Tested-by: Fei Shao Link: https://patchwork.kernel.org/project/dri-devel/patch/20231004024013.18956-3-jason-jh.lin@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 6 +++--- drivers/gpu/drm/mediatek/mtk_drm_drv.h | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index ff4d245dfaba..8fe10e72edcb 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -469,21 +469,21 @@ 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 (i == 0 && priv_n->data->main_len) { + 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); if (ret) goto err_component_unbind; continue; - } else if (i == 1 && priv_n->data->ext_len) { + } 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); if (ret) goto err_component_unbind; continue; - } else if (i == 2 && priv_n->data->third_len) { + } 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); if (ret) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h index eb2fd45941f0..f4de8bb27685 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h @@ -9,11 +9,17 @@ #include #include "mtk_drm_ddp_comp.h" -#define MAX_CRTC 3 #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 { + CRTC_MAIN, + CRTC_EXT, + CRTC_THIRD, + MAX_CRTC, +}; + struct device; struct device_node; struct drm_crtc; From ebba0960993045787ca00bb0932d83dad98c2e26 Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Wed, 4 Oct 2023 10:40:07 +0800 Subject: [PATCH 14/38] drm/mediatek: Fix using wrong drm private data to bind mediatek-drm According to mtk_drm_kms_init(), the all_drm_private array in each drm private data stores all drm private data in display path order. In mtk_drm_get_all_drm_priv(), each element in all_drm_priv should have one display path private data, such as: all_drm_priv[CRTC_MAIN] should only have main_path data all_drm_priv[CRTC_EXT] should only have ext_path data all_drm_priv[CRTC_THIRD] should only have third_path data So we need to add the length checking for each display path before assigning their drm private data into all_drm_priv array. Then the all_drm_private array in each drm private data needs to be assigned in their display path order. Fixes: 1ef7ed48356c ("drm/mediatek: Modify mediatek-drm for mt8195 multi mmsys support") Signed-off-by: Jason-JH.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Tested-by: Fei Shao Link: https://patchwork.kernel.org/project/dri-devel/patch/20231004024013.18956-4-jason-jh.lin@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 8fe10e72edcb..436d46bc23f3 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -352,6 +352,7 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev) { struct mtk_drm_private *drm_priv = dev_get_drvdata(dev); struct mtk_drm_private *all_drm_priv[MAX_CRTC]; + struct mtk_drm_private *temp_drm_priv; struct device_node *phandle = dev->parent->of_node; const struct of_device_id *of_id; struct device_node *node; @@ -371,11 +372,21 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev) continue; drm_dev = device_find_child(&pdev->dev, NULL, mtk_drm_match); - if (!drm_dev || !dev_get_drvdata(drm_dev)) + if (!drm_dev) continue; - all_drm_priv[cnt] = dev_get_drvdata(drm_dev); - if (all_drm_priv[cnt] && all_drm_priv[cnt]->mtk_drm_bound) + temp_drm_priv = dev_get_drvdata(drm_dev); + if (!temp_drm_priv) + continue; + + if (temp_drm_priv->data->main_len) + all_drm_priv[CRTC_MAIN] = temp_drm_priv; + else if (temp_drm_priv->data->ext_len) + all_drm_priv[CRTC_EXT] = temp_drm_priv; + else if (temp_drm_priv->data->third_len) + all_drm_priv[CRTC_THIRD] = temp_drm_priv; + + if (temp_drm_priv->mtk_drm_bound) cnt++; if (cnt == MAX_CRTC) From a260f5624dfc6ec3eb7b5349f51d34c687c07b5c Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Wed, 4 Oct 2023 10:40:08 +0800 Subject: [PATCH 15/38] drm/mediatek: Add encoder_index interface for mtk_ddp_comp_funcs To support dynamic connector selection function, each ddp_comp need to get their encoder_index to identify which connector should be selected. Add encoder_index interface for mtk_ddp_comp_funcs to get the encoder identifier by drm_encoder_index(). Then drm driver will call mtk_ddp_comp_encoder_index_set() to store the encoder_index to each ddp_comp in connector routes. Signed-off-by: Jason-JH.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20231004024013.18956-5-jason-jh.lin@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h index febcaeef16a1..0797b3ac75d8 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h @@ -80,12 +80,14 @@ struct mtk_ddp_comp_funcs { void (*disconnect)(struct device *dev, struct device *mmsys_dev, unsigned int next); void (*add)(struct device *dev, struct mtk_mutex *mutex); void (*remove)(struct device *dev, struct mtk_mutex *mutex); + unsigned int (*encoder_index)(struct device *dev); }; struct mtk_ddp_comp { struct device *dev; int irq; unsigned int id; + int encoder_index; const struct mtk_ddp_comp_funcs *funcs; }; @@ -275,6 +277,12 @@ static inline bool mtk_ddp_comp_disconnect(struct mtk_ddp_comp *comp, struct dev return false; } +static inline void mtk_ddp_comp_encoder_index_set(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->encoder_index) + comp->encoder_index = (int)comp->funcs->encoder_index(comp->dev); +} + int mtk_ddp_comp_get_id(struct device_node *node, enum mtk_ddp_comp_type comp_type); unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm, From 01389b324c97ff8f04e9c33b9ee246084f9f6dd2 Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Wed, 4 Oct 2023 10:40:09 +0800 Subject: [PATCH 16/38] drm/mediatek: Add connector dynamic selection capability Add dynamic select available connector flow in mtk_drm_crtc_create() and mtk_drm_crtc_atomic_enable(). In mtk_drm_crtc_create(), if there is a connector routes array in drm driver data, all components definded in the connector routes array will be checked and their encoder_index will be set. In mtk_drm_crtc_atomic_enable(), crtc will check its encoder_index to identify which componet in the connector routes array should append. Signed-off-by: Jason-JH.Lin Signed-off-by: Nancy Lin Signed-off-by: Nathan Lu Tested-by: Fei Shao Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20231004024013.18956-6-jason-jh.lin@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 72 ++++++++++++++++++++- drivers/gpu/drm/mediatek/mtk_drm_crtc.h | 5 +- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 30 ++++++++- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 13 +++- drivers/gpu/drm/mediatek/mtk_drm_drv.h | 7 ++ 5 files changed, 120 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index b6fa4ad2f94d..742218691080 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -63,6 +63,8 @@ struct mtk_drm_crtc { struct mtk_mutex *mutex; unsigned int ddp_comp_nr; struct mtk_ddp_comp **ddp_comp; + unsigned int num_conn_routes; + const struct mtk_drm_route *conn_routes; /* lock for display hardware access */ struct mutex hw_lock; @@ -647,6 +649,43 @@ static void mtk_drm_crtc_disable_vblank(struct drm_crtc *crtc) mtk_ddp_comp_disable_vblank(comp); } +static void mtk_drm_crtc_update_output(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + int crtc_index = drm_crtc_index(crtc); + int i; + struct device *dev; + struct drm_crtc_state *crtc_state = state->crtcs[crtc_index].new_state; + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); + struct mtk_drm_private *priv; + unsigned int encoder_mask = crtc_state->encoder_mask; + + if (!crtc_state->connectors_changed) + return; + + if (!mtk_crtc->num_conn_routes) + return; + + priv = ((struct mtk_drm_private *)crtc->dev->dev_private)->all_drm_private[crtc_index]; + dev = priv->dev; + + dev_dbg(dev, "connector change:%d, encoder mask:0x%x for crtc:%d\n", + crtc_state->connectors_changed, encoder_mask, crtc_index); + + for (i = 0; i < mtk_crtc->num_conn_routes; i++) { + unsigned int comp_id = mtk_crtc->conn_routes[i].route_ddp; + struct mtk_ddp_comp *comp = &priv->ddp_comp[comp_id]; + + if (comp->encoder_index >= 0 && + (encoder_mask & BIT(comp->encoder_index))) { + mtk_crtc->ddp_comp[mtk_crtc->ddp_comp_nr - 1] = comp; + dev_dbg(dev, "Add comp_id: %d at path index %d\n", + comp->id, mtk_crtc->ddp_comp_nr - 1); + break; + } + } +} + int mtk_drm_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane, struct mtk_plane_state *state) { @@ -685,6 +724,8 @@ static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc, return; } + mtk_drm_crtc_update_output(crtc, state); + ret = mtk_crtc_ddp_hw_init(mtk_crtc); if (ret) { pm_runtime_put(comp->dev); @@ -884,7 +925,8 @@ struct device *mtk_drm_crtc_dma_dev_get(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) + 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; @@ -935,7 +977,8 @@ 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, + mtk_crtc->ddp_comp = devm_kmalloc_array(dev, + mtk_crtc->ddp_comp_nr + (conn_routes ? 1 : 0), sizeof(*mtk_crtc->ddp_comp), GFP_KERNEL); if (!mtk_crtc->ddp_comp) @@ -1038,5 +1081,30 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, init_waitqueue_head(&mtk_crtc->cb_blocking_queue); } #endif + + if (conn_routes) { + for (i = 0; i < num_conn_routes; i++) { + unsigned int comp_id = conn_routes[i].route_ddp; + struct device_node *node = priv->comp_node[comp_id]; + struct mtk_ddp_comp *comp = &priv->ddp_comp[comp_id]; + + if (!comp->dev) { + dev_dbg(dev, "comp_id:%d, Component %pOF not initialized\n", + comp_id, node); + /* mark encoder_index to -1, if route comp device is not enabled */ + comp->encoder_index = -1; + continue; + } + + mtk_ddp_comp_encoder_index_set(&priv->ddp_comp[comp_id]); + } + + mtk_crtc->num_conn_routes = num_conn_routes; + mtk_crtc->conn_routes = conn_routes; + + /* increase ddp_comp_nr at the end of mtk_drm_crtc_create */ + mtk_crtc->ddp_comp_nr++; + } + return 0; } diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h index 3e9046993d09..3c224595fa71 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h @@ -8,6 +8,7 @@ #include #include "mtk_drm_ddp_comp.h" +#include "mtk_drm_drv.h" #include "mtk_drm_plane.h" #define MTK_LUT_SIZE 512 @@ -18,7 +19,9 @@ 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); + 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, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index 771f4e173353..02f0ada3754b 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -507,6 +507,31 @@ 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) +{ + int ret; + unsigned int i; + + if (!routes) { + ret = -EINVAL; + goto err; + } + + for (i = 0; i < num_routes; i++) + if (dev == ddp_comp[routes[i].route_ddp].dev) + return BIT(routes[i].crtc_id); + + ret = -ENODEV; +err: + + DRM_INFO("Failed to find comp in ddp table, ret = %d\n", ret); + + return 0; +} + int mtk_ddp_comp_get_id(struct device_node *node, enum mtk_ddp_comp_type comp_type) { @@ -538,7 +563,10 @@ unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm, private->data->third_len, private->ddp_comp)) ret = BIT(2); else - DRM_INFO("Failed to find comp in ddp table\n"); + ret = mtk_drm_find_comp_in_ddp_conn_path(dev, + private->data->conn_routes, + private->data->num_conn_routes, + private->ddp_comp); return ret; } diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 436d46bc23f3..4d520d0cb127 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -424,6 +424,11 @@ static bool mtk_drm_find_mmsys_comp(struct mtk_drm_private *private, int comp_id if (drv_data->third_path[i] == comp_id) return true; + if (drv_data->num_conn_routes) + for (i = 0; i < drv_data->num_conn_routes; i++) + if (drv_data->conn_routes[i].route_ddp == comp_id) + return true; + return false; } @@ -482,21 +487,23 @@ static int mtk_drm_kms_init(struct drm_device *drm) 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->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); + 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); + priv_n->data->third_len, j, NULL, 0); if (ret) goto err_component_unbind; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h index f4de8bb27685..6f98fff4f1a4 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h @@ -28,6 +28,11 @@ struct drm_fb_helper; struct drm_property; struct regmap; +struct mtk_drm_route { + const unsigned int crtc_id; + const unsigned int route_ddp; +}; + struct mtk_mmsys_driver_data { const unsigned int *main_path; unsigned int main_len; @@ -35,6 +40,8 @@ struct mtk_mmsys_driver_data { unsigned int ext_len; const unsigned int *third_path; unsigned int third_len; + const struct mtk_drm_route *conn_routes; + unsigned int num_conn_routes; bool shadow_register; unsigned int mmsys_id; From f6ec9da1e7ac1c52c6496b0ffb140622be858734 Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Wed, 4 Oct 2023 10:40:10 +0800 Subject: [PATCH 17/38] drm/mediatek: dpi: Support dynamic connector selection Add implementation of mtk_dpi_encoder_index to mtk_ddp_comp_func to make mtk_dpi support dynamic connector selection. Signed-off-by: Jason-JH.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20231004024013.18956-7-jason-jh.lin@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_drv.h | 1 + drivers/gpu/drm/mediatek/mtk_dpi.c | 9 +++++++++ drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 1 + 3 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h index 2254038519e1..5f07037670e9 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h @@ -44,6 +44,7 @@ void mtk_dither_set_common(void __iomem *regs, struct cmdq_client_reg *cmdq_reg, void mtk_dpi_start(struct device *dev); void mtk_dpi_stop(struct device *dev); +unsigned int mtk_dpi_encoder_index(struct device *dev); void mtk_dsi_ddp_start(struct device *dev); void mtk_dsi_ddp_stop(struct device *dev); diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 2f931e4e2b60..4e3d9f7b4d8c 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -781,6 +781,15 @@ void mtk_dpi_stop(struct device *dev) mtk_dpi_power_off(dpi); } +unsigned int mtk_dpi_encoder_index(struct device *dev) +{ + struct mtk_dpi *dpi = dev_get_drvdata(dev); + unsigned int encoder_index = drm_encoder_index(&dpi->encoder); + + dev_dbg(dev, "encoder index:%d\n", encoder_index); + return encoder_index; +} + static int mtk_dpi_bind(struct device *dev, struct device *master, void *data) { struct mtk_dpi *dpi = dev_get_drvdata(dev); diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index 02f0ada3754b..601755925520 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -304,6 +304,7 @@ static const struct mtk_ddp_comp_funcs ddp_dither = { static const struct mtk_ddp_comp_funcs ddp_dpi = { .start = mtk_dpi_start, .stop = mtk_dpi_stop, + .encoder_index = mtk_dpi_encoder_index, }; static const struct mtk_ddp_comp_funcs ddp_dsc = { From 00d035228f8c57277d497340bf5bb0d1df2caa1e Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Wed, 4 Oct 2023 10:40:12 +0800 Subject: [PATCH 18/38] drm/mediatek: dsi: Support dynamic connector selection Add implementation of mtk_dsi_encoder_index to mtk_ddp_comp_func to make mtk_dsi support dynamic connector selection. Signed-off-by: Jason-JH.Lin Reviewed-by: CK Hu Reviewed-by: Fei Shao Reviewed-by: AngeloGioacchino Del Regno Tested-by: Fei Shao Link: https://patchwork.kernel.org/project/dri-devel/patch/20231004024013.18956-9-jason-jh.lin@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_drv.h | 1 + drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 1 + drivers/gpu/drm/mediatek/mtk_dsi.c | 9 +++++++++ 3 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h index 5f07037670e9..fdaa21b6a9da 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h @@ -48,6 +48,7 @@ unsigned int mtk_dpi_encoder_index(struct device *dev); void mtk_dsi_ddp_start(struct device *dev); void mtk_dsi_ddp_stop(struct device *dev); +unsigned int mtk_dsi_encoder_index(struct device *dev); int mtk_gamma_clk_enable(struct device *dev); void mtk_gamma_clk_disable(struct device *dev); diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index 601755925520..f3345af12cb8 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -318,6 +318,7 @@ static const struct mtk_ddp_comp_funcs ddp_dsc = { static const struct mtk_ddp_comp_funcs ddp_dsi = { .start = mtk_dsi_ddp_start, .stop = mtk_dsi_ddp_stop, + .encoder_index = mtk_dsi_encoder_index, }; static const struct mtk_ddp_comp_funcs ddp_gamma = { diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 798611570666..dc0d4bae4ff8 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -887,6 +887,15 @@ err_cleanup_encoder: return ret; } +unsigned int mtk_dsi_encoder_index(struct device *dev) +{ + struct mtk_dsi *dsi = dev_get_drvdata(dev); + unsigned int encoder_index = drm_encoder_index(&dsi->encoder); + + dev_dbg(dev, "encoder index:%d\n", encoder_index); + return encoder_index; +} + static int mtk_dsi_bind(struct device *dev, struct device *master, void *data) { int ret; From 26fdd23ff861d5436f70f67a09161b06d2c306e2 Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Wed, 4 Oct 2023 10:40:11 +0800 Subject: [PATCH 19/38] drm/mediatek: Support dynamic selection of MT8188 VDOSYS0 Move DDP_COMPONENT_DP_INTF0 from mt8188_mtk_ddp_main array to a connector routes array called mt8188_mtk_ddp_main_routes and add DDP_COMPONENT_DSI0 to mt8188_mtk_ddp_main_routes to support dynamic selection capability for mt8188. Signed-off-by: Jason-JH.Lin Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Nathan Lu Reviewed-by: Matthias Brugger Reviewed-by: Fei Shao Tested-by: Fei Shao Link: https://patchwork.kernel.org/project/dri-devel/patch/20231004024013.18956-8-jason-jh.lin@mediatek.com/ Link: https://patchwork.kernel.org/project/dri-devel/patch/20231004024013.18956-10-jason-jh.lin@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 4d520d0cb127..2dfaa613276a 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -186,7 +186,11 @@ static const unsigned int mt8188_mtk_ddp_main[] = { DDP_COMPONENT_GAMMA, DDP_COMPONENT_POSTMASK0, DDP_COMPONENT_DITHER0, - DDP_COMPONENT_DP_INTF0, +}; + +static const struct mtk_drm_route mt8188_mtk_ddp_main_routes[] = { + {0, DDP_COMPONENT_DP_INTF0}, + {0, DDP_COMPONENT_DSI0}, }; static const unsigned int mt8192_mtk_ddp_main[] = { @@ -288,6 +292,8 @@ static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = { static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = { .main_path = mt8188_mtk_ddp_main, .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, }; From 3ec71e05ae6e7f46512e568ed81c92be589003dd Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Wed, 9 Aug 2023 20:57:21 +0800 Subject: [PATCH 20/38] drm/mediatek: Fix iommu fault by swapping FBs after updating plane state According to the comment in drm_atomic_helper_async_commit(), we should make sure FBs have been swapped, so that cleanups in the new_state performs a cleanup in the old FB. So we should move swapping FBs after calling mtk_plane_update_new_state(), to avoid using the old FB which could be freed. Fixes: 1a64a7aff8da ("drm/mediatek: Fix cursor plane no update") Signed-off-by: Jason-JH.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Reviewed-by: Alexandre Mergnat Link: https://patchwork.kernel.org/project/linux-mediatek/patch/20230809125722.24112-2-jason-jh.lin@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_drm_plane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 5acb03b7c6fe..ddc9355b06d5 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -227,9 +227,9 @@ 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; - swap(plane->state->fb, new_state->fb); 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); From 53412dc2905401207f264dc30890f6b9e41524a6 Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Wed, 9 Aug 2023 20:57:22 +0800 Subject: [PATCH 21/38] drm/mediatek: Fix iommu fault during crtc enabling The difference between drm_atomic_helper_commit_tail() and drm_atomic_helper_commit_tail_rpm() is drm_atomic_helper_commit_tail() will commit plane first and then enable crtc, drm_atomic_helper_commit_tail_rpm() will enable crtc first and then commit plane. Before mediatek-drm enables crtc, the power and clk required by OVL have not been turned on, so the commit plane cannot be committed before crtc is enabled. That means OVL layer should not be enabled before crtc is enabled. Therefore, the atomic_commit_tail of mediatek-drm is hooked with drm_atomic_helper_commit_tail_rpm(). Another reason is that the plane_state of drm_atomic_state is not synchronized with the plane_state stored in mtk_crtc during crtc enablng, so just set all planes to disabled. Fixes: 119f5173628a ("drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.") Signed-off-by: Jason-JH.Lin Reviewed-by: Alexandre Mergnat Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/linux-mediatek/patch/20230809125722.24112-3-jason-jh.lin@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 742218691080..ef02b412bb52 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -410,6 +410,9 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc) unsigned int local_layer; plane_state = to_mtk_plane_state(plane->state); + + /* should not enable layer before crtc enabled */ + plane_state->pending.enable = false; comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer); if (comp) mtk_ddp_comp_layer_config(comp, local_layer, From 1c5a880a2a4c2e24163f06b9dd76e18d8217f5c1 Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Thu, 12 Oct 2023 11:57:21 +0200 Subject: [PATCH 22/38] drm/mediatek: gamma: Adjust mtk_drm_gamma_set_common parameters Adjust the parameters in mtk_drm_gamma_set_common() - add (struct device *dev) to get lut_diff from gamma's driver data - remove (bool lut_diff) and use false as default value in the function Signed-off-by: Jason-JH.Lin Reviewed-by: Alexandre Mergnat Reviewed-by: CK Hu Signed-off-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-2-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_aal.c | 2 +- drivers/gpu/drm/mediatek/mtk_disp_drv.h | 2 +- drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 18 ++++++++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c b/drivers/gpu/drm/mediatek/mtk_disp_aal.c index 4da9ac93b29e..c6c749689532 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c @@ -61,7 +61,7 @@ void mtk_aal_gamma_set(struct device *dev, struct drm_crtc_state *state) struct mtk_disp_aal *aal = dev_get_drvdata(dev); if (aal->data && aal->data->has_gamma) - mtk_gamma_set_common(aal->regs, state, false); + mtk_gamma_set_common(NULL, aal->regs, state); } void mtk_aal_start(struct device *dev) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h index fdaa21b6a9da..2edbefb78003 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h @@ -56,7 +56,7 @@ void mtk_gamma_config(struct device *dev, unsigned int w, unsigned int h, unsigned int vrefresh, unsigned int bpc, struct cmdq_pkt *cmdq_pkt); void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state); -void mtk_gamma_set_common(void __iomem *regs, struct drm_crtc_state *state, bool lut_diff); +void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crtc_state *state); void mtk_gamma_start(struct device *dev); void mtk_gamma_stop(struct device *dev); diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index 673f9a5738f2..cb46ac0478f1 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -54,14 +54,24 @@ void mtk_gamma_clk_disable(struct device *dev) clk_disable_unprepare(gamma->clk); } -void mtk_gamma_set_common(void __iomem *regs, struct drm_crtc_state *state, bool lut_diff) +void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crtc_state *state) { + struct mtk_disp_gamma *gamma; unsigned int i, reg; struct drm_color_lut *lut; void __iomem *lut_base; + bool lut_diff; u32 word; u32 diff[3] = {0}; + /* If we're called from AAL, dev is NULL */ + gamma = dev ? dev_get_drvdata(dev) : NULL; + + if (gamma && gamma->data) + lut_diff = gamma->data->lut_diff; + else + lut_diff = false; + if (state->gamma_lut) { reg = readl(regs + DISP_GAMMA_CFG); reg = reg | GAMMA_LUT_EN; @@ -91,12 +101,8 @@ void mtk_gamma_set_common(void __iomem *regs, struct drm_crtc_state *state, bool void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state) { struct mtk_disp_gamma *gamma = dev_get_drvdata(dev); - bool lut_diff = false; - if (gamma->data) - lut_diff = gamma->data->lut_diff; - - mtk_gamma_set_common(gamma->regs, state, lut_diff); + mtk_gamma_set_common(dev, gamma->regs, state); } void mtk_gamma_config(struct device *dev, unsigned int w, From aa5fb24f971dd4b27a4e16fe7c054d052e0f8030 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:22 +0200 Subject: [PATCH 23/38] drm/mediatek: gamma: Reduce indentation in mtk_gamma_set_common() Invert the check for state->gamma_lut and move it at the beginning of the function to reduce indentation: this prepares the code for keeping readability on later additions. This commit brings no functional changes. Reviewed-by: Jason-JH.Lin Reviewed-by: Alexandre Mergnat Reviewed-by: CK Hu Signed-off-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-3-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 43 ++++++++++++----------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index cb46ac0478f1..91e82b6d86a9 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -64,6 +64,10 @@ void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crt u32 word; u32 diff[3] = {0}; + /* If there's no gamma lut there's nothing to do here. */ + if (!state->gamma_lut) + return; + /* If we're called from AAL, dev is NULL */ gamma = dev ? dev_get_drvdata(dev) : NULL; @@ -72,29 +76,26 @@ void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crt else lut_diff = false; - if (state->gamma_lut) { - reg = readl(regs + DISP_GAMMA_CFG); - reg = reg | GAMMA_LUT_EN; - writel(reg, regs + DISP_GAMMA_CFG); - lut_base = regs + DISP_GAMMA_LUT; - lut = (struct drm_color_lut *)state->gamma_lut->data; - for (i = 0; i < MTK_LUT_SIZE; i++) { + reg = readl(regs + DISP_GAMMA_CFG); + reg = reg | GAMMA_LUT_EN; + writel(reg, regs + DISP_GAMMA_CFG); + lut_base = regs + DISP_GAMMA_LUT; + lut = (struct drm_color_lut *)state->gamma_lut->data; + for (i = 0; i < MTK_LUT_SIZE; i++) { + if (!lut_diff || (i % 2 == 0)) { + word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) + + (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) + + ((lut[i].blue >> 6) & LUT_10BIT_MASK); + } else { + diff[0] = (lut[i].red >> 6) - (lut[i - 1].red >> 6); + diff[1] = (lut[i].green >> 6) - (lut[i - 1].green >> 6); + diff[2] = (lut[i].blue >> 6) - (lut[i - 1].blue >> 6); - if (!lut_diff || (i % 2 == 0)) { - word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) + - (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) + - ((lut[i].blue >> 6) & LUT_10BIT_MASK); - } else { - diff[0] = (lut[i].red >> 6) - (lut[i - 1].red >> 6); - diff[1] = (lut[i].green >> 6) - (lut[i - 1].green >> 6); - diff[2] = (lut[i].blue >> 6) - (lut[i - 1].blue >> 6); - - word = ((diff[0] & LUT_10BIT_MASK) << 20) + - ((diff[1] & LUT_10BIT_MASK) << 10) + - (diff[2] & LUT_10BIT_MASK); - } - writel(word, (lut_base + i * 4)); + word = ((diff[0] & LUT_10BIT_MASK) << 20) + + ((diff[1] & LUT_10BIT_MASK) << 10) + + (diff[2] & LUT_10BIT_MASK); } + writel(word, (lut_base + i * 4)); } } From d243907bb42f6652d88f9f3023d1028a34971465 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:23 +0200 Subject: [PATCH 24/38] drm/mediatek: gamma: Support SoC specific LUT size Newer SoCs support a bigger Gamma LUT table: wire up a callback to retrieve the correct LUT size for each different Gamma IP. Co-developed-by: Jason-JH.Lin Signed-off-by: Jason-JH.Lin [Angelo: Rewritten commit message/description + porting] Reviewed-by: Jason-JH.Lin Reviewed-by: Alexandre Mergnat Reviewed-by: CK Hu Signed-off-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-4-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_aal.c | 17 +++++++++++++++- drivers/gpu/drm/mediatek/mtk_disp_drv.h | 2 ++ drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 22 ++++++++++++++++++--- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 8 ++++++-- drivers/gpu/drm/mediatek/mtk_drm_crtc.h | 1 - drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 2 ++ drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 9 +++++++++ 7 files changed, 54 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c b/drivers/gpu/drm/mediatek/mtk_disp_aal.c index c6c749689532..e1406b37a86d 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c @@ -19,7 +19,7 @@ #define AAL_EN BIT(0) #define DISP_AAL_SIZE 0x0030 #define DISP_AAL_OUTPUT_SIZE 0x04d8 - +#define DISP_AAL_LUT_SIZE 512 struct mtk_disp_aal_data { bool has_gamma; @@ -56,6 +56,21 @@ void mtk_aal_config(struct device *dev, unsigned int w, mtk_ddp_write(cmdq_pkt, w << 16 | h, &aal->cmdq_reg, aal->regs, DISP_AAL_OUTPUT_SIZE); } +/** + * mtk_aal_gamma_get_lut_size() - Get gamma LUT size for AAL + * @dev: Pointer to struct device + * + * Return: 0 if gamma control not supported in AAL or gamma LUT size + */ +unsigned int mtk_aal_gamma_get_lut_size(struct device *dev) +{ + struct mtk_disp_aal *aal = dev_get_drvdata(dev); + + if (aal->data && aal->data->has_gamma) + return DISP_AAL_LUT_SIZE; + return 0; +} + void mtk_aal_gamma_set(struct device *dev, struct drm_crtc_state *state) { struct mtk_disp_aal *aal = dev_get_drvdata(dev); diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h index 2edbefb78003..ade2108a3273 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h @@ -17,6 +17,7 @@ void mtk_aal_clk_disable(struct device *dev); void mtk_aal_config(struct device *dev, unsigned int w, unsigned int h, unsigned int vrefresh, unsigned int bpc, struct cmdq_pkt *cmdq_pkt); +unsigned int mtk_aal_gamma_get_lut_size(struct device *dev); void mtk_aal_gamma_set(struct device *dev, struct drm_crtc_state *state); void mtk_aal_start(struct device *dev); void mtk_aal_stop(struct device *dev); @@ -55,6 +56,7 @@ void mtk_gamma_clk_disable(struct device *dev); void mtk_gamma_config(struct device *dev, unsigned int w, unsigned int h, unsigned int vrefresh, unsigned int bpc, struct cmdq_pkt *cmdq_pkt); +unsigned int mtk_gamma_get_lut_size(struct device *dev); void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state); void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crtc_state *state); void mtk_gamma_start(struct device *dev); diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index 91e82b6d86a9..326dd69fbf9d 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -28,6 +28,7 @@ struct mtk_disp_gamma_data { bool has_dither; bool lut_diff; + u16 lut_size; }; /* @@ -54,6 +55,15 @@ void mtk_gamma_clk_disable(struct device *dev) clk_disable_unprepare(gamma->clk); } +unsigned int mtk_gamma_get_lut_size(struct device *dev) +{ + struct mtk_disp_gamma *gamma = dev_get_drvdata(dev); + + if (gamma && gamma->data) + return gamma->data->lut_size; + return 0; +} + void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crtc_state *state) { struct mtk_disp_gamma *gamma; @@ -61,6 +71,7 @@ void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crt struct drm_color_lut *lut; void __iomem *lut_base; bool lut_diff; + u16 lut_size; u32 word; u32 diff[3] = {0}; @@ -71,17 +82,20 @@ void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crt /* If we're called from AAL, dev is NULL */ gamma = dev ? dev_get_drvdata(dev) : NULL; - if (gamma && gamma->data) + if (gamma && gamma->data) { lut_diff = gamma->data->lut_diff; - else + lut_size = gamma->data->lut_size; + } else { lut_diff = false; + lut_size = 512; + } reg = readl(regs + DISP_GAMMA_CFG); reg = reg | GAMMA_LUT_EN; writel(reg, regs + DISP_GAMMA_CFG); lut_base = regs + DISP_GAMMA_LUT; lut = (struct drm_color_lut *)state->gamma_lut->data; - for (i = 0; i < MTK_LUT_SIZE; i++) { + for (i = 0; i < lut_size; i++) { if (!lut_diff || (i % 2 == 0)) { word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) + (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) + @@ -196,10 +210,12 @@ static void mtk_disp_gamma_remove(struct platform_device *pdev) static const struct mtk_disp_gamma_data mt8173_gamma_driver_data = { .has_dither = true, + .lut_size = 512, }; static const struct mtk_disp_gamma_data mt8183_gamma_driver_data = { .lut_diff = true, + .lut_size = 512, }; static const struct of_device_id mtk_disp_gamma_driver_dt_match[] = { diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index ef02b412bb52..c277b9fae950 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -1002,8 +1002,12 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, mtk_crtc->ddp_comp[i] = comp; if (comp->funcs) { - if (comp->funcs->gamma_set) - gamma_lut_size = MTK_LUT_SIZE; + if (comp->funcs->gamma_set && comp->funcs->gamma_get_lut_size) { + unsigned int lut_sz = mtk_ddp_gamma_get_lut_size(comp); + + if (lut_sz) + gamma_lut_size = lut_sz; + } if (comp->funcs->ctm_set) has_ctm = true; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h index 3c224595fa71..1f988ff1bf9f 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h @@ -11,7 +11,6 @@ #include "mtk_drm_drv.h" #include "mtk_drm_plane.h" -#define MTK_LUT_SIZE 512 #define MTK_MAX_BPC 10 #define MTK_MIN_BPC 3 diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index f3345af12cb8..3046c0409353 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -271,6 +271,7 @@ static void mtk_ufoe_start(struct device *dev) static const struct mtk_ddp_comp_funcs ddp_aal = { .clk_enable = mtk_aal_clk_enable, .clk_disable = mtk_aal_clk_disable, + .gamma_get_lut_size = mtk_aal_gamma_get_lut_size, .gamma_set = mtk_aal_gamma_set, .config = mtk_aal_config, .start = mtk_aal_start, @@ -324,6 +325,7 @@ static const struct mtk_ddp_comp_funcs ddp_dsi = { static const struct mtk_ddp_comp_funcs ddp_gamma = { .clk_enable = mtk_gamma_clk_enable, .clk_disable = mtk_gamma_clk_disable, + .gamma_get_lut_size = mtk_gamma_get_lut_size, .gamma_set = mtk_gamma_set, .config = mtk_gamma_config, .start = mtk_gamma_start, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h index 0797b3ac75d8..4bae55bdb034 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h @@ -67,6 +67,7 @@ struct mtk_ddp_comp_funcs { void (*layer_config)(struct device *dev, unsigned int idx, struct mtk_plane_state *state, struct cmdq_pkt *cmdq_pkt); + unsigned int (*gamma_get_lut_size)(struct device *dev); void (*gamma_set)(struct device *dev, struct drm_crtc_state *state); void (*bgclr_in_on)(struct device *dev); @@ -188,6 +189,14 @@ static inline void mtk_ddp_comp_layer_config(struct mtk_ddp_comp *comp, comp->funcs->layer_config(comp->dev, idx, state, cmdq_pkt); } +static inline unsigned int mtk_ddp_gamma_get_lut_size(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->gamma_get_lut_size) + return comp->funcs->gamma_get_lut_size(comp->dev); + + return 0; +} + static inline void mtk_ddp_gamma_set(struct mtk_ddp_comp *comp, struct drm_crtc_state *state) { From c18119dee1919ce60565efd85f63707ceae38420 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:24 +0200 Subject: [PATCH 25/38] drm/mediatek: gamma: Improve and simplify HW LUT calculation Use drm_color_lut_extract() to avoid open-coding the bits reduction calculations for each color channel and use a struct drm_color_lut to temporarily store the information instead of an array of u32. Also, slightly improve the precision of the HW LUT calculation in the LUT DIFF case by performing the subtractions on the 16-bits values and doing the 10 bits conversion later. Reviewed-by: Jason-JH.Lin Reviewed-by: Alexandre Mergnat Reviewed-by: CK Hu Signed-off-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-5-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 38 ++++++++++++++--------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index 326dd69fbf9d..d51367330092 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -23,8 +23,6 @@ #define DISP_GAMMA_SIZE 0x0030 #define DISP_GAMMA_LUT 0x0700 -#define LUT_10BIT_MASK 0x03ff - struct mtk_disp_gamma_data { bool has_dither; bool lut_diff; @@ -73,7 +71,6 @@ void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crt bool lut_diff; u16 lut_size; u32 word; - u32 diff[3] = {0}; /* If there's no gamma lut there's nothing to do here. */ if (!state->gamma_lut) @@ -96,20 +93,31 @@ void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crt lut_base = regs + DISP_GAMMA_LUT; lut = (struct drm_color_lut *)state->gamma_lut->data; for (i = 0; i < lut_size; i++) { - if (!lut_diff || (i % 2 == 0)) { - word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) + - (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) + - ((lut[i].blue >> 6) & LUT_10BIT_MASK); - } else { - diff[0] = (lut[i].red >> 6) - (lut[i - 1].red >> 6); - diff[1] = (lut[i].green >> 6) - (lut[i - 1].green >> 6); - diff[2] = (lut[i].blue >> 6) - (lut[i - 1].blue >> 6); + struct drm_color_lut diff, hwlut; - word = ((diff[0] & LUT_10BIT_MASK) << 20) + - ((diff[1] & LUT_10BIT_MASK) << 10) + - (diff[2] & LUT_10BIT_MASK); + hwlut.red = drm_color_lut_extract(lut[i].red, 10); + hwlut.green = drm_color_lut_extract(lut[i].green, 10); + hwlut.blue = drm_color_lut_extract(lut[i].blue, 10); + + if (!lut_diff || (i % 2 == 0)) { + word = (hwlut.red << 20) + + (hwlut.green << 10) + + hwlut.red; + } else { + diff.red = lut[i].red - lut[i - 1].red; + diff.red = drm_color_lut_extract(diff.red, 10); + + diff.green = lut[i].green - lut[i - 1].green; + diff.green = drm_color_lut_extract(diff.green, 10); + + diff.blue = lut[i].blue - lut[i - 1].blue; + diff.blue = drm_color_lut_extract(diff.blue, 10); + + word = (diff.blue << 20) + + (diff.green << 10) + + diff.red; } - writel(word, (lut_base + i * 4)); + writel(word, lut_base + i * 4); } } From 0d4caaaf61ce0556843e2fa9d41ec65962b51c14 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:25 +0200 Subject: [PATCH 26/38] drm/mediatek: gamma: Enable the Gamma LUT table only after programming Move the write to DISP_GAMMA_CFG to enable the Gamma LUT to after programming the actual table to avoid potential visual glitches during table modification. Note: GAMMA should get enabled in between vblanks, but this requires many efforts in order to make this happen, as that requires migrating all of the writes to make use of CMDQ instead of cpu writes and that's not trivial. For this reason, this patch only moves the LUT enable. The CMDQ rework will come at a later time. Reviewed-by: Jason-JH.Lin Reviewed-by: Alexandre Mergnat Reviewed-by: CK Hu Signed-off-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-6-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index d51367330092..9a8f9306f076 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -65,12 +65,12 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev) void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crtc_state *state) { struct mtk_disp_gamma *gamma; - unsigned int i, reg; + unsigned int i; struct drm_color_lut *lut; void __iomem *lut_base; bool lut_diff; u16 lut_size; - u32 word; + u32 cfg_val, word; /* If there's no gamma lut there's nothing to do here. */ if (!state->gamma_lut) @@ -87,9 +87,6 @@ void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crt lut_size = 512; } - reg = readl(regs + DISP_GAMMA_CFG); - reg = reg | GAMMA_LUT_EN; - writel(reg, regs + DISP_GAMMA_CFG); lut_base = regs + DISP_GAMMA_LUT; lut = (struct drm_color_lut *)state->gamma_lut->data; for (i = 0; i < lut_size; i++) { @@ -119,6 +116,13 @@ void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crt } writel(word, lut_base + i * 4); } + + cfg_val = readl(regs + DISP_GAMMA_CFG); + + /* Enable the gamma table */ + cfg_val |= GAMMA_LUT_EN; + + writel(cfg_val, regs + DISP_GAMMA_CFG); } void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state) From 6e46998c13f1235929091edeeb577585f3e00e10 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:26 +0200 Subject: [PATCH 27/38] drm/mediatek: gamma: Use bitfield macros Make the code more robust and improve readability by using bitfield macros instead of open coding bit operations. Reviewed-by: Jason-JH.Lin Reviewed-by: Alexandre Mergnat Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-7-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 28 +++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index 9a8f9306f076..b0180b746b5a 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -3,6 +3,7 @@ * Copyright (c) 2021 MediaTek Inc. */ +#include #include #include #include @@ -21,8 +22,14 @@ #define GAMMA_LUT_EN BIT(1) #define GAMMA_DITHERING BIT(2) #define DISP_GAMMA_SIZE 0x0030 +#define DISP_GAMMA_SIZE_HSIZE GENMASK(28, 16) +#define DISP_GAMMA_SIZE_VSIZE GENMASK(12, 0) #define DISP_GAMMA_LUT 0x0700 +#define DISP_GAMMA_LUT_10BIT_R GENMASK(29, 20) +#define DISP_GAMMA_LUT_10BIT_G GENMASK(19, 10) +#define DISP_GAMMA_LUT_10BIT_B GENMASK(9, 0) + struct mtk_disp_gamma_data { bool has_dither; bool lut_diff; @@ -97,9 +104,9 @@ void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crt hwlut.blue = drm_color_lut_extract(lut[i].blue, 10); if (!lut_diff || (i % 2 == 0)) { - word = (hwlut.red << 20) + - (hwlut.green << 10) + - hwlut.red; + word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red); + word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green); + word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue); } else { diff.red = lut[i].red - lut[i - 1].red; diff.red = drm_color_lut_extract(diff.red, 10); @@ -110,9 +117,9 @@ void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crt diff.blue = lut[i].blue - lut[i - 1].blue; diff.blue = drm_color_lut_extract(diff.blue, 10); - word = (diff.blue << 20) + - (diff.green << 10) + - diff.red; + word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red); + word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green); + word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, diff.blue); } writel(word, lut_base + i * 4); } @@ -120,7 +127,7 @@ void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crt cfg_val = readl(regs + DISP_GAMMA_CFG); /* Enable the gamma table */ - cfg_val |= GAMMA_LUT_EN; + cfg_val |= FIELD_PREP(GAMMA_LUT_EN, 1); writel(cfg_val, regs + DISP_GAMMA_CFG); } @@ -137,9 +144,12 @@ void mtk_gamma_config(struct device *dev, unsigned int w, unsigned int bpc, struct cmdq_pkt *cmdq_pkt) { struct mtk_disp_gamma *gamma = dev_get_drvdata(dev); + u32 sz; - mtk_ddp_write(cmdq_pkt, h << 16 | w, &gamma->cmdq_reg, gamma->regs, - DISP_GAMMA_SIZE); + sz = FIELD_PREP(DISP_GAMMA_SIZE_HSIZE, w); + sz |= FIELD_PREP(DISP_GAMMA_SIZE_VSIZE, h); + + mtk_ddp_write(cmdq_pkt, sz, &gamma->cmdq_reg, gamma->regs, DISP_GAMMA_SIZE); if (gamma->data && gamma->data->has_dither) mtk_dither_set_common(gamma->regs, &gamma->cmdq_reg, bpc, DISP_GAMMA_CFG, GAMMA_DITHERING, cmdq_pkt); From 36e5da13779309793aae2bb7dab39415dfce11ed Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:27 +0200 Subject: [PATCH 28/38] drm/mediatek: aal: Use bitfield macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the code more robust and improve readability by using bitfield macros instead of open coding bit operations. Reviewed-by: CK Hu Reviewed-by: NĂ­colas F. R. A. Prado Signed-off-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-8-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_aal.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c b/drivers/gpu/drm/mediatek/mtk_disp_aal.c index e1406b37a86d..f97c194f9caa 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c @@ -18,6 +18,8 @@ #define DISP_AAL_EN 0x0000 #define AAL_EN BIT(0) #define DISP_AAL_SIZE 0x0030 +#define DISP_AAL_SIZE_HSIZE GENMASK(28, 16) +#define DISP_AAL_SIZE_VSIZE GENMASK(12, 0) #define DISP_AAL_OUTPUT_SIZE 0x04d8 #define DISP_AAL_LUT_SIZE 512 @@ -51,9 +53,13 @@ void mtk_aal_config(struct device *dev, unsigned int w, unsigned int bpc, struct cmdq_pkt *cmdq_pkt) { struct mtk_disp_aal *aal = dev_get_drvdata(dev); + u32 sz; - mtk_ddp_write(cmdq_pkt, w << 16 | h, &aal->cmdq_reg, aal->regs, DISP_AAL_SIZE); - mtk_ddp_write(cmdq_pkt, w << 16 | h, &aal->cmdq_reg, aal->regs, DISP_AAL_OUTPUT_SIZE); + sz = FIELD_PREP(DISP_AAL_SIZE_HSIZE, w); + sz |= FIELD_PREP(DISP_AAL_SIZE_VSIZE, h); + + mtk_ddp_write(cmdq_pkt, sz, &aal->cmdq_reg, aal->regs, DISP_AAL_SIZE); + mtk_ddp_write(cmdq_pkt, sz, &aal->cmdq_reg, aal->regs, DISP_AAL_OUTPUT_SIZE); } /** From a6b39cd248f3321dbf066f95f95a9841f891229e Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:28 +0200 Subject: [PATCH 29/38] drm/mediatek: De-commonize disp_aal/disp_gamma gamma_set functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for adding a 12-bits gamma support for the DISP_GAMMA IP, remove the mtk_gamma_set_common() function and move the relevant bits in mtk_gamma_set() for DISP_GAMMA and mtk_aal_gamma_set() for DISP_AAL: since the latter has no more support for gamma manipulation (being moved to a different IP) in newer revisions, those functions are about to diverge and it makes no sense to keep a common one (with all the complications of passing common data and making exclusions for device driver data) for just a few bits. This commit brings no functional changes. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: NĂ­colas F. R. A. Prado Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-9-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 34 +++++------------------ 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index b0180b746b5a..95493de24a00 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -69,41 +69,28 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev) return 0; } -void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crtc_state *state) +void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state) { - struct mtk_disp_gamma *gamma; + struct mtk_disp_gamma *gamma = dev_get_drvdata(dev); unsigned int i; struct drm_color_lut *lut; void __iomem *lut_base; - bool lut_diff; - u16 lut_size; u32 cfg_val, word; /* If there's no gamma lut there's nothing to do here. */ if (!state->gamma_lut) return; - /* If we're called from AAL, dev is NULL */ - gamma = dev ? dev_get_drvdata(dev) : NULL; - - if (gamma && gamma->data) { - lut_diff = gamma->data->lut_diff; - lut_size = gamma->data->lut_size; - } else { - lut_diff = false; - lut_size = 512; - } - - lut_base = regs + DISP_GAMMA_LUT; + lut_base = gamma->regs + DISP_GAMMA_LUT; lut = (struct drm_color_lut *)state->gamma_lut->data; - for (i = 0; i < lut_size; i++) { + for (i = 0; i < gamma->data->lut_size; i++) { struct drm_color_lut diff, hwlut; hwlut.red = drm_color_lut_extract(lut[i].red, 10); hwlut.green = drm_color_lut_extract(lut[i].green, 10); hwlut.blue = drm_color_lut_extract(lut[i].blue, 10); - if (!lut_diff || (i % 2 == 0)) { + if (!gamma->data->lut_diff || (i % 2 == 0)) { word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red); word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green); word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue); @@ -124,19 +111,12 @@ void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crt writel(word, lut_base + i * 4); } - cfg_val = readl(regs + DISP_GAMMA_CFG); + cfg_val = readl(gamma->regs + DISP_GAMMA_CFG); /* Enable the gamma table */ cfg_val |= FIELD_PREP(GAMMA_LUT_EN, 1); - writel(cfg_val, regs + DISP_GAMMA_CFG); -} - -void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state) -{ - struct mtk_disp_gamma *gamma = dev_get_drvdata(dev); - - mtk_gamma_set_common(dev, gamma->regs, state); + cfg_val = readl(gamma->regs + DISP_GAMMA_CFG); } void mtk_gamma_config(struct device *dev, unsigned int w, From 4708b01a49171ad6d88499bd9c437629ec4a92d1 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:29 +0200 Subject: [PATCH 30/38] drm/mediatek: gamma: Support multi-bank gamma LUT Newer Gamma IP have got multiple LUT banks: support specifying the size of the LUT banks and handle bank-switching before programming the LUT in mtk_gamma_set_common() in preparation for adding support for MT8195 and newer SoCs. Suggested-by: Jason-JH.Lin [Angelo: Refactored original commit] Reviewed-by: Alexandre Mergnat Reviewed-by: CK Hu Signed-off-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-10-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_aal.c | 41 +++++++++++++- drivers/gpu/drm/mediatek/mtk_disp_drv.h | 1 - drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 66 ++++++++++++++--------- 3 files changed, 81 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c b/drivers/gpu/drm/mediatek/mtk_disp_aal.c index f97c194f9caa..4516eaf577b2 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c @@ -17,10 +17,17 @@ #define DISP_AAL_EN 0x0000 #define AAL_EN BIT(0) +#define DISP_AAL_CFG 0x0020 +#define AAL_GAMMA_LUT_EN BIT(1) #define DISP_AAL_SIZE 0x0030 #define DISP_AAL_SIZE_HSIZE GENMASK(28, 16) #define DISP_AAL_SIZE_VSIZE GENMASK(12, 0) #define DISP_AAL_OUTPUT_SIZE 0x04d8 +#define DISP_AAL_GAMMA_LUT 0x0700 +#define DISP_AAL_GAMMA_LUT_R GENMASK(29, 20) +#define DISP_AAL_GAMMA_LUT_G GENMASK(19, 10) +#define DISP_AAL_GAMMA_LUT_B GENMASK(9, 0) +#define DISP_AAL_LUT_BITS 10 #define DISP_AAL_LUT_SIZE 512 struct mtk_disp_aal_data { @@ -80,9 +87,39 @@ unsigned int mtk_aal_gamma_get_lut_size(struct device *dev) void mtk_aal_gamma_set(struct device *dev, struct drm_crtc_state *state) { struct mtk_disp_aal *aal = dev_get_drvdata(dev); + struct drm_color_lut *lut; + unsigned int i; + u32 cfg_val; - if (aal->data && aal->data->has_gamma) - mtk_gamma_set_common(NULL, aal->regs, state); + /* If gamma is not supported in AAL, go out immediately */ + if (!(aal->data && aal->data->has_gamma)) + return; + + /* Also, if there's no gamma lut there's nothing to do here. */ + if (!state->gamma_lut) + return; + + lut = (struct drm_color_lut *)state->gamma_lut->data; + for (i = 0; i < DISP_AAL_LUT_SIZE; i++) { + struct drm_color_lut hwlut = { + .red = drm_color_lut_extract(lut[i].red, DISP_AAL_LUT_BITS), + .green = drm_color_lut_extract(lut[i].green, DISP_AAL_LUT_BITS), + .blue = drm_color_lut_extract(lut[i].blue, DISP_AAL_LUT_BITS) + }; + u32 word; + + word = FIELD_PREP(DISP_AAL_GAMMA_LUT_R, hwlut.red); + word |= FIELD_PREP(DISP_AAL_GAMMA_LUT_G, hwlut.green); + word |= FIELD_PREP(DISP_AAL_GAMMA_LUT_B, hwlut.blue); + writel(word, aal->regs + DISP_AAL_GAMMA_LUT + i * 4); + } + + cfg_val = readl(aal->regs + DISP_AAL_CFG); + + /* Enable the gamma table */ + cfg_val |= FIELD_PREP(AAL_GAMMA_LUT_EN, 1); + + writel(cfg_val, aal->regs + DISP_AAL_CFG); } void mtk_aal_start(struct device *dev) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h index ade2108a3273..1311562d25cc 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h @@ -58,7 +58,6 @@ void mtk_gamma_config(struct device *dev, unsigned int w, unsigned int bpc, struct cmdq_pkt *cmdq_pkt); unsigned int mtk_gamma_get_lut_size(struct device *dev); void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state); -void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct drm_crtc_state *state); void mtk_gamma_start(struct device *dev); void mtk_gamma_stop(struct device *dev); diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index 95493de24a00..421a3edad770 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -24,6 +24,8 @@ #define DISP_GAMMA_SIZE 0x0030 #define DISP_GAMMA_SIZE_HSIZE GENMASK(28, 16) #define DISP_GAMMA_SIZE_VSIZE GENMASK(12, 0) +#define DISP_GAMMA_BANK 0x0100 +#define DISP_GAMMA_BANK_BANK GENMASK(1, 0) #define DISP_GAMMA_LUT 0x0700 #define DISP_GAMMA_LUT_10BIT_R GENMASK(29, 20) @@ -33,6 +35,7 @@ struct mtk_disp_gamma_data { bool has_dither; bool lut_diff; + u16 lut_bank_size; u16 lut_size; }; @@ -75,40 +78,53 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state) unsigned int i; struct drm_color_lut *lut; void __iomem *lut_base; - u32 cfg_val, word; + u32 cfg_val, lbank_val, word; + int cur_bank, num_lut_banks; /* If there's no gamma lut there's nothing to do here. */ if (!state->gamma_lut) return; + num_lut_banks = gamma->data->lut_size / gamma->data->lut_bank_size; lut_base = gamma->regs + DISP_GAMMA_LUT; lut = (struct drm_color_lut *)state->gamma_lut->data; - for (i = 0; i < gamma->data->lut_size; i++) { - struct drm_color_lut diff, hwlut; - hwlut.red = drm_color_lut_extract(lut[i].red, 10); - hwlut.green = drm_color_lut_extract(lut[i].green, 10); - hwlut.blue = drm_color_lut_extract(lut[i].blue, 10); + for (cur_bank = 0; cur_bank < num_lut_banks; cur_bank++) { - if (!gamma->data->lut_diff || (i % 2 == 0)) { - word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red); - word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green); - word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue); - } else { - diff.red = lut[i].red - lut[i - 1].red; - diff.red = drm_color_lut_extract(diff.red, 10); - - diff.green = lut[i].green - lut[i - 1].green; - diff.green = drm_color_lut_extract(diff.green, 10); - - diff.blue = lut[i].blue - lut[i - 1].blue; - diff.blue = drm_color_lut_extract(diff.blue, 10); - - word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red); - word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green); - word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, diff.blue); + /* Switch gamma bank and set data mode before writing LUT */ + if (num_lut_banks > 1) { + lbank_val = FIELD_PREP(DISP_GAMMA_BANK_BANK, cur_bank); + writel(lbank_val, gamma->regs + DISP_GAMMA_BANK); + } + + for (i = 0; i < gamma->data->lut_bank_size; i++) { + int n = cur_bank * gamma->data->lut_bank_size + i; + struct drm_color_lut diff, hwlut; + + hwlut.red = drm_color_lut_extract(lut[n].red, 10); + hwlut.green = drm_color_lut_extract(lut[n].green, 10); + hwlut.blue = drm_color_lut_extract(lut[n].blue, 10); + + if (!gamma->data->lut_diff || (i % 2 == 0)) { + word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red); + word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green); + word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue); + } else { + diff.red = lut[n].red - lut[n - 1].red; + diff.red = drm_color_lut_extract(diff.red, 10); + + diff.green = lut[n].green - lut[n - 1].green; + diff.green = drm_color_lut_extract(diff.green, 10); + + diff.blue = lut[n].blue - lut[n - 1].blue; + diff.blue = drm_color_lut_extract(diff.blue, 10); + + word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red); + word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green); + word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, diff.blue); + } + writel(word, lut_base + i * 4); } - writel(word, lut_base + i * 4); } cfg_val = readl(gamma->regs + DISP_GAMMA_CFG); @@ -212,10 +228,12 @@ static void mtk_disp_gamma_remove(struct platform_device *pdev) static const struct mtk_disp_gamma_data mt8173_gamma_driver_data = { .has_dither = true, + .lut_bank_size = 512, .lut_size = 512, }; static const struct mtk_disp_gamma_data mt8183_gamma_driver_data = { + .lut_bank_size = 512, .lut_diff = true, .lut_size = 512, }; From af0e042e162a5899f11996abc17d648a2c82f7cd Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:30 +0200 Subject: [PATCH 31/38] drm/mediatek: gamma: Add support for 12-bit LUT New SoCs, like MT8195, not only may support bigger lookup tables, but have got a different register layout to support bigger precision: support specifying the number of `lut_bits` for each SoC and use it in mtk_gamma_set_common() to perform the right calculations and add support for 12-bit gamma lookup tables. While at it, also reorder the variables in mtk_gamma_set_common() and rename `lut_base` to `lut0_base` to improve readability. Reviewed-by: Jason-JH.Lin Reviewed-by: Alexandre Mergnat Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-11-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 81 ++++++++++++++++++----- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index 421a3edad770..c44a04735421 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -26,17 +26,26 @@ #define DISP_GAMMA_SIZE_VSIZE GENMASK(12, 0) #define DISP_GAMMA_BANK 0x0100 #define DISP_GAMMA_BANK_BANK GENMASK(1, 0) +#define DISP_GAMMA_BANK_DATA_MODE BIT(2) #define DISP_GAMMA_LUT 0x0700 +#define DISP_GAMMA_LUT1 0x0b00 +/* For 10 bit LUT layout, R/G/B are in the same register */ #define DISP_GAMMA_LUT_10BIT_R GENMASK(29, 20) #define DISP_GAMMA_LUT_10BIT_G GENMASK(19, 10) #define DISP_GAMMA_LUT_10BIT_B GENMASK(9, 0) +/* For 12 bit LUT layout, R/G are in LUT, B is in LUT1 */ +#define DISP_GAMMA_LUT_12BIT_R GENMASK(11, 0) +#define DISP_GAMMA_LUT_12BIT_G GENMASK(23, 12) +#define DISP_GAMMA_LUT_12BIT_B GENMASK(11, 0) + struct mtk_disp_gamma_data { bool has_dither; bool lut_diff; u16 lut_bank_size; u16 lut_size; + u8 lut_bits; }; /* @@ -72,28 +81,48 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev) return 0; } +/* + * SoCs supporting 12-bits LUTs are using a new register layout that does + * always support (by HW) both 12-bits and 10-bits LUT but, on those, we + * ignore the support for 10-bits in this driver and always use 12-bits. + * + * Summarizing: + * - SoC HW support 9/10-bits LUT only + * - Old register layout + * - 10-bits LUT supported + * - 9-bits LUT not supported + * - SoC HW support both 10/12bits LUT + * - New register layout + * - 12-bits LUT supported + * - 10-its LUT not supported + */ void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state) { struct mtk_disp_gamma *gamma = dev_get_drvdata(dev); - unsigned int i; - struct drm_color_lut *lut; - void __iomem *lut_base; - u32 cfg_val, lbank_val, word; + void __iomem *lut0_base = gamma->regs + DISP_GAMMA_LUT; + void __iomem *lut1_base = gamma->regs + DISP_GAMMA_LUT1; + u32 cfg_val, data_mode, lbank_val, word[2]; + u8 lut_bits = gamma->data->lut_bits; int cur_bank, num_lut_banks; + struct drm_color_lut *lut; + unsigned int i; /* If there's no gamma lut there's nothing to do here. */ if (!state->gamma_lut) return; num_lut_banks = gamma->data->lut_size / gamma->data->lut_bank_size; - lut_base = gamma->regs + DISP_GAMMA_LUT; lut = (struct drm_color_lut *)state->gamma_lut->data; + /* Switch to 12 bits data mode if supported */ + data_mode = FIELD_PREP(DISP_GAMMA_BANK_DATA_MODE, !!(lut_bits == 12)); + for (cur_bank = 0; cur_bank < num_lut_banks; cur_bank++) { /* Switch gamma bank and set data mode before writing LUT */ if (num_lut_banks > 1) { lbank_val = FIELD_PREP(DISP_GAMMA_BANK_BANK, cur_bank); + lbank_val |= data_mode; writel(lbank_val, gamma->regs + DISP_GAMMA_BANK); } @@ -101,29 +130,43 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state) int n = cur_bank * gamma->data->lut_bank_size + i; struct drm_color_lut diff, hwlut; - hwlut.red = drm_color_lut_extract(lut[n].red, 10); - hwlut.green = drm_color_lut_extract(lut[n].green, 10); - hwlut.blue = drm_color_lut_extract(lut[n].blue, 10); + hwlut.red = drm_color_lut_extract(lut[n].red, lut_bits); + hwlut.green = drm_color_lut_extract(lut[n].green, lut_bits); + hwlut.blue = drm_color_lut_extract(lut[n].blue, lut_bits); if (!gamma->data->lut_diff || (i % 2 == 0)) { - word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red); - word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green); - word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue); + if (lut_bits == 12) { + word[0] = FIELD_PREP(DISP_GAMMA_LUT_12BIT_R, hwlut.red); + word[0] |= FIELD_PREP(DISP_GAMMA_LUT_12BIT_G, hwlut.green); + word[1] = FIELD_PREP(DISP_GAMMA_LUT_12BIT_B, hwlut.blue); + } else { + word[0] = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red); + word[0] |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green); + word[0] |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue); + } } else { diff.red = lut[n].red - lut[n - 1].red; - diff.red = drm_color_lut_extract(diff.red, 10); + diff.red = drm_color_lut_extract(diff.red, lut_bits); diff.green = lut[n].green - lut[n - 1].green; - diff.green = drm_color_lut_extract(diff.green, 10); + diff.green = drm_color_lut_extract(diff.green, lut_bits); diff.blue = lut[n].blue - lut[n - 1].blue; - diff.blue = drm_color_lut_extract(diff.blue, 10); + diff.blue = drm_color_lut_extract(diff.blue, lut_bits); - word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red); - word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green); - word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, diff.blue); + if (lut_bits == 12) { + word[0] = FIELD_PREP(DISP_GAMMA_LUT_12BIT_R, diff.red); + word[0] |= FIELD_PREP(DISP_GAMMA_LUT_12BIT_G, diff.green); + word[1] = FIELD_PREP(DISP_GAMMA_LUT_12BIT_B, diff.blue); + } else { + word[0] = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red); + word[0] |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green); + word[0] |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, diff.blue); + } } - writel(word, lut_base + i * 4); + writel(word[0], lut0_base + i * 4); + if (lut_bits == 12) + writel(word[1], lut1_base + i * 4); } } @@ -229,11 +272,13 @@ static void mtk_disp_gamma_remove(struct platform_device *pdev) static const struct mtk_disp_gamma_data mt8173_gamma_driver_data = { .has_dither = true, .lut_bank_size = 512, + .lut_bits = 10, .lut_size = 512, }; static const struct mtk_disp_gamma_data mt8183_gamma_driver_data = { .lut_bank_size = 512, + .lut_bits = 10, .lut_diff = true, .lut_size = 512, }; From 6841f6f9c699660452bdd30f5ee3a3708972ebd3 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:31 +0200 Subject: [PATCH 32/38] drm/mediatek: gamma: Add support for MT8195 Now that this driver supports 12-bit LUTs, we can add support for the DISP_GAMMA found on the MT8195 SoC: add its driver data and compatible. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-12-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index c44a04735421..b4699b454495 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -283,11 +283,20 @@ static const struct mtk_disp_gamma_data mt8183_gamma_driver_data = { .lut_size = 512, }; +static const struct mtk_disp_gamma_data mt8195_gamma_driver_data = { + .lut_bank_size = 256, + .lut_bits = 12, + .lut_diff = true, + .lut_size = 1024, +}; + static const struct of_device_id mtk_disp_gamma_driver_dt_match[] = { { .compatible = "mediatek,mt8173-disp-gamma", .data = &mt8173_gamma_driver_data}, { .compatible = "mediatek,mt8183-disp-gamma", .data = &mt8183_gamma_driver_data}, + { .compatible = "mediatek,mt8195-disp-gamma", + .data = &mt8195_gamma_driver_data}, {}, }; MODULE_DEVICE_TABLE(of, mtk_disp_gamma_driver_dt_match); From 921e902b2cb5e05fef370c853bfda0dbd240778d Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:32 +0200 Subject: [PATCH 33/38] drm/mediatek: gamma: Make sure relay mode is disabled Disable relay mode at the end of LUT programming to make sure that the processed image goes through in both DISP_GAMMA and DISP_AAL for gamma setting. Reviewed-by: Jason-JH.Lin Reviewed-by: Alexandre Mergnat Reviewed-by: CK Hu Signed-off-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-13-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_aal.c | 4 ++++ drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c b/drivers/gpu/drm/mediatek/mtk_disp_aal.c index 4516eaf577b2..a29651bf566f 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c @@ -18,6 +18,7 @@ #define DISP_AAL_EN 0x0000 #define AAL_EN BIT(0) #define DISP_AAL_CFG 0x0020 +#define AAL_RELAY_MODE BIT(0) #define AAL_GAMMA_LUT_EN BIT(1) #define DISP_AAL_SIZE 0x0030 #define DISP_AAL_SIZE_HSIZE GENMASK(28, 16) @@ -119,6 +120,9 @@ void mtk_aal_gamma_set(struct device *dev, struct drm_crtc_state *state) /* Enable the gamma table */ cfg_val |= FIELD_PREP(AAL_GAMMA_LUT_EN, 1); + /* Disable RELAY mode to pass the processed image */ + cfg_val &= ~AAL_RELAY_MODE; + writel(cfg_val, aal->regs + DISP_AAL_CFG); } diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index b4699b454495..129b5f9ded99 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -19,6 +19,7 @@ #define DISP_GAMMA_EN 0x0000 #define GAMMA_EN BIT(0) #define DISP_GAMMA_CFG 0x0020 +#define GAMMA_RELAY_MODE BIT(0) #define GAMMA_LUT_EN BIT(1) #define GAMMA_DITHERING BIT(2) #define DISP_GAMMA_SIZE 0x0030 @@ -175,6 +176,9 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state) /* Enable the gamma table */ cfg_val |= FIELD_PREP(GAMMA_LUT_EN, 1); + /* Disable RELAY mode to pass the processed image */ + cfg_val &= ~GAMMA_RELAY_MODE; + cfg_val = readl(gamma->regs + DISP_GAMMA_CFG); } From 692e1a08ae3f4ca772e4841a4caedbb4a5075445 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:33 +0200 Subject: [PATCH 34/38] drm/mediatek: gamma: Program gamma LUT type for descending or rising All of the SoCs that don't have dithering control in the gamma IP have got a GAMMA_LUT_TYPE bit that tells to the IP if the LUT is "descending" (bit set) or "rising" (bit cleared): make sure to set it correctly after programming the LUT. Reviewed-by: Jason-JH.Lin Reviewed-by: Alexandre Mergnat Reviewed-by: CK Hu Signed-off-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-14-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index 129b5f9ded99..16ecb43b2365 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -22,6 +22,7 @@ #define GAMMA_RELAY_MODE BIT(0) #define GAMMA_LUT_EN BIT(1) #define GAMMA_DITHERING BIT(2) +#define GAMMA_LUT_TYPE BIT(2) #define DISP_GAMMA_SIZE 0x0030 #define DISP_GAMMA_SIZE_HSIZE GENMASK(28, 16) #define DISP_GAMMA_SIZE_VSIZE GENMASK(12, 0) @@ -82,6 +83,17 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev) return 0; } +static bool mtk_gamma_lut_is_descending(struct drm_color_lut *lut, u32 lut_size) +{ + u64 first, last; + int last_entry = lut_size - 1; + + first = lut[0].red + lut[0].green + lut[0].blue; + last = lut[last_entry].red + lut[last_entry].green + lut[last_entry].blue; + + return !!(first > last); +} + /* * SoCs supporting 12-bits LUTs are using a new register layout that does * always support (by HW) both 12-bits and 10-bits LUT but, on those, we @@ -173,6 +185,14 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state) cfg_val = readl(gamma->regs + DISP_GAMMA_CFG); + if (!gamma->data->has_dither) { + /* Descending or Rising LUT */ + if (mtk_gamma_lut_is_descending(lut, gamma->data->lut_size - 1)) + cfg_val |= FIELD_PREP(GAMMA_LUT_TYPE, 1); + else + cfg_val &= ~GAMMA_LUT_TYPE; + } + /* Enable the gamma table */ cfg_val |= FIELD_PREP(GAMMA_LUT_EN, 1); From 2b6c3197b267e97d640cca78a036efda19e398a5 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:34 +0200 Subject: [PATCH 35/38] drm/mediatek: aal: Add kerneldoc for struct mtk_disp_aal The kerneldoc for struct mtk_disp_aal is missing: write one and document this structure. Reviewed-by: CK Hu Signed-off-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-15-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_aal.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c b/drivers/gpu/drm/mediatek/mtk_disp_aal.c index a29651bf566f..bfcdb711a29f 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c @@ -35,6 +35,13 @@ struct mtk_disp_aal_data { bool has_gamma; }; + /** + * struct mtk_disp_aal - Display Adaptive Ambient Light driver structure + * @clk: clock for DISP_AAL controller + * @regs: MMIO registers base + * @cmdq_reg: CMDQ Client register + * @data: platform specific data for DISP_AAL + */ struct mtk_disp_aal { struct clk *clk; void __iomem *regs; From a33a56ad0844176b0aa84a8aca1efec20b888766 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:35 +0200 Subject: [PATCH 36/38] drm/mediatek: gamma: Add kerneldoc for struct mtk_disp_gamma The mtk_disp_gamma structure was completely undocumented: add some kerneldoc documentation to it. Reviewed-by: CK Hu Signed-off-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-16-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c index 16ecb43b2365..f81dc34c9c3e 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -50,8 +50,12 @@ struct mtk_disp_gamma_data { u8 lut_bits; }; -/* - * struct mtk_disp_gamma - DISP_GAMMA driver structure +/** + * struct mtk_disp_gamma - Display Gamma driver structure + * @clk: clock for DISP_GAMMA block + * @regs: MMIO registers base + * @cmdq_reg: CMDQ Client register + * @data: platform data for DISP_GAMMA */ struct mtk_disp_gamma { struct clk *clk; From 3f86604154ccb3597e11d334d99ae45452418b12 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 12 Oct 2023 11:57:36 +0200 Subject: [PATCH 37/38] drm/mediatek: aal: Compress of_device_id entries and add sentinel Compress the entry for mediatek,mt8173-disp-aal, as it fits in one line, and fix the style; while at it, also add the usual sentinel comment to the last entry. This commit brings no functional changes. Reviewed-by: CK Hu Signed-off-by: AngeloGioacchino Del Regno Link: https://patchwork.kernel.org/project/dri-devel/patch/20231012095736.100784-17-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_disp_aal.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c b/drivers/gpu/drm/mediatek/mtk_disp_aal.c index bfcdb711a29f..ca50160a0c73 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c @@ -213,10 +213,9 @@ static const struct mtk_disp_aal_data mt8173_aal_driver_data = { }; static const struct of_device_id mtk_disp_aal_driver_dt_match[] = { - { .compatible = "mediatek,mt8173-disp-aal", - .data = &mt8173_aal_driver_data}, - { .compatible = "mediatek,mt8183-disp-aal"}, - {}, + { .compatible = "mediatek,mt8173-disp-aal", .data = &mt8173_aal_driver_data }, + { .compatible = "mediatek,mt8183-disp-aal" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mtk_disp_aal_driver_dt_match); From 5855d422a6f250f3518f43b49092c8e87a5e42be Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 23 May 2023 12:42:34 +0200 Subject: [PATCH 38/38] drm: mediatek: mtk_dsi: Fix NO_EOT_PACKET settings/handling Due to the initial confusion about MIPI_DSI_MODE_EOT_PACKET, properly renamed to MIPI_DSI_MODE_NO_EOT_PACKET, reflecting its actual meaning, both the DSI_TXRX_CON register setting for bit (HSTX_)DIS_EOT and the later calculation for horizontal sync-active (HSA), back (HBP) and front (HFP) porches got incorrect due to the logic being inverted. This means that a number of settings were wrong because....: - DSI_TXRX_CON register setting: bit (HSTX_)DIS_EOT should be set in order to disable the End of Transmission packet; - Horizontal Sync and Back/Front porches: The delta used to calculate all of HSA, HBP and HFP should account for the additional EOT packet. Before this change... - Bit (HSTX_)DIS_EOT was being set when EOT packet was enabled; - For HSA/HBP/HFP delta... all three were wrong, as words were added when EOT disabled, instead of when EOT packet enabled! Invert the logic around flag MIPI_DSI_MODE_NO_EOT_PACKET in the MediaTek DSI driver to fix the aforementioned issues. Fixes: 8b2b99fd7931 ("drm/mediatek: dsi: Fine tune the line time caused by EOTp") Fixes: c87d1c4b5b9a ("drm/mediatek: dsi: Use symbolized register definition") Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Alexandre Mergnat Tested-by: Michael Walle Link: https://patchwork.kernel.org/project/dri-devel/patch/20230523104234.7849-1-angelogioacchino.delregno@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_dsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index dc0d4bae4ff8..a2fdfc8ddb15 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -409,7 +409,7 @@ static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi) if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) tmp_reg |= HSTX_CKLP_EN; - if (!(dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)) + if (dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET) tmp_reg |= DIS_EOT; writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL); @@ -486,7 +486,7 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi) timing->da_hs_zero + timing->da_hs_exit + 3; delta = dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST ? 18 : 12; - delta += dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET ? 2 : 0; + delta += dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET ? 0 : 2; horizontal_frontporch_byte = vm->hfront_porch * dsi_tmp_buf_bpp; horizontal_front_back_byte = horizontal_frontporch_byte + horizontal_backporch_byte;