Commit 035fdc38 authored by Dave Airlie's avatar Dave Airlie

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

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

Mediatek DRM Next for Linux 6.7

1. Add support MT8188 dsi function
2. Fix coverity issue with unintentional integer overflow
3. Add support MT8188 dp/edp function
4. Fix memory leak on ->get_edid callback audio detection
   and error path.
5. Add connector dynamic selection capability
6. MediaTek DDP GAMMA - 12-bit LUT support
7. mtk_dsi: Fix NO_EOT_PACKET settings/handling

[airlied: add bitfield.h include]
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Chun-Kuang Hu <chunkuang.hu@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20231018135846.5811-1-chunkuang.hu@kernel.org
parents 55b72855 5855d422
......@@ -21,6 +21,8 @@ description: |
properties:
compatible:
enum:
- mediatek,mt8188-dp-tx
- mediatek,mt8188-edp-tx
- mediatek,mt8195-dp-tx
- mediatek,mt8195-edp-tx
......
......@@ -30,6 +30,7 @@ properties:
- mediatek,mt8173-dsi
- mediatek,mt8183-dsi
- mediatek,mt8186-dsi
- mediatek,mt8188-dsi
- items:
- enum:
- mediatek,mt6795-dsi
......
......@@ -3,6 +3,7 @@
* Copyright (c) 2021 MediaTek Inc.
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/module.h>
......@@ -17,14 +18,31 @@
#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)
#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 {
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;
......@@ -51,17 +69,69 @@ 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;
sz = FIELD_PREP(DISP_AAL_SIZE_HSIZE, w);
sz |= FIELD_PREP(DISP_AAL_SIZE_VSIZE, h);
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);
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);
}
void mtk_aal_gamma_set(struct device *dev, struct drm_crtc_state *state)
/**
* 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)
mtk_gamma_set_common(aal->regs, state, false);
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);
struct drm_color_lut *lut;
unsigned int i;
u32 cfg_val;
/* 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);
/* Disable RELAY mode to pass the processed image */
cfg_val &= ~AAL_RELAY_MODE;
writel(cfg_val, aal->regs + DISP_AAL_CFG);
}
void mtk_aal_start(struct device *dev)
......@@ -144,10 +214,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);
......
......@@ -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);
......@@ -44,17 +45,19 @@ 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);
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);
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(void __iomem *regs, struct drm_crtc_state *state, bool lut_diff);
void mtk_gamma_start(struct device *dev);
void mtk_gamma_stop(struct device *dev);
......
......@@ -3,6 +3,7 @@
* Copyright (c) 2021 MediaTek Inc.
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/module.h>
......@@ -18,20 +19,43 @@
#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 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)
#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
#define LUT_10BIT_MASK 0x03ff
/* 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;
};
/*
* 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;
......@@ -54,49 +78,132 @@ 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)
unsigned int mtk_gamma_get_lut_size(struct device *dev)
{
unsigned int i, reg;
struct drm_color_lut *lut;
void __iomem *lut_base;
u32 word;
u32 diff[3] = {0};
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++) {
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 mtk_disp_gamma *gamma = dev_get_drvdata(dev);
word = ((diff[0] & LUT_10BIT_MASK) << 20) +
((diff[1] & LUT_10BIT_MASK) << 10) +
(diff[2] & LUT_10BIT_MASK);
}
writel(word, (lut_base + i * 4));
}
}
if (gamma && gamma->data)
return gamma->data->lut_size;
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
* 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);
bool lut_diff = false;
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;
if (gamma->data)
lut_diff = gamma->data->lut_diff;
num_lut_banks = gamma->data->lut_size / gamma->data->lut_bank_size;
lut = (struct drm_color_lut *)state->gamma_lut->data;
mtk_gamma_set_common(gamma->regs, state, lut_diff);
/* 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);
}
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, 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)) {
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, lut_bits);
diff.green = lut[n].green - lut[n - 1].green;
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, lut_bits);
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[0], lut0_base + i * 4);
if (lut_bits == 12)
writel(word[1], lut1_base + i * 4);
}
}
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);
/* Disable RELAY mode to pass the processed image */
cfg_val &= ~GAMMA_RELAY_MODE;
cfg_val = readl(gamma->regs + DISP_GAMMA_CFG);
}
void mtk_gamma_config(struct device *dev, unsigned int w,
......@@ -104,9 +211,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);
......@@ -189,10 +299,23 @@ 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,
};
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[] = {
......@@ -200,6 +323,8 @@ static const struct of_device_id mtk_disp_gamma_driver_dt_match[] = {
.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);
......
......@@ -141,6 +141,8 @@ 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;
u16 audio_m_div2_bit;
};
static const struct mtk_dp_efuse_fmt mt8195_edp_efuse_fmt[MTK_DP_CAL_MAX] = {
......@@ -649,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);
}
......@@ -1394,6 +1396,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 +1417,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);
}
......@@ -2034,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);
......@@ -2049,11 +2063,16 @@ 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;
}
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);
}
......@@ -2736,11 +2755,21 @@ 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,
.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 = {
......@@ -2748,9 +2777,18 @@ 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[] = {
{
.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,
......
......@@ -159,12 +159,18 @@
#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 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)
......@@ -228,6 +234,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)
......
......@@ -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);
......
......@@ -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;
......@@ -408,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,
......@@ -647,6 +652,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 +727,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 +928,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 +980,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)
......@@ -956,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;
......@@ -1038,5 +1088,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;
}
......@@ -8,9 +8,9 @@
#include <drm/drm_crtc.h>
#include "mtk_drm_ddp_comp.h"
#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
......@@ -18,7 +18,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,
......
......@@ -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,
......@@ -304,6 +305,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 = {
......@@ -317,11 +319,13 @@ 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 = {
.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,
......@@ -507,6 +511,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 +567,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;
}
......
......@@ -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);
......@@ -80,12 +81,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;
};
......@@ -186,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)
{
......@@ -275,6 +286,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,
......
......@@ -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,9 @@ 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,
};
static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
......@@ -351,6 +358,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;
......@@ -370,11 +378,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;
temp_drm_priv = dev_get_drvdata(drm_dev);
if (!temp_drm_priv)
continue;
all_drm_priv[cnt] = dev_get_drvdata(drm_dev);
if (all_drm_priv[cnt] && all_drm_priv[cnt]->mtk_drm_bound)
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)
......@@ -412,6 +430,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;
}
......@@ -468,23 +491,25 @@ 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);
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 == 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);
priv_n->data->ext_len, j, NULL, 0);
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);
priv_n->data->third_len, j, NULL, 0);
if (ret)
goto err_component_unbind;
......@@ -765,6 +790,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 },
{ }
};
......
......@@ -9,11 +9,17 @@
#include <linux/io.h>
#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;
......@@ -22,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;
......@@ -29,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;
......
......@@ -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))
......
......@@ -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;
......@@ -206,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);
......
......@@ -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 {
......@@ -407,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);
......@@ -484,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;
......@@ -806,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,
......@@ -815,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,
};
......@@ -865,6 +887,15 @@ static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi)
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;
......@@ -996,6 +1027,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,
......@@ -1206,6 +1241,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 },
......@@ -1215,6 +1257,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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment