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 -----BEGIN PGP SIGNATURE----- iQJMBAABCgA2FiEEACwLKSDmq+9RDv5P4cpzo8lZTiQFAmUv4c4YHGNodW5rdWFu Zy5odUBrZXJuZWwub3JnAAoJEOHKc6PJWU4kNjMP/0bwC87POxGxsMazgQ5unN6l qSp1UFT4ZP7LmwtW1Za8/RMFWKi9999c7nB/oFGsuaV27bH3QvbgZIXA9+4RzJyi Cb6aLdc+mG1+fedOIvDn5GU412s1UU2Kga8U6iWUaKTrvDuoicQ9zfEeUN8t92d7 8EzC7XnT2UWsZOZSVM1uyM1bgvwmmOvzyNTKakB6ar+5zFhs9EoGfTefJze1ZuUe fWHWGFDu38+zsq0TFk1sa5vv0nGIkxQBOaFaelVepg6w5k9L3EmfbYHpxm7pXHtJ TxiULDjNozRAoxCQYxqXXq1bhvc2AII/1osaBIYE84+dxJr6fTaEfksyi/V2UcJb O87+o0ycUefVhIkEr1JfgT4TrY7we/RY/87kshKYIIFrCAh0KJ9gFoxK+HoEHzlv gMiqw2ay3/leIXWJgLUczus/fupGG44oL9GlgAc6jk1UKWFPar1g1UItFRlexXxS pT49szIhd+2E7BzpdkWR1Rtrcc0JZMczkZbYiQUCQ5wCYEwihtyH2meMjMbvKvpl ERkmvCwqCsMC9K17lHJajRlnK2TuVQp67r0VBeX0Uoud7gO56Dgg6sdkT1qLRxKN STMsNq5SW6TObrJzalh5Q7rnnBy5qGtFrNake9wBCClu4Ymjco2Vtcu/Q+gTWRR4 +vrlwlfh1vCOyIX77IiX =s/CM -----END PGP SIGNATURE----- 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: Dave 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
This commit is contained in:
commit
035fdc38c1
@ -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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
struct drm_color_lut *lut;
|
||||
unsigned int i;
|
||||
u32 cfg_val;
|
||||
|
||||
if (aal->data && aal->data->has_gamma)
|
||||
mtk_gamma_set_common(aal->regs, state, false);
|
||||
/* 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};
|
||||
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
|
||||
|
||||
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);
|
||||
|
||||
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 (gamma->data)
|
||||
lut_diff = gamma->data->lut_diff;
|
||||
/* If there's no gamma lut there's nothing to do here. */
|
||||
if (!state->gamma_lut)
|
||||
return;
|
||||
|
||||
mtk_gamma_set_common(gamma->regs, state, lut_diff);
|
||||
num_lut_banks = gamma->data->lut_size / gamma->data->lut_bank_size;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
@ -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 @@ 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;
|
||||
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user