this series is built around the DisplayPort driver. The dpi/dpintf
driver and the added helper functions are required for the DisplayPort
driver to work.
This v9 is not quite ready yet, as project constraints forces me to
publish v9 this week, I'm sorry if it's not standard practice.
Moreover, it is still un-tested on a recent kernel.
The integration kernel we are using is still based on 5.10... but we
are actively working on bringing up a mt8195 integration branch on 5.17.
The patches have been rebased on top of next-20220301 and have been
tested to build sucessfully (no functional testing).
Changes from v8:
- The DP-Phy now has its own dt-bindings and now shares a regmap using the
syscon facility with the DP driver.
- hot plug detection has been removed from the Embedded Display Port.
patch and moved to the patch adding External Display Port support.
- started working on better error handling for the mtk_dp driver.
- rebased on linux-next.
- removal of tvd pll clocks re-introduced by mistake.
- various coding style fixes.
Things that are in my todolist for v10:
- fixing the train_handler in the mtk_dp driver, as I haven't been able
to reproduce locally (hopefully migrating to running the tests on a
more recent kernel will help)
- explaining the various sleep/delays introduced in the drivers
- explaining some of the differences between mt8195 and "legacy"
- retrieve CK/DE support from panel driver instead of hardcoding it into
the dpi driver.
- better error handling/reporting in mtk_dp
- look into re-implementing mtk_dp_aux_transfer() using drm_dp_dpcd_read and
drm_dp_dpcd_write as suggested by Rex.
Older revisions:
RFC - https://lore.kernel.org/linux-mediatek/[email protected]/
v1 - https://lore.kernel.org/linux-mediatek/[email protected]/
v2 - https://lore.kernel.org/linux-mediatek/[email protected]/
v3 - https://lore.kernel.org/linux-mediatek/[email protected]/
v4 - https://lore.kernel.org/linux-mediatek/[email protected]/
v5 - https://lore.kernel.org/all/[email protected]/
v6 - https://lore.kernel.org/linux-mediatek/[email protected]/
v7 - https://lore.kernel.org/linux-mediatek/[email protected]/
v8 - https://lore.kernel.org/linux-mediatek/[email protected]/
Functional dependencies are:
- Add Mediatek Soc DRM (vdosys0) support for mt8195
https://lore.kernel.org/all/[email protected]/
- Add MediaTek SoC DRM (vdosys1) support for mt8195
https://lore.kernel.org/all/[email protected]/
Guillaume Ranquet (15):
dt-bindings: mediatek,dp_phy: Add Display Port PHY binding
drm/edid: Convert cea_sad helper struct to kernelDoc
drm/edid: Add cea_sad helpers for freq/length
drm/mediatek: dpi: move dpi limits to SoC config
drm/mediatek: dpi: implement a CK/DE pol toggle in SoC config
drm/mediatek: dpi: implement a swap_input toggle in SoC config
drm/mediatek: dpi: move dimension mask to SoC config
drm/mediatek: dpi: move hvsize_mask to SoC config
drm/mediatek: dpi: move swap_shift to SoC config
drm/mediatek: dpi: move the yuv422_en_bit to SoC config
drm/mediatek: dpi: move the csc_enable bit to SoC config
drm/mediatek: dpi: Add dpintf support
drm/meditek: dpi: Add matrix_sel helper
drm/mediatek: Add mt8195 External DisplayPort support
drm/mediatek: DP audio support for mt8195
Jitao Shi (2):
drm/mediatek: add hpd debounce
drm/mediatek: change the aux retries times when receiving AUX_DEFER
Markus Schneider-Pargmann (5):
dt-bindings: mediatek,dpi: Add DP_INTF compatible
dt-bindings: mediatek,dp: Add Display Port binding
video/hdmi: Add audio_infoframe packing for DP
phy: phy-mtk-dp: Add driver for DP phy
drm/mediatek: Add mt8195 Embedded DisplayPort driver
.../display/mediatek/mediatek,dp.yaml | 97 +
.../display/mediatek/mediatek,dpi.yaml | 11 +-
.../bindings/phy/mediatek,dp-phy.yaml | 43 +
MAINTAINERS | 1 +
drivers/gpu/drm/drm_edid.c | 74 +
drivers/gpu/drm/mediatek/Kconfig | 8 +
drivers/gpu/drm/mediatek/Makefile | 2 +
drivers/gpu/drm/mediatek/mtk_dp.c | 3204 +++++++++++++++++
drivers/gpu/drm/mediatek/mtk_dp_reg.h | 568 +++
drivers/gpu/drm/mediatek/mtk_dpi.c | 222 +-
drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 38 +
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 8 +
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 1 +
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 6 +-
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
drivers/phy/mediatek/Kconfig | 8 +
drivers/phy/mediatek/Makefile | 1 +
drivers/phy/mediatek/phy-mtk-dp.c | 202 ++
drivers/video/hdmi.c | 82 +-
include/drm/dp/drm_dp_helper.h | 2 +
include/drm/drm_edid.h | 25 +-
include/linux/hdmi.h | 7 +-
include/linux/soc/mediatek/mtk-mmsys.h | 3 +-
23 files changed, 4541 insertions(+), 73 deletions(-)
create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
create mode 100644 Documentation/devicetree/bindings/phy/mediatek,dp-phy.yaml
create mode 100644 drivers/gpu/drm/mediatek/mtk_dp.c
create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_reg.h
create mode 100644 drivers/phy/mediatek/phy-mtk-dp.c
--
2.34.1
Add a mtk_dpi_matrix_sel() helper to update the DPI_MATRIX_SET
register depending on the color format.
Signed-off-by: Guillaume Ranquet <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 8198d3cf23ac..82f97c687652 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -385,6 +385,25 @@ static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi)
mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, 0, EDGE_SEL_EN);
}
+static void mtk_dpi_matrix_sel(struct mtk_dpi *dpi, enum mtk_dpi_out_color_format format)
+{
+ u32 matrix_sel = 0;
+
+ switch (format) {
+ case MTK_DPI_COLOR_FORMAT_YCBCR_422:
+ case MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL:
+ case MTK_DPI_COLOR_FORMAT_YCBCR_444:
+ case MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL:
+ case MTK_DPI_COLOR_FORMAT_XV_YCC:
+ if (dpi->mode.hdisplay <= 720)
+ matrix_sel = 0x2;
+ break;
+ default:
+ break;
+ }
+ mtk_dpi_mask(dpi, DPI_MATRIX_SET, matrix_sel, INT_MATRIX_SEL_MASK);
+}
+
static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
enum mtk_dpi_out_color_format format)
{
@@ -392,6 +411,7 @@ static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
(format == MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL)) {
mtk_dpi_config_yuv422_enable(dpi, false);
mtk_dpi_config_csc_enable(dpi, true);
+ mtk_dpi_matrix_sel(dpi, format);
if (dpi->conf->swap_input_support)
mtk_dpi_config_swap_input(dpi, false);
mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_BGR);
@@ -399,6 +419,7 @@ static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
(format == MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL)) {
mtk_dpi_config_yuv422_enable(dpi, true);
mtk_dpi_config_csc_enable(dpi, true);
+ mtk_dpi_matrix_sel(dpi, format);
if (dpi->conf->swap_input_support)
mtk_dpi_config_swap_input(dpi, true);
mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
--
2.34.1
From: Jitao Shi <[email protected]>
DP 1.4a Section 2.8.7.1.5.6.1:
A DP Source device shall retry at least seven times upon receiving
AUX_DEFER before giving up the AUX transaction.
Aux should retry to send msg whether how many bytes.
Signed-off-by: Jitao Shi <[email protected]>
Signed-off-by: Guillaume Ranquet <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dp.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index e099491cc6a4..7a197c4a7143 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -2016,7 +2016,7 @@ static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux,
bool is_read;
u8 request;
size_t accessed_bytes = 0;
- int retry = 3, ret = 0;
+ int retry, ret = 0;
mtk_dp = container_of(mtk_aux, struct mtk_dp, aux);
@@ -2050,14 +2050,21 @@ static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux,
}
if (msg->size == 0) {
- ret = mtk_dp_aux_do_transfer(mtk_dp, is_read, request,
- msg->address + accessed_bytes,
- msg->buffer + accessed_bytes, 0);
+ retry = 32;
+ while (retry--) {
+ ret = mtk_dp_aux_do_transfer(mtk_dp, is_read, request,
+ msg->address + accessed_bytes,
+ msg->buffer + accessed_bytes, 0);
+ if (ret == 0)
+ break;
+ usleep_range(500, 600);
+ }
} else {
while (accessed_bytes < msg->size) {
size_t to_access =
min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES,
msg->size - accessed_bytes);
+ retry = 32;
while (retry--) {
ret = mtk_dp_aux_do_transfer(mtk_dp,
is_read, request,
@@ -2066,7 +2073,7 @@ static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux,
to_access);
if (ret == 0)
break;
- usleep_range(50, 100);
+ usleep_range(500, 600);
}
if (!retry || ret) {
drm_info(mtk_dp->drm_dev,
--
2.34.1
Add flexibility by moving the yuv422 en bit to SoC specific config
Signed-off-by: Guillaume Ranquet <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 6d4d8c6ec47d..40254cd9d168 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -132,6 +132,7 @@ struct mtk_dpi_conf {
/* HSIZE and VSIZE mask (no shift) */
u32 hvsize_mask;
u32 channel_swap_shift;
+ u32 yuv422_en_bit;
const struct mtk_dpi_yc_limit *limit;
};
@@ -356,7 +357,8 @@ static void mtk_dpi_config_channel_swap(struct mtk_dpi *dpi,
static void mtk_dpi_config_yuv422_enable(struct mtk_dpi *dpi, bool enable)
{
- mtk_dpi_mask(dpi, DPI_CON, enable ? YUV422_EN : 0, YUV422_EN);
+ mtk_dpi_mask(dpi, DPI_CON, enable ? dpi->conf->yuv422_en_bit : 0,
+ dpi->conf->yuv422_en_bit);
}
static void mtk_dpi_config_csc_enable(struct mtk_dpi *dpi, bool enable)
@@ -824,6 +826,7 @@ static const struct mtk_dpi_conf mt8173_conf = {
.dimension_mask = HPW_MASK,
.hvsize_mask = HSIZE_MASK,
.channel_swap_shift = CH_SWAP,
+ .yuv422_en_bit = YUV422_EN,
.limit = &mtk_dpi_limit,
};
@@ -839,6 +842,7 @@ static const struct mtk_dpi_conf mt2701_conf = {
.dimension_mask = HPW_MASK,
.hvsize_mask = HSIZE_MASK,
.channel_swap_shift = CH_SWAP,
+ .yuv422_en_bit = YUV422_EN,
.limit = &mtk_dpi_limit,
};
@@ -853,6 +857,7 @@ static const struct mtk_dpi_conf mt8183_conf = {
.dimension_mask = HPW_MASK,
.hvsize_mask = HSIZE_MASK,
.channel_swap_shift = CH_SWAP,
+ .yuv422_en_bit = YUV422_EN,
.limit = &mtk_dpi_limit,
};
@@ -867,6 +872,7 @@ static const struct mtk_dpi_conf mt8192_conf = {
.dimension_mask = HPW_MASK,
.hvsize_mask = HSIZE_MASK,
.channel_swap_shift = CH_SWAP,
+ .yuv422_en_bit = YUV422_EN,
.limit = &mtk_dpi_limit,
};
--
2.34.1
Add flexibility by moving the dimension mask to the SoC config
Signed-off-by: Guillaume Ranquet <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 454f8563efae..bf098f36a466 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -127,6 +127,8 @@ struct mtk_dpi_conf {
u32 num_output_fmts;
bool is_ck_de_pol;
bool swap_input_support;
+ /* Mask used for HWIDTH, HPORCH, VSYNC_WIDTH and VSYNC_PORCH (no shift) */
+ u32 dimension_mask;
const struct mtk_dpi_yc_limit *limit;
};
@@ -156,30 +158,30 @@ static void mtk_dpi_disable(struct mtk_dpi *dpi)
static void mtk_dpi_config_hsync(struct mtk_dpi *dpi,
struct mtk_dpi_sync_param *sync)
{
- mtk_dpi_mask(dpi, DPI_TGEN_HWIDTH,
- sync->sync_width << HPW, HPW_MASK);
- mtk_dpi_mask(dpi, DPI_TGEN_HPORCH,
- sync->back_porch << HBP, HBP_MASK);
+ mtk_dpi_mask(dpi, DPI_TGEN_HWIDTH, sync->sync_width << HPW,
+ dpi->conf->dimension_mask << HPW);
+ mtk_dpi_mask(dpi, DPI_TGEN_HPORCH, sync->back_porch << HBP,
+ dpi->conf->dimension_mask << HBP);
mtk_dpi_mask(dpi, DPI_TGEN_HPORCH, sync->front_porch << HFP,
- HFP_MASK);
+ dpi->conf->dimension_mask << HFP);
}
static void mtk_dpi_config_vsync(struct mtk_dpi *dpi,
struct mtk_dpi_sync_param *sync,
u32 width_addr, u32 porch_addr)
{
- mtk_dpi_mask(dpi, width_addr,
- sync->sync_width << VSYNC_WIDTH_SHIFT,
- VSYNC_WIDTH_MASK);
mtk_dpi_mask(dpi, width_addr,
sync->shift_half_line << VSYNC_HALF_LINE_SHIFT,
VSYNC_HALF_LINE_MASK);
+ mtk_dpi_mask(dpi, width_addr,
+ sync->sync_width << VSYNC_WIDTH_SHIFT,
+ dpi->conf->dimension_mask << VSYNC_WIDTH_SHIFT);
mtk_dpi_mask(dpi, porch_addr,
sync->back_porch << VSYNC_BACK_PORCH_SHIFT,
- VSYNC_BACK_PORCH_MASK);
+ dpi->conf->dimension_mask << VSYNC_BACK_PORCH_SHIFT);
mtk_dpi_mask(dpi, porch_addr,
sync->front_porch << VSYNC_FRONT_PORCH_SHIFT,
- VSYNC_FRONT_PORCH_MASK);
+ dpi->conf->dimension_mask << VSYNC_FRONT_PORCH_SHIFT);
}
static void mtk_dpi_config_vsync_lodd(struct mtk_dpi *dpi,
@@ -813,6 +815,7 @@ static const struct mtk_dpi_conf mt8173_conf = {
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
.is_ck_de_pol = true,
.swap_input_support = true,
+ .dimension_mask = HPW_MASK,
.limit = &mtk_dpi_limit,
};
@@ -825,6 +828,7 @@ static const struct mtk_dpi_conf mt2701_conf = {
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
.is_ck_de_pol = true,
.swap_input_support = true,
+ .dimension_mask = HPW_MASK,
.limit = &mtk_dpi_limit,
};
@@ -836,6 +840,7 @@ static const struct mtk_dpi_conf mt8183_conf = {
.num_output_fmts = ARRAY_SIZE(mt8183_output_fmts),
.is_ck_de_pol = true,
.swap_input_support = true,
+ .dimension_mask = HPW_MASK,
.limit = &mtk_dpi_limit,
};
@@ -847,6 +852,7 @@ static const struct mtk_dpi_conf mt8192_conf = {
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
.is_ck_de_pol = true,
.swap_input_support = true,
+ .dimension_mask = HPW_MASK,
.limit = &mtk_dpi_limit,
};
--
2.34.1
Adds a bit of flexibility to support SoCs without swap_input support
Signed-off-by: Guillaume Ranquet <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 545a1337cc89..454f8563efae 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -126,6 +126,7 @@ struct mtk_dpi_conf {
const u32 *output_fmts;
u32 num_output_fmts;
bool is_ck_de_pol;
+ bool swap_input_support;
const struct mtk_dpi_yc_limit *limit;
};
@@ -378,18 +379,21 @@ static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
(format == MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL)) {
mtk_dpi_config_yuv422_enable(dpi, false);
mtk_dpi_config_csc_enable(dpi, true);
- mtk_dpi_config_swap_input(dpi, false);
+ if (dpi->conf->swap_input_support)
+ mtk_dpi_config_swap_input(dpi, false);
mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_BGR);
} else if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_422) ||
(format == MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL)) {
mtk_dpi_config_yuv422_enable(dpi, true);
mtk_dpi_config_csc_enable(dpi, true);
- mtk_dpi_config_swap_input(dpi, true);
+ if (dpi->conf->swap_input_support)
+ mtk_dpi_config_swap_input(dpi, true);
mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
} else {
mtk_dpi_config_yuv422_enable(dpi, false);
mtk_dpi_config_csc_enable(dpi, false);
- mtk_dpi_config_swap_input(dpi, false);
+ if (dpi->conf->swap_input_support)
+ mtk_dpi_config_swap_input(dpi, false);
mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
}
}
@@ -808,6 +812,7 @@ static const struct mtk_dpi_conf mt8173_conf = {
.output_fmts = mt8173_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
.is_ck_de_pol = true,
+ .swap_input_support = true,
.limit = &mtk_dpi_limit,
};
@@ -819,6 +824,7 @@ static const struct mtk_dpi_conf mt2701_conf = {
.output_fmts = mt8173_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
.is_ck_de_pol = true,
+ .swap_input_support = true,
.limit = &mtk_dpi_limit,
};
@@ -829,6 +835,7 @@ static const struct mtk_dpi_conf mt8183_conf = {
.output_fmts = mt8183_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8183_output_fmts),
.is_ck_de_pol = true,
+ .swap_input_support = true,
.limit = &mtk_dpi_limit,
};
@@ -839,6 +846,7 @@ static const struct mtk_dpi_conf mt8192_conf = {
.output_fmts = mt8173_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
.is_ck_de_pol = true,
+ .swap_input_support = true,
.limit = &mtk_dpi_limit,
};
--
2.34.1
Add flexibility by moving the swap shift value to SoC specific config
Signed-off-by: Guillaume Ranquet <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 6eeda222a973..6d4d8c6ec47d 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -131,6 +131,7 @@ struct mtk_dpi_conf {
u32 dimension_mask;
/* HSIZE and VSIZE mask (no shift) */
u32 hvsize_mask;
+ u32 channel_swap_shift;
const struct mtk_dpi_yc_limit *limit;
};
@@ -349,7 +350,8 @@ static void mtk_dpi_config_channel_swap(struct mtk_dpi *dpi,
break;
}
- mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << CH_SWAP, CH_SWAP_MASK);
+ mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << dpi->conf->channel_swap_shift,
+ CH_SWAP_MASK);
}
static void mtk_dpi_config_yuv422_enable(struct mtk_dpi *dpi, bool enable)
@@ -821,6 +823,7 @@ static const struct mtk_dpi_conf mt8173_conf = {
.swap_input_support = true,
.dimension_mask = HPW_MASK,
.hvsize_mask = HSIZE_MASK,
+ .channel_swap_shift = CH_SWAP,
.limit = &mtk_dpi_limit,
};
@@ -835,6 +838,7 @@ static const struct mtk_dpi_conf mt2701_conf = {
.swap_input_support = true,
.dimension_mask = HPW_MASK,
.hvsize_mask = HSIZE_MASK,
+ .channel_swap_shift = CH_SWAP,
.limit = &mtk_dpi_limit,
};
@@ -848,6 +852,7 @@ static const struct mtk_dpi_conf mt8183_conf = {
.swap_input_support = true,
.dimension_mask = HPW_MASK,
.hvsize_mask = HSIZE_MASK,
+ .channel_swap_shift = CH_SWAP,
.limit = &mtk_dpi_limit,
};
@@ -861,6 +866,7 @@ static const struct mtk_dpi_conf mt8192_conf = {
.swap_input_support = true,
.dimension_mask = HPW_MASK,
.hvsize_mask = HSIZE_MASK,
+ .channel_swap_shift = CH_SWAP,
.limit = &mtk_dpi_limit,
};
--
2.34.1
This patch adds two helper functions that extract the frequency and word
length from a struct cea_sad.
For these helper functions new defines are added that help translate the
'freq' and 'byte2' fields into real numbers.
Signed-off-by: Markus Schneider-Pargmann <[email protected]>
Signed-off-by: Guillaume Ranquet <[email protected]>
---
drivers/gpu/drm/drm_edid.c | 74 ++++++++++++++++++++++++++++++++++++++
include/drm/drm_edid.h | 14 ++++++++
2 files changed, 88 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index cc7bd58369df..eeceae4411ba 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -4758,6 +4758,80 @@ int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb)
}
EXPORT_SYMBOL(drm_edid_to_speaker_allocation);
+/**
+ * drm_cea_sad_get_sample_rate - Extract the sample rate from cea_sad
+ * @sad: Pointer to the cea_sad struct
+ *
+ * Extracts the cea_sad frequency field and returns the sample rate in Hz.
+ *
+ * Return: Sample rate in Hz or a negative errno if parsing failed.
+ */
+int drm_cea_sad_get_sample_rate(const struct cea_sad *sad)
+{
+ switch (sad->freq) {
+ case DRM_CEA_SAD_FREQ_32KHZ:
+ return 32000;
+ case DRM_CEA_SAD_FREQ_44KHZ:
+ return 44100;
+ case DRM_CEA_SAD_FREQ_48KHZ:
+ return 48000;
+ case DRM_CEA_SAD_FREQ_88KHZ:
+ return 88200;
+ case DRM_CEA_SAD_FREQ_96KHZ:
+ return 96000;
+ case DRM_CEA_SAD_FREQ_176KHZ:
+ return 176400;
+ case DRM_CEA_SAD_FREQ_192KHZ:
+ return 192000;
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(drm_cea_sad_get_sample_rate);
+
+static bool drm_cea_sad_is_uncompressed(const struct cea_sad *sad)
+{
+ switch (sad->format) {
+ case HDMI_AUDIO_CODING_TYPE_STREAM:
+ case HDMI_AUDIO_CODING_TYPE_PCM:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * drm_cea_sad_get_uncompressed_word_length - Extract word length
+ * @sad: Pointer to the cea_sad struct
+ *
+ * Extracts the cea_sad byte2 field and returns the word length for an
+ * uncompressed stream.
+ *
+ * Note: This function may only be called for uncompressed audio.
+ *
+ * Return: Word length in bits or a negative errno if parsing failed.
+ */
+int drm_cea_sad_get_uncompressed_word_length(const struct cea_sad *sad)
+{
+ if (!drm_cea_sad_is_uncompressed(sad)) {
+ DRM_WARN("Unable to get the uncompressed word length for a compressed format: %u\n",
+ sad->format);
+ return -EINVAL;
+ }
+
+ switch (sad->byte2) {
+ case DRM_CEA_SAD_UNCOMPRESSED_WORD_16BIT:
+ return 16;
+ case DRM_CEA_SAD_UNCOMPRESSED_WORD_20BIT:
+ return 20;
+ case DRM_CEA_SAD_UNCOMPRESSED_WORD_24BIT:
+ return 24;
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(drm_cea_sad_get_uncompressed_word_length);
+
/**
* drm_av_sync_delay - compute the HDMI/DP sink audio-video sync delay
* @connector: connector associated with the HDMI/DP sink
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 5d4d840b9904..ebd00ecae205 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -372,6 +372,18 @@ struct cea_sad {
u8 byte2;
};
+#define DRM_CEA_SAD_FREQ_32KHZ BIT(0)
+#define DRM_CEA_SAD_FREQ_44KHZ BIT(1)
+#define DRM_CEA_SAD_FREQ_48KHZ BIT(2)
+#define DRM_CEA_SAD_FREQ_88KHZ BIT(3)
+#define DRM_CEA_SAD_FREQ_96KHZ BIT(4)
+#define DRM_CEA_SAD_FREQ_176KHZ BIT(5)
+#define DRM_CEA_SAD_FREQ_192KHZ BIT(6)
+
+#define DRM_CEA_SAD_UNCOMPRESSED_WORD_16BIT BIT(0)
+#define DRM_CEA_SAD_UNCOMPRESSED_WORD_20BIT BIT(1)
+#define DRM_CEA_SAD_UNCOMPRESSED_WORD_24BIT BIT(2)
+
struct drm_encoder;
struct drm_connector;
struct drm_connector_state;
@@ -379,6 +391,8 @@ struct drm_display_mode;
int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads);
int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb);
+int drm_cea_sad_get_sample_rate(const struct cea_sad *sad);
+int drm_cea_sad_get_uncompressed_word_length(const struct cea_sad *sad);
int drm_av_sync_delay(struct drm_connector *connector,
const struct drm_display_mode *mode);
--
2.34.1
From: Markus Schneider-Pargmann <[email protected]>
This is a new driver that supports the integrated DisplayPort phy for
mediatek SoCs, especially the mt8195. The phy is integrated into the
DisplayPort controller and will be created by the mtk-dp driver. This
driver expects a struct regmap to be able to work on the same registers
as the DisplayPort controller. It sets the device data to be the struct
phy so that the DisplayPort controller can easily work with it.
The driver does not have any devicetree bindings because the datasheet
does not list the controller and the phy as distinct units.
The interaction with the controller can be covered by the configure
callback of the phy framework and its displayport parameters.
Signed-off-by: Markus Schneider-Pargmann <[email protected]>
Signed-off-by: Guillaume Ranquet <[email protected]>
---
MAINTAINERS | 1 +
drivers/phy/mediatek/Kconfig | 8 ++
drivers/phy/mediatek/Makefile | 1 +
drivers/phy/mediatek/phy-mtk-dp.c | 201 ++++++++++++++++++++++++++++++
4 files changed, 211 insertions(+)
create mode 100644 drivers/phy/mediatek/phy-mtk-dp.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 4cc47b2dbdc9..bfca96469d80 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6604,6 +6604,7 @@ L: [email protected] (moderated for non-subscribers)
S: Supported
F: Documentation/devicetree/bindings/display/mediatek/
F: drivers/gpu/drm/mediatek/
+F: drivers/phy/mediatek/phy-mtk-dp.c
F: drivers/phy/mediatek/phy-mtk-hdmi*
F: drivers/phy/mediatek/phy-mtk-mipi*
diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig
index 55f8e6c048ab..f7ec86059049 100644
--- a/drivers/phy/mediatek/Kconfig
+++ b/drivers/phy/mediatek/Kconfig
@@ -55,3 +55,11 @@ config PHY_MTK_MIPI_DSI
select GENERIC_PHY
help
Support MIPI DSI for Mediatek SoCs.
+
+config PHY_MTK_DP
+ tristate "MediaTek DP-PHY Driver"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ depends on OF
+ select GENERIC_PHY
+ help
+ Support DisplayPort PHY for Mediatek SoCs.
diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile
index ace660fbed3a..4ba1e0650434 100644
--- a/drivers/phy/mediatek/Makefile
+++ b/drivers/phy/mediatek/Makefile
@@ -3,6 +3,7 @@
# Makefile for the phy drivers.
#
+obj-$(CONFIG_PHY_MTK_DP) += phy-mtk-dp.o
obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o
obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o
diff --git a/drivers/phy/mediatek/phy-mtk-dp.c b/drivers/phy/mediatek/phy-mtk-dp.c
new file mode 100644
index 000000000000..e5c5494f3636
--- /dev/null
+++ b/drivers/phy/mediatek/phy-mtk-dp.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek DisplayPort PHY driver
+ *
+ * Copyright (c) 2021 BayLibre
+ * Author: Markus Schneider-Pargmann <[email protected]>
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define PHY_OFFSET 0x1000
+
+#define MTK_DP_PHY_DIG_PLL_CTL_1 (PHY_OFFSET + 0x14)
+#define TPLL_SSC_EN BIT(3)
+
+#define MTK_DP_PHY_DIG_BIT_RATE (PHY_OFFSET + 0x3C)
+#define BIT_RATE_RBR 0
+#define BIT_RATE_HBR 1
+#define BIT_RATE_HBR2 2
+#define BIT_RATE_HBR3 3
+
+#define MTK_DP_PHY_DIG_SW_RST (PHY_OFFSET + 0x38)
+#define DP_GLB_SW_RST_PHYD BIT(0)
+
+#define MTK_DP_LANE0_DRIVING_PARAM_3 (PHY_OFFSET + 0x138)
+#define MTK_DP_LANE1_DRIVING_PARAM_3 (PHY_OFFSET + 0x238)
+#define MTK_DP_LANE2_DRIVING_PARAM_3 (PHY_OFFSET + 0x338)
+#define MTK_DP_LANE3_DRIVING_PARAM_3 (PHY_OFFSET + 0x438)
+#define XTP_LN_TX_LCTXC0_SW0_PRE0_DEFAULT BIT(4)
+#define XTP_LN_TX_LCTXC0_SW0_PRE1_DEFAULT ((BIT(2) | BIT(4)) << 8)
+#define XTP_LN_TX_LCTXC0_SW0_PRE2_DEFAULT GENMASK(20, 19)
+#define XTP_LN_TX_LCTXC0_SW0_PRE3_DEFAULT GENMASK(29, 29)
+#define DRIVING_PARAM_3_DEFAULT (XTP_LN_TX_LCTXC0_SW0_PRE0_DEFAULT | \
+ XTP_LN_TX_LCTXC0_SW0_PRE1_DEFAULT | \
+ XTP_LN_TX_LCTXC0_SW0_PRE2_DEFAULT | \
+ XTP_LN_TX_LCTXC0_SW0_PRE3_DEFAULT)
+
+#define XTP_LN_TX_LCTXC0_SW1_PRE0_DEFAULT GENMASK(4, 3)
+#define XTP_LN_TX_LCTXC0_SW1_PRE1_DEFAULT GENMASK(12, 9)
+#define XTP_LN_TX_LCTXC0_SW1_PRE2_DEFAULT ((BIT(2) | BIT(5)) << 16)
+#define XTP_LN_TX_LCTXC0_SW2_PRE0_DEFAULT GENMASK(29, 29)
+#define DRIVING_PARAM_4_DEFAULT (XTP_LN_TX_LCTXC0_SW1_PRE0_DEFAULT | \
+ XTP_LN_TX_LCTXC0_SW1_PRE1_DEFAULT | \
+ XTP_LN_TX_LCTXC0_SW1_PRE2_DEFAULT | \
+ XTP_LN_TX_LCTXC0_SW2_PRE0_DEFAULT)
+
+#define XTP_LN_TX_LCTXC0_SW2_PRE1_DEFAULT (BIT(3) | BIT(5))
+#define XTP_LN_TX_LCTXC0_SW3_PRE0_DEFAULT GENMASK(13, 12)
+#define DRIVING_PARAM_5_DEFAULT (XTP_LN_TX_LCTXC0_SW2_PRE1_DEFAULT | \
+ XTP_LN_TX_LCTXC0_SW3_PRE0_DEFAULT)
+
+#define XTP_LN_TX_LCTXCP1_SW0_PRE0_DEFAULT 0
+#define XTP_LN_TX_LCTXCP1_SW0_PRE1_DEFAULT GENMASK(10, 10)
+#define XTP_LN_TX_LCTXCP1_SW0_PRE2_DEFAULT GENMASK(19, 19)
+#define XTP_LN_TX_LCTXCP1_SW0_PRE3_DEFAULT GENMASK(28, 28)
+#define DRIVING_PARAM_6_DEFAULT (XTP_LN_TX_LCTXCP1_SW0_PRE0_DEFAULT | \
+ XTP_LN_TX_LCTXCP1_SW0_PRE1_DEFAULT | \
+ XTP_LN_TX_LCTXCP1_SW0_PRE2_DEFAULT | \
+ XTP_LN_TX_LCTXCP1_SW0_PRE3_DEFAULT)
+
+#define XTP_LN_TX_LCTXCP1_SW1_PRE0_DEFAULT 0
+#define XTP_LN_TX_LCTXCP1_SW1_PRE1_DEFAULT GENMASK(10, 9)
+#define XTP_LN_TX_LCTXCP1_SW1_PRE2_DEFAULT GENMASK(19, 18)
+#define XTP_LN_TX_LCTXCP1_SW2_PRE0_DEFAULT 0
+#define DRIVING_PARAM_7_DEFAULT (XTP_LN_TX_LCTXCP1_SW1_PRE0_DEFAULT | \
+ XTP_LN_TX_LCTXCP1_SW1_PRE1_DEFAULT | \
+ XTP_LN_TX_LCTXCP1_SW1_PRE2_DEFAULT | \
+ XTP_LN_TX_LCTXCP1_SW2_PRE0_DEFAULT)
+
+#define XTP_LN_TX_LCTXCP1_SW2_PRE1_DEFAULT GENMASK(3, 3)
+#define XTP_LN_TX_LCTXCP1_SW3_PRE0_DEFAULT 0
+#define DRIVING_PARAM_8_DEFAULT (XTP_LN_TX_LCTXCP1_SW2_PRE1_DEFAULT | \
+ XTP_LN_TX_LCTXCP1_SW3_PRE0_DEFAULT)
+
+struct mtk_dp_phy {
+ struct regmap *regs;
+};
+
+static int mtk_dp_phy_init(struct phy *phy)
+{
+ struct mtk_dp_phy *dp_phy = phy_get_drvdata(phy);
+ u32 driving_params[] = {
+ DRIVING_PARAM_3_DEFAULT,
+ DRIVING_PARAM_4_DEFAULT,
+ DRIVING_PARAM_5_DEFAULT,
+ DRIVING_PARAM_6_DEFAULT,
+ DRIVING_PARAM_7_DEFAULT,
+ DRIVING_PARAM_8_DEFAULT
+ };
+
+ regmap_bulk_write(dp_phy->regs, MTK_DP_LANE0_DRIVING_PARAM_3,
+ driving_params, ARRAY_SIZE(driving_params));
+ regmap_bulk_write(dp_phy->regs, MTK_DP_LANE1_DRIVING_PARAM_3,
+ driving_params, ARRAY_SIZE(driving_params));
+ regmap_bulk_write(dp_phy->regs, MTK_DP_LANE2_DRIVING_PARAM_3,
+ driving_params, ARRAY_SIZE(driving_params));
+ regmap_bulk_write(dp_phy->regs, MTK_DP_LANE3_DRIVING_PARAM_3,
+ driving_params, ARRAY_SIZE(driving_params));
+
+ return 0;
+}
+
+static int mtk_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts)
+{
+ struct mtk_dp_phy *dp_phy = phy_get_drvdata(phy);
+ u32 val;
+
+ if (opts->dp.set_rate) {
+ switch (opts->dp.link_rate) {
+ default:
+ dev_err(&phy->dev,
+ "Implementation error, unknown linkrate %x\n",
+ opts->dp.link_rate);
+ return -EINVAL;
+ case 1620:
+ val = BIT_RATE_RBR;
+ break;
+ case 2700:
+ val = BIT_RATE_HBR;
+ break;
+ case 5400:
+ val = BIT_RATE_HBR2;
+ break;
+ case 8100:
+ val = BIT_RATE_HBR3;
+ break;
+ }
+ regmap_write(dp_phy->regs, MTK_DP_PHY_DIG_BIT_RATE, val);
+ }
+
+ regmap_update_bits(dp_phy->regs, MTK_DP_PHY_DIG_PLL_CTL_1,
+ TPLL_SSC_EN, opts->dp.ssc ? TPLL_SSC_EN : 0);
+
+ return 0;
+}
+
+static int mtk_dp_phy_reset(struct phy *phy)
+{
+ struct mtk_dp_phy *dp_phy = phy_get_drvdata(phy);
+
+ regmap_update_bits(dp_phy->regs, MTK_DP_PHY_DIG_SW_RST,
+ DP_GLB_SW_RST_PHYD, 0);
+ usleep_range(50, 200);
+ regmap_update_bits(dp_phy->regs, MTK_DP_PHY_DIG_SW_RST,
+ DP_GLB_SW_RST_PHYD, 1);
+
+ return 0;
+}
+
+static const struct phy_ops mtk_dp_phy_dev_ops = {
+ .init = mtk_dp_phy_init,
+ .configure = mtk_dp_phy_configure,
+ .reset = mtk_dp_phy_reset,
+ .owner = THIS_MODULE,
+};
+
+static int mtk_dp_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_dp_phy *dp_phy;
+ struct phy *phy;
+ struct regmap *regs;
+
+ regs = syscon_regmap_lookup_by_phandle(dev->of_node, "mediatek,dp-syscon");
+
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ dp_phy = devm_kzalloc(dev, sizeof(*dp_phy), GFP_KERNEL);
+ if (!dp_phy)
+ return -ENOMEM;
+
+ dp_phy->regs = regs;
+
+ phy = devm_phy_create(dev, NULL, &mtk_dp_phy_dev_ops);
+
+ if (IS_ERR(phy))
+ return dev_err_probe(dev, PTR_ERR(phy), "Failed to create DP PHY: %ld\n", PTR_ERR(phy));
+
+ phy_set_drvdata(phy, dp_phy);
+
+ return 0;
+}
+
+struct platform_driver mtk_dp_phy_driver = {
+ .probe = mtk_dp_phy_probe,
+ .driver = {
+ .name = "mediatek-dp-phy",
+ },
+};
+module_platform_driver(mtk_dp_phy_driver);
+
+MODULE_AUTHOR("Markus Schneider-Pargmann <[email protected]>");
+MODULE_DESCRIPTION("MediaTek DP PHY Driver");
+MODULE_LICENSE("GPL");
--
2.34.1
This patch adds External DisplayPort support to the mt8195 eDP driver.
Signed-off-by: Guillaume Ranquet <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dp.c | 301 +++++++++++++++++++++++++++---
1 file changed, 278 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 7cd8459cf719..9e532408f12e 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -176,6 +176,11 @@ struct mtk_dp {
struct drm_connector *conn;
};
+static bool mtk_dp_is_edp(struct mtk_dp *mtk_dp)
+{
+ return mtk_dp->next_bridge;
+}
+
static struct mtk_dp *mtk_dp_from_bridge(struct drm_bridge *b)
{
return container_of(b, struct mtk_dp, bridge);
@@ -741,6 +746,47 @@ static int mtk_dp_fec_enable(struct mtk_dp *mtk_dp, bool enable)
FEC_EN_DP_TRANS_P0_MASK);
}
+static u32 mtk_dp_swirq_get_clear(struct mtk_dp *mtk_dp)
+{
+ int ret;
+
+ u32 irq_status = mtk_dp_read(mtk_dp, MTK_DP_TRANS_P0_35D0) &
+ SW_IRQ_FINAL_STATUS_DP_TRANS_P0_MASK;
+
+ if (irq_status) {
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_35C8, irq_status,
+ SW_IRQ_CLR_DP_TRANS_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_35C8, 0,
+ SW_IRQ_CLR_DP_TRANS_P0_MASK, ret, out);
+ }
+
+ return irq_status;
+
+out:
+ return ret;
+}
+
+static u32 mtk_dp_hwirq_get_clear(struct mtk_dp *mtk_dp)
+{
+ int ret;
+
+ u8 irq_status = (mtk_dp_read(mtk_dp, MTK_DP_TRANS_P0_3418) &
+ IRQ_STATUS_DP_TRANS_P0_MASK) >>
+ IRQ_STATUS_DP_TRANS_P0_SHIFT;
+
+ if (irq_status) {
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_3418, irq_status,
+ IRQ_CLR_DP_TRANS_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_3418, 0,
+ IRQ_CLR_DP_TRANS_P0_MASK, ret, out);
+ }
+
+ return irq_status;
+
+out:
+ return ret;
+}
+
static int mtk_dp_hwirq_enable(struct mtk_dp *mtk_dp, bool enable)
{
u32 val = 0;
@@ -932,26 +978,49 @@ static int mtk_dp_get_calibration_data(struct mtk_dp *mtk_dp)
return PTR_ERR(buf);
}
- cal_data->glb_bias_trim =
- check_cal_data_valid(1, 0x1e, (buf[3] >> 27) & 0x1f, 0xf);
- cal_data->clktx_impse =
- check_cal_data_valid(1, 0xe, (buf[0] >> 9) & 0xf, 0x8);
- cal_data->ln_tx_impsel_pmos[0] =
- check_cal_data_valid(1, 0xe, (buf[2] >> 28) & 0xf, 0x8);
- cal_data->ln_tx_impsel_nmos[0] =
- check_cal_data_valid(1, 0xe, (buf[2] >> 24) & 0xf, 0x8);
- cal_data->ln_tx_impsel_pmos[1] =
- check_cal_data_valid(1, 0xe, (buf[2] >> 20) & 0xf, 0x8);
- cal_data->ln_tx_impsel_nmos[1] =
- check_cal_data_valid(1, 0xe, (buf[2] >> 16) & 0xf, 0x8);
- cal_data->ln_tx_impsel_pmos[2] =
- check_cal_data_valid(1, 0xe, (buf[2] >> 12) & 0xf, 0x8);
- cal_data->ln_tx_impsel_nmos[2] =
- check_cal_data_valid(1, 0xe, (buf[2] >> 8) & 0xf, 0x8);
- cal_data->ln_tx_impsel_pmos[3] =
- check_cal_data_valid(1, 0xe, (buf[2] >> 4) & 0xf, 0x8);
- cal_data->ln_tx_impsel_nmos[3] =
- check_cal_data_valid(1, 0xe, buf[2] & 0xf, 0x8);
+ if (mtk_dp_is_edp(mtk_dp)) {
+ cal_data->glb_bias_trim =
+ check_cal_data_valid(1, 0x1e, (buf[3] >> 27) & 0x1f, 0xf);
+ cal_data->clktx_impse =
+ check_cal_data_valid(1, 0xe, (buf[0] >> 9) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_pmos[0] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 28) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_nmos[0] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 24) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_pmos[1] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 20) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_nmos[1] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 16) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_pmos[2] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 12) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_nmos[2] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 8) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_pmos[3] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 4) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_nmos[3] =
+ check_cal_data_valid(1, 0xe, buf[2] & 0xf, 0x8);
+ } else {
+ cal_data->glb_bias_trim =
+ check_cal_data_valid(1, 0x1e, (buf[0] >> 27) & 0x1f, 0xf);
+ cal_data->clktx_impse =
+ check_cal_data_valid(1, 0xe, (buf[0] >> 13) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_pmos[0] =
+ check_cal_data_valid(1, 0xe, (buf[1] >> 28) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_nmos[0] =
+ check_cal_data_valid(1, 0xe, (buf[1] >> 24) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_pmos[1] =
+ check_cal_data_valid(1, 0xe, (buf[1] >> 20) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_nmos[1] =
+ check_cal_data_valid(1, 0xe, (buf[1] >> 16) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_pmos[2] =
+ check_cal_data_valid(1, 0xe, (buf[1] >> 12) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_nmos[2] =
+ check_cal_data_valid(1, 0xe, (buf[1] >> 8) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_pmos[3] =
+ check_cal_data_valid(1, 0xe, (buf[1] >> 4) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_nmos[3] =
+ check_cal_data_valid(1, 0xe, buf[1] & 0xf, 0x8);
+ }
kfree(buf);
@@ -1080,7 +1149,10 @@ static void mtk_dp_video_mute(struct mtk_dp *mtk_dp, bool enable)
VIDEO_MUTE_SEL_DP_ENC0_P0_MASK |
VIDEO_MUTE_SW_DP_ENC0_P0_MASK);
- mtk_dp_sip_atf_call(MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE, enable);
+ if (mtk_dp_is_edp(mtk_dp))
+ mtk_dp_sip_atf_call(MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE, enable);
+ else
+ mtk_dp_sip_atf_call(MTK_DP_SIP_ATF_VIDEO_UNMUTE, enable);
}
static int mtk_dp_power_enable(struct mtk_dp *mtk_dp)
@@ -1195,6 +1267,57 @@ static void mtk_dp_set_tx_out(struct mtk_dp *mtk_dp)
mtk_dp_setup_tu(mtk_dp);
}
+static void mtk_dp_edid_free(struct mtk_dp *mtk_dp)
+{
+ mutex_lock(&mtk_dp->edid_lock);
+ kfree(mtk_dp->edid);
+ mtk_dp->edid = NULL;
+ mutex_unlock(&mtk_dp->edid_lock);
+}
+
+static int mtk_dp_hpd_sink_event(struct mtk_dp *mtk_dp)
+{
+ ssize_t ret;
+ u8 sink_count;
+ bool locked;
+ u8 link_status[DP_LINK_STATUS_SIZE] = {};
+ u32 sink_count_reg = DP_SINK_COUNT_ESI;
+ u32 link_status_reg = DP_LANE0_1_STATUS;
+
+ ret = drm_dp_dpcd_readb(&mtk_dp->aux, sink_count_reg, &sink_count);
+ if (ret < 0) {
+ drm_err(mtk_dp->drm_dev, "Read sink count failed: %ld\n", ret);
+ return ret;
+ }
+
+ ret = drm_dp_dpcd_read(&mtk_dp->aux, link_status_reg, link_status,
+ sizeof(link_status));
+ if (!ret) {
+ drm_err(mtk_dp->drm_dev, "Read link status failed: %ld\n",
+ ret);
+ return ret;
+ }
+
+ locked = drm_dp_channel_eq_ok(link_status,
+ mtk_dp->train_info.lane_count);
+ if (!locked && mtk_dp->train_state > MTK_DP_TRAIN_STATE_TRAINING_PRE)
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_TRAINING_PRE;
+
+ if (link_status[1] & DP_REMOTE_CONTROL_COMMAND_PENDING)
+ drm_dp_dpcd_writeb(&mtk_dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR,
+ DP_REMOTE_CONTROL_COMMAND_PENDING);
+
+ if (DP_GET_SINK_COUNT(sink_count) &&
+ (link_status[2] & DP_DOWNSTREAM_PORT_STATUS_CHANGED)) {
+ mtk_dp_edid_free(mtk_dp);
+ mtk_dp->train_info.check_cap_count = 0;
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_CHECKEDID;
+ msleep(20);
+ }
+
+ return 0;
+}
+
static void mtk_dp_train_update_swing_pre(struct mtk_dp *mtk_dp, int lanes,
u8 dpcd_adjust_req[2])
{
@@ -1677,6 +1800,115 @@ static void mtk_dp_init_port(struct mtk_dp *mtk_dp)
mtk_dp_digital_sw_reset(mtk_dp);
}
+static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
+{
+ struct mtk_dp *mtk_dp = dev;
+ int event;
+ u8 buf[DP_RECEIVER_CAP_SIZE] = {};
+
+ event = mtk_dp_plug_state(mtk_dp) ? connector_status_connected :
+ connector_status_disconnected;
+
+ if (event < 0)
+ return IRQ_HANDLED;
+
+ if (mtk_dp->drm_dev) {
+ dev_info(mtk_dp->dev, "drm_helper_hpd_irq_event\n");
+ drm_helper_hpd_irq_event(mtk_dp->bridge.dev);
+ }
+
+ if (mtk_dp->train_info.cable_state_change) {
+ mtk_dp->train_info.cable_state_change = false;
+
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_STARTUP;
+
+ if (!mtk_dp->train_info.cable_plugged_in ||
+ !mtk_dp_plug_state(mtk_dp)) {
+ mtk_dp_video_mute(mtk_dp, true);
+
+ mtk_dp_initialize_priv_data(mtk_dp);
+ mtk_dp_set_idle_pattern(mtk_dp, true);
+ if (mtk_dp->has_fec)
+ mtk_dp_fec_enable(mtk_dp, false);
+
+ mtk_dp_edid_free(mtk_dp);
+ mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
+ DP_PWR_STATE_BANDGAP_TPLL,
+ DP_PWR_STATE_MASK);
+ } else {
+ mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
+ DP_PWR_STATE_BANDGAP_TPLL_LANE,
+ DP_PWR_STATE_MASK);
+ drm_dp_read_dpcd_caps(&mtk_dp->aux, buf);
+ mtk_dp->train_info.link_rate =
+ min_t(int, MTK_DP_MAX_LINK_RATE,
+ buf[DP_MAX_LINK_RATE]);
+ mtk_dp->train_info.lane_count =
+ min_t(int, MTK_DP_MAX_LANES,
+ drm_dp_max_lane_count(buf));
+ }
+ }
+
+ if (mtk_dp->train_info.irq_status & MTK_DP_HPD_INTERRUPT) {
+ dev_dbg(mtk_dp->dev, "MTK_DP_HPD_INTERRUPT\n");
+ mtk_dp->train_info.irq_status &= ~MTK_DP_HPD_INTERRUPT;
+ mtk_dp_hpd_sink_event(mtk_dp);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mtk_dp_hpd_isr_handler(struct mtk_dp *mtk_dp)
+{
+ bool connected;
+ u16 swirq_status = mtk_dp_swirq_get_clear(mtk_dp);
+ u8 hwirq_status = mtk_dp_hwirq_get_clear(mtk_dp);
+ struct mtk_dp_train_info *train_info = &mtk_dp->train_info;
+
+ train_info->irq_status |= hwirq_status | swirq_status;
+
+ if (!train_info->irq_status)
+ return IRQ_HANDLED;
+
+ connected = mtk_dp_plug_state(mtk_dp);
+ if (connected || !train_info->cable_plugged_in)
+ train_info->irq_status &= ~MTK_DP_HPD_DISCONNECT;
+ else if (!connected || train_info->cable_plugged_in)
+ train_info->irq_status &= ~MTK_DP_HPD_CONNECT;
+
+ if (!(train_info->irq_status &
+ (MTK_DP_HPD_CONNECT | MTK_DP_HPD_DISCONNECT)))
+ return IRQ_HANDLED;
+
+ if (train_info->irq_status & MTK_DP_HPD_CONNECT) {
+ train_info->irq_status &= ~MTK_DP_HPD_CONNECT;
+ train_info->cable_plugged_in = true;
+ } else {
+ train_info->irq_status &= ~MTK_DP_HPD_DISCONNECT;
+ train_info->cable_plugged_in = false;
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_STARTUP;
+ }
+ train_info->cable_state_change = true;
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t mtk_dp_hpd_event(int hpd, void *dev)
+{
+ struct mtk_dp *mtk_dp = dev;
+ u32 irq_status;
+
+ irq_status = mtk_dp_read(mtk_dp, MTK_DP_TOP_IRQ_STATUS);
+
+ if (!irq_status)
+ return IRQ_HANDLED;
+
+ if (irq_status & RGS_IRQ_STATUS_TRANSMITTER)
+ return mtk_dp_hpd_isr_handler(mtk_dp);
+
+ return IRQ_HANDLED;
+}
+
static int mtk_dp_dt_parse(struct mtk_dp *mtk_dp,
struct platform_device *pdev)
{
@@ -2110,6 +2342,7 @@ static int mtk_dp_probe(struct platform_device *pdev)
struct mtk_dp *mtk_dp;
struct device *dev = &pdev->dev;
int ret;
+ int irq_num = 0;
mtk_dp = devm_kzalloc(dev, sizeof(*mtk_dp), GFP_KERNEL);
if (!mtk_dp)
@@ -2117,9 +2350,18 @@ static int mtk_dp_probe(struct platform_device *pdev)
mtk_dp->dev = dev;
+ irq_num = platform_get_irq(pdev, 0);
+ if (irq_num < 0)
+ return dev_err_probe(dev, irq_num, "failed to request dp irq resource\n");
+
mtk_dp->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
- if (IS_ERR(mtk_dp->next_bridge))
+ if (IS_ERR(mtk_dp->next_bridge) && PTR_ERR(mtk_dp->next_bridge) == -ENODEV) {
+ dev_info(dev,
+ "No panel connected in devicetree, continuing as external DP\n");
+ mtk_dp->next_bridge = NULL;
+ } else if (IS_ERR(mtk_dp->next_bridge)) {
return dev_err_probe(dev, PTR_ERR(mtk_dp->next_bridge), "Failed to get bridge\n");
+ }
ret = mtk_dp_dt_parse(mtk_dp, pdev);
if (ret)
@@ -2129,6 +2371,13 @@ static int mtk_dp_probe(struct platform_device *pdev)
mtk_dp->aux.name = "aux_mtk_dp";
mtk_dp->aux.transfer = mtk_dp_aux_transfer;
+ ret = devm_request_threaded_irq(dev, irq_num, mtk_dp_hpd_event,
+ mtk_dp_hpd_event_thread,
+ IRQ_TYPE_LEVEL_HIGH, dev_name(dev),
+ mtk_dp);
+ if (ret)
+ return dev_err_probe(dev, -EPROBE_DEFER, "failed to request mediatek dptx irq\n");
+
mutex_init(&mtk_dp->dp_lock);
mutex_init(&mtk_dp->edid_lock);
@@ -2145,8 +2394,13 @@ static int mtk_dp_probe(struct platform_device *pdev)
mtk_dp->bridge.of_node = dev->of_node;
mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP;
- mtk_dp->bridge.ops = DRM_BRIDGE_OP_EDID;
+ mtk_dp->bridge.ops =
+ DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD;
drm_bridge_add(&mtk_dp->bridge);
+ if (mtk_dp_is_edp(mtk_dp))
+ mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP;
+ else
+ mtk_dp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
@@ -2201,6 +2455,7 @@ static SIMPLE_DEV_PM_OPS(mtk_dp_pm_ops, mtk_dp_suspend, mtk_dp_resume);
static const struct of_device_id mtk_dp_of_match[] = {
{ .compatible = "mediatek,mt8195-edp-tx", },
+ { .compatible = "mediatek,mt8195-dp-tx", },
{},
};
MODULE_DEVICE_TABLE(of, mtk_dp_of_match);
--
2.34.1
dpintf is the displayport interface hardware unit. This unit is similar
to dpi and can reuse most of the code.
This patch adds support for mt8195-dpintf to this dpi driver. Main
differences are:
- Some features/functional components are not available for dpintf
which are now excluded from code execution once is_dpintf is set
- dpintf can and needs to choose between different clockdividers based
on the clockspeed. This is done by choosing a different clock parent.
- There are two additional clocks that need to be managed. These are
only set for dpintf and will be set to NULL if not supplied. The
clk_* calls handle these as normal clocks then.
- Some register contents differ slightly between the two components. To
work around this I added register bits/masks with a DPINTF_ prefix
and use them where different.
Based on a separate driver for dpintf created by
Jason-JH.Lin <[email protected]>.
Signed-off-by: Markus Schneider-Pargmann <[email protected]>
Signed-off-by: Guillaume Ranquet <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 78 ++++++++++++++++++---
drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 38 ++++++++++
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 8 +++
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 1 +
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 5 +-
include/linux/soc/mediatek/mtk-mmsys.h | 2 +
6 files changed, 120 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index eb969c5c5c2e..8198d3cf23ac 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -126,6 +126,7 @@ struct mtk_dpi_conf {
const u32 *output_fmts;
u32 num_output_fmts;
bool is_ck_de_pol;
+ bool is_dpintf;
bool swap_input_support;
/* Mask used for HWIDTH, HPORCH, VSYNC_WIDTH and VSYNC_PORCH (no shift) */
u32 dimension_mask;
@@ -498,11 +499,11 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
vm.pixelclock = pll_rate / factor;
if ((dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE) ||
- (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE))
+ (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE)) {
clk_set_rate(dpi->pixel_clk, vm.pixelclock * 2);
- else
+ } else {
clk_set_rate(dpi->pixel_clk, vm.pixelclock);
-
+ }
vm.pixelclock = clk_get_rate(dpi->pixel_clk);
@@ -515,9 +516,15 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING;
dpi_pol.vsync_pol = vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ?
MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING;
- hsync.sync_width = vm.hsync_len;
- hsync.back_porch = vm.hback_porch;
- hsync.front_porch = vm.hfront_porch;
+ if (dpi->conf->is_dpintf) {
+ hsync.sync_width = vm.hsync_len / 4;
+ hsync.back_porch = vm.hback_porch / 4;
+ hsync.front_porch = vm.hfront_porch / 4;
+ } else {
+ hsync.sync_width = vm.hsync_len;
+ hsync.back_porch = vm.hback_porch;
+ hsync.front_porch = vm.hfront_porch;
+ }
hsync.shift_half_line = false;
vsync_lodd.sync_width = vm.vsync_len;
vsync_lodd.back_porch = vm.vback_porch;
@@ -559,13 +566,20 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
mtk_dpi_config_channel_limit(dpi);
mtk_dpi_config_bit_num(dpi, dpi->bit_num);
mtk_dpi_config_channel_swap(dpi, dpi->channel_swap);
- mtk_dpi_config_yc_map(dpi, dpi->yc_map);
mtk_dpi_config_color_format(dpi, dpi->color_format);
- mtk_dpi_config_2n_h_fre(dpi);
- mtk_dpi_dual_edge(dpi);
- mtk_dpi_config_disable_edge(dpi);
+ if (dpi->conf->is_dpintf) {
+ mtk_dpi_mask(dpi, DPI_CON, DPINTF_INPUT_2P_EN,
+ DPINTF_INPUT_2P_EN);
+ } else {
+ mtk_dpi_config_yc_map(dpi, dpi->yc_map);
+ mtk_dpi_config_2n_h_fre(dpi);
+ mtk_dpi_dual_edge(dpi);
+ mtk_dpi_config_disable_edge(dpi);
+ }
mtk_dpi_sw_reset(dpi, false);
+ mtk_dpi_enable(dpi);
+
return 0;
}
@@ -642,7 +656,10 @@ static int mtk_dpi_bridge_atomic_check(struct drm_bridge *bridge,
dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS;
dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB;
dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
- dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
+ if (out_bus_format == MEDIA_BUS_FMT_YUYV8_1X16)
+ dpi->color_format = MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL;
+ else
+ dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
return 0;
}
@@ -801,6 +818,16 @@ static unsigned int mt8183_calculate_factor(int clock)
return 2;
}
+static unsigned int mt8195_dpintf_calculate_factor(int clock)
+{
+ if (clock < 70000)
+ return 4;
+ else if (clock < 200000)
+ return 2;
+ else
+ return 1;
+}
+
static const u32 mt8173_output_fmts[] = {
MEDIA_BUS_FMT_RGB888_1X24,
};
@@ -810,6 +837,12 @@ static const u32 mt8183_output_fmts[] = {
MEDIA_BUS_FMT_RGB888_2X12_BE,
};
+static const u32 mt8195_output_fmts[] = {
+ MEDIA_BUS_FMT_RGB888_1X24,
+ MEDIA_BUS_FMT_YUV8_1X24,
+ MEDIA_BUS_FMT_YUYV8_1X16,
+};
+
static const struct mtk_dpi_yc_limit mtk_dpi_limit = {
.c_bottom = 0x0010,
.c_top = 0x0FE0,
@@ -817,6 +850,13 @@ static const struct mtk_dpi_yc_limit mtk_dpi_limit = {
.y_top = 0x0FE0,
};
+static const struct mtk_dpi_yc_limit mtk_dpintf_limit = {
+ .c_bottom = 0x0000,
+ .c_top = 0xFFF,
+ .y_bottom = 0x0000,
+ .y_top = 0xFFF,
+};
+
static const struct mtk_dpi_conf mt8173_conf = {
.cal_factor = mt8173_calculate_factor,
.reg_h_fre_con = 0xe0,
@@ -882,6 +922,19 @@ static const struct mtk_dpi_conf mt8192_conf = {
.limit = &mtk_dpi_limit,
};
+static const struct mtk_dpi_conf mt8195_dpintf_conf = {
+ .cal_factor = mt8195_dpintf_calculate_factor,
+ .output_fmts = mt8195_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8195_output_fmts),
+ .is_dpintf = true,
+ .dimension_mask = DPINTF_HPW_MASK,
+ .hvsize_mask = DPINTF_HSIZE_MASK,
+ .channel_swap_shift = DPINTF_CH_SWAP,
+ .yuv422_en_bit = DPINTF_YUV422_EN,
+ .csc_enable_bit = DPINTF_CSC_ENABLE,
+ .limit = &mtk_dpintf_limit,
+};
+
static int mtk_dpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1004,6 +1057,9 @@ static const struct of_device_id mtk_dpi_of_ids[] = {
{ .compatible = "mediatek,mt8192-dpi",
.data = &mt8192_conf,
},
+ { .compatible = "mediatek,mt8195-dpintf",
+ .data = &mt8195_dpintf_conf,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, mtk_dpi_of_ids);
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
index 3a02fabe1662..91b32dfffced 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
+++ b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
@@ -40,10 +40,15 @@
#define FAKE_DE_LEVEN BIT(21)
#define FAKE_DE_RODD BIT(22)
#define FAKE_DE_REVEN BIT(23)
+#define DPINTF_YUV422_EN BIT(24)
+#define DPINTF_CSC_ENABLE BIT(26)
+#define DPINTF_INPUT_2P_EN BIT(29)
#define DPI_OUTPUT_SETTING 0x14
#define CH_SWAP 0
+#define DPINTF_CH_SWAP BIT(1)
#define CH_SWAP_MASK (0x7 << 0)
+#define DPINTF_CH_SWAP_MASK (0x7 << 1)
#define SWAP_RGB 0x00
#define SWAP_GBR 0x01
#define SWAP_BRG 0x02
@@ -80,8 +85,10 @@
#define DPI_SIZE 0x18
#define HSIZE 0
#define HSIZE_MASK (0x1FFF << 0)
+#define DPINTF_HSIZE_MASK (0xFFFF << 0)
#define VSIZE 16
#define VSIZE_MASK (0x1FFF << 16)
+#define DPINTF_VSIZE_MASK (0xFFFF << 16)
#define DPI_DDR_SETTING 0x1C
#define DDR_EN BIT(0)
@@ -93,24 +100,30 @@
#define DPI_TGEN_HWIDTH 0x20
#define HPW 0
#define HPW_MASK (0xFFF << 0)
+#define DPINTF_HPW_MASK (0xFFFF << 0)
#define DPI_TGEN_HPORCH 0x24
#define HBP 0
#define HBP_MASK (0xFFF << 0)
+#define DPINTF_HBP_MASK (0xFFFF << 0)
#define HFP 16
#define HFP_MASK (0xFFF << 16)
+#define DPINTF_HFP_MASK (0xFFFF << 16)
#define DPI_TGEN_VWIDTH 0x28
#define DPI_TGEN_VPORCH 0x2C
#define VSYNC_WIDTH_SHIFT 0
#define VSYNC_WIDTH_MASK (0xFFF << 0)
+#define DPINTF_VSYNC_WIDTH_MASK (0xFFFF << 0)
#define VSYNC_HALF_LINE_SHIFT 16
#define VSYNC_HALF_LINE_MASK BIT(16)
#define VSYNC_BACK_PORCH_SHIFT 0
#define VSYNC_BACK_PORCH_MASK (0xFFF << 0)
+#define DPINTF_VSYNC_BACK_PORCH_MASK (0xFFFF << 0)
#define VSYNC_FRONT_PORCH_SHIFT 16
#define VSYNC_FRONT_PORCH_MASK (0xFFF << 16)
+#define DPINTF_VSYNC_FRONT_PORCH_MASK (0xFFFF << 16)
#define DPI_BG_HCNTL 0x30
#define BG_RIGHT (0x1FFF << 0)
@@ -217,4 +230,29 @@
#define EDGE_SEL_EN BIT(5)
#define H_FRE_2N BIT(25)
+
+#define DPI_MATRIX_SET 0xB4
+#define INT_MATRIX_SEL BIT(0)
+#define INT_MATRIX_SEL_MASK (0x1F << 0)
+#define RGB_TO_JPEG 0x00
+#define RGB_TO_FULL709 0x01
+#define RGB_TO_BT601 0x02
+#define RGB_TO_BT709 0x03
+#define JPEG_TO_RGB 0x04
+#define FULL709_TO_RGB 0x05
+#define BT601_TO_RGB 0x06
+#define BT709_TO_RGB 0x07
+#define JPEG_TO_BT601 0x08
+#define JPEG_TO_BT709 0x09
+#define BT601_TO_JPEG 0xA
+#define BT709_TO_JPEG 0xB
+#define BT709_TO_BT601 0xC
+#define BT601_TO_BT709 0xD
+#define JPEG_TO_CERGB 0x14
+#define FULL709_TO_CERGB 0x15
+#define BT601_TO_CERGB 0x16
+#define BT709_TO_CERGB 0x17
+#define RGB_TO_CERGB 0x1C
+#define MATRIX_BIT BIT(8)
+#define EXT_MATRIX_EN BIT(12)
#endif /* __MTK_DPI_REGS_H */
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 2e99aee13dfe..558fc2733358 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -351,6 +351,11 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_WDMA] = "wdma",
[MTK_DPI] = "dpi",
[MTK_DSI] = "dsi",
+ [MTK_DP_INTF] = "dp-intf",
+ [MTK_DISP_PWM] = "pwm",
+ [MTK_DISP_MUTEX] = "mutex",
+ [MTK_DISP_OD] = "od",
+ [MTK_DISP_BLS] = "bls",
};
struct mtk_ddp_comp_match {
@@ -369,6 +374,8 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_DITHER] = { MTK_DISP_DITHER, 0, &ddp_dither },
[DDP_COMPONENT_DPI0] = { MTK_DPI, 0, &ddp_dpi },
[DDP_COMPONENT_DPI1] = { MTK_DPI, 1, &ddp_dpi },
+ [DDP_COMPONENT_DP_INTF0] = { MTK_DP_INTF, 0, &ddp_dpi },
+ [DDP_COMPONENT_DP_INTF1] = { MTK_DP_INTF, 1, &ddp_dpi },
[DDP_COMPONENT_DSI0] = { MTK_DSI, 0, &ddp_dsi },
[DDP_COMPONENT_DSI1] = { MTK_DSI, 1, &ddp_dsi },
[DDP_COMPONENT_DSI2] = { MTK_DSI, 2, &ddp_dsi },
@@ -481,6 +488,7 @@ int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp,
type == MTK_DISP_PWM ||
type == MTK_DISP_RDMA ||
type == MTK_DPI ||
+ type == MTK_DP_INTF ||
type == MTK_DSI)
return 0;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
index ad267bb8fc9b..43ad74be509e 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
@@ -34,6 +34,7 @@ enum mtk_ddp_comp_type {
MTK_DISP_UFOE,
MTK_DISP_WDMA,
MTK_DPI,
+ MTK_DP_INTF,
MTK_DSI,
MTK_DDP_COMP_TYPE_MAX,
};
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 247c6ff277ef..c8a233f609f0 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -509,6 +509,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt8183-dpi",
.data = (void *)MTK_DPI },
+ { .compatible = "mediatek,mt8195-dpintf",
+ .data = (void *)MTK_DP_INTF },
{ .compatible = "mediatek,mt2701-dsi",
.data = (void *)MTK_DSI },
{ .compatible = "mediatek,mt8173-dsi",
@@ -609,7 +611,8 @@ static int mtk_drm_probe(struct platform_device *pdev)
comp_type == MTK_DISP_OVL_2L ||
comp_type == MTK_DISP_RDMA ||
comp_type == MTK_DPI ||
- comp_type == MTK_DSI) {
+ comp_type == MTK_DPI ||
+ comp_type == MTK_DP_INTF) {
dev_info(dev, "Adding component match for %pOF\n",
node);
drm_of_component_match_add(dev, &match, component_compare_of,
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index 4bba275e235a..56ed2fa5f59e 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -19,6 +19,8 @@ enum mtk_ddp_comp_id {
DDP_COMPONENT_DITHER,
DDP_COMPONENT_DPI0,
DDP_COMPONENT_DPI1,
+ DDP_COMPONENT_DP_INTF0,
+ DDP_COMPONENT_DP_INTF1,
DDP_COMPONENT_DSI0,
DDP_COMPONENT_DSI1,
DDP_COMPONENT_DSI2,
--
2.34.1
Signed-off-by: Guillaume Ranquet <[email protected]>
---
include/drm/drm_edid.h | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 144c495b99c4..5d4d840b9904 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -359,12 +359,17 @@ struct edid {
#define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
-/* Short Audio Descriptor */
+/* struct cea_sad - Short Audio Descriptor.
+ @format: See HDMI_AUDIO_CODING_TYPE_*.
+ @channels: max number of channels - 1.
+ @freq: See CEA_SAD_FREQ_*.
+ @byte2: meaning depends on format.
+*/
struct cea_sad {
u8 format;
- u8 channels; /* max number of channels - 1 */
+ u8 channels;
u8 freq;
- u8 byte2; /* meaning depends on format */
+ u8 byte2;
};
struct drm_encoder;
--
2.34.1
Add flexibility by moving the dpi limits to the SoC specific config
Signed-off-by: Guillaume Ranquet <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 4554e2de1430..4746eb342567 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -125,6 +125,7 @@ struct mtk_dpi_conf {
bool edge_sel_en;
const u32 *output_fmts;
u32 num_output_fmts;
+ const struct mtk_dpi_yc_limit *limit;
};
static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
@@ -235,9 +236,10 @@ static void mtk_dpi_config_fb_size(struct mtk_dpi *dpi, u32 width, u32 height)
mtk_dpi_mask(dpi, DPI_SIZE, height << VSIZE, VSIZE_MASK);
}
-static void mtk_dpi_config_channel_limit(struct mtk_dpi *dpi,
- struct mtk_dpi_yc_limit *limit)
+static void mtk_dpi_config_channel_limit(struct mtk_dpi *dpi)
{
+ const struct mtk_dpi_yc_limit *limit = dpi->conf->limit;
+
mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_bottom << Y_LIMINT_BOT,
Y_LIMINT_BOT_MASK);
mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_top << Y_LIMINT_TOP,
@@ -449,7 +451,6 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi)
static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
struct drm_display_mode *mode)
{
- struct mtk_dpi_yc_limit limit;
struct mtk_dpi_polarities dpi_pol;
struct mtk_dpi_sync_param hsync;
struct mtk_dpi_sync_param vsync_lodd = { 0 };
@@ -484,11 +485,6 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
dev_dbg(dpi->dev, "Got PLL %lu Hz, pixel clock %lu Hz\n",
pll_rate, vm.pixelclock);
- limit.c_bottom = 0x0010;
- limit.c_top = 0x0FE0;
- limit.y_bottom = 0x0010;
- limit.y_top = 0x0FE0;
-
dpi_pol.ck_pol = MTK_DPI_POLARITY_FALLING;
dpi_pol.de_pol = MTK_DPI_POLARITY_RISING;
dpi_pol.hsync_pol = vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ?
@@ -536,7 +532,7 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
else
mtk_dpi_config_fb_size(dpi, vm.hactive, vm.vactive);
- mtk_dpi_config_channel_limit(dpi, &limit);
+ mtk_dpi_config_channel_limit(dpi);
mtk_dpi_config_bit_num(dpi, dpi->bit_num);
mtk_dpi_config_channel_swap(dpi, dpi->channel_swap);
mtk_dpi_config_yc_map(dpi, dpi->yc_map);
@@ -790,12 +786,20 @@ static const u32 mt8183_output_fmts[] = {
MEDIA_BUS_FMT_RGB888_2X12_BE,
};
+static const struct mtk_dpi_yc_limit mtk_dpi_limit = {
+ .c_bottom = 0x0010,
+ .c_top = 0x0FE0,
+ .y_bottom = 0x0010,
+ .y_top = 0x0FE0,
+};
+
static const struct mtk_dpi_conf mt8173_conf = {
.cal_factor = mt8173_calculate_factor,
.reg_h_fre_con = 0xe0,
.max_clock_khz = 300000,
.output_fmts = mt8173_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
+ .limit = &mtk_dpi_limit,
};
static const struct mtk_dpi_conf mt2701_conf = {
@@ -805,6 +809,7 @@ static const struct mtk_dpi_conf mt2701_conf = {
.max_clock_khz = 150000,
.output_fmts = mt8173_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
+ .limit = &mtk_dpi_limit,
};
static const struct mtk_dpi_conf mt8183_conf = {
@@ -813,6 +818,7 @@ static const struct mtk_dpi_conf mt8183_conf = {
.max_clock_khz = 100000,
.output_fmts = mt8183_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8183_output_fmts),
+ .limit = &mtk_dpi_limit,
};
static const struct mtk_dpi_conf mt8192_conf = {
@@ -821,6 +827,7 @@ static const struct mtk_dpi_conf mt8192_conf = {
.max_clock_khz = 150000,
.output_fmts = mt8173_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
+ .limit = &mtk_dpi_limit,
};
static int mtk_dpi_probe(struct platform_device *pdev)
--
2.34.1
From: Markus Schneider-Pargmann <[email protected]>
DP_INTF is similar to DPI but does not have the exact same feature set
or register layouts.
DP_INTF is the sink of the display pipeline that is connected to the
DisplayPort controller and encoder unit. It takes the same clocks as
DPI.
Signed-off-by: Markus Schneider-Pargmann <[email protected]>
Signed-off-by: Guillaume Ranquet <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
.../bindings/display/mediatek/mediatek,dpi.yaml | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
index dd2896a40ff0..2dba80ad3b18 100644
--- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
@@ -4,16 +4,16 @@
$id: http://devicetree.org/schemas/display/mediatek/mediatek,dpi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: mediatek DPI Controller Device Tree Bindings
+title: mediatek DPI/DP_INTF Controller
maintainers:
- CK Hu <[email protected]>
- Jitao shi <[email protected]>
description: |
- The Mediatek DPI function block is a sink of the display subsystem and
- provides 8-bit RGB/YUV444 or 8/10/10-bit YUV422 pixel data on a parallel
- output bus.
+ The Mediatek DPI and DP_INTF function blocks are a sink of the display
+ subsystem and provides 8-bit RGB/YUV444 or 8/10/10-bit YUV422 pixel data on a
+ parallel output bus.
properties:
compatible:
@@ -23,6 +23,7 @@ properties:
- mediatek,mt8173-dpi
- mediatek,mt8183-dpi
- mediatek,mt8192-dpi
+ - mediatek,mt8195-dpintf
reg:
maxItems: 1
@@ -54,7 +55,7 @@ properties:
$ref: /schemas/graph.yaml#/properties/port
description:
Output port node. This port should be connected to the input port of an
- attached HDMI or LVDS encoder chip.
+ attached HDMI, LVDS or DisplayPort encoder chip.
required:
- compatible
--
2.34.1
Adds a bit of flexibility to support SoCs without CK/DE pol support
Signed-off-by: Guillaume Ranquet <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 4746eb342567..545a1337cc89 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -125,6 +125,7 @@ struct mtk_dpi_conf {
bool edge_sel_en;
const u32 *output_fmts;
u32 num_output_fmts;
+ bool is_ck_de_pol;
const struct mtk_dpi_yc_limit *limit;
};
@@ -211,13 +212,20 @@ static void mtk_dpi_config_pol(struct mtk_dpi *dpi,
struct mtk_dpi_polarities *dpi_pol)
{
unsigned int pol;
+ unsigned int mask;
- pol = (dpi_pol->ck_pol == MTK_DPI_POLARITY_RISING ? 0 : CK_POL) |
- (dpi_pol->de_pol == MTK_DPI_POLARITY_RISING ? 0 : DE_POL) |
- (dpi_pol->hsync_pol == MTK_DPI_POLARITY_RISING ? 0 : HSYNC_POL) |
+ mask = HSYNC_POL | VSYNC_POL;
+ pol = (dpi_pol->hsync_pol == MTK_DPI_POLARITY_RISING ? 0 : HSYNC_POL) |
(dpi_pol->vsync_pol == MTK_DPI_POLARITY_RISING ? 0 : VSYNC_POL);
- mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, pol,
- CK_POL | DE_POL | HSYNC_POL | VSYNC_POL);
+ if (dpi->conf->is_ck_de_pol) {
+ mask |= CK_POL | DE_POL;
+ pol |= (dpi_pol->ck_pol == MTK_DPI_POLARITY_RISING ?
+ 0 : CK_POL) |
+ (dpi_pol->de_pol == MTK_DPI_POLARITY_RISING ?
+ 0 : DE_POL);
+ }
+
+ mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, pol, mask);
}
static void mtk_dpi_config_3d(struct mtk_dpi *dpi, bool en_3d)
@@ -799,6 +807,7 @@ static const struct mtk_dpi_conf mt8173_conf = {
.max_clock_khz = 300000,
.output_fmts = mt8173_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
+ .is_ck_de_pol = true,
.limit = &mtk_dpi_limit,
};
@@ -809,6 +818,7 @@ static const struct mtk_dpi_conf mt2701_conf = {
.max_clock_khz = 150000,
.output_fmts = mt8173_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
+ .is_ck_de_pol = true,
.limit = &mtk_dpi_limit,
};
@@ -818,6 +828,7 @@ static const struct mtk_dpi_conf mt8183_conf = {
.max_clock_khz = 100000,
.output_fmts = mt8183_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8183_output_fmts),
+ .is_ck_de_pol = true,
.limit = &mtk_dpi_limit,
};
@@ -827,6 +838,7 @@ static const struct mtk_dpi_conf mt8192_conf = {
.max_clock_khz = 150000,
.output_fmts = mt8173_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
+ .is_ck_de_pol = true,
.limit = &mtk_dpi_limit,
};
--
2.34.1
Il 28/03/22 00:39, Guillaume Ranquet ha scritto:
> Signed-off-by: Guillaume Ranquet <[email protected]>
> ---
> include/drm/drm_edid.h | 11 ++++++++---
> 1 file changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
> index 144c495b99c4..5d4d840b9904 100644
> --- a/include/drm/drm_edid.h
> +++ b/include/drm/drm_edid.h
> @@ -359,12 +359,17 @@ struct edid {
>
> #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
>
> -/* Short Audio Descriptor */
Hello Guillaume,
> +/* struct cea_sad - Short Audio Descriptor.
> + @format: See HDMI_AUDIO_CODING_TYPE_*.
> + @channels: max number of channels - 1.
> + @freq: See CEA_SAD_FREQ_*.
> + @byte2: meaning depends on format.
> +*/
I appreciate the effort, but this is not valid kerneldoc.
Please refer to https://docs.kernel.org/doc-guide/kernel-doc.html
Regards,
Angelo
Il 28/03/22 00:39, Guillaume Ranquet ha scritto:
> From: Markus Schneider-Pargmann <[email protected]>
>
> This is a new driver that supports the integrated DisplayPort phy for
> mediatek SoCs, especially the mt8195. The phy is integrated into the
> DisplayPort controller and will be created by the mtk-dp driver. This
> driver expects a struct regmap to be able to work on the same registers
> as the DisplayPort controller. It sets the device data to be the struct
> phy so that the DisplayPort controller can easily work with it.
>
> The driver does not have any devicetree bindings because the datasheet
> does not list the controller and the phy as distinct units.
>
> The interaction with the controller can be covered by the configure
> callback of the phy framework and its displayport parameters.
>
> Signed-off-by: Markus Schneider-Pargmann <[email protected]>
> Signed-off-by: Guillaume Ranquet <[email protected]>
> ---
> MAINTAINERS | 1 +
> drivers/phy/mediatek/Kconfig | 8 ++
> drivers/phy/mediatek/Makefile | 1 +
> drivers/phy/mediatek/phy-mtk-dp.c | 201 ++++++++++++++++++++++++++++++
> 4 files changed, 211 insertions(+)
> create mode 100644 drivers/phy/mediatek/phy-mtk-dp.c
>
..snip..
> diff --git a/drivers/phy/mediatek/phy-mtk-dp.c b/drivers/phy/mediatek/phy-mtk-dp.c
> new file mode 100644
> index 000000000000..e5c5494f3636
> --- /dev/null
> +++ b/drivers/phy/mediatek/phy-mtk-dp.c
..snip..
> +
> +static int mtk_dp_phy_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct mtk_dp_phy *dp_phy;
> + struct phy *phy;
> + struct regmap *regs;
> +
> + regs = syscon_regmap_lookup_by_phandle(dev->of_node, "mediatek,dp-syscon");
> +
Please drop this blank line
> + if (IS_ERR(regs))
> + return PTR_ERR(regs);
> +
> + dp_phy = devm_kzalloc(dev, sizeof(*dp_phy), GFP_KERNEL);
> + if (!dp_phy)
> + return -ENOMEM;
> +
> + dp_phy->regs = regs;
> +
> + phy = devm_phy_create(dev, NULL, &mtk_dp_phy_dev_ops);
> +
Same here
> + if (IS_ERR(phy))
> + return dev_err_probe(dev, PTR_ERR(phy), "Failed to create DP PHY: %ld\n", PTR_ERR(phy));
> +
Using dev_err_probe automates printing the error, so the correct usage is:
return dev_err_probe(dev, PTR_ERR(phy), "Failed to create DP PHY\n");
> + phy_set_drvdata(phy, dp_phy);
> +
> + return 0;
> +}
> +
> +struct platform_driver mtk_dp_phy_driver = {
> + .probe = mtk_dp_phy_probe,
> + .driver = {
> + .name = "mediatek-dp-phy",
> + },
> +};
> +module_platform_driver(mtk_dp_phy_driver);
Also, in your dt-binding, you mention a compatible for this driver, but I don't see
any, here. This means that you do know what to do, so please do it.
Regards,
Angelo
> +
> +MODULE_AUTHOR("Markus Schneider-Pargmann <[email protected]>");
> +MODULE_DESCRIPTION("MediaTek DP PHY Driver");
> +MODULE_LICENSE("GPL");
From: Markus Schneider-Pargmann <[email protected]>
This patch adds a DisplayPort driver for the Mediatek mt8195 SoC.
It supports the mt8195, the embedded DisplayPort units. It offers
DisplayPort 1.4 with up to 4 lanes.
The driver shares its iomap range with the mtk-dp-phy driver using
the regmap/syscon facility.
This driver is based on an initial version by
Jason-JH.Lin <[email protected]>.
Signed-off-by: Markus Schneider-Pargmann <[email protected]>
Signed-off-by: Guillaume Ranquet <[email protected]>
Reported-by: kernel test robot <[email protected]>
---
drivers/gpu/drm/mediatek/Kconfig | 8 +
drivers/gpu/drm/mediatek/Makefile | 2 +
drivers/gpu/drm/mediatek/mtk_dp.c | 2221 ++++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_dp_reg.h | 568 ++++++
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 1 +
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
6 files changed, 2801 insertions(+)
create mode 100644 drivers/gpu/drm/mediatek/mtk_dp.c
create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_reg.h
diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig
index 2976d21e9a34..03ffa9b896c3 100644
--- a/drivers/gpu/drm/mediatek/Kconfig
+++ b/drivers/gpu/drm/mediatek/Kconfig
@@ -28,3 +28,11 @@ config DRM_MEDIATEK_HDMI
select PHY_MTK_HDMI
help
DRM/KMS HDMI driver for Mediatek SoCs
+
+config MTK_DPTX_SUPPORT
+ tristate "DRM DPTX Support for Mediatek SoCs"
+ depends on DRM_MEDIATEK
+ select PHY_MTK_DP
+ select DRM_DP_HELPER
+ help
+ DRM/KMS Display Port driver for Mediatek SoCs.
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index 29098d7c8307..d86a6406055e 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -21,3 +21,5 @@ mediatek-drm-hdmi-objs := mtk_cec.o \
mtk_hdmi_ddc.o
obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
+
+obj-$(CONFIG_MTK_DPTX_SUPPORT) += mtk_dp.o
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
new file mode 100644
index 000000000000..7cd8459cf719
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -0,0 +1,2221 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Copyright (c) 2021 BayLibre
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_crtc.h>
+#include <drm/dp/drm_dp_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+#include <linux/arm-smccc.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/hdmi-codec.h>
+#include <video/videomode.h>
+
+#include "mtk_dp_reg.h"
+
+#define MTK_DP_AUX_WAIT_REPLY_COUNT 20
+#define MTK_DP_CHECK_SINK_CAP_TIMEOUT_COUNT 3
+
+//TODO: platform/device data or dts?
+#define MTK_DP_MAX_LANES 4
+#define MTK_DP_MAX_LINK_RATE MTK_DP_LINKRATE_HBR3
+
+#define MTK_DP_TBC_BUF_READ_START_ADDR 0x08
+
+#define MTK_DP_TRAIN_RETRY_LIMIT 8
+#define MTK_DP_TRAIN_MAX_ITERATIONS 5
+
+#define MTK_DP_AUX_WRITE_READ_WAIT_TIME_US 20
+
+#define MTK_DP_DP_VERSION_11 0x11
+
+enum mtk_dp_state {
+ MTK_DP_STATE_INITIAL,
+ MTK_DP_STATE_IDLE,
+ MTK_DP_STATE_PREPARE,
+ MTK_DP_STATE_NORMAL,
+};
+
+enum mtk_dp_train_state {
+ MTK_DP_TRAIN_STATE_STARTUP = 0,
+ MTK_DP_TRAIN_STATE_CHECKCAP,
+ MTK_DP_TRAIN_STATE_CHECKEDID,
+ MTK_DP_TRAIN_STATE_TRAINING_PRE,
+ MTK_DP_TRAIN_STATE_TRAINING,
+ MTK_DP_TRAIN_STATE_NORMAL,
+ MTK_DP_TRAIN_STATE_DPIDLE,
+};
+
+struct mtk_dp_timings {
+ struct videomode vm;
+
+ u16 htotal;
+ u16 vtotal;
+ u8 frame_rate;
+ u32 pix_rate_khz;
+};
+
+struct mtk_dp_train_info {
+ bool tps3;
+ bool tps4;
+ bool sink_ssc;
+ bool cable_plugged_in;
+ bool cable_state_change;
+ bool cr_done;
+ bool eq_done;
+
+ /* link_rate is in multiple of 0.27Gbps */
+ int link_rate;
+ int lane_count;
+
+ u8 irq_status;
+ int check_cap_count;
+};
+
+/* Same values as used by the DP Spec for MISC0 bits 1 and 2 */
+enum mtk_dp_color_format {
+ MTK_DP_COLOR_FORMAT_RGB_444 = 0,
+ MTK_DP_COLOR_FORMAT_YUV_422 = 1,
+ MTK_DP_COLOR_FORMAT_YUV_444 = 2,
+ MTK_DP_COLOR_FORMAT_YUV_420 = 3,
+ MTK_DP_COLOR_FORMAT_YONLY = 4,
+ MTK_DP_COLOR_FORMAT_RAW = 5,
+ MTK_DP_COLOR_FORMAT_RESERVED = 6,
+ MTK_DP_COLOR_FORMAT_DEFAULT = MTK_DP_COLOR_FORMAT_RGB_444,
+ MTK_DP_COLOR_FORMAT_UNKNOWN = 15,
+};
+
+/* Multiple of 0.27Gbps */
+enum mtk_dp_linkrate {
+ MTK_DP_LINKRATE_RBR = 0x6,
+ MTK_DP_LINKRATE_HBR = 0xA,
+ MTK_DP_LINKRATE_HBR2 = 0x14,
+ MTK_DP_LINKRATE_HBR25 = 0x19,
+ MTK_DP_LINKRATE_HBR3 = 0x1E,
+};
+
+/* Same values as used for DP Spec MISC0 bits 5,6,7 */
+enum mtk_dp_color_depth {
+ MTK_DP_COLOR_DEPTH_6BIT = 0,
+ MTK_DP_COLOR_DEPTH_8BIT = 1,
+ MTK_DP_COLOR_DEPTH_10BIT = 2,
+ MTK_DP_COLOR_DEPTH_12BIT = 3,
+ MTK_DP_COLOR_DEPTH_16BIT = 4,
+ MTK_DP_COLOR_DEPTH_UNKNOWN = 5,
+};
+
+struct mtk_dp_info {
+ enum mtk_dp_color_depth depth;
+ enum mtk_dp_color_format format;
+ struct mtk_dp_timings timings;
+};
+
+struct dp_cal_data {
+ unsigned int glb_bias_trim;
+ unsigned int clktx_impse;
+
+ //TODO: see above with MTK_DP_MAX_LANES, make it SoC specific
+ unsigned int ln_tx_impsel_pmos[MTK_DP_MAX_LANES];
+ unsigned int ln_tx_impsel_nmos[MTK_DP_MAX_LANES];
+};
+
+struct mtk_dp {
+ struct device *dev;
+ struct phy *phy;
+ struct dp_cal_data cal_data;
+
+ struct drm_device *drm_dev;
+ struct drm_bridge bridge;
+ struct drm_bridge *next_bridge;
+ struct drm_dp_aux aux;
+
+ /* Protects edid as it is used in both bridge ops and IRQ handler */
+ struct mutex edid_lock;
+ struct edid *edid;
+
+ u8 rx_cap[DP_RECEIVER_CAP_SIZE];
+
+ struct mtk_dp_info info;
+ enum mtk_dp_state state;
+
+ struct mtk_dp_train_info train_info;
+ enum mtk_dp_train_state train_state;
+ unsigned int input_fmt;
+
+ struct regmap *regs;
+ struct clk *dp_tx_clk;
+
+ bool enabled;
+
+ bool has_fec;
+ /* Protects the mtk_dp struct */
+ struct mutex dp_lock;
+
+ hdmi_codec_plugged_cb plugged_cb;
+ struct device *codec_dev;
+ u8 connector_eld[MAX_ELD_BYTES];
+ struct drm_connector *conn;
+};
+
+static struct mtk_dp *mtk_dp_from_bridge(struct drm_bridge *b)
+{
+ return container_of(b, struct mtk_dp, bridge);
+}
+
+static u32 mtk_dp_read(struct mtk_dp *mtk_dp, u32 offset)
+{
+ u32 read_val;
+ int ret;
+
+ ret = regmap_read(mtk_dp->regs, offset, &read_val);
+ if (ret) {
+ dev_err(mtk_dp->dev, "Failed to read register 0x%x: %d\n",
+ offset, ret);
+ return 0;
+ }
+
+ return read_val;
+}
+
+static int mtk_dp_write(struct mtk_dp *mtk_dp, u32 offset, u32 val)
+{
+ int ret;
+
+ ret = regmap_write(mtk_dp->regs, offset, val);
+ if (ret)
+ dev_err(mtk_dp->dev,
+ "Failed to write register 0x%x with value 0x%x: %d\n",
+ offset, val, ret);
+ return ret;
+}
+
+static int mtk_dp_update_bits(struct mtk_dp *mtk_dp, u32 offset, u32 val,
+ u32 mask)
+{
+ int ret;
+
+ ret = regmap_update_bits(mtk_dp->regs, offset, mask, val);
+ if (ret)
+ dev_err(mtk_dp->dev,
+ "Failed to update register 0x%x with value 0x%x, mask 0x%x: %d\n",
+ offset, val, mask, ret);
+ return ret;
+}
+
+static int mtk_dp_bulk_16bit_write(struct mtk_dp *mtk_dp, u32 offset, u8 *buf,
+ size_t length)
+{
+ int i;
+ int ret = 0;
+ int num_regs = (length + 1) / 2;
+
+ /* 2 bytes per register */
+ for (i = 0; i < num_regs; i++) {
+ u32 val = buf[i * 2] |
+ (i * 2 + 1 < length ? buf[i * 2 + 1] << 8 : 0);
+
+ ret = mtk_dp_write(mtk_dp, offset + i * 4, val);
+ if (ret)
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static unsigned long mtk_dp_sip_atf_call(unsigned int cmd, unsigned int para)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(MTK_DP_SIP_CONTROL_AARCH32, cmd, para, 0, 0, 0, 0, 0,
+ &res);
+
+ pr_debug("[DPTX]%s cmd 0x%x, p1 0x%x, ret 0x%lx-0x%lx", __func__, cmd,
+ para, res.a0, res.a1);
+ return res.a1;
+}
+
+static int mtk_dp_msa_bypass_disable(struct mtk_dp *mtk_dp)
+{
+ const u16 bits_to_set =
+ BIT(HTOTAL_SEL_DP_ENC0_P0_SHIFT) |
+ BIT(VTOTAL_SEL_DP_ENC0_P0_SHIFT) |
+ BIT(HSTART_SEL_DP_ENC0_P0_SHIFT) |
+ BIT(VSTART_SEL_DP_ENC0_P0_SHIFT) |
+ BIT(HWIDTH_SEL_DP_ENC0_P0_SHIFT) |
+ BIT(VHEIGHT_SEL_DP_ENC0_P0_SHIFT) |
+ BIT(HSP_SEL_DP_ENC0_P0_SHIFT) | BIT(HSW_SEL_DP_ENC0_P0_SHIFT) |
+ BIT(VSP_SEL_DP_ENC0_P0_SHIFT) | BIT(VSW_SEL_DP_ENC0_P0_SHIFT);
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3030, bits_to_set,
+ bits_to_set);
+}
+
+#define MTK_UPD_BITS_OR_OUT(mtk_dp, offset, val, mask, ret, label) \
+ do {\
+ ret = mtk_dp_update_bits(mtk_dp, offset, val, mask); \
+ if (ret) \
+ goto label; \
+ } while (0)
+
+static int mtk_dp_set_msa(struct mtk_dp *mtk_dp)
+{
+ int ret;
+ struct mtk_dp_timings *timings = &mtk_dp->info.timings;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3010, timings->htotal,
+ HTOTAL_SW_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3018,
+ timings->vm.hsync_len + timings->vm.hback_porch,
+ HSTART_SW_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3028,
+ timings->vm.hsync_len << HSW_SW_DP_ENC0_P0_SHIFT,
+ HSW_SW_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3028, 0,
+ HSP_SW_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3020, timings->vm.hactive,
+ HWIDTH_SW_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3014, timings->vtotal,
+ VTOTAL_SW_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_301C,
+ timings->vm.vsync_len + timings->vm.vback_porch,
+ VSTART_SW_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_302C,
+ timings->vm.vsync_len << VSW_SW_DP_ENC0_P0_SHIFT,
+ VSW_SW_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_302C, 0,
+ VSP_SW_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3024, timings->vm.vactive,
+ VHEIGHT_SW_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3064, timings->vm.hactive,
+ HDE_NUM_LAST_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3154, timings->htotal,
+ PGEN_HTOTAL_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3158,
+ timings->vm.hfront_porch,
+ PGEN_HSYNC_RISING_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_315C, timings->vm.hsync_len,
+ PGEN_HSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3160,
+ timings->vm.hback_porch + timings->vm.hsync_len,
+ PGEN_HFDE_START_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3164, timings->vm.hactive,
+ PGEN_HFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3168, timings->vtotal,
+ PGEN_VTOTAL_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_316C,
+ timings->vm.vfront_porch,
+ PGEN_VSYNC_RISING_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3170, timings->vm.vsync_len,
+ PGEN_VSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3174,
+ timings->vm.vback_porch + timings->vm.vsync_len,
+ PGEN_VFDE_START_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3178, timings->vm.vactive,
+ PGEN_VFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK, ret, out);
+
+out:
+ return ret;
+}
+
+static int mtk_dp_set_color_format(struct mtk_dp *mtk_dp,
+ enum mtk_dp_color_format color_format)
+{
+ u32 val;
+ int ret;
+
+ mtk_dp->info.format = color_format;
+
+ /* Update MISC0 */
+ ret = mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
+ color_format << DP_TEST_COLOR_FORMAT_SHIFT,
+ DP_TEST_COLOR_FORMAT_MASK);
+
+ if (ret)
+ return ret;
+
+ switch (color_format) {
+ case MTK_DP_COLOR_FORMAT_YUV_422:
+ val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422;
+ break;
+ case MTK_DP_COLOR_FORMAT_YUV_420:
+ val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR420;
+ break;
+ case MTK_DP_COLOR_FORMAT_YONLY:
+ case MTK_DP_COLOR_FORMAT_RAW:
+ case MTK_DP_COLOR_FORMAT_RESERVED:
+ case MTK_DP_COLOR_FORMAT_UNKNOWN:
+ drm_warn(mtk_dp->drm_dev, "Unsupported color format: %d\n",
+ color_format);
+ fallthrough;
+ case MTK_DP_COLOR_FORMAT_RGB_444:
+ case MTK_DP_COLOR_FORMAT_YUV_444:
+ val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB;
+ break;
+ }
+
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C, val,
+ PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK);
+}
+
+static int mtk_dp_set_color_depth(struct mtk_dp *mtk_dp,
+ enum mtk_dp_color_depth color_depth)
+{
+ int ret;
+ u32 val;
+
+ mtk_dp->info.depth = color_depth;
+
+ /* Update MISC0 */
+ ret = mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
+ color_depth << DP_TEST_BIT_DEPTH_SHIFT,
+ DP_TEST_BIT_DEPTH_MASK);
+
+ if (ret)
+ return ret;
+
+ switch (color_depth) {
+ case MTK_DP_COLOR_DEPTH_6BIT:
+ val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_6BIT;
+ break;
+ case MTK_DP_COLOR_DEPTH_8BIT:
+ val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_8BIT;
+ break;
+ case MTK_DP_COLOR_DEPTH_10BIT:
+ val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_10BIT;
+ break;
+ case MTK_DP_COLOR_DEPTH_12BIT:
+ val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_12BIT;
+ break;
+ case MTK_DP_COLOR_DEPTH_16BIT:
+ val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_16BIT;
+ break;
+ case MTK_DP_COLOR_DEPTH_UNKNOWN:
+ drm_warn(mtk_dp->drm_dev, "Unsupported color depth %d\n",
+ color_depth);
+ return -EINVAL;
+ }
+
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C, val,
+ VIDEO_COLOR_DEPTH_DP_ENC0_P0_MASK);
+}
+
+static int mtk_dp_mn_overwrite_disable(struct mtk_dp *mtk_dp)
+{
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004, 0,
+ VIDEO_M_CODE_SEL_DP_ENC0_P0_MASK);
+}
+
+static int mtk_dp_set_sram_read_start(struct mtk_dp *mtk_dp, u32 val)
+{
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
+ val << SRAM_START_READ_THRD_DP_ENC0_P0_SHIFT,
+ SRAM_START_READ_THRD_DP_ENC0_P0_MASK);
+}
+
+static int mtk_dp_setup_encoder(struct mtk_dp *mtk_dp)
+{
+ int ret;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_303C,
+ BIT(VIDEO_MN_GEN_EN_DP_ENC0_P0_SHIFT),
+ VIDEO_MN_GEN_EN_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3040,
+ 0x20 << SDP_DOWN_CNT_INIT_DP_ENC0_P0_SHIFT,
+ SDP_DOWN_CNT_INIT_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3364,
+ 0x20 << SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_SHIFT,
+ SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3300,
+ 2 << VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_SHIFT,
+ VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3364,
+ 4 << FIFO_READ_START_POINT_DP_ENC1_P0_SHIFT,
+ FIFO_READ_START_POINT_DP_ENC1_P0_MASK, ret, out);
+ ret = mtk_dp_write(mtk_dp, MTK_DP_ENC1_P0_3368,
+ 1 << VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0_SHIFT |
+ 1 << VIDEO_STABLE_CNT_THRD_DP_ENC1_P0_SHIFT |
+ BIT(SDP_DP13_EN_DP_ENC1_P0_SHIFT) |
+ 1 << BS2BS_MODE_DP_ENC1_P0_SHIFT);
+
+out:
+ return ret;
+}
+
+static int mtk_dp_pg_disable(struct mtk_dp *mtk_dp)
+{
+ int ret;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3038, 0,
+ VIDEO_SOURCE_SEL_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_31B0,
+ 4 << PGEN_PATTERN_SEL_SHIFT, PGEN_PATTERN_SEL_MASK, ret, out);
+
+out:
+ return ret;
+}
+
+static bool mtk_dp_plug_state(struct mtk_dp *mtk_dp)
+{
+ return !!(mtk_dp_read(mtk_dp, MTK_DP_TRANS_P0_3414) &
+ HPD_DB_DP_TRANS_P0_MASK);
+}
+
+static void mtk_dp_aux_irq_clear(struct mtk_dp *mtk_dp)
+{
+ mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3640,
+ BIT(AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_SHIFT) |
+ BIT(AUX_RX_DATA_RECV_IRQ_AUX_TX_P0_SHIFT) |
+ BIT(AUX_RX_ADDR_RECV_IRQ_AUX_TX_P0_SHIFT) |
+ BIT(AUX_RX_CMD_RECV_IRQ_AUX_TX_P0_SHIFT) |
+ BIT(AUX_RX_MCCS_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT) |
+ BIT(AUX_RX_EDID_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT) |
+ BIT(AUX_RX_AUX_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT));
+}
+
+static int mtk_dp_aux_set_cmd(struct mtk_dp *mtk_dp, u8 cmd, u32 addr)
+{
+ int ret;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3644, cmd,
+ MCU_REQUEST_COMMAND_AUX_TX_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3648, addr,
+ MCU_REQUEST_ADDRESS_LSB_AUX_TX_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_364C, addr >> 16,
+ MCU_REQUEST_ADDRESS_MSB_AUX_TX_P0_MASK, ret, out);
+
+out:
+ return ret;
+}
+
+static int mtk_dp_aux_cmd_complete(struct mtk_dp *mtk_dp)
+{
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3650,
+ BIT(MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_SHIFT),
+ MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_MASK |
+ PHY_FIFO_RST_AUX_TX_P0_MASK |
+ MCU_REQ_DATA_NUM_AUX_TX_P0_MASK);
+}
+
+static int mtk_dp_aux_request_ready(struct mtk_dp *mtk_dp)
+{
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3630,
+ BIT(AUX_TX_REQUEST_READY_AUX_TX_P0_SHIFT),
+ AUX_TX_REQUEST_READY_AUX_TX_P0_MASK);
+}
+
+static void mtk_dp_aux_fill_write_fifo(struct mtk_dp *mtk_dp, u8 *buf,
+ size_t length)
+{
+ mtk_dp_bulk_16bit_write(mtk_dp, MTK_DP_AUX_P0_3708, buf, length);
+}
+
+static int mtk_dp_aux_read_rx_fifo(struct mtk_dp *mtk_dp, u8 *buf,
+ size_t length, int read_delay)
+{
+ int ret;
+ int read_pos;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3620, 0,
+ AUX_RD_MODE_AUX_TX_P0_MASK, ret, out);
+
+ for (read_pos = 0; read_pos < length; read_pos++) {
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3620,
+ BIT(AUX_RX_FIFO_R_PULSE_TX_P0_SHIFT),
+ AUX_RX_FIFO_READ_PULSE_TX_P0_MASK, ret, out);
+ usleep_range(read_delay, read_delay * 2);
+ buf[read_pos] =
+ (u8)(mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3620) &
+ AUX_RX_FIFO_READ_DATA_AUX_TX_P0_MASK >>
+ AUX_RX_FIFO_READ_DATA_AUX_TX_P0_SHIFT);
+ }
+
+out:
+ return ret;
+}
+
+static int mtk_dp_aux_set_length(struct mtk_dp *mtk_dp, size_t length)
+{
+ int ret;
+
+ if (length > 0) {
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3650,
+ (length - 1)
+ << MCU_REQ_DATA_NUM_AUX_TX_P0_SHIFT,
+ MCU_REQ_DATA_NUM_AUX_TX_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_362C, 0,
+ AUX_NO_LENGTH_AUX_TX_P0_MASK |
+ AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK |
+ AUX_RESERVED_RW_0_AUX_TX_P0_MASK, ret, out);
+ } else {
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_362C,
+ BIT(AUX_NO_LENGTH_AUX_TX_P0_SHIFT),
+ AUX_NO_LENGTH_AUX_TX_P0_MASK |
+ AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK |
+ AUX_RESERVED_RW_0_AUX_TX_P0_MASK, ret, out);
+ }
+
+out:
+ return ret;
+}
+
+static int mtk_dp_aux_wait_for_completion(struct mtk_dp *mtk_dp, bool is_read)
+{
+ int wait_reply = MTK_DP_AUX_WAIT_REPLY_COUNT;
+
+ while (--wait_reply) {
+ u32 aux_irq_status;
+
+ if (is_read) {
+ u32 fifo_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3618);
+
+ if (fifo_status &
+ (AUX_RX_FIFO_WRITE_POINTER_AUX_TX_P0_MASK |
+ AUX_RX_FIFO_FULL_AUX_TX_P0_MASK)) {
+ return 0;
+ }
+ }
+
+ aux_irq_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3640);
+ if (aux_irq_status & AUX_RX_RECV_COMPLETE_IRQ_TX_P0_MASK)
+ return 0;
+
+ if (aux_irq_status & AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_MASK)
+ return -ETIMEDOUT;
+
+ usleep_range(100, 500);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int mtk_dp_aux_do_transfer(struct mtk_dp *mtk_dp, bool is_read, u8 cmd,
+ u32 addr, u8 *buf, size_t length)
+{
+ int ret;
+ u32 reply_cmd;
+
+ if (is_read && (length > DP_AUX_MAX_PAYLOAD_BYTES ||
+ (cmd == DP_AUX_NATIVE_READ && !length)))
+ return -EINVAL;
+
+ if (!is_read) {
+ ret = mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3704,
+ BIT(AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_SHIFT),
+ AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_MASK);
+
+ if (ret)
+ return ret;
+ }
+
+ mtk_dp_aux_cmd_complete(mtk_dp);
+ mtk_dp_aux_irq_clear(mtk_dp);
+ usleep_range(MTK_DP_AUX_WRITE_READ_WAIT_TIME_US,
+ MTK_DP_AUX_WRITE_READ_WAIT_TIME_US * 2);
+
+ mtk_dp_aux_set_cmd(mtk_dp, cmd, addr);
+ mtk_dp_aux_set_length(mtk_dp, length);
+
+ if (!is_read) {
+ if (length)
+ mtk_dp_aux_fill_write_fifo(mtk_dp, buf, length);
+
+ ret = mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3704,
+ AUX_TX_FIFO_WRITE_DATA_NEW_MODE_TOGGLE_AUX_TX_P0_MASK,
+ AUX_TX_FIFO_WRITE_DATA_NEW_MODE_TOGGLE_AUX_TX_P0_MASK);
+
+ if (ret)
+ return ret;
+ }
+
+ mtk_dp_aux_request_ready(mtk_dp);
+
+ ret = mtk_dp_aux_wait_for_completion(mtk_dp, is_read);
+
+ reply_cmd = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3624) &
+ AUX_RX_REPLY_COMMAND_AUX_TX_P0_MASK;
+
+ if (ret || reply_cmd) {
+ u32 phy_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3628) &
+ AUX_RX_PHY_STATE_AUX_TX_P0_MASK;
+ if (phy_status != AUX_RX_PHY_STATE_AUX_TX_P0_RX_IDLE) {
+ drm_err(mtk_dp->drm_dev,
+ "AUX Rx Aux hang, need SW reset\n");
+ return -EIO;
+ }
+
+ mtk_dp_aux_cmd_complete(mtk_dp);
+ mtk_dp_aux_irq_clear(mtk_dp);
+
+ usleep_range(MTK_DP_AUX_WRITE_READ_WAIT_TIME_US,
+ MTK_DP_AUX_WRITE_READ_WAIT_TIME_US * 2);
+ return -ETIMEDOUT;
+ }
+
+ if (!length) {
+ ret = mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_362C, 0,
+ AUX_NO_LENGTH_AUX_TX_P0_MASK |
+ AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK |
+ AUX_RESERVED_RW_0_AUX_TX_P0_MASK);
+
+ if (ret)
+ return ret;
+
+ } else if (is_read) {
+ int read_delay;
+
+ if (cmd == (DP_AUX_I2C_READ | DP_AUX_I2C_MOT) ||
+ cmd == DP_AUX_I2C_READ)
+ read_delay = 500;
+ else
+ read_delay = 100;
+
+ mtk_dp_aux_read_rx_fifo(mtk_dp, buf, length, read_delay);
+ }
+
+ mtk_dp_aux_cmd_complete(mtk_dp);
+ mtk_dp_aux_irq_clear(mtk_dp);
+ usleep_range(MTK_DP_AUX_WRITE_READ_WAIT_TIME_US,
+ MTK_DP_AUX_WRITE_READ_WAIT_TIME_US * 2);
+
+ return 0;
+}
+
+static bool mtk_dp_set_swing_pre_emphasis(struct mtk_dp *mtk_dp, int lane_num,
+ int swing_val, int preemphasis)
+{
+ int ret;
+
+ u32 lane_shift = lane_num * DP_TX1_VOLT_SWING_SHIFT;
+
+ if (lane_num < 0 || lane_num > 3)
+ return false;
+
+ dev_dbg(mtk_dp->dev,
+ "link training swing_val= 0x%x, preemphasis = 0x%x\n",
+ swing_val, preemphasis);
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_SWING_EMP,
+ swing_val << (DP_TX0_VOLT_SWING_SHIFT + lane_shift),
+ DP_TX0_VOLT_SWING_MASK << lane_shift, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_SWING_EMP,
+ preemphasis << (DP_TX0_PRE_EMPH_SHIFT + lane_shift),
+ DP_TX0_PRE_EMPH_MASK << lane_shift, ret, out);
+
+out:
+ return !ret;
+}
+
+static int mtk_dp_reset_swing_pre_emphasis(struct mtk_dp *mtk_dp)
+{
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_SWING_EMP, 0,
+ DP_TX0_VOLT_SWING_MASK | DP_TX1_VOLT_SWING_MASK |
+ DP_TX2_VOLT_SWING_MASK |
+ DP_TX3_VOLT_SWING_MASK |
+ DP_TX0_PRE_EMPH_MASK | DP_TX1_PRE_EMPH_MASK |
+ DP_TX2_PRE_EMPH_MASK | DP_TX3_PRE_EMPH_MASK);
+}
+
+static int mtk_dp_fec_enable(struct mtk_dp *mtk_dp, bool enable)
+{
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3540,
+ enable ? BIT(FEC_EN_DP_TRANS_P0_SHIFT) : 0,
+ FEC_EN_DP_TRANS_P0_MASK);
+}
+
+static int mtk_dp_hwirq_enable(struct mtk_dp *mtk_dp, bool enable)
+{
+ u32 val = 0;
+
+ if (!enable)
+ val = IRQ_MASK_DP_TRANS_P0_DISC_IRQ |
+ IRQ_MASK_DP_TRANS_P0_CONN_IRQ |
+ IRQ_MASK_DP_TRANS_P0_INT_IRQ;
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3418, val,
+ IRQ_MASK_DP_TRANS_P0_MASK);
+}
+
+static int mtk_dp_initialize_settings(struct mtk_dp *mtk_dp)
+{
+ int ret;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_342C,
+ XTAL_FREQ_DP_TRANS_P0_DEFAULT,
+ XTAL_FREQ_DP_TRANS_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_3540,
+ BIT(FEC_CLOCK_EN_MODE_DP_TRANS_P0_SHIFT),
+ FEC_CLOCK_EN_MODE_DP_TRANS_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_31EC,
+ BIT(AUDIO_CH_SRC_SEL_DP_ENC0_P0_SHIFT),
+ AUDIO_CH_SRC_SEL_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_304C, 0,
+ SDP_VSYNC_RISING_MASK_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_IRQ_MASK, IRQ_MASK_AUX_TOP_IRQ,
+ IRQ_MASK_AUX_TOP_IRQ, ret, out);
+
+out:
+ return ret;
+}
+
+static void mtk_dp_initialize_hpd_detect_settings(struct mtk_dp *mtk_dp)
+{
+ // Debounce threshold
+ mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
+ 8 << HPD_DEB_THD_DP_TRANS_P0_SHIFT,
+ HPD_DEB_THD_DP_TRANS_P0_MASK);
+ mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
+ (HPD_INT_THD_DP_TRANS_P0_LOWER_500US |
+ HPD_INT_THD_DP_TRANS_P0_UPPER_1100US)
+ << HPD_INT_THD_DP_TRANS_P0_SHIFT,
+ HPD_INT_THD_DP_TRANS_P0_MASK);
+
+ // Connect threshold 1.5ms + 5 x 0.1ms = 2ms
+ // Disconnect threshold 1.5ms + 5 x 0.1ms = 2ms
+ mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
+ (5 << HPD_DISC_THD_DP_TRANS_P0_SHIFT) |
+ (5 << HPD_CONN_THD_DP_TRANS_P0_SHIFT),
+ HPD_DISC_THD_DP_TRANS_P0_MASK |
+ HPD_CONN_THD_DP_TRANS_P0_MASK);
+ mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3430,
+ HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT,
+ HPD_INT_THD_ECO_DP_TRANS_P0_MASK);
+}
+
+static int mtk_dp_initialize_aux_settings(struct mtk_dp *mtk_dp)
+{
+ int ret;
+
+ /* modify timeout threshold = 1595 [12 : 8] */
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_360C, 0x1595,
+ AUX_TIMEOUT_THR_AUX_TX_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3658, 0,
+ AUX_TX_OV_EN_AUX_TX_P0_MASK, ret, out);
+ /* 25 for 26M */
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3634,
+ 25 << AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_SHIFT,
+ AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_MASK, ret, out);
+ /* 13 for 26M */
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3614,
+ 13 << AUX_RX_UI_CNT_THR_AUX_TX_P0_SHIFT,
+ AUX_RX_UI_CNT_THR_AUX_TX_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_37C8,
+ BIT(MTK_ATOP_EN_AUX_TX_P0_SHIFT),
+ MTK_ATOP_EN_AUX_TX_P0_MASK, ret, out);
+
+out:
+ return ret;
+}
+
+static int mtk_dp_initialize_digital_settings(struct mtk_dp *mtk_dp)
+{
+ int ret;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_304C, 0,
+ VBID_VIDEO_MUTE_DP_ENC0_P0_MASK, ret, out);
+ mtk_dp_set_color_format(mtk_dp, MTK_DP_COLOR_FORMAT_RGB_444);
+ mtk_dp_set_color_depth(mtk_dp, MTK_DP_COLOR_DEPTH_8BIT);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3368,
+ 1 << BS2BS_MODE_DP_ENC1_P0_SHIFT,
+ BS2BS_MODE_DP_ENC1_P0_MASK, ret, out);
+
+ /* dp tx encoder reset all sw */
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3004,
+ BIT(DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_SHIFT),
+ DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_MASK, ret, out);
+ usleep_range(1000, 5000);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3004, 0,
+ DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_MASK, ret, out);
+
+out:
+ return ret;
+}
+
+static int mtk_dp_digital_sw_reset(struct mtk_dp *mtk_dp)
+{
+ int ret;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_340C,
+ BIT(DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_SHIFT),
+ DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_MASK, ret, out);
+ usleep_range(1000, 5000);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_340C, 0,
+ DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_MASK, ret, out);
+
+out:
+ return ret;
+}
+
+static int mtk_dp_set_lanes(struct mtk_dp *mtk_dp, int lanes)
+{
+ int ret;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_35F0,
+ lanes == 0 ? 0 : BIT(3), BIT(3) | BIT(2), ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3000, lanes,
+ LANE_NUM_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_34A4,
+ lanes << LANE_NUM_DP_TRANS_P0_SHIFT,
+ LANE_NUM_DP_TRANS_P0_MASK, ret, out);
+
+out:
+ return ret;
+}
+
+static int link_rate_to_mb_per_s(struct mtk_dp *mtk_dp,
+ enum mtk_dp_linkrate linkrate)
+{
+ switch (linkrate) {
+ default:
+ drm_err(mtk_dp->drm_dev,
+ "Implementation error, unknown linkrate %d\n",
+ linkrate);
+ fallthrough;
+ case MTK_DP_LINKRATE_RBR:
+ return 1620;
+ case MTK_DP_LINKRATE_HBR:
+ return 2700;
+ case MTK_DP_LINKRATE_HBR2:
+ return 5400;
+ case MTK_DP_LINKRATE_HBR3:
+ return 8100;
+ }
+}
+
+static u32 check_cal_data_valid(u32 min, u32 max, u32 val, u32 default_val)
+{
+ if (val < min || val > max)
+ return default_val;
+
+ return val;
+}
+
+static int mtk_dp_get_calibration_data(struct mtk_dp *mtk_dp)
+{
+ struct dp_cal_data *cal_data = &mtk_dp->cal_data;
+ struct device *dev = mtk_dp->dev;
+ struct nvmem_cell *cell;
+ u32 *buf;
+ size_t len;
+
+ cell = nvmem_cell_get(dev, "dp_calibration_data");
+ if (IS_ERR(cell)) {
+ dev_err(dev,
+ "Error: Failed to get nvmem cell dp_calibration_data\n");
+ return PTR_ERR(cell);
+ }
+
+ buf = (u32 *)nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+
+ if (IS_ERR(buf) || ((len / sizeof(u32)) != 4)) {
+ dev_err(dev,
+ "Error: Failed to read nvmem_cell_read fail len %ld\n",
+ (len / sizeof(u32)));
+ return PTR_ERR(buf);
+ }
+
+ cal_data->glb_bias_trim =
+ check_cal_data_valid(1, 0x1e, (buf[3] >> 27) & 0x1f, 0xf);
+ cal_data->clktx_impse =
+ check_cal_data_valid(1, 0xe, (buf[0] >> 9) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_pmos[0] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 28) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_nmos[0] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 24) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_pmos[1] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 20) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_nmos[1] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 16) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_pmos[2] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 12) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_nmos[2] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 8) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_pmos[3] =
+ check_cal_data_valid(1, 0xe, (buf[2] >> 4) & 0xf, 0x8);
+ cal_data->ln_tx_impsel_nmos[3] =
+ check_cal_data_valid(1, 0xe, buf[2] & 0xf, 0x8);
+
+ kfree(buf);
+
+ return 0;
+}
+
+static int mtk_dp_set_cal_data(struct mtk_dp *mtk_dp)
+{
+ int ret;
+ struct dp_cal_data *cal_data = &mtk_dp->cal_data;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_GLB_DPAUX_TX,
+ cal_data->clktx_impse << 20, RG_CKM_PT0_CKTX_IMPSEL, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_GLB_BIAS_GEN_00,
+ cal_data->glb_bias_trim << 16,
+ RG_XTP_GLB_BIAS_INTR_CTRL, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_0,
+ cal_data->ln_tx_impsel_pmos[0] << 12,
+ RG_XTP_LN0_TX_IMPSEL_PMOS, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_0,
+ cal_data->ln_tx_impsel_nmos[0] << 16,
+ RG_XTP_LN0_TX_IMPSEL_NMOS, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_1,
+ cal_data->ln_tx_impsel_pmos[1] << 12,
+ RG_XTP_LN1_TX_IMPSEL_PMOS, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_1,
+ cal_data->ln_tx_impsel_nmos[1] << 16,
+ RG_XTP_LN1_TX_IMPSEL_NMOS, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_2,
+ cal_data->ln_tx_impsel_pmos[2] << 12,
+ RG_XTP_LN2_TX_IMPSEL_PMOS, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_2,
+ cal_data->ln_tx_impsel_nmos[2] << 16,
+ RG_XTP_LN2_TX_IMPSEL_NMOS, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_3,
+ cal_data->ln_tx_impsel_pmos[3] << 12,
+ RG_XTP_LN3_TX_IMPSEL_PMOS, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_3,
+ cal_data->ln_tx_impsel_nmos[3] << 16,
+ RG_XTP_LN3_TX_IMPSEL_NMOS, ret, out);
+
+out:
+ return ret;
+}
+
+static int mtk_dp_phy_configure(struct mtk_dp *mtk_dp,
+ enum mtk_dp_linkrate link_rate, int lane_count)
+{
+ int ret;
+ union phy_configure_opts phy_opts = {
+ .dp = {
+ .link_rate = link_rate_to_mb_per_s(mtk_dp, link_rate),
+ .set_rate = 1,
+ .lanes = lane_count,
+ .set_lanes = 1,
+ .ssc = mtk_dp->train_info.sink_ssc,
+ }
+ };
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_PWR_STATE, DP_PWR_STATE_BANDGAP,
+ DP_PWR_STATE_MASK, ret, out);
+
+ ret = phy_configure(mtk_dp->phy, &phy_opts);
+
+ if (ret)
+ goto out;
+
+ mtk_dp_set_cal_data(mtk_dp);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_PWR_STATE,
+ DP_PWR_STATE_BANDGAP_TPLL_LANE, DP_PWR_STATE_MASK, ret, out);
+
+out:
+ return ret;
+}
+
+static int mtk_dp_set_idle_pattern(struct mtk_dp *mtk_dp, bool enable)
+{
+ const u32 val = POST_MISC_DATA_LANE0_OV_DP_TRANS_P0_MASK |
+ POST_MISC_DATA_LANE1_OV_DP_TRANS_P0_MASK |
+ POST_MISC_DATA_LANE2_OV_DP_TRANS_P0_MASK |
+ POST_MISC_DATA_LANE3_OV_DP_TRANS_P0_MASK;
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3580, enable ? val : 0, val);
+}
+
+//TODO: check return value in callee
+static int mtk_dp_train_set_pattern(struct mtk_dp *mtk_dp, int pattern)
+{
+ if (pattern < 0 || pattern > 4) {
+ drm_err(mtk_dp->drm_dev,
+ "Implementation error, no such pattern %d\n", pattern);
+ return -EINVAL;
+ }
+
+ if (pattern == 1) /* TPS1 */
+ mtk_dp_set_idle_pattern(mtk_dp, false);
+
+ return mtk_dp_update_bits(mtk_dp,
+ MTK_DP_TRANS_P0_3400,
+ pattern ? BIT(pattern - 1) << PATTERN1_EN_DP_TRANS_P0_SHIFT : 0,
+ PATTERN1_EN_DP_TRANS_P0_MASK | PATTERN2_EN_DP_TRANS_P0_MASK |
+ PATTERN3_EN_DP_TRANS_P0_MASK |
+ PATTERN4_EN_DP_TRANS_P0_MASK);
+}
+
+static int mtk_dp_set_enhanced_frame_mode(struct mtk_dp *mtk_dp, bool enable)
+{
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000,
+ enable ? BIT(ENHANCED_FRAME_EN_DP_ENC0_P0_SHIFT) : 0,
+ ENHANCED_FRAME_EN_DP_ENC0_P0_MASK);
+}
+
+static int mtk_dp_training_set_scramble(struct mtk_dp *mtk_dp, bool enable)
+{
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3404,
+ enable ? DP_SCR_EN_DP_TRANS_P0_MASK : 0,
+ DP_SCR_EN_DP_TRANS_P0_MASK);
+}
+
+static void mtk_dp_video_mute(struct mtk_dp *mtk_dp, bool enable)
+{
+ u32 val = BIT(VIDEO_MUTE_SEL_DP_ENC0_P0_SHIFT);
+
+ if (enable)
+ val |= BIT(VIDEO_MUTE_SW_DP_ENC0_P0_SHIFT);
+ mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000, val,
+ VIDEO_MUTE_SEL_DP_ENC0_P0_MASK |
+ VIDEO_MUTE_SW_DP_ENC0_P0_MASK);
+
+ mtk_dp_sip_atf_call(MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE, enable);
+}
+
+static int mtk_dp_power_enable(struct mtk_dp *mtk_dp)
+{
+ int ret;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE, 0,
+ SW_RST_B_PHYD, ret, out);
+ usleep_range(10, 200);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE, SW_RST_B_PHYD,
+ SW_RST_B_PHYD, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_PWR_STATE,
+ DP_PWR_STATE_BANDGAP_TPLL,
+ DP_PWR_STATE_MASK, ret, out);
+
+out:
+ return ret;
+}
+
+static int mtk_dp_power_disable(struct mtk_dp *mtk_dp)
+{
+ int ret;
+
+ ret = mtk_dp_write(mtk_dp, MTK_DP_TOP_PWR_STATE, 0);
+
+ if (ret)
+ goto out;
+
+ usleep_range(10, 200);
+ ret = mtk_dp_write(mtk_dp, MTK_DP_0034,
+ DA_CKM_CKTX0_EN_FORCE_EN | DA_CKM_BIAS_LPF_EN_FORCE_VAL |
+ DA_CKM_BIAS_EN_FORCE_VAL |
+ DA_XTP_GLB_LDO_EN_FORCE_VAL |
+ DA_XTP_GLB_AVD10_ON_FORCE_VAL);
+
+ if (ret)
+ goto out;
+
+ /* Disable RX */
+ ret = mtk_dp_write(mtk_dp, MTK_DP_1040, 0);
+
+ if (ret)
+ goto out;
+
+ ret = mtk_dp_write(mtk_dp, MTK_DP_TOP_MEM_PD,
+ 0x550 | BIT(FUSE_SEL_SHIFT) | BIT(MEM_ISO_EN_SHIFT));
+
+out:
+ return ret;
+}
+
+static void mtk_dp_initialize_priv_data(struct mtk_dp *mtk_dp)
+{
+ mtk_dp->train_info.link_rate = MTK_DP_LINKRATE_HBR2;
+ mtk_dp->train_info.lane_count = MTK_DP_MAX_LANES;
+ mtk_dp->train_info.irq_status = 0;
+ mtk_dp->train_info.cable_plugged_in = false;
+ mtk_dp->train_info.cable_state_change = false;
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_STARTUP;
+ mtk_dp->state = MTK_DP_STATE_INITIAL;
+
+ mtk_dp->info.format = MTK_DP_COLOR_FORMAT_RGB_444;
+ mtk_dp->info.depth = MTK_DP_COLOR_DEPTH_8BIT;
+ memset(&mtk_dp->info.timings, 0, sizeof(struct mtk_dp_timings));
+ mtk_dp->info.timings.frame_rate = 60;
+
+ mtk_dp->has_fec = false;
+}
+
+static void mtk_dp_setup_tu(struct mtk_dp *mtk_dp)
+{
+ u32 sram_read_start = MTK_DP_TBC_BUF_READ_START_ADDR;
+
+ if (mtk_dp->train_info.lane_count > 0) {
+ sram_read_start = min_t(u32,
+ MTK_DP_TBC_BUF_READ_START_ADDR,
+ mtk_dp->info.timings.vm.hactive /
+ (mtk_dp->train_info.lane_count * 4 * 2 * 2));
+ mtk_dp_set_sram_read_start(mtk_dp, sram_read_start);
+ }
+
+ mtk_dp_setup_encoder(mtk_dp);
+}
+
+static void mtk_dp_calculate_pixrate(struct mtk_dp *mtk_dp)
+{
+ int target_frame_rate = 60;
+ int target_pixel_clk;
+
+ if (mtk_dp->info.timings.frame_rate > 0) {
+ target_frame_rate = mtk_dp->info.timings.frame_rate;
+ target_pixel_clk = (int)mtk_dp->info.timings.htotal *
+ (int)mtk_dp->info.timings.vtotal *
+ target_frame_rate;
+ } else if (mtk_dp->info.timings.pix_rate_khz > 0) {
+ target_pixel_clk = mtk_dp->info.timings.pix_rate_khz * 1000;
+ } else {
+ target_pixel_clk = (int)mtk_dp->info.timings.htotal *
+ (int)mtk_dp->info.timings.vtotal *
+ target_frame_rate;
+ }
+
+ if (target_pixel_clk > 0)
+ mtk_dp->info.timings.pix_rate_khz = target_pixel_clk / 1000;
+}
+
+static void mtk_dp_set_tx_out(struct mtk_dp *mtk_dp)
+{
+ mtk_dp_msa_bypass_disable(mtk_dp);
+ mtk_dp_calculate_pixrate(mtk_dp);
+ mtk_dp_pg_disable(mtk_dp);
+ mtk_dp_setup_tu(mtk_dp);
+}
+
+static void mtk_dp_train_update_swing_pre(struct mtk_dp *mtk_dp, int lanes,
+ u8 dpcd_adjust_req[2])
+{
+ int lane;
+
+ for (lane = 0; lane < lanes; ++lane) {
+ u8 val;
+ u8 swing;
+ u8 preemphasis;
+ int index = lane / 2;
+ int shift = lane % 2 ? DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : 0;
+
+ swing = (dpcd_adjust_req[index] >> shift) &
+ DP_ADJUST_VOLTAGE_SWING_LANE0_MASK;
+ preemphasis = ((dpcd_adjust_req[index] >> shift) &
+ DP_ADJUST_PRE_EMPHASIS_LANE0_MASK) >>
+ DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT;
+ val = swing << DP_TRAIN_VOLTAGE_SWING_SHIFT |
+ preemphasis << DP_TRAIN_PRE_EMPHASIS_SHIFT;
+
+ if (swing == DP_TRAIN_VOLTAGE_SWING_LEVEL_3)
+ val |= DP_TRAIN_MAX_SWING_REACHED;
+ if (preemphasis == 3)
+ val |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+
+ mtk_dp_set_swing_pre_emphasis(mtk_dp, lane, swing, preemphasis);
+ drm_dp_dpcd_writeb(&mtk_dp->aux, DP_TRAINING_LANE0_SET + lane,
+ val);
+ }
+
+ /* Wait for the signal to be stable enough */
+ usleep_range(2000, 5000);
+}
+
+static void mtk_dp_read_link_status(struct mtk_dp *mtk_dp,
+ u8 link_status[DP_LINK_STATUS_SIZE])
+{
+ drm_dp_dpcd_read(&mtk_dp->aux, DP_LANE0_1_STATUS, link_status,
+ DP_LINK_STATUS_SIZE);
+}
+
+static int mtk_dp_train_flow(struct mtk_dp *mtk_dp, int target_link_rate,
+ int target_lane_count)
+{
+ u8 link_status[DP_LINK_STATUS_SIZE] = {};
+ u8 lane_adjust[2] = {};
+ bool pass_tps1 = false;
+ bool pass_tps2_3 = false;
+ int train_retries;
+ int status_control;
+ int iteration_count;
+ u8 prev_lane_adjust;
+ u8 val;
+
+ drm_dp_dpcd_writeb(&mtk_dp->aux, DP_LINK_BW_SET, target_link_rate);
+ drm_dp_dpcd_writeb(&mtk_dp->aux, DP_LANE_COUNT_SET,
+ target_lane_count | DP_LANE_COUNT_ENHANCED_FRAME_EN);
+
+ if (mtk_dp->train_info.sink_ssc)
+ drm_dp_dpcd_writeb(&mtk_dp->aux, DP_DOWNSPREAD_CTRL,
+ DP_SPREAD_AMP_0_5);
+
+ train_retries = 0;
+ status_control = 0;
+ iteration_count = 1;
+ prev_lane_adjust = 0xFF;
+
+ mtk_dp_set_lanes(mtk_dp, target_lane_count / 2);
+ mtk_dp_phy_configure(mtk_dp, target_link_rate, target_lane_count);
+
+ dev_dbg(mtk_dp->dev,
+ "Link train target_link_rate = 0x%x, target_lane_count = 0x%x\n",
+ target_link_rate, target_lane_count);
+
+ do {
+ train_retries++;
+ if (!mtk_dp->train_info.cable_plugged_in ||
+ ((mtk_dp->train_info.irq_status & MTK_DP_HPD_DISCONNECT) !=
+ 0x0)) {
+ return -ENODEV;
+ }
+
+ if (mtk_dp->train_state < MTK_DP_TRAIN_STATE_TRAINING)
+ return -EAGAIN;
+
+ if (!pass_tps1) {
+ mtk_dp_training_set_scramble(mtk_dp, false);
+
+ if (status_control == 0) {
+ status_control = 1;
+ mtk_dp_train_set_pattern(mtk_dp, 1);
+ val = DP_LINK_SCRAMBLING_DISABLE |
+ DP_TRAINING_PATTERN_1;
+ drm_dp_dpcd_writeb(&mtk_dp->aux,
+ DP_TRAINING_PATTERN_SET,
+ DP_LINK_SCRAMBLING_DISABLE |
+ DP_TRAINING_PATTERN_1);
+ drm_dp_dpcd_read(&mtk_dp->aux,
+ DP_ADJUST_REQUEST_LANE0_1,
+ lane_adjust,
+ sizeof(lane_adjust));
+ iteration_count++;
+
+ mtk_dp_train_update_swing_pre(mtk_dp,
+ target_lane_count, lane_adjust);
+ }
+
+ drm_dp_link_train_clock_recovery_delay(&mtk_dp->aux,
+ mtk_dp->rx_cap);
+ mtk_dp_read_link_status(mtk_dp, link_status);
+
+ if (drm_dp_clock_recovery_ok(link_status,
+ target_lane_count)) {
+ mtk_dp->train_info.cr_done = true;
+ pass_tps1 = true;
+ train_retries = 0;
+ iteration_count = 1;
+ dev_dbg(mtk_dp->dev, "Link train CR pass\n");
+ } else if (prev_lane_adjust == link_status[4]) {
+ iteration_count++;
+ if (prev_lane_adjust &
+ DP_ADJUST_VOLTAGE_SWING_LANE0_MASK)
+ break;
+ } else {
+ prev_lane_adjust = link_status[4];
+ }
+ dev_dbg(mtk_dp->dev, "Link train CQ fail\n");
+ } else if (pass_tps1 && !pass_tps2_3) {
+ if (status_control == 1) {
+ status_control = 2;
+ if (mtk_dp->train_info.tps4) {
+ mtk_dp_train_set_pattern(mtk_dp, 4);
+ val = DP_TRAINING_PATTERN_4;
+ } else if (mtk_dp->train_info.tps3) {
+ mtk_dp_train_set_pattern(mtk_dp, 3);
+ val = DP_LINK_SCRAMBLING_DISABLE |
+ DP_TRAINING_PATTERN_3;
+ } else {
+ mtk_dp_train_set_pattern(mtk_dp, 2);
+ val = DP_LINK_SCRAMBLING_DISABLE |
+ DP_TRAINING_PATTERN_2;
+ }
+ drm_dp_dpcd_writeb(&mtk_dp->aux,
+ DP_TRAINING_PATTERN_SET,
+ val);
+
+ drm_dp_dpcd_read(&mtk_dp->aux,
+ DP_ADJUST_REQUEST_LANE0_1,
+ lane_adjust,
+ sizeof(lane_adjust));
+
+ iteration_count++;
+ mtk_dp_train_update_swing_pre(mtk_dp,
+ target_lane_count, lane_adjust);
+ }
+
+ drm_dp_link_train_channel_eq_delay(&mtk_dp->aux,
+ mtk_dp->rx_cap);
+
+ mtk_dp_read_link_status(mtk_dp, link_status);
+
+ if (!drm_dp_clock_recovery_ok(link_status,
+ target_lane_count)) {
+ mtk_dp->train_info.cr_done = false;
+ mtk_dp->train_info.eq_done = false;
+ dev_dbg(mtk_dp->dev, "Link train EQ fail\n");
+ break;
+ }
+
+ if (drm_dp_channel_eq_ok(link_status,
+ target_lane_count)) {
+ mtk_dp->train_info.eq_done = true;
+ pass_tps2_3 = true;
+ dev_dbg(mtk_dp->dev, "Link train EQ pass\n");
+ break;
+ }
+
+ if (prev_lane_adjust == link_status[4])
+ iteration_count++;
+ else
+ prev_lane_adjust = link_status[4];
+ }
+
+ drm_dp_dpcd_read(&mtk_dp->aux, DP_ADJUST_REQUEST_LANE0_1,
+ lane_adjust, sizeof(lane_adjust));
+ mtk_dp_train_update_swing_pre(mtk_dp, target_lane_count,
+ lane_adjust);
+ } while (train_retries < MTK_DP_TRAIN_RETRY_LIMIT &&
+ iteration_count < MTK_DP_TRAIN_MAX_ITERATIONS);
+
+ drm_dp_dpcd_writeb(&mtk_dp->aux, DP_TRAINING_PATTERN_SET,
+ DP_TRAINING_PATTERN_DISABLE);
+ mtk_dp_train_set_pattern(mtk_dp, 0);
+
+ if (!pass_tps2_3)
+ return -ETIMEDOUT;
+
+ mtk_dp->train_info.link_rate = target_link_rate;
+ mtk_dp->train_info.lane_count = target_lane_count;
+
+ mtk_dp_training_set_scramble(mtk_dp, true);
+
+ drm_dp_dpcd_writeb(&mtk_dp->aux, DP_LANE_COUNT_SET,
+ target_lane_count |
+ DP_LANE_COUNT_ENHANCED_FRAME_EN);
+ mtk_dp_set_enhanced_frame_mode(mtk_dp, true);
+
+ return 0;
+}
+
+static bool mtk_dp_parse_capabilities(struct mtk_dp *mtk_dp)
+{
+ u8 buf[DP_RECEIVER_CAP_SIZE] = {};
+ u8 val;
+ struct mtk_dp_train_info *train_info = &mtk_dp->train_info;
+
+ if (!mtk_dp_plug_state(mtk_dp))
+ return false;
+
+ drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
+ usleep_range(2000, 5000);
+
+ drm_dp_read_dpcd_caps(&mtk_dp->aux, buf);
+
+ memcpy(mtk_dp->rx_cap, buf, min(sizeof(mtk_dp->rx_cap), sizeof(buf)));
+ mtk_dp->rx_cap[DP_TRAINING_AUX_RD_INTERVAL] &= DP_TRAINING_AUX_RD_MASK;
+
+ train_info->link_rate =
+ min_t(int, MTK_DP_MAX_LINK_RATE, buf[DP_MAX_LINK_RATE]);
+ train_info->lane_count =
+ min_t(int, MTK_DP_MAX_LANES, drm_dp_max_lane_count(buf));
+
+ train_info->tps3 = drm_dp_tps3_supported(buf);
+ train_info->tps4 = drm_dp_tps4_supported(buf);
+
+ train_info->sink_ssc =
+ !!(buf[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5);
+
+ train_info->sink_ssc = false;
+
+ drm_dp_dpcd_readb(&mtk_dp->aux, DP_MSTM_CAP, &val);
+ if (val & DP_MST_CAP) {
+ /* Clear DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 */
+ drm_dp_dpcd_readb(&mtk_dp->aux,
+ DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0, &val);
+ if (val)
+ drm_dp_dpcd_writeb(&mtk_dp->aux,
+ DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0,
+ val);
+ }
+
+ return true;
+}
+
+static void mtk_dp_train_change_mode(struct mtk_dp *mtk_dp)
+{
+ phy_reset(mtk_dp->phy);
+ mtk_dp_reset_swing_pre_emphasis(mtk_dp);
+
+ usleep_range(2000, 5000);
+}
+
+static int mtk_dp_train_start(struct mtk_dp *mtk_dp)
+{
+ int ret = 0;
+ int lane_count;
+ int link_rate;
+ int train_limit;
+ int max_link_rate;
+ int plug_wait;
+
+ for (plug_wait = 7; !mtk_dp_plug_state(mtk_dp) && plug_wait > 0;
+ --plug_wait)
+ usleep_range(1000, 5000);
+ if (plug_wait == 0) {
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_DPIDLE;
+ return -ENODEV;
+ }
+
+ link_rate = mtk_dp->rx_cap[1];
+ lane_count = mtk_dp->rx_cap[2] & 0x1F;
+
+ mtk_dp->train_info.link_rate = min(MTK_DP_MAX_LINK_RATE, link_rate);
+ mtk_dp->train_info.lane_count = min(MTK_DP_MAX_LANES, lane_count);
+ link_rate = mtk_dp->train_info.link_rate;
+ lane_count = mtk_dp->train_info.lane_count;
+
+ switch (link_rate) {
+ case MTK_DP_LINKRATE_RBR:
+ case MTK_DP_LINKRATE_HBR:
+ case MTK_DP_LINKRATE_HBR2:
+ case MTK_DP_LINKRATE_HBR25:
+ case MTK_DP_LINKRATE_HBR3:
+ break;
+ default:
+ mtk_dp->train_info.link_rate = MTK_DP_LINKRATE_HBR3;
+ break;
+ };
+
+ max_link_rate = link_rate;
+ for (train_limit = 6; train_limit > 0; train_limit--) {
+ mtk_dp->train_info.cr_done = false;
+ mtk_dp->train_info.eq_done = false;
+
+ mtk_dp_train_change_mode(mtk_dp);
+ ret = mtk_dp_train_flow(mtk_dp, link_rate, lane_count);
+ if (ret)
+ return ret;
+
+ if (!mtk_dp->train_info.cr_done) {
+ switch (link_rate) {
+ case MTK_DP_LINKRATE_RBR:
+ lane_count = lane_count / 2;
+ link_rate = max_link_rate;
+ if (lane_count == 0) {
+ mtk_dp->train_state =
+ MTK_DP_TRAIN_STATE_DPIDLE;
+ return -EIO;
+ }
+ break;
+ case MTK_DP_LINKRATE_HBR:
+ link_rate = MTK_DP_LINKRATE_RBR;
+ break;
+ case MTK_DP_LINKRATE_HBR2:
+ link_rate = MTK_DP_LINKRATE_HBR;
+ break;
+ case MTK_DP_LINKRATE_HBR3:
+ link_rate = MTK_DP_LINKRATE_HBR2;
+ break;
+ default:
+ return -EINVAL;
+ };
+ } else if (!mtk_dp->train_info.eq_done) {
+ if (lane_count == 0)
+ return -EIO;
+
+ lane_count /= 2;
+ } else {
+ break;
+ }
+ }
+
+ if (train_limit == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int mtk_dp_train_handler(struct mtk_dp *mtk_dp)
+{
+ int ret = 0;
+ int i = 50;
+
+ for (; ret && i; i--) {
+ if (mtk_dp->train_state == MTK_DP_TRAIN_STATE_NORMAL)
+ continue;
+
+ switch (mtk_dp->train_state) {
+ case MTK_DP_TRAIN_STATE_STARTUP:
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_CHECKCAP;
+ break;
+
+ case MTK_DP_TRAIN_STATE_CHECKCAP:
+ if (mtk_dp_parse_capabilities(mtk_dp)) {
+ mtk_dp->train_info.check_cap_count = 0;
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_CHECKEDID;
+ } else {
+ mtk_dp->train_info.check_cap_count++;
+
+ if (mtk_dp->train_info.check_cap_count >
+ MTK_DP_CHECK_SINK_CAP_TIMEOUT_COUNT) {
+ mtk_dp->train_info.check_cap_count = 0;
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_DPIDLE;
+ ret = -ETIMEDOUT;
+ }
+ }
+ break;
+
+ case MTK_DP_TRAIN_STATE_CHECKEDID:
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_TRAINING_PRE;
+ break;
+
+ case MTK_DP_TRAIN_STATE_TRAINING_PRE:
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_TRAINING;
+ break;
+
+ case MTK_DP_TRAIN_STATE_TRAINING:
+ ret = mtk_dp_train_start(mtk_dp);
+ if (!ret) {
+ mtk_dp_video_mute(mtk_dp, true);
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_NORMAL;
+ mtk_dp_fec_enable(mtk_dp, mtk_dp->has_fec);
+ } else if (ret != -EAGAIN) {
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_DPIDLE;
+ }
+
+ ret = 0;
+ break;
+
+ case MTK_DP_TRAIN_STATE_NORMAL:
+ break;
+ case MTK_DP_TRAIN_STATE_DPIDLE:
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (ret)
+ drm_err(mtk_dp->drm_dev, "Train handler failed %d\n", ret);
+
+ return ret;
+}
+
+static void mtk_dp_video_enable(struct mtk_dp *mtk_dp, bool enable)
+{
+ if (enable) {
+ mtk_dp_set_tx_out(mtk_dp);
+ mtk_dp_video_mute(mtk_dp, false);
+ } else {
+ mtk_dp_video_mute(mtk_dp, true);
+ }
+}
+
+static void mtk_dp_video_config(struct mtk_dp *mtk_dp)
+{
+ mtk_dp_mn_overwrite_disable(mtk_dp);
+
+ mtk_dp_set_msa(mtk_dp);
+
+ mtk_dp_set_color_depth(mtk_dp, mtk_dp->info.depth);
+ mtk_dp_set_color_format(mtk_dp, mtk_dp->info.format);
+}
+
+static void mtk_dp_state_handler(struct mtk_dp *mtk_dp)
+{
+ switch (mtk_dp->state) {
+ case MTK_DP_STATE_INITIAL:
+ mtk_dp_video_mute(mtk_dp, true);
+ mtk_dp->state = MTK_DP_STATE_IDLE;
+ break;
+
+ case MTK_DP_STATE_IDLE:
+ if (mtk_dp->train_state == MTK_DP_TRAIN_STATE_NORMAL)
+ mtk_dp->state = MTK_DP_STATE_PREPARE;
+ break;
+
+ case MTK_DP_STATE_PREPARE:
+ mtk_dp_video_config(mtk_dp);
+ mtk_dp_video_enable(mtk_dp, true);
+
+ mtk_dp->state = MTK_DP_STATE_NORMAL;
+ break;
+
+ case MTK_DP_STATE_NORMAL:
+ if (mtk_dp->train_state != MTK_DP_TRAIN_STATE_NORMAL) {
+ mtk_dp_video_mute(mtk_dp, true);
+ mtk_dp->state = MTK_DP_STATE_IDLE;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void mtk_dp_init_port(struct mtk_dp *mtk_dp)
+{
+ mtk_dp_set_idle_pattern(mtk_dp, true);
+ mtk_dp_initialize_priv_data(mtk_dp);
+
+ mtk_dp_initialize_settings(mtk_dp);
+ mtk_dp_initialize_aux_settings(mtk_dp);
+ mtk_dp_initialize_digital_settings(mtk_dp);
+ mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3690,
+ BIT(RX_REPLY_COMPLETE_MODE_AUX_TX_P0_SHIFT),
+ RX_REPLY_COMPLETE_MODE_AUX_TX_P0_MASK);
+ mtk_dp_initialize_hpd_detect_settings(mtk_dp);
+
+ mtk_dp_digital_sw_reset(mtk_dp);
+}
+
+static int mtk_dp_dt_parse(struct mtk_dp *mtk_dp,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int ret = 0;
+ void __iomem *base;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ mtk_dp->regs = syscon_node_to_regmap(dev->of_node);
+ if (IS_ERR(mtk_dp->regs))
+ return PTR_ERR(mtk_dp->regs);
+
+ //TODO: optional clock?
+ mtk_dp->dp_tx_clk = devm_clk_get(dev, "faxi");
+ if (IS_ERR(mtk_dp->dp_tx_clk)) {
+ ret = PTR_ERR(mtk_dp->dp_tx_clk);
+ dev_info(dev, "Failed to get dptx clock: %d\n", ret);
+ mtk_dp->dp_tx_clk = NULL;
+ }
+
+ return 0;
+}
+
+static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge)
+{
+ return connector_status_connected;
+}
+
+static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
+ bool enabled = mtk_dp->enabled;
+ struct edid *new_edid = NULL;
+
+ if (!enabled)
+ drm_bridge_chain_pre_enable(bridge);
+
+ drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
+ usleep_range(2000, 5000);
+
+ if (mtk_dp_plug_state(mtk_dp))
+ new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
+
+ if (!enabled)
+ drm_bridge_chain_post_disable(bridge);
+
+ mutex_lock(&mtk_dp->edid_lock);
+ kfree(mtk_dp->edid);
+ mtk_dp->edid = NULL;
+
+ if (!new_edid) {
+ mutex_unlock(&mtk_dp->edid_lock);
+ return NULL;
+ }
+
+ mtk_dp->edid = drm_edid_duplicate(new_edid);
+ mutex_unlock(&mtk_dp->edid_lock);
+
+ return new_edid;
+}
+
+static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux,
+ struct drm_dp_aux_msg *msg)
+{
+ struct mtk_dp *mtk_dp;
+ bool is_read;
+ u8 request;
+ size_t accessed_bytes = 0;
+ int retry = 3, ret = 0;
+
+ mtk_dp = container_of(mtk_aux, struct mtk_dp, aux);
+
+ if (!mtk_dp->train_info.cable_plugged_in ||
+ mtk_dp->train_info.irq_status & MTK_DP_HPD_DISCONNECT) {
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_CHECKCAP;
+ ret = -EAGAIN;
+ goto err;
+ }
+
+ switch (msg->request) {
+ case DP_AUX_I2C_MOT:
+ case DP_AUX_I2C_WRITE:
+ case DP_AUX_NATIVE_WRITE:
+ case DP_AUX_I2C_WRITE_STATUS_UPDATE:
+ case DP_AUX_I2C_WRITE_STATUS_UPDATE | DP_AUX_I2C_MOT:
+ request = msg->request & ~DP_AUX_I2C_WRITE_STATUS_UPDATE;
+ is_read = false;
+ break;
+ case DP_AUX_I2C_READ:
+ case DP_AUX_NATIVE_READ:
+ case DP_AUX_I2C_READ | DP_AUX_I2C_MOT:
+ request = msg->request;
+ is_read = true;
+ break;
+ default:
+ drm_err(mtk_aux->drm_dev, "invalid aux cmd = %d\n",
+ msg->request);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (msg->size == 0) {
+ ret = mtk_dp_aux_do_transfer(mtk_dp, is_read, request,
+ msg->address + accessed_bytes,
+ msg->buffer + accessed_bytes, 0);
+ } else {
+ while (accessed_bytes < msg->size) {
+ size_t to_access =
+ min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES,
+ msg->size - accessed_bytes);
+ while (retry--) {
+ ret = mtk_dp_aux_do_transfer(mtk_dp,
+ is_read, request,
+ msg->address + accessed_bytes,
+ msg->buffer + accessed_bytes,
+ to_access);
+ if (ret == 0)
+ break;
+ usleep_range(50, 100);
+ }
+ if (!retry || ret) {
+ drm_info(mtk_dp->drm_dev,
+ "Failed to do AUX transfer: %d\n",
+ ret);
+ break;
+ }
+ accessed_bytes += to_access;
+ }
+ }
+err:
+ if (ret) {
+ msg->reply = DP_AUX_NATIVE_REPLY_NACK | DP_AUX_I2C_REPLY_NACK;
+ return ret;
+ }
+
+ msg->reply = DP_AUX_NATIVE_REPLY_ACK | DP_AUX_I2C_REPLY_ACK;
+ return msg->size;
+}
+
+static void mtk_dp_poweroff(struct mtk_dp *mtk_dp)
+{
+ mutex_lock(&mtk_dp->dp_lock);
+
+ mtk_dp_hwirq_enable(mtk_dp, false);
+ mtk_dp_power_disable(mtk_dp);
+ phy_exit(mtk_dp->phy);
+ clk_disable_unprepare(mtk_dp->dp_tx_clk);
+
+ mutex_unlock(&mtk_dp->dp_lock);
+}
+
+static int mtk_dp_poweron(struct mtk_dp *mtk_dp)
+{
+ int ret = 0;
+
+ mutex_lock(&mtk_dp->dp_lock);
+
+ ret = clk_prepare_enable(mtk_dp->dp_tx_clk);
+ if (ret < 0) {
+ dev_err(mtk_dp->dev, "Fail to enable clock: %d\n", ret);
+ goto err;
+ }
+ ret = phy_init(mtk_dp->phy);
+ if (ret) {
+ dev_err(mtk_dp->dev, "Failed to initialize phy: %d\n", ret);
+ goto err_phy_init;
+ }
+ ret = mtk_dp_phy_configure(mtk_dp, MTK_DP_LINKRATE_RBR, 1);
+ if (ret) {
+ dev_err(mtk_dp->dev, "Failed to configure phy: %d\n", ret);
+ goto err_phy_config;
+ }
+
+ mtk_dp_init_port(mtk_dp);
+ mtk_dp_power_enable(mtk_dp);
+ mtk_dp_hwirq_enable(mtk_dp, true);
+
+err_phy_config:
+ phy_exit(mtk_dp->phy);
+err_phy_init:
+ clk_disable_unprepare(mtk_dp->dp_tx_clk);
+err:
+ mutex_unlock(&mtk_dp->dp_lock);
+ return ret;
+}
+
+static int mtk_dp_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
+ int ret;
+
+ ret = mtk_dp_poweron(mtk_dp);
+ if (ret)
+ return ret;
+
+ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
+ dev_err(mtk_dp->dev, "Driver does not provide a connector!");
+ return -EINVAL;
+ }
+
+ if (mtk_dp->next_bridge) {
+ ret = drm_bridge_attach(bridge->encoder, mtk_dp->next_bridge,
+ &mtk_dp->bridge, flags);
+ if (ret) {
+ drm_warn(mtk_dp->drm_dev,
+ "Failed to attach external bridge: %d\n", ret);
+ return ret;
+ }
+ }
+
+ mtk_dp->drm_dev = bridge->dev;
+
+ return 0;
+}
+
+static void mtk_dp_bridge_detach(struct drm_bridge *bridge)
+{
+ struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
+
+ mtk_dp->drm_dev = NULL;
+}
+
+static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_state)
+{
+ struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
+
+ mtk_dp_video_mute(mtk_dp, true);
+ mtk_dp->state = MTK_DP_STATE_IDLE;
+ mtk_dp->train_state = MTK_DP_TRAIN_STATE_STARTUP;
+
+ mtk_dp->enabled = false;
+ msleep(100);
+ mtk_dp_poweroff(mtk_dp);
+}
+
+static void mtk_dp_parse_drm_mode_timings(struct mtk_dp *mtk_dp,
+ struct drm_display_mode *mode)
+{
+ struct mtk_dp_timings *timings = &mtk_dp->info.timings;
+
+ drm_display_mode_to_videomode(mode, &timings->vm);
+ timings->frame_rate = mode->clock * 1000 / mode->htotal / mode->vtotal;
+ timings->htotal = mode->htotal;
+ timings->vtotal = mode->vtotal;
+}
+
+static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_state)
+{
+ struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
+ struct drm_connector_state *conn_state;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+
+ mtk_dp->conn = drm_atomic_get_new_connector_for_encoder(old_state->base.state,
+ bridge->encoder);
+ if (!mtk_dp->conn) {
+ drm_err(mtk_dp->drm_dev,
+ "Can't enable bridge as connector is missing\n");
+ return;
+ }
+
+ memcpy(mtk_dp->connector_eld, mtk_dp->conn->eld, MAX_ELD_BYTES);
+
+ conn_state =
+ drm_atomic_get_new_connector_state(old_state->base.state, mtk_dp->conn);
+ if (!conn_state) {
+ drm_err(mtk_dp->drm_dev,
+ "Can't enable bridge as connector state is missing\n");
+ return;
+ }
+
+ crtc = conn_state->crtc;
+ if (!crtc) {
+ drm_err(mtk_dp->drm_dev,
+ "Can't enable bridge as connector state doesn't have a crtc\n");
+ return;
+ }
+
+ crtc_state = drm_atomic_get_new_crtc_state(old_state->base.state, crtc);
+ if (!crtc_state) {
+ drm_err(mtk_dp->drm_dev,
+ "Can't enable bridge as crtc state is missing\n");
+ return;
+ }
+
+ mtk_dp_parse_drm_mode_timings(mtk_dp, &crtc_state->adjusted_mode);
+ if (!mtk_dp_parse_capabilities(mtk_dp)) {
+ drm_err(mtk_dp->drm_dev,
+ "Can't enable bridge as nothing is plugged in\n");
+ return;
+ }
+
+ /* Training */
+ mtk_dp_train_handler(mtk_dp);
+ mtk_dp_state_handler(mtk_dp);
+ mtk_dp->enabled = true;
+}
+
+static enum drm_mode_status
+mtk_dp_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
+ u32 rx_linkrate = (u32)mtk_dp->train_info.link_rate * 27000;
+ u32 bpp = info->color_formats & DRM_COLOR_FORMAT_YCBCR422 ? 16 : 24;
+
+ if (rx_linkrate * mtk_dp->train_info.lane_count < mode->clock * bpp / 8)
+ return MODE_CLOCK_HIGH;
+
+ if (mode->clock > 600000)
+ return MODE_CLOCK_HIGH;
+
+ //TODO: explain magic number: 62?
+ if ((mode->clock * 1000) / (mode->htotal * mode->vtotal) > 62)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static u32 *mtk_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ unsigned int *num_output_fmts)
+{
+ u32 *output_fmts;
+
+ *num_output_fmts = 0;
+ output_fmts = kmalloc(sizeof(*output_fmts), GFP_KERNEL);
+ if (!output_fmts)
+ return NULL;
+ *num_output_fmts = 1;
+ output_fmts[0] = MEDIA_BUS_FMT_FIXED;
+ return output_fmts;
+}
+
+static const u32 mt8195_input_fmts[] = {
+ MEDIA_BUS_FMT_RGB888_1X24,
+ MEDIA_BUS_FMT_YUV8_1X24,
+ MEDIA_BUS_FMT_YUYV8_1X16,
+};
+
+static u32 *mtk_dp_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ u32 output_fmt,
+ unsigned int *num_input_fmts)
+{
+ u32 *input_fmts;
+ struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
+ struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+ struct drm_display_info *display_info =
+ &conn_state->connector->display_info;
+ u32 rx_linkrate = (u32)mtk_dp->train_info.link_rate * 27000;
+
+ *num_input_fmts = 0;
+
+ if (((rx_linkrate * mtk_dp->train_info.lane_count) <
+ (mode->clock * 24 / 8)) &&
+ ((rx_linkrate * mtk_dp->train_info.lane_count) >
+ (mode->clock * 16 / 8)) &&
+ (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR422)) {
+ input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
+ if (!input_fmts)
+ return NULL;
+
+ *num_input_fmts = 1;
+ input_fmts[0] = MEDIA_BUS_FMT_YUYV8_1X16;
+ } else {
+ input_fmts = kmalloc(sizeof(mt8195_input_fmts), GFP_KERNEL);
+ if (!input_fmts)
+ return NULL;
+
+ *num_input_fmts = ARRAY_SIZE(mt8195_input_fmts);
+ memcpy(input_fmts, mt8195_input_fmts, sizeof(mt8195_input_fmts));
+ }
+
+ return input_fmts;
+}
+
+static int mtk_dp_bridge_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
+ unsigned int input_bus_format;
+
+ input_bus_format = bridge_state->input_bus_cfg.format;
+
+ dev_dbg(mtk_dp->dev, "input format 0x%04x, output format 0x%04x\n",
+ bridge_state->input_bus_cfg.format,
+ bridge_state->output_bus_cfg.format);
+
+ mtk_dp->input_fmt = input_bus_format;
+ if (mtk_dp->input_fmt == MEDIA_BUS_FMT_YUYV8_1X16)
+ mtk_dp->info.format = MTK_DP_COLOR_FORMAT_YUV_422;
+ else
+ mtk_dp->info.format = MTK_DP_COLOR_FORMAT_RGB_444;
+
+ return 0;
+}
+
+static const struct drm_bridge_funcs mtk_dp_bridge_funcs = {
+ .atomic_check = mtk_dp_bridge_atomic_check,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_get_output_bus_fmts = mtk_dp_bridge_atomic_get_output_bus_fmts,
+ .atomic_get_input_bus_fmts = mtk_dp_bridge_atomic_get_input_bus_fmts,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .attach = mtk_dp_bridge_attach,
+ .detach = mtk_dp_bridge_detach,
+ .atomic_enable = mtk_dp_bridge_atomic_enable,
+ .atomic_disable = mtk_dp_bridge_atomic_disable,
+ .mode_valid = mtk_dp_bridge_mode_valid,
+ .get_edid = mtk_dp_get_edid,
+ .detect = mtk_dp_bdg_detect,
+};
+
+static int mtk_dp_probe(struct platform_device *pdev)
+{
+ struct mtk_dp *mtk_dp;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ mtk_dp = devm_kzalloc(dev, sizeof(*mtk_dp), GFP_KERNEL);
+ if (!mtk_dp)
+ return -ENOMEM;
+
+ mtk_dp->dev = dev;
+
+ mtk_dp->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
+ if (IS_ERR(mtk_dp->next_bridge))
+ return dev_err_probe(dev, PTR_ERR(mtk_dp->next_bridge), "Failed to get bridge\n");
+
+ ret = mtk_dp_dt_parse(mtk_dp, pdev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to parsed dt\n");
+
+ drm_dp_aux_init(&mtk_dp->aux);
+ mtk_dp->aux.name = "aux_mtk_dp";
+ mtk_dp->aux.transfer = mtk_dp_aux_transfer;
+
+ mutex_init(&mtk_dp->dp_lock);
+ mutex_init(&mtk_dp->edid_lock);
+
+ platform_set_drvdata(pdev, mtk_dp);
+
+ mtk_dp_get_calibration_data(mtk_dp);
+
+ mtk_dp->phy = devm_phy_get(dev, "dp");
+
+ if (IS_ERR(mtk_dp->phy))
+ return dev_err_probe(dev, PTR_ERR(mtk_dp->phy), "Failed to get phy\n");
+
+ mtk_dp->bridge.funcs = &mtk_dp_bridge_funcs;
+ mtk_dp->bridge.of_node = dev->of_node;
+ mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP;
+
+ mtk_dp->bridge.ops = DRM_BRIDGE_OP_EDID;
+ drm_bridge_add(&mtk_dp->bridge);
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
+ return 0;
+}
+
+static int mtk_dp_remove(struct platform_device *pdev)
+{
+ struct mtk_dp *mtk_dp = platform_get_drvdata(pdev);
+
+ mtk_dp_video_mute(mtk_dp, true);
+
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_dp_suspend(struct device *dev)
+{
+ struct mtk_dp *mtk_dp = dev_get_drvdata(dev);
+
+ if (mtk_dp_plug_state(mtk_dp)) {
+ drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
+ usleep_range(2000, 3000);
+ }
+
+ mtk_dp_power_disable(mtk_dp);
+ mtk_dp_hwirq_enable(mtk_dp, false);
+
+ pm_runtime_put_sync(dev);
+
+ return 0;
+}
+
+static int mtk_dp_resume(struct device *dev)
+{
+ struct mtk_dp *mtk_dp = dev_get_drvdata(dev);
+
+ pm_runtime_get_sync(dev);
+
+ mtk_dp_init_port(mtk_dp);
+ mtk_dp_power_enable(mtk_dp);
+ mtk_dp_hwirq_enable(mtk_dp, true);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(mtk_dp_pm_ops, mtk_dp_suspend, mtk_dp_resume);
+
+static const struct of_device_id mtk_dp_of_match[] = {
+ { .compatible = "mediatek,mt8195-edp-tx", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mtk_dp_of_match);
+
+struct platform_driver mtk_dp_driver = {
+ .probe = mtk_dp_probe,
+ .remove = mtk_dp_remove,
+ .driver = {
+ .name = "mediatek-drm-dp",
+ .of_match_table = mtk_dp_of_match,
+ .pm = &mtk_dp_pm_ops,
+ },
+};
+
+MODULE_AUTHOR("Jason-JH.Lin <[email protected]>");
+MODULE_AUTHOR("Markus Schneider-Pargmann <[email protected]>");
+MODULE_DESCRIPTION("MediaTek DisplayPort Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
new file mode 100644
index 000000000000..c446eef18169
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
@@ -0,0 +1,568 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Copyright (c) 2021 BayLibre
+ */
+#ifndef _MTK_DP_REG_H_
+#define _MTK_DP_REG_H_
+
+#define MTK_DP_SIP_CONTROL_AARCH32 (BIT(0) | BIT(1) | BIT(5) | BIT(8) | BIT(10) | BIT(25) | BIT(31))
+#define MTK_DP_SIP_ATF_VIDEO_UNMUTE (BIT(5))
+#define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE (BIT(0) | BIT(5))
+
+#define DP_PHY_GLB_BIAS_GEN_00 0
+#define RG_XTP_GLB_BIAS_INTR_CTRL GENMASK(20, 16)
+
+#define DP_PHY_GLB_DPAUX_TX (BIT(3))
+#define RG_CKM_PT0_CKTX_IMPSEL GENMASK(23, 20)
+
+#define DP_PHY_LANE_TX_0 (BIT(2) | BIT(8))
+#define RG_XTP_LN0_TX_IMPSEL_PMOS GENMASK(15, 12)
+#define RG_XTP_LN0_TX_IMPSEL_NMOS GENMASK(19, 16)
+
+#define DP_PHY_LANE_TX_1 (BIT(2) | BIT(9))
+#define RG_XTP_LN1_TX_IMPSEL_PMOS GENMASK(15, 12)
+#define RG_XTP_LN1_TX_IMPSEL_NMOS GENMASK(19, 16)
+
+#define DP_PHY_LANE_TX_2 (BIT(2) | BIT(8) | BIT(9))
+#define RG_XTP_LN2_TX_IMPSEL_PMOS GENMASK(15, 12)
+#define RG_XTP_LN2_TX_IMPSEL_NMOS GENMASK(19, 16)
+
+#define DP_PHY_LANE_TX_3 (BIT(2) | BIT(10))
+#define RG_XTP_LN3_TX_IMPSEL_PMOS GENMASK(15, 12)
+#define RG_XTP_LN3_TX_IMPSEL_NMOS GENMASK(19, 16)
+
+#define TOP_OFFSET (BIT(13))
+#define ENC0_OFFSET GENMASK(13, 12)
+#define ENC1_OFFSET (BIT(9) | BIT(12) | BIT(13))
+#define TRANS_OFFSET (BIT(10) | BIT(12) | BIT(13))
+#define AUX_OFFSET (BIT(9) | BIT(10) | BIT(12) | BIT(13))
+#define SEC_OFFSET (BIT(14))
+
+#define MTK_DP_HPD_DISCONNECT BIT(1)
+#define MTK_DP_HPD_CONNECT BIT(2)
+#define MTK_DP_HPD_INTERRUPT BIT(3)
+
+#define MTK_DP_0034 (BIT(2) | BIT(4) | BIT(5))
+#define DA_XTP_GLB_CKDET_EN_FORCE_VAL BIT(15)
+#define DA_XTP_GLB_CKDET_EN_FORCE_EN BIT(14)
+#define DA_CKM_INTCKTX_EN_FORCE_VAL BIT(13)
+#define DA_CKM_INTCKTX_EN_FORCE_EN BIT(12)
+#define DA_CKM_CKTX0_EN_FORCE_VAL BIT(11)
+#define DA_CKM_CKTX0_EN_FORCE_EN BIT(10)
+#define DA_CKM_XTAL_CK_FORCE_VAL BIT(9)
+#define DA_CKM_XTAL_CK_FORCE_EN BIT(8)
+#define DA_CKM_BIAS_LPF_EN_FORCE_VAL BIT(7)
+#define DA_CKM_BIAS_LPF_EN_FORCE_EN BIT(6)
+#define DA_CKM_BIAS_EN_FORCE_VAL BIT(5)
+#define DA_CKM_BIAS_EN_FORCE_EN BIT(4)
+#define DA_XTP_GLB_AVD10_ON_FORCE_VAL BIT(3)
+#define DA_XTP_GLB_AVD10_ON_FORCE BIT(2)
+#define DA_XTP_GLB_LDO_EN_FORCE_VAL BIT(1)
+#define DA_XTP_GLB_LDO_EN_FORCE_EN BIT(0)
+
+#define MTK_DP_1040 (BIT(6) | BIT(12))
+#define RG_DPAUX_RX_VALID_DEGLITCH_EN BIT(2)
+#define RG_XTP_GLB_CKDET_EN BIT(1)
+#define RG_DPAUX_RX_EN BIT(0)
+
+#define MTK_DP_ENC0_P0_3000 (ENC0_OFFSET + 0x00)
+#define LANE_NUM_DP_ENC0_P0_MASK GENMASK(1, 0)
+#define VIDEO_MUTE_SW_DP_ENC0_P0_MASK (BIT(2))
+#define VIDEO_MUTE_SW_DP_ENC0_P0_SHIFT (BIT(1))
+#define VIDEO_MUTE_SEL_DP_ENC0_P0_MASK (BIT(3))
+#define VIDEO_MUTE_SEL_DP_ENC0_P0_SHIFT GENMASK(1, 0)
+#define ENHANCED_FRAME_EN_DP_ENC0_P0_MASK (BIT(4))
+#define ENHANCED_FRAME_EN_DP_ENC0_P0_SHIFT (BIT(2))
+
+#define MTK_DP_ENC0_P0_3004 (ENC0_OFFSET + 0x04)
+#define VIDEO_M_CODE_SEL_DP_ENC0_P0_MASK (BIT(8))
+#define VIDEO_M_CODE_SEL_DP_ENC0_P0_SHIFT (BIT(3))
+#define DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_MASK (BIT(9))
+#define DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_SHIFT (BIT(0) | BIT(3))
+
+#define MTK_DP_ENC0_P0_3008 (ENC0_OFFSET + 0x08)
+#define VIDEO_M_CODE_SW_0_DP_ENC0_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_ENC0_P0_300C (ENC0_OFFSET + 0x0C)
+#define VIDEO_M_CODE_SW_1_DP_ENC0_P0_MASK GENMASK(7, 0)
+
+#define MTK_DP_ENC0_P0_3010 (ENC0_OFFSET + 0x10)
+#define HTOTAL_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_ENC0_P0_3014 (ENC0_OFFSET + 0x14)
+#define VTOTAL_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_ENC0_P0_3018 (ENC0_OFFSET + 0x18)
+#define HSTART_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_ENC0_P0_301C (ENC0_OFFSET + 0x1C)
+#define VSTART_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_ENC0_P0_3020 (ENC0_OFFSET + 0x20)
+#define HWIDTH_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_ENC0_P0_3024 (ENC0_OFFSET + 0x24)
+#define VHEIGHT_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_ENC0_P0_3028 (ENC0_OFFSET + 0x28)
+#define HSW_SW_DP_ENC0_P0_MASK GENMASK(14, 0)
+#define HSW_SW_DP_ENC0_P0_SHIFT 0
+#define HSP_SW_DP_ENC0_P0_MASK (BIT(15))
+
+#define MTK_DP_ENC0_P0_302C (ENC0_OFFSET + 0x2C)
+#define VSW_SW_DP_ENC0_P0_MASK GENMASK(14, 0)
+#define VSW_SW_DP_ENC0_P0_SHIFT 0
+#define VSP_SW_DP_ENC0_P0_MASK (BIT(15))
+
+#define MTK_DP_ENC0_P0_3030 (ENC0_OFFSET + 0x30)
+#define HTOTAL_SEL_DP_ENC0_P0_SHIFT 0
+#define VTOTAL_SEL_DP_ENC0_P0_SHIFT (BIT(0))
+#define HSTART_SEL_DP_ENC0_P0_SHIFT (BIT(1))
+#define VSTART_SEL_DP_ENC0_P0_SHIFT GENMASK(1, 0)
+#define HWIDTH_SEL_DP_ENC0_P0_SHIFT (BIT(2))
+#define VHEIGHT_SEL_DP_ENC0_P0_SHIFT (BIT(0) | BIT(2))
+#define HSP_SEL_DP_ENC0_P0_SHIFT GENMASK(2, 1)
+#define HSW_SEL_DP_ENC0_P0_SHIFT GENMASK(2, 0)
+#define VSP_SEL_DP_ENC0_P0_SHIFT (BIT(3))
+#define VSW_SEL_DP_ENC0_P0_SHIFT (BIT(0) | BIT(3))
+#define VBID_AUDIO_MUTE_FLAG_SW_DP_ENC0_P0_MASK (BIT(11))
+#define VBID_AUDIO_MUTE_SW_DP_ENC0_P0_SHIFT (BIT(0) | BIT(1) | BIT(3))
+#define VBID_AUDIO_MUTE_FLAG_SEL_DP_ENC0_P0_MASK (BIT(12))
+#define VBID_AUDIO_MUTE_SEL_DP_ENC0_P0_SHIFT GENMASK(3, 2)
+
+#define MTK_DP_ENC0_P0_3034 (ENC0_OFFSET + 0x34)
+
+#define MTK_DP_ENC0_P0_3038 (ENC0_OFFSET + 0x38)
+#define VIDEO_SOURCE_SEL_DP_ENC0_P0_MASK (BIT(11))
+#define VIDEO_SOURCE_SEL_DP_ENC0_P0_SHIFT (BIT(0) | BIT(1) | BIT(3))
+
+#define MTK_DP_ENC0_P0_303C (ENC0_OFFSET + 0x3C)
+#define SRAM_START_READ_THRD_DP_ENC0_P0_MASK GENMASK(5, 0)
+#define SRAM_START_READ_THRD_DP_ENC0_P0_SHIFT 0
+#define VIDEO_COLOR_DEPTH_DP_ENC0_P0_MASK GENMASK(10, 8)
+#define VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT (BIT(3))
+#define VIDEO_COLOR_DEPTH_DP_ENC0_P0_16BIT \
+ (0 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
+#define VIDEO_COLOR_DEPTH_DP_ENC0_P0_12BIT \
+ (1 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
+#define VIDEO_COLOR_DEPTH_DP_ENC0_P0_10BIT \
+ (2 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
+#define VIDEO_COLOR_DEPTH_DP_ENC0_P0_8BIT \
+ (3 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
+#define VIDEO_COLOR_DEPTH_DP_ENC0_P0_6BIT \
+ (4 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
+#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK GENMASK(14, 12)
+#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_SHIFT GENMASK(3, 2)
+#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB \
+ (0 << PIXEL_ENCODE_FORMAT_DP_ENC0_P0_SHIFT)
+#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422 \
+ (1 << PIXEL_ENCODE_FORMAT_DP_ENC0_P0_SHIFT)
+#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR420 \
+ (2 << PIXEL_ENCODE_FORMAT_DP_ENC0_P0_SHIFT)
+#define VIDEO_MN_GEN_EN_DP_ENC0_P0_MASK (BIT(15))
+#define VIDEO_MN_GEN_EN_DP_ENC0_P0_SHIFT GENMASK(3, 0)
+
+#define MTK_DP_ENC0_P0_3040 (ENC0_OFFSET + 0x40)
+#define SDP_DOWN_CNT_INIT_DP_ENC0_P0_MASK GENMASK(11, 0)
+#define SDP_DOWN_CNT_INIT_DP_ENC0_P0_SHIFT 0
+
+#define MTK_DP_ENC0_P0_3044 (ENC0_OFFSET + 0x44)
+#define VIDEO_N_CODE_0_DP_ENC0_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_ENC0_P0_3048 (ENC0_OFFSET + 0x48)
+#define VIDEO_N_CODE_1_DP_ENC0_P0_MASK GENMASK(7, 0)
+
+#define MTK_DP_ENC0_P0_304C (ENC0_OFFSET + 0x4C)
+#define VBID_VIDEO_MUTE_DP_ENC0_P0_MASK (BIT(2))
+#define SDP_VSYNC_RISING_MASK_DP_ENC0_P0_MASK (BIT(8))
+
+#define MTK_DP_ENC0_P0_3050 (ENC0_OFFSET + 0x50)
+#define VIDEO_N_CODE_MN_GEN_0_DP_ENC0_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_ENC0_P0_3054 (ENC0_OFFSET + 0x54)
+#define VIDEO_N_CODE_MN_GEN_1_DP_ENC0_P0_MASK GENMASK(7, 0)
+
+#define MTK_DP_ENC0_P0_3064 (ENC0_OFFSET + 0x64)
+#define HDE_NUM_LAST_DP_ENC0_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_ENC0_P0_3088 (ENC0_OFFSET + 0x88)
+#define AU_EN_DP_ENC0_P0_MASK (BIT(6))
+#define AU_EN_DP_ENC0_P0_SHIFT GENMASK(2, 1)
+#define AUDIO_8CH_EN_DP_ENC0_P0_MASK (BIT(7))
+#define AUDIO_8CH_SEL_DP_ENC0_P0_MASK (BIT(8))
+#define AUDIO_2CH_EN_DP_ENC0_P0_MASK (BIT(14))
+#define AUDIO_2CH_SEL_DP_ENC0_P0_MASK (BIT(15))
+
+#define MTK_DP_ENC0_P0_308C (ENC0_OFFSET + 0x8C)
+#define CH_STATUS_0_DP_ENC0_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_ENC0_P0_3090 (ENC0_OFFSET + 0x90)
+#define CH_STATUS_1_DP_ENC0_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_ENC0_P0_3094 (ENC0_OFFSET + 0x94)
+#define CH_STATUS_2_DP_ENC0_P0_MASK GENMASK(7, 0)
+
+#define MTK_DP_ENC0_P0_30A0 (ENC0_OFFSET + 0xA0)
+
+#define MTK_DP_ENC0_P0_30A4 (ENC0_OFFSET + 0xA4)
+#define AU_TS_CFG_DP_ENC0_P0_MASK GENMASK(7, 0)
+
+#define MTK_DP_ENC0_P0_30A8 (ENC0_OFFSET + 0xA8)
+
+#define MTK_DP_ENC0_P0_30AC (ENC0_OFFSET + 0xAC)
+
+#define MTK_DP_ENC0_P0_30B0 (ENC0_OFFSET + 0xB0)
+
+#define MTK_DP_ENC0_P0_30B4 (ENC0_OFFSET + 0xB4)
+#define ISRC_CFG_DP_ENC0_P0_MASK GENMASK(15, 8)
+#define ISRC_CFG_DP_ENC0_P0_SHIFT (BIT(3))
+
+#define MTK_DP_ENC0_P0_30B8 (ENC0_OFFSET + 0xB8)
+
+#define MTK_DP_ENC0_P0_30BC (ENC0_OFFSET + 0xBC)
+#define ISRC_CONT_DP_ENC0_P0_MASK (BIT(0))
+#define ISRC_CONT_DP_ENC0_P0_SHIFT 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_SHIFT (BIT(3))
+#define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_2 \
+ (1 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
+#define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_4 \
+ (2 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
+#define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_8 \
+ (3 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
+#define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2 \
+ (5 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
+#define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_4 \
+ (6 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
+#define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_8 \
+ (7 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
+
+#define MTK_DP_ENC0_P0_30D8 (ENC0_OFFSET + 0xD8)
+
+#define MTK_DP_ENC0_P0_312C (ENC0_OFFSET + 0x12C)
+#define ASP_HB2_DP_ENC0_P0_MASK GENMASK(7, 0)
+#define ASP_HB3_DP_ENC0_P0_MASK GENMASK(15, 8)
+#define ASP_HB3_DP_ENC0_P0_SHIFT (BIT(3))
+
+#define MTK_DP_ENC0_P0_3130 (ENC0_OFFSET + 0x130)
+
+#define MTK_DP_ENC0_P0_3138 (ENC0_OFFSET + 0x138)
+
+#define MTK_DP_ENC0_P0_3154 (ENC0_OFFSET + 0x154)
+#define PGEN_HTOTAL_DP_ENC0_P0_MASK GENMASK(13, 0)
+
+#define MTK_DP_ENC0_P0_3158 (ENC0_OFFSET + 0x158)
+#define PGEN_HSYNC_RISING_DP_ENC0_P0_MASK GENMASK(13, 0)
+
+#define MTK_DP_ENC0_P0_315C (ENC0_OFFSET + 0x15C)
+#define PGEN_HSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK GENMASK(13, 0)
+
+#define MTK_DP_ENC0_P0_3160 (ENC0_OFFSET + 0x160)
+#define PGEN_HFDE_START_DP_ENC0_P0_MASK GENMASK(13, 0)
+
+#define MTK_DP_ENC0_P0_3164 (ENC0_OFFSET + 0x164)
+#define PGEN_HFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK GENMASK(13, 0)
+
+#define MTK_DP_ENC0_P0_3168 (ENC0_OFFSET + 0x168)
+#define PGEN_VTOTAL_DP_ENC0_P0_MASK GENMASK(12, 0)
+
+#define MTK_DP_ENC0_P0_316C (ENC0_OFFSET + 0x16C)
+#define PGEN_VSYNC_RISING_DP_ENC0_P0_MASK GENMASK(12, 0)
+
+#define MTK_DP_ENC0_P0_3170 (ENC0_OFFSET + 0x170)
+#define PGEN_VSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK GENMASK(12, 0)
+
+#define MTK_DP_ENC0_P0_3174 (ENC0_OFFSET + 0x174)
+#define PGEN_VFDE_START_DP_ENC0_P0_MASK GENMASK(12, 0)
+
+#define MTK_DP_ENC0_P0_3178 (ENC0_OFFSET + 0x178)
+#define PGEN_VFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK GENMASK(12, 0)
+
+#define MTK_DP_ENC0_P0_31B0 (ENC0_OFFSET + 0x1B0)
+#define PGEN_PATTERN_SEL_SHIFT (BIT(2))
+#define PGEN_PATTERN_SEL_MASK GENMASK(6, 4)
+
+#define MTK_DP_ENC0_P0_31C8 (ENC0_OFFSET + 0x1C8)
+#define VSC_EXT_VESA_HB0_DP_ENC0_P0_MASK GENMASK(7, 0)
+#define VSC_EXT_VESA_HB1_DP_ENC0_P0_MASK GENMASK(15, 8)
+#define VSC_EXT_VESA_HB1_DP_ENC0_P0_SHIFT (BIT(3))
+
+#define MTK_DP_ENC0_P0_31CC (ENC0_OFFSET + 0x1CC)
+#define VSC_EXT_VESA_HB2_DP_ENC0_P0_MASK GENMASK(7, 0)
+#define VSC_EXT_VESA_HB2_DP_ENC0_P0_SHIFT 0
+#define VSC_EXT_VESA_HB3_DP_ENC0_P0_MASK GENMASK(15, 8)
+
+#define MTK_DP_ENC0_P0_31D0 (ENC0_OFFSET + 0x1D0)
+#define VSC_EXT_CEA_HB0_DP_ENC0_P0_MASK GENMASK(7, 0)
+#define VSC_EXT_CEA_HB1_DP_ENC0_P0_MASK GENMASK(15, 8)
+#define VSC_EXT_CEA_HB1_DP_ENC0_P0_SHIFT (BIT(3))
+
+#define MTK_DP_ENC0_P0_31D4 (ENC0_OFFSET + 0x1D4)
+#define VSC_EXT_CEA_HB2_DP_ENC0_P0_MASK GENMASK(7, 0)
+#define VSC_EXT_CEA_HB2_DP_ENC0_P0_SHIFT 0
+#define VSC_EXT_CEA_HB3_DP_ENC0_P0_MASK GENMASK(15, 8)
+
+#define MTK_DP_ENC0_P0_31D8 (ENC0_OFFSET + 0x1D8)
+#define VSC_EXT_VESA_NUM_DP_ENC0_P0_MASK GENMASK(5, 0)
+#define VSC_EXT_VESA_NUM_DP_ENC0_P0_SHIFT 0
+#define VSC_EXT_CEA_NUM_DP_ENC0_P0_MASK GENMASK(13, 8)
+#define VSC_EXT_CEA_NUM_DP_ENC0_P0_SHIFT (BIT(3))
+
+#define MTK_DP_ENC0_P0_31DC (ENC0_OFFSET + 0x1DC)
+#define HDR0_CFG_DP_ENC0_P0_MASK GENMASK(7, 0)
+#define HDR0_CFG_DP_ENC0_P0_SHIFT 0
+
+#define MTK_DP_ENC0_P0_31E8 (ENC0_OFFSET + 0x1E8)
+
+#define MTK_DP_ENC0_P0_31EC (ENC0_OFFSET + 0x1EC)
+#define AUDIO_CH_SRC_SEL_DP_ENC0_P0_MASK (BIT(4))
+#define AUDIO_CH_SRC_SEL_DP_ENC0_P0_SHIFT (BIT(2))
+#define ISRC1_HB3_DP_ENC0_P0_MASK GENMASK(15, 8)
+#define ISRC1_HB3_DP_ENC0_P0_SHIFT (BIT(3))
+
+#define MTK_DP_ENC1_P0_3200 (ENC1_OFFSET + 0x00)
+
+#define MTK_DP_ENC1_P0_3280 (ENC1_OFFSET + 0x80)
+#define SDP_PACKET_TYPE_DP_ENC1_P0_MASK GENMASK(4, 0)
+#define SDP_PACKET_W_DP_ENC1_P0 (BIT(5))
+#define SDP_PACKET_W_DP_ENC1_P0_MASK (BIT(5))
+#define SDP_PACKET_W_DP_ENC1_P0_SHIFT (BIT(0) | BIT(2))
+
+#define MTK_DP_ENC1_P0_328C (ENC1_OFFSET + 0x8C)
+
+#define MTK_DP_ENC1_P0_3290 (ENC1_OFFSET + 0x90)
+
+#define MTK_DP_ENC1_P0_32A0 (ENC1_OFFSET + 0xA0)
+
+#define MTK_DP_ENC1_P0_32A4 (ENC1_OFFSET + 0xA4)
+
+#define MTK_DP_ENC1_P0_3300 (ENC1_OFFSET + 0x100)
+#define VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_MASK GENMASK(9, 8)
+#define VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_SHIFT (BIT(3))
+
+#define MTK_DP_ENC1_P0_3304 (ENC1_OFFSET + 0x104)
+#define AU_PRTY_REGEN_DP_ENC1_P0_MASK (BIT(8))
+#define AU_CH_STS_REGEN_DP_ENC1_P0_MASK (BIT(9))
+#define AUDIO_SAMPLE_PRSENT_REGEN_DP_ENC1_P0_MASK (BIT(12))
+
+#define MTK_DP_ENC1_P0_3324 (ENC1_OFFSET + 0x124)
+#define AUDIO_SOURCE_MUX_DP_ENC1_P0_MASK GENMASK(9, 8)
+#define AUDIO_SOURCE_MUX_DP_ENC1_P0_SHIFT (BIT(3))
+#define AUDIO_SOURCE_MUX_DP_ENC1_P0_DPRX \
+ (0 << AUDIO_SOURCE_MUX_DP_ENC1_P0_SHIFT)
+
+#define MTK_DP_ENC1_P0_3364 (ENC1_OFFSET + 0x164)
+#define SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_MASK GENMASK(11, 0)
+#define SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_SHIFT 0
+#define FIFO_READ_START_POINT_DP_ENC1_P0_MASK GENMASK(15, 12)
+#define FIFO_READ_START_POINT_DP_ENC1_P0_SHIFT GENMASK(3, 2)
+
+#define MTK_DP_ENC1_P0_3368 (ENC1_OFFSET + 0x168)
+#define VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0_SHIFT 0
+#define VIDEO_STABLE_CNT_THRD_DP_ENC1_P0_SHIFT (BIT(2))
+#define SDP_DP13_EN_DP_ENC1_P0_SHIFT (BIT(3))
+#define BS2BS_MODE_DP_ENC1_P0_MASK GENMASK(13, 12)
+#define BS2BS_MODE_DP_ENC1_P0_SHIFT GENMASK(3, 2)
+
+#define MTK_DP_ENC1_P0_33F4 (ENC1_OFFSET + 0x1F4)
+
+#define MTK_DP_TRANS_P0_3400 (TRANS_OFFSET + 0)
+#define PATTERN1_EN_DP_TRANS_P0_MASK (BIT(12))
+#define PATTERN1_EN_DP_TRANS_P0_SHIFT GENMASK(3, 2)
+#define PATTERN2_EN_DP_TRANS_P0_MASK (BIT(13))
+#define PATTERN3_EN_DP_TRANS_P0_MASK (BIT(14))
+#define PATTERN4_EN_DP_TRANS_P0_MASK (BIT(15))
+
+#define MTK_DP_TRANS_P0_3404 (TRANS_OFFSET + 0x4)
+#define DP_SCR_EN_DP_TRANS_P0_MASK (BIT(0))
+
+#define MTK_DP_TRANS_P0_340C (TRANS_OFFSET + 0xC)
+#define DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_MASK (BIT(13))
+#define DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_SHIFT (BIT(0) | BIT(2) | BIT(3))
+
+#define MTK_DP_TRANS_P0_3410 (TRANS_OFFSET + 0x10)
+#define HPD_DEB_THD_DP_TRANS_P0_MASK GENMASK(3, 0)
+#define HPD_DEB_THD_DP_TRANS_P0_SHIFT 0
+#define HPD_INT_THD_DP_TRANS_P0_MASK GENMASK(7, 4)
+#define HPD_INT_THD_DP_TRANS_P0_SHIFT (BIT(2))
+#define HPD_INT_THD_DP_TRANS_P0_LOWER_500US (2 << HPD_INT_THD_DP_TRANS_P0_SHIFT)
+#define HPD_INT_THD_DP_TRANS_P0_UPPER_1100US \
+ (2 << (HPD_INT_THD_DP_TRANS_P0_SHIFT + 2))
+#define HPD_DISC_THD_DP_TRANS_P0_MASK GENMASK(11, 8)
+#define HPD_DISC_THD_DP_TRANS_P0_SHIFT (BIT(3))
+#define HPD_CONN_THD_DP_TRANS_P0_MASK GENMASK(15, 12)
+#define HPD_CONN_THD_DP_TRANS_P0_SHIFT GENMASK(3, 2)
+
+#define MTK_DP_TRANS_P0_3414 (TRANS_OFFSET + 0x14)
+#define HPD_DB_DP_TRANS_P0_MASK (BIT(2))
+
+#define MTK_DP_TRANS_P0_3418 (TRANS_OFFSET + 0x18)
+#define IRQ_CLR_DP_TRANS_P0_MASK GENMASK(3, 0)
+#define IRQ_MASK_DP_TRANS_P0_MASK GENMASK(7, 4)
+#define IRQ_MASK_DP_TRANS_P0_SHIFT (BIT(2))
+#define IRQ_MASK_DP_TRANS_P0_DISC_IRQ (BIT(1) << IRQ_MASK_DP_TRANS_P0_SHIFT)
+#define IRQ_MASK_DP_TRANS_P0_CONN_IRQ (BIT(2) << IRQ_MASK_DP_TRANS_P0_SHIFT)
+#define IRQ_MASK_DP_TRANS_P0_INT_IRQ (BIT(3) << IRQ_MASK_DP_TRANS_P0_SHIFT)
+#define IRQ_STATUS_DP_TRANS_P0_MASK GENMASK(15, 12)
+#define IRQ_STATUS_DP_TRANS_P0_SHIFT GENMASK(3, 2)
+
+#define MTK_DP_TRANS_P0_342C (TRANS_OFFSET + 0x2C)
+#define XTAL_FREQ_DP_TRANS_P0_DEFAULT (BIT(0) | BIT(3) | BIT(5) | BIT(6))
+#define XTAL_FREQ_DP_TRANS_P0_MASK GENMASK(7, 0)
+
+#define MTK_DP_TRANS_P0_3430 (TRANS_OFFSET + 0x30)
+#define HPD_INT_THD_ECO_DP_TRANS_P0_MASK GENMASK(1, 0)
+#define HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT BIT(1)
+
+#define MTK_DP_TRANS_P0_34A4 (TRANS_OFFSET + 0xA4)
+#define LANE_NUM_DP_TRANS_P0_MASK GENMASK(3, 2)
+#define LANE_NUM_DP_TRANS_P0_SHIFT (BIT(1))
+
+#define MTK_DP_TRANS_P0_3540 (TRANS_OFFSET + 0x140)
+#define FEC_EN_DP_TRANS_P0_MASK (BIT(0))
+#define FEC_EN_DP_TRANS_P0_SHIFT 0
+#define FEC_CLOCK_EN_MODE_DP_TRANS_P0_MASK (BIT(3))
+#define FEC_CLOCK_EN_MODE_DP_TRANS_P0_SHIFT GENMASK(1, 0)
+
+#define MTK_DP_TRANS_P0_3580 (TRANS_OFFSET + 0x180)
+#define POST_MISC_DATA_LANE0_OV_DP_TRANS_P0_MASK (BIT(8))
+#define POST_MISC_DATA_LANE1_OV_DP_TRANS_P0_MASK (BIT(9))
+#define POST_MISC_DATA_LANE2_OV_DP_TRANS_P0_MASK (BIT(10))
+#define POST_MISC_DATA_LANE3_OV_DP_TRANS_P0_MASK (BIT(11))
+
+#define MTK_DP_TRANS_P0_35C4 (TRANS_OFFSET + 0x1C4)
+#define SW_IRQ_MASK_DP_TRANS_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_TRANS_P0_35C8 (TRANS_OFFSET + 0x1C8)
+#define SW_IRQ_CLR_DP_TRANS_P0_MASK GENMASK(15, 0)
+
+#define SW_IRQ_STATUS_DP_TRANS_P0_MASK GENMASK(15, 0)
+#define SW_IRQ_STATUS_DP_TRANS_P0_SHIFT 0
+
+#define MTK_DP_TRANS_P0_35D0 (TRANS_OFFSET + 0x1D0)
+#define SW_IRQ_FINAL_STATUS_DP_TRANS_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_TRANS_P0_35F0 (TRANS_OFFSET + 0x1F0)
+
+#define MTK_DP_AUX_P0_360C (AUX_OFFSET + 0xC)
+#define AUX_TIMEOUT_THR_AUX_TX_P0_MASK GENMASK(12, 0)
+
+#define MTK_DP_AUX_P0_3614 (AUX_OFFSET + 0x14)
+#define AUX_RX_UI_CNT_THR_AUX_TX_P0_MASK GENMASK(6, 0)
+#define AUX_RX_UI_CNT_THR_AUX_TX_P0_SHIFT 0
+
+#define MTK_DP_AUX_P0_3618 (AUX_OFFSET + 0x18)
+#define AUX_RX_FIFO_FULL_AUX_TX_P0_MASK (BIT(9))
+#define AUX_RX_FIFO_WRITE_POINTER_AUX_TX_P0_MASK GENMASK(3, 0)
+
+#define MTK_DP_AUX_P0_3620 (AUX_OFFSET + 0x20)
+#define AUX_RD_MODE_AUX_TX_P0_MASK (BIT(9))
+#define AUX_RX_FIFO_READ_PULSE_TX_P0_MASK (BIT(8))
+#define AUX_RX_FIFO_R_PULSE_TX_P0_SHIFT (BIT(3))
+#define AUX_RX_FIFO_READ_DATA_AUX_TX_P0_MASK GENMASK(7, 0)
+#define AUX_RX_FIFO_READ_DATA_AUX_TX_P0_SHIFT 0
+
+#define MTK_DP_AUX_P0_3624 (AUX_OFFSET + 0x24)
+#define AUX_RX_REPLY_COMMAND_AUX_TX_P0_MASK GENMASK(3, 0)
+
+#define MTK_DP_AUX_P0_3628 (AUX_OFFSET + 0x28)
+#define AUX_RX_PHY_STATE_AUX_TX_P0_MASK GENMASK(9, 0)
+#define AUX_RX_PHY_STATE_AUX_TX_P0_SHIFT 0
+#define AUX_RX_PHY_STATE_AUX_TX_P0_RX_IDLE \
+ (BIT(0) << AUX_RX_PHY_STATE_AUX_TX_P0_SHIFT)
+
+#define MTK_DP_AUX_P0_362C (AUX_OFFSET + 0x2C)
+#define AUX_NO_LENGTH_AUX_TX_P0_MASK (BIT(0))
+#define AUX_NO_LENGTH_AUX_TX_P0_SHIFT 0
+#define AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK (BIT(1))
+#define AUX_RESERVED_RW_0_AUX_TX_P0_MASK GENMASK(15, 2)
+
+#define MTK_DP_AUX_P0_3630 (AUX_OFFSET + 0x30)
+#define AUX_TX_REQUEST_READY_AUX_TX_P0_MASK (BIT(3))
+#define AUX_TX_REQUEST_READY_AUX_TX_P0_SHIFT GENMASK(1, 0)
+
+#define MTK_DP_AUX_P0_3634 (AUX_OFFSET + 0x34)
+#define AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_MASK GENMASK(15, 8)
+#define AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_SHIFT (BIT(3))
+
+#define MTK_DP_AUX_P0_3640 (AUX_OFFSET + 0x40)
+#define AUX_RX_RECV_COMPLETE_IRQ_TX_P0_MASK (BIT(6))
+#define AUX_RX_AUX_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT GENMASK(2, 1)
+#define AUX_RX_EDID_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT (BIT(0) | BIT(2))
+#define AUX_RX_MCCS_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT (BIT(2))
+#define AUX_RX_CMD_RECV_IRQ_AUX_TX_P0_SHIFT GENMASK(1, 0)
+#define AUX_RX_ADDR_RECV_IRQ_AUX_TX_P0_SHIFT (BIT(1))
+#define AUX_RX_DATA_RECV_IRQ_AUX_TX_P0_SHIFT (BIT(0))
+#define AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_MASK (BIT(0))
+#define AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_SHIFT 0
+
+#define MTK_DP_AUX_P0_3644 (AUX_OFFSET + 0x44)
+#define MCU_REQUEST_COMMAND_AUX_TX_P0_MASK GENMASK(3, 0)
+
+#define MTK_DP_AUX_P0_3648 (AUX_OFFSET + 0x48)
+#define MCU_REQUEST_ADDRESS_LSB_AUX_TX_P0_MASK GENMASK(15, 0)
+
+#define MTK_DP_AUX_P0_364C (AUX_OFFSET + 0x4C)
+#define MCU_REQUEST_ADDRESS_MSB_AUX_TX_P0_MASK GENMASK(3, 0)
+
+#define MTK_DP_AUX_P0_3650 (AUX_OFFSET + 0x50)
+#define MCU_REQ_DATA_NUM_AUX_TX_P0_MASK GENMASK(15, 12)
+#define MCU_REQ_DATA_NUM_AUX_TX_P0_SHIFT GENMASK(3, 2)
+#define PHY_FIFO_RST_AUX_TX_P0_MASK (BIT(9))
+#define MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_MASK (BIT(8))
+#define MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_SHIFT (BIT(3))
+
+#define MTK_DP_AUX_P0_3658 (AUX_OFFSET + 0x58)
+#define AUX_TX_OV_EN_AUX_TX_P0_MASK (BIT(0))
+
+#define MTK_DP_AUX_P0_3690 (AUX_OFFSET + 0x90)
+#define RX_REPLY_COMPLETE_MODE_AUX_TX_P0_MASK (BIT(8))
+#define RX_REPLY_COMPLETE_MODE_AUX_TX_P0_SHIFT (BIT(3))
+
+#define MTK_DP_AUX_P0_3704 (AUX_OFFSET + 0x104)
+#define AUX_TX_FIFO_WRITE_DATA_NEW_MODE_TOGGLE_AUX_TX_P0_MASK (BIT(1))
+#define AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_MASK (BIT(2))
+#define AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_SHIFT (BIT(1))
+
+#define MTK_DP_AUX_P0_3708 (AUX_OFFSET + 0x108)
+
+#define MTK_DP_AUX_P0_37C8 (AUX_OFFSET + 0x1C8)
+#define MTK_ATOP_EN_AUX_TX_P0_MASK (BIT(0))
+#define MTK_ATOP_EN_AUX_TX_P0_SHIFT 0
+
+#define MTK_DP_TOP_PWR_STATE (TOP_OFFSET + 0x0)
+#define DP_PWR_STATE_MASK GENMASK(1, 0)
+#define DP_PWR_STATE_BANDGAP (BIT(0))
+#define DP_PWR_STATE_BANDGAP_TPLL (BIT(1))
+#define DP_PWR_STATE_BANDGAP_TPLL_LANE GENMASK(1, 0)
+
+#define MTK_DP_TOP_SWING_EMP (TOP_OFFSET + 0x4)
+#define DP_TX0_VOLT_SWING_MASK GENMASK(1, 0)
+#define DP_TX0_VOLT_SWING_SHIFT 0
+#define DP_TX0_PRE_EMPH_MASK GENMASK(3, 2)
+#define DP_TX0_PRE_EMPH_SHIFT (BIT(1))
+#define DP_TX1_VOLT_SWING_MASK GENMASK(9, 8)
+#define DP_TX1_VOLT_SWING_SHIFT (BIT(3))
+#define DP_TX1_PRE_EMPH_MASK GENMASK(11, 10)
+#define DP_TX2_VOLT_SWING_MASK GENMASK(17, 16)
+#define DP_TX2_PRE_EMPH_MASK GENMASK(19, 18)
+#define DP_TX3_VOLT_SWING_MASK GENMASK(25, 24)
+#define DP_TX3_PRE_EMPH_MASK GENMASK(27, 26)
+
+#define MTK_DP_TOP_RESET_AND_PROBE (TOP_OFFSET + 0x20)
+#define SW_RST_B_SHIFT 0
+#define SW_RST_B_PHYD (BIT(4) << SW_RST_B_SHIFT)
+
+#define MTK_DP_TOP_IRQ_STATUS (TOP_OFFSET + 0x28)
+#define RGS_IRQ_STATUS_SHIFT 0
+#define RGS_IRQ_STATUS_TRANSMITTER (BIT(1) << RGS_IRQ_STATUS_SHIFT)
+
+#define MTK_DP_TOP_IRQ_MASK (TOP_OFFSET + 0x2C)
+#define IRQ_MASK_AUX_TOP_IRQ BIT(2)
+
+#define MTK_DP_TOP_MEM_PD (TOP_OFFSET + 0x38)
+#define MEM_ISO_EN_SHIFT 0
+#define FUSE_SEL_SHIFT (BIT(1))
+
+#endif /*_MTK_DP_REG_H_*/
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index c8a233f609f0..eab64d4c241b 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -709,6 +709,7 @@ static struct platform_driver * const mtk_drm_drivers[] = {
&mtk_disp_ovl_driver,
&mtk_disp_rdma_driver,
&mtk_dpi_driver,
+ &mtk_dp_driver,
&mtk_drm_platform_driver,
&mtk_dsi_driver,
};
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index 3e7d1e6fbe01..8926416f4419 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -53,6 +53,7 @@ extern struct platform_driver mtk_disp_gamma_driver;
extern struct platform_driver mtk_disp_ovl_driver;
extern struct platform_driver mtk_disp_rdma_driver;
extern struct platform_driver mtk_dpi_driver;
+extern struct platform_driver mtk_dp_driver;
extern struct platform_driver mtk_dsi_driver;
#endif /* MTK_DRM_DRV_H */
--
2.34.1
Add flexibility by moving the csc_enable bit to SoC specific config
Signed-off-by: Guillaume Ranquet <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 40254cd9d168..eb969c5c5c2e 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -133,6 +133,7 @@ struct mtk_dpi_conf {
u32 hvsize_mask;
u32 channel_swap_shift;
u32 yuv422_en_bit;
+ u32 csc_enable_bit;
const struct mtk_dpi_yc_limit *limit;
};
@@ -363,7 +364,8 @@ static void mtk_dpi_config_yuv422_enable(struct mtk_dpi *dpi, bool enable)
static void mtk_dpi_config_csc_enable(struct mtk_dpi *dpi, bool enable)
{
- mtk_dpi_mask(dpi, DPI_CON, enable ? CSC_ENABLE : 0, CSC_ENABLE);
+ mtk_dpi_mask(dpi, DPI_CON, enable ? dpi->conf->csc_enable_bit : 0,
+ dpi->conf->csc_enable_bit);
}
static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable)
@@ -827,6 +829,7 @@ static const struct mtk_dpi_conf mt8173_conf = {
.hvsize_mask = HSIZE_MASK,
.channel_swap_shift = CH_SWAP,
.yuv422_en_bit = YUV422_EN,
+ .csc_enable_bit = CSC_ENABLE,
.limit = &mtk_dpi_limit,
};
@@ -843,6 +846,7 @@ static const struct mtk_dpi_conf mt2701_conf = {
.hvsize_mask = HSIZE_MASK,
.channel_swap_shift = CH_SWAP,
.yuv422_en_bit = YUV422_EN,
+ .csc_enable_bit = CSC_ENABLE,
.limit = &mtk_dpi_limit,
};
@@ -858,6 +862,7 @@ static const struct mtk_dpi_conf mt8183_conf = {
.hvsize_mask = HSIZE_MASK,
.channel_swap_shift = CH_SWAP,
.yuv422_en_bit = YUV422_EN,
+ .csc_enable_bit = CSC_ENABLE,
.limit = &mtk_dpi_limit,
};
@@ -873,6 +878,7 @@ static const struct mtk_dpi_conf mt8192_conf = {
.hvsize_mask = HSIZE_MASK,
.channel_swap_shift = CH_SWAP,
.yuv422_en_bit = YUV422_EN,
+ .csc_enable_bit = CSC_ENABLE,
.limit = &mtk_dpi_limit,
};
--
2.34.1
Il 28/03/22 00:39, Guillaume Ranquet ha scritto:
> Add flexibility by moving the swap shift value to SoC specific config
>
> Signed-off-by: Guillaume Ranquet <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
This patch adds audio support to the DP driver for mt8195 with up to 8
channels.
Signed-off-by: Guillaume Ranquet <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dp.c | 712 +++++++++++++++++++++++++++++-
1 file changed, 693 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 7a197c4a7143..a033e6d62e15 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -123,9 +123,16 @@ enum mtk_dp_color_depth {
MTK_DP_COLOR_DEPTH_UNKNOWN = 5,
};
+struct mtk_dp_audio_cfg {
+ int sample_rate;
+ int word_length_bits;
+ int channels;
+};
+
struct mtk_dp_info {
enum mtk_dp_color_depth depth;
enum mtk_dp_color_format format;
+ struct mtk_dp_audio_cfg audio_caps;
struct mtk_dp_timings timings;
};
@@ -165,13 +172,19 @@ struct mtk_dp {
struct clk *dp_tx_clk;
bool enabled;
+ bool audio_enable;
bool has_fec;
/* Protects the mtk_dp struct */
struct mutex dp_lock;
+ /* Protects the plugged_cb as it's used in both bridge ops and audio */
+ struct mutex update_plugged_status_lock;
+
hdmi_codec_plugged_cb plugged_cb;
struct device *codec_dev;
+ /* Protects the eld data as it's used in both bridge ops and audio */
+ struct mutex eld_lock;
u8 connector_eld[MAX_ELD_BYTES];
struct drm_connector *conn;
bool need_debounce;
@@ -505,15 +518,317 @@ static int mtk_dp_pg_disable(struct mtk_dp *mtk_dp)
return ret;
}
+static int mtk_dp_audio_setup_channels(struct mtk_dp *mtk_dp,
+ struct mtk_dp_audio_cfg *cfg)
+{
+ int ret;
+ u32 channel_enable_bits;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3324,
+ AUDIO_SOURCE_MUX_DP_ENC1_P0_DPRX,
+ AUDIO_SOURCE_MUX_DP_ENC1_P0_MASK, ret, out);
+
+ /* audio channel count change reset */
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_33F4, BIT(9), BIT(9), ret, out);
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3304,
+ AU_PRTY_REGEN_DP_ENC1_P0_MASK,
+ AU_PRTY_REGEN_DP_ENC1_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3304,
+ AU_CH_STS_REGEN_DP_ENC1_P0_MASK,
+ AU_CH_STS_REGEN_DP_ENC1_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3304,
+ AUDIO_SAMPLE_PRSENT_REGEN_DP_ENC1_P0_MASK,
+ AUDIO_SAMPLE_PRSENT_REGEN_DP_ENC1_P0_MASK, ret, out);
+
+ switch (cfg->channels) {
+ case 2:
+ channel_enable_bits = AUDIO_2CH_SEL_DP_ENC0_P0_MASK |
+ AUDIO_2CH_EN_DP_ENC0_P0_MASK;
+ break;
+ case 8:
+ default:
+ channel_enable_bits = AUDIO_8CH_SEL_DP_ENC0_P0_MASK |
+ AUDIO_8CH_EN_DP_ENC0_P0_MASK;
+ break;
+ }
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3088,
+ channel_enable_bits | AU_EN_DP_ENC0_P0_MASK,
+ AUDIO_2CH_SEL_DP_ENC0_P0_MASK | AUDIO_2CH_EN_DP_ENC0_P0_MASK |
+ AUDIO_8CH_SEL_DP_ENC0_P0_MASK |
+ AUDIO_8CH_EN_DP_ENC0_P0_MASK | AU_EN_DP_ENC0_P0_MASK, ret, out);
+
+ /* audio channel count change reset */
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_33F4, 0, BIT(9), ret, out);
+
+ /* enable audio reset */
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_33F4, BIT(0), BIT(0), ret, out);
+
+out:
+ return ret;
+}
+
+static int mtk_dp_audio_channel_status_set(struct mtk_dp *mtk_dp,
+ struct mtk_dp_audio_cfg *cfg)
+{
+ int ret;
+ struct snd_aes_iec958 iec = { 0 };
+
+ switch (cfg->sample_rate) {
+ case 32000:
+ iec.status[3] = IEC958_AES3_CON_FS_32000;
+ break;
+ case 44100:
+ iec.status[3] = IEC958_AES3_CON_FS_44100;
+ break;
+ case 48000:
+ iec.status[3] = IEC958_AES3_CON_FS_48000;
+ break;
+ case 88200:
+ iec.status[3] = IEC958_AES3_CON_FS_88200;
+ break;
+ case 96000:
+ iec.status[3] = IEC958_AES3_CON_FS_96000;
+ break;
+ case 192000:
+ iec.status[3] = IEC958_AES3_CON_FS_192000;
+ break;
+ default:
+ iec.status[3] = IEC958_AES3_CON_FS_NOTID;
+ break;
+ }
+
+ switch (cfg->word_length_bits) {
+ case 16:
+ iec.status[4] = IEC958_AES4_CON_WORDLEN_20_16;
+ break;
+ case 20:
+ iec.status[4] = IEC958_AES4_CON_WORDLEN_20_16 |
+ IEC958_AES4_CON_MAX_WORDLEN_24;
+ break;
+ case 24:
+ iec.status[4] = IEC958_AES4_CON_WORDLEN_24_20 |
+ IEC958_AES4_CON_MAX_WORDLEN_24;
+ break;
+ default:
+ iec.status[4] = IEC958_AES4_CON_WORDLEN_NOTID;
+ }
+
+ /* IEC 60958 consumer channel status bits */
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_308C,
+ 0,
+ CH_STATUS_0_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3090,
+ iec.status[3] << 8,
+ CH_STATUS_1_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3094, iec.status[4],
+ CH_STATUS_2_DP_ENC0_P0_MASK, ret, out);
+
+out:
+ return ret;
+}
+
+static int mtk_dp_audio_sdp_asp_set_channels(struct mtk_dp *mtk_dp,
+ int channels)
+{
+ if (channels != 2 && channels != 8)
+ channels = 8;
+
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_312C,
+ (channels - 1) << ASP_HB3_DP_ENC0_P0_SHIFT,
+ ASP_HB2_DP_ENC0_P0_MASK | ASP_HB3_DP_ENC0_P0_MASK);
+}
+
+static int mtk_dp_audio_set_divider(struct mtk_dp *mtk_dp)
+{
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_30BC,
+ AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
+ AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MASK);
+}
+
static bool mtk_dp_plug_state(struct mtk_dp *mtk_dp)
{
return !!(mtk_dp_read(mtk_dp, MTK_DP_TRANS_P0_3414) &
HPD_DB_DP_TRANS_P0_MASK);
}
-static void mtk_dp_aux_irq_clear(struct mtk_dp *mtk_dp)
+static int mtk_dp_sdp_trigger_packet(struct mtk_dp *mtk_dp,
+ enum mtk_dp_sdp_type type)
+{
+ int ret;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3280, type,
+ SDP_PACKET_TYPE_DP_ENC1_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3280, SDP_PACKET_W_DP_ENC1_P0,
+ SDP_PACKET_W_DP_ENC1_P0, ret, out);
+
+out:
+ return ret;
+}
+
+static void mtk_dp_sdp_set_data(struct mtk_dp *mtk_dp, u8 *data_bytes)
+{
+ mtk_dp_bulk_16bit_write(mtk_dp, MTK_DP_ENC1_P0_3200, data_bytes, 0x10);
+}
+
+static void mtk_dp_sdp_set_header(struct mtk_dp *mtk_dp,
+ enum mtk_dp_sdp_type type,
+ struct dp_sdp_header *header)
+{
+ u32 db_addr;
+
+ switch (type) {
+ case MTK_DP_SDP_DRM:
+ db_addr = MTK_DP_ENC0_P0_3138;
+ break;
+ case MTK_DP_SDP_PPS0:
+ case MTK_DP_SDP_PPS1:
+ case MTK_DP_SDP_PPS2:
+ case MTK_DP_SDP_PPS3:
+ db_addr = MTK_DP_ENC0_P0_3130;
+ break;
+ default:
+ db_addr = MTK_DP_ENC0_P0_30D8 + (type - MTK_DP_SDP_ACM) * 8;
+ }
+
+ mtk_dp_bulk_16bit_write(mtk_dp, db_addr, (u8 *)header, 4);
+}
+
+static const u32 mtk_dp_sdp_type_to_reg[MTK_DP_SDP_MAX_NUM] = {
+ /* MTK_DP_SDP_NONE => */ 0x0,
+ /* MTK_DP_SDP_ACM => */ MTK_DP_ENC0_P0_30B4,
+ /* MTK_DP_SDP_ISRC => */ MTK_DP_ENC0_P0_30B4 + 1,
+ /* MTK_DP_SDP_AVI => */ MTK_DP_ENC0_P0_30A4 + 1,
+ /* MTK_DP_SDP_AUI => */ MTK_DP_ENC0_P0_30A8,
+ /* MTK_DP_SDP_SPD => */ MTK_DP_ENC0_P0_30A8 + 1,
+ /* MTK_DP_SDP_MPEG => */ MTK_DP_ENC0_P0_30AC,
+ /* MTK_DP_SDP_NTSC => */ MTK_DP_ENC0_P0_30AC + 1,
+ /* MTK_DP_SDP_VSP => */ MTK_DP_ENC0_P0_30B0,
+ /* MTK_DP_SDP_VSC => */ MTK_DP_ENC0_P0_30B8,
+ /* MTK_DP_SDP_EXT => */ MTK_DP_ENC0_P0_30B0 + 1,
+ /* MTK_DP_SDP_PPS0 => */ MTK_DP_ENC0_P0_31E8,
+ /* MTK_DP_SDP_PPS1 => */ MTK_DP_ENC0_P0_31E8,
+ /* MTK_DP_SDP_PPS2 => */ MTK_DP_ENC0_P0_31E8,
+ /* MTK_DP_SDP_PPS3 => */ MTK_DP_ENC0_P0_31E8,
+ /* MTK_DP_SDP_DRM => */ MTK_DP_ENC0_P0_31DC,
+};
+
+static int mtk_dp_disable_sdp(struct mtk_dp *mtk_dp, enum mtk_dp_sdp_type type)
+{
+ if (type == MTK_DP_SDP_NONE)
+ return -EINVAL;
+
+ /* Disable periodic send */
+ return mtk_dp_update_bits(mtk_dp, mtk_dp_sdp_type_to_reg[type] & 0xfffc, 0,
+ 0xFF << ((mtk_dp_sdp_type_to_reg[type] & 3) * 8));
+}
+
+static int mtk_dp_setup_sdp(struct mtk_dp *mtk_dp,
+ struct mtk_dp_sdp_packet *packet)
+{
+ int ret;
+
+ mtk_dp_sdp_set_data(mtk_dp, packet->sdp.db);
+ mtk_dp_sdp_set_header(mtk_dp, packet->type, &packet->sdp.sdp_header);
+
+ mtk_dp_disable_sdp(mtk_dp, packet->type);
+
+ switch (packet->type) {
+ case MTK_DP_SDP_NONE:
+ break;
+ case MTK_DP_SDP_ISRC:
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_31EC,
+ 0x1C << ISRC1_HB3_DP_ENC0_P0_SHIFT,
+ ISRC1_HB3_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3280, MTK_DP_SDP_ISRC,
+ SDP_PACKET_TYPE_DP_ENC1_P0_MASK, ret, out);
+
+ if (packet->sdp.sdp_header.HB3 & BIT(2))
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_30BC,
+ BIT(ISRC_CONT_DP_ENC0_P0_SHIFT),
+ ISRC_CONT_DP_ENC0_P0_MASK, ret, out);
+ else
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_30BC, 0,
+ ISRC_CONT_DP_ENC0_P0_MASK, ret, out);
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3280,
+ SDP_PACKET_W_DP_ENC1_P0,
+ SDP_PACKET_W_DP_ENC1_P0, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_30B4,
+ 5 << ISRC_CFG_DP_ENC0_P0_SHIFT,
+ ISRC_CFG_DP_ENC0_P0_MASK, ret, out);
+ break;
+ case MTK_DP_SDP_DRM:
+ mtk_dp_sdp_trigger_packet(mtk_dp, packet->type);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_31DC,
+ 5 << HDR0_CFG_DP_ENC0_P0_SHIFT,
+ HDR0_CFG_DP_ENC0_P0_MASK, ret, out);
+
+ mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_31EC,
+ 0x1C << ISRC1_HB3_DP_ENC0_P0_SHIFT,
+ ISRC1_HB3_DP_ENC0_P0_MASK);
+ mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3280, MTK_DP_SDP_ISRC,
+ SDP_PACKET_TYPE_DP_ENC1_P0_MASK);
+
+ if (packet->sdp.sdp_header.HB3 & BIT(2))
+ mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_30BC,
+ BIT(ISRC_CONT_DP_ENC0_P0_SHIFT),
+ ISRC_CONT_DP_ENC0_P0_MASK);
+ else
+ mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_30BC, 0,
+ ISRC_CONT_DP_ENC0_P0_MASK);
+
+ mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3280,
+ SDP_PACKET_W_DP_ENC1_P0,
+ SDP_PACKET_W_DP_ENC1_P0);
+ mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_30B4,
+ 5 << ISRC_CFG_DP_ENC0_P0_SHIFT,
+ ISRC_CFG_DP_ENC0_P0_MASK);
+ break;
+ case MTK_DP_SDP_ACM:
+ case MTK_DP_SDP_AVI:
+ case MTK_DP_SDP_AUI:
+ case MTK_DP_SDP_SPD:
+ case MTK_DP_SDP_MPEG:
+ case MTK_DP_SDP_NTSC:
+ case MTK_DP_SDP_VSP:
+ case MTK_DP_SDP_VSC:
+ case MTK_DP_SDP_EXT:
+ case MTK_DP_SDP_PPS0:
+ case MTK_DP_SDP_PPS1:
+ case MTK_DP_SDP_PPS2:
+ case MTK_DP_SDP_PPS3:
+ mtk_dp_sdp_trigger_packet(mtk_dp, packet->type);
+ /* Enable periodic sending */
+ MTK_UPD_BITS_OR_OUT(mtk_dp,
+ mtk_dp_sdp_type_to_reg[packet->type] & 0xfffc,
+ 0x05 << ((mtk_dp_sdp_type_to_reg[packet->type] & 3) * 8),
+ 0xff << ((mtk_dp_sdp_type_to_reg[packet->type] & 3) * 8),
+ ret, out);
+ break;
+ default:
+ break;
+ }
+
+out:
+ return ret;
+}
+
+static int mtk_dp_sdp_vsc_ext_disable(struct mtk_dp *mtk_dp)
{
- mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3640,
+ int ret;
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_30A0, 0,
+ BIT(7) | BIT(8) | BIT(12), ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_328C, 0, BIT(7), ret, out);
+
+out:
+ return ret;
+}
+
+static int mtk_dp_aux_irq_clear(struct mtk_dp *mtk_dp)
+{
+ return mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3640,
BIT(AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_SHIFT) |
BIT(AUX_RX_DATA_RECV_IRQ_AUX_TX_P0_SHIFT) |
BIT(AUX_RX_ADDR_RECV_IRQ_AUX_TX_P0_SHIFT) |
@@ -848,28 +1163,33 @@ static int mtk_dp_initialize_settings(struct mtk_dp *mtk_dp)
return ret;
}
-static void mtk_dp_initialize_hpd_detect_settings(struct mtk_dp *mtk_dp)
+static int mtk_dp_initialize_hpd_detect_settings(struct mtk_dp *mtk_dp)
{
- // Debounce threshold
- mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
+ int ret;
+
+ /* Debounce threshold */
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_3410,
8 << HPD_DEB_THD_DP_TRANS_P0_SHIFT,
- HPD_DEB_THD_DP_TRANS_P0_MASK);
- mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
+ HPD_DEB_THD_DP_TRANS_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_3410,
(HPD_INT_THD_DP_TRANS_P0_LOWER_500US |
HPD_INT_THD_DP_TRANS_P0_UPPER_1100US)
<< HPD_INT_THD_DP_TRANS_P0_SHIFT,
- HPD_INT_THD_DP_TRANS_P0_MASK);
+ HPD_INT_THD_DP_TRANS_P0_MASK, ret, out);
- // Connect threshold 1.5ms + 5 x 0.1ms = 2ms
- // Disconnect threshold 1.5ms + 5 x 0.1ms = 2ms
- mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
+ /* Connect threshold 1.5ms + 5 x 0.1ms = 2ms */
+ /* Disconnect threshold 1.5ms + 5 x 0.1ms = 2ms */
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_3410,
(5 << HPD_DISC_THD_DP_TRANS_P0_SHIFT) |
(5 << HPD_CONN_THD_DP_TRANS_P0_SHIFT),
HPD_DISC_THD_DP_TRANS_P0_MASK |
- HPD_CONN_THD_DP_TRANS_P0_MASK);
- mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3430,
+ HPD_CONN_THD_DP_TRANS_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_3430,
HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT,
- HPD_INT_THD_ECO_DP_TRANS_P0_MASK);
+ HPD_INT_THD_ECO_DP_TRANS_P0_MASK, ret, out);
+
+out:
+ return ret;
}
static int mtk_dp_initialize_aux_settings(struct mtk_dp *mtk_dp)
@@ -1166,20 +1486,60 @@ static int mtk_dp_training_set_scramble(struct mtk_dp *mtk_dp, bool enable)
DP_SCR_EN_DP_TRANS_P0_MASK);
}
-static void mtk_dp_video_mute(struct mtk_dp *mtk_dp, bool enable)
+static int mtk_dp_video_mute(struct mtk_dp *mtk_dp, bool enable)
{
+ int ret;
u32 val = BIT(VIDEO_MUTE_SEL_DP_ENC0_P0_SHIFT);
if (enable)
val |= BIT(VIDEO_MUTE_SW_DP_ENC0_P0_SHIFT);
- mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000, val,
- VIDEO_MUTE_SEL_DP_ENC0_P0_MASK |
- VIDEO_MUTE_SW_DP_ENC0_P0_MASK);
+ ret = mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000, val,
+ VIDEO_MUTE_SEL_DP_ENC0_P0_MASK | VIDEO_MUTE_SW_DP_ENC0_P0_MASK);
+
+ if (ret)
+ return ret;
if (mtk_dp_is_edp(mtk_dp))
mtk_dp_sip_atf_call(MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE, enable);
else
mtk_dp_sip_atf_call(MTK_DP_SIP_ATF_VIDEO_UNMUTE, enable);
+
+ return 0;
+}
+
+static int mtk_dp_audio_mute(struct mtk_dp *mtk_dp, bool mute)
+{
+ int ret;
+
+ if (mute) {
+ MTK_UPD_BITS_OR_OUT(mtk_dp,
+ MTK_DP_ENC0_P0_3030,
+ BIT(VBID_AUDIO_MUTE_SW_DP_ENC0_P0_SHIFT) |
+ BIT(VBID_AUDIO_MUTE_SEL_DP_ENC0_P0_SHIFT),
+ VBID_AUDIO_MUTE_FLAG_SW_DP_ENC0_P0_MASK |
+ VBID_AUDIO_MUTE_FLAG_SEL_DP_ENC0_P0_MASK, ret, out);
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3088, 0,
+ AU_EN_DP_ENC0_P0_MASK, ret, out);
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_30A4, 0,
+ AU_TS_CFG_DP_ENC0_P0_MASK, ret, out);
+
+ } else {
+ MTK_UPD_BITS_OR_OUT(mtk_dp,
+ MTK_DP_ENC0_P0_3030, 0,
+ VBID_AUDIO_MUTE_FLAG_SW_DP_ENC0_P0_MASK |
+ VBID_AUDIO_MUTE_FLAG_SEL_DP_ENC0_P0_MASK, ret, out);
+
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3088,
+ BIT(AU_EN_DP_ENC0_P0_SHIFT),
+ AU_EN_DP_ENC0_P0_MASK, ret, out);
+ /* Send one every two frames */
+ MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_30A4, 0x0F,
+ AU_TS_CFG_DP_ENC0_P0_MASK, ret, out);
+ }
+
+out:
+ return ret;
}
static int mtk_dp_power_enable(struct mtk_dp *mtk_dp)
@@ -1247,6 +1607,75 @@ static void mtk_dp_initialize_priv_data(struct mtk_dp *mtk_dp)
mtk_dp->info.timings.frame_rate = 60;
mtk_dp->has_fec = false;
+ mtk_dp->audio_enable = false;
+}
+
+static int mtk_dp_sdp_set_down_cnt_init(struct mtk_dp *mtk_dp,
+ u32 sram_read_start)
+{
+ u32 sdp_down_cnt_init = 0;
+ u32 dc_offset;
+
+ if (mtk_dp->info.timings.pix_rate_khz > 0)
+ sdp_down_cnt_init = sram_read_start *
+ mtk_dp->train_info.link_rate * 2700 * 8 /
+ (mtk_dp->info.timings.pix_rate_khz * 4);
+
+ switch (mtk_dp->train_info.lane_count) {
+ case 1:
+ sdp_down_cnt_init = sdp_down_cnt_init > 0x1A ?
+ sdp_down_cnt_init :
+ 0x1A; /* 26 */
+ break;
+ case 2:
+ /* case for LowResolution && High Audio Sample Rate */
+ dc_offset = mtk_dp->info.timings.vtotal <= 525 ? 0x04 : 0x00;
+ sdp_down_cnt_init = sdp_down_cnt_init > 0x10 ?
+ sdp_down_cnt_init :
+ 0x10 + dc_offset; /* 20 or 16 */
+ break;
+ case 4:
+ default:
+ sdp_down_cnt_init =
+ sdp_down_cnt_init > 0x06 ? sdp_down_cnt_init : 0x06; /*6 */
+ break;
+ }
+
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3040,
+ sdp_down_cnt_init
+ << SDP_DOWN_CNT_INIT_DP_ENC0_P0_SHIFT,
+ SDP_DOWN_CNT_INIT_DP_ENC0_P0_MASK);
+}
+
+static int mtk_dp_sdp_set_down_cnt_init_in_hblank(struct mtk_dp *mtk_dp)
+{
+ int pix_clk_mhz;
+ u32 dc_offset;
+ u32 spd_down_cnt_init = 0;
+
+ pix_clk_mhz = mtk_dp->info.format == MTK_DP_COLOR_FORMAT_YUV_420 ?
+ mtk_dp->info.timings.pix_rate_khz / 2000 :
+ mtk_dp->info.timings.pix_rate_khz / 1000;
+
+ switch (mtk_dp->train_info.lane_count) {
+ case 1:
+ spd_down_cnt_init = 0x20;
+ break;
+ case 2:
+ dc_offset = (mtk_dp->info.timings.vtotal <= 525) ? 0x14 : 0x00;
+ spd_down_cnt_init = 0x18 + dc_offset;
+ break;
+ case 4:
+ default:
+ dc_offset = (mtk_dp->info.timings.vtotal <= 525) ? 0x08 : 0x00;
+ if (pix_clk_mhz > mtk_dp->train_info.link_rate * 27)
+ spd_down_cnt_init = 0x8;
+ else
+ spd_down_cnt_init = 0x10 + dc_offset;
+ break;
+ }
+ return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3364, spd_down_cnt_init,
+ SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_MASK);
}
static void mtk_dp_setup_tu(struct mtk_dp *mtk_dp)
@@ -1262,6 +1691,8 @@ static void mtk_dp_setup_tu(struct mtk_dp *mtk_dp)
}
mtk_dp_setup_encoder(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);
}
static void mtk_dp_calculate_pixrate(struct mtk_dp *mtk_dp)
@@ -1345,6 +1776,17 @@ static int mtk_dp_hpd_sink_event(struct mtk_dp *mtk_dp)
return 0;
}
+static void mtk_dp_sdp_stop_sending(struct mtk_dp *mtk_dp)
+{
+ u8 packet_type;
+
+ for (packet_type = MTK_DP_SDP_ACM; packet_type < MTK_DP_SDP_MAX_NUM;
+ packet_type++)
+ mtk_dp_disable_sdp(mtk_dp, packet_type);
+
+ mtk_dp_sdp_vsc_ext_disable(mtk_dp);
+}
+
static void mtk_dp_train_update_swing_pre(struct mtk_dp *mtk_dp, int lanes,
u8 dpcd_adjust_req[2])
{
@@ -1599,6 +2041,52 @@ static bool mtk_dp_parse_capabilities(struct mtk_dp *mtk_dp)
return true;
}
+static int mtk_dp_edid_parse_audio_capabilities(struct mtk_dp *mtk_dp,
+ struct mtk_dp_audio_cfg *cfg)
+{
+ struct cea_sad *sads;
+ int sad_count;
+ int i;
+ int ret = 0;
+
+ mutex_lock(&mtk_dp->edid_lock);
+ if (!mtk_dp->edid) {
+ mutex_unlock(&mtk_dp->edid_lock);
+ dev_err(mtk_dp->dev, "EDID not found!\n");
+ return -EINVAL;
+ }
+
+ sad_count = drm_edid_to_sad(mtk_dp->edid, &sads);
+ mutex_unlock(&mtk_dp->edid_lock);
+ if (sad_count <= 0) {
+ drm_info(mtk_dp->drm_dev, "The SADs is NULL\n");
+ return 0;
+ }
+
+ for (i = 0; i < sad_count; i++) {
+ int sample_rate;
+ int word_length;
+ /* Only PCM supported at the moment */
+ if (sads[i].format != HDMI_AUDIO_CODING_TYPE_PCM)
+ continue;
+
+ sample_rate = drm_cea_sad_get_sample_rate(&sads[i]);
+ word_length =
+ drm_cea_sad_get_uncompressed_word_length(&sads[i]);
+ if (sample_rate <= 0 || word_length <= 0)
+ continue;
+
+ cfg->channels = sads[i].channels;
+ cfg->word_length_bits = word_length;
+ cfg->sample_rate = sample_rate;
+ ret = 1;
+ break;
+ }
+ kfree(sads);
+
+ return ret;
+}
+
static void mtk_dp_train_change_mode(struct mtk_dp *mtk_dp)
{
phy_reset(mtk_dp->phy);
@@ -1723,7 +2211,15 @@ static int mtk_dp_train_handler(struct mtk_dp *mtk_dp)
}
break;
- case MTK_DP_TRAIN_STATE_CHECKEDID:
+ case MTK_DP_TRAIN_STATE_CHECKEDID: {
+ int caps_found = mtk_dp_edid_parse_audio_capabilities(mtk_dp,
+ &mtk_dp->info.audio_caps);
+ mtk_dp->audio_enable = caps_found > 0;
+ if (!mtk_dp->audio_enable)
+ memset(&mtk_dp->info.audio_caps, 0,
+ sizeof(mtk_dp->info.audio_caps));
+ }
+
mtk_dp->train_state = MTK_DP_TRAIN_STATE_TRAINING_PRE;
break;
@@ -1735,6 +2231,7 @@ static int mtk_dp_train_handler(struct mtk_dp *mtk_dp)
ret = mtk_dp_train_start(mtk_dp);
if (!ret) {
mtk_dp_video_mute(mtk_dp, true);
+ mtk_dp_audio_mute(mtk_dp, true);
mtk_dp->train_state = MTK_DP_TRAIN_STATE_NORMAL;
mtk_dp_fec_enable(mtk_dp, mtk_dp->has_fec);
} else if (ret != -EAGAIN) {
@@ -1769,6 +2266,48 @@ static void mtk_dp_video_enable(struct mtk_dp *mtk_dp, bool enable)
}
}
+static void mtk_dp_audio_sdp_setup(struct mtk_dp *mtk_dp,
+ struct mtk_dp_audio_cfg *cfg)
+{
+ struct mtk_dp_sdp_packet packet;
+ struct hdmi_audio_infoframe frame;
+
+ hdmi_audio_infoframe_init(&frame);
+ frame.coding_type = HDMI_AUDIO_CODING_TYPE_PCM;
+ frame.channels = cfg->channels;
+ frame.sample_frequency = cfg->sample_rate;
+
+ switch (cfg->word_length_bits) {
+ case 16:
+ frame.sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
+ break;
+ case 20:
+ frame.sample_size = HDMI_AUDIO_SAMPLE_SIZE_20;
+ break;
+ case 24:
+ default:
+ frame.sample_size = HDMI_AUDIO_SAMPLE_SIZE_24;
+ break;
+ }
+
+ packet.type = MTK_DP_SDP_AUI;
+ hdmi_audio_infoframe_pack_for_dp(&frame, &packet.sdp,
+ MTK_DP_DP_VERSION_11);
+
+ mtk_dp_audio_sdp_asp_set_channels(mtk_dp, cfg->channels);
+ mtk_dp_setup_sdp(mtk_dp, &packet);
+}
+
+static void mtk_dp_audio_setup(struct mtk_dp *mtk_dp,
+ struct mtk_dp_audio_cfg *cfg)
+{
+ mtk_dp_audio_sdp_setup(mtk_dp, cfg);
+ mtk_dp_audio_channel_status_set(mtk_dp, cfg);
+
+ mtk_dp_audio_setup_channels(mtk_dp, cfg);
+ mtk_dp_audio_set_divider(mtk_dp);
+}
+
static void mtk_dp_video_config(struct mtk_dp *mtk_dp)
{
mtk_dp_mn_overwrite_disable(mtk_dp);
@@ -1784,6 +2323,7 @@ static void mtk_dp_state_handler(struct mtk_dp *mtk_dp)
switch (mtk_dp->state) {
case MTK_DP_STATE_INITIAL:
mtk_dp_video_mute(mtk_dp, true);
+ mtk_dp_audio_mute(mtk_dp, true);
mtk_dp->state = MTK_DP_STATE_IDLE;
break;
@@ -1796,12 +2336,19 @@ static void mtk_dp_state_handler(struct mtk_dp *mtk_dp)
mtk_dp_video_config(mtk_dp);
mtk_dp_video_enable(mtk_dp, true);
+ if (mtk_dp->audio_enable) {
+ mtk_dp_audio_setup(mtk_dp, &mtk_dp->info.audio_caps);
+ mtk_dp_audio_mute(mtk_dp, false);
+ }
+
mtk_dp->state = MTK_DP_STATE_NORMAL;
break;
case MTK_DP_STATE_NORMAL:
if (mtk_dp->train_state != MTK_DP_TRAIN_STATE_NORMAL) {
mtk_dp_video_mute(mtk_dp, true);
+ mtk_dp_audio_mute(mtk_dp, true);
+ mtk_dp_sdp_stop_sending(mtk_dp);
mtk_dp->state = MTK_DP_STATE_IDLE;
}
break;
@@ -1855,11 +2402,13 @@ static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
if (!mtk_dp->train_info.cable_plugged_in ||
!mtk_dp_plug_state(mtk_dp)) {
mtk_dp_video_mute(mtk_dp, true);
+ mtk_dp_audio_mute(mtk_dp, true);
mtk_dp_initialize_priv_data(mtk_dp);
mtk_dp_set_idle_pattern(mtk_dp, true);
if (mtk_dp->has_fec)
mtk_dp_fec_enable(mtk_dp, false);
+ mtk_dp_sdp_stop_sending(mtk_dp);
mtk_dp_edid_free(mtk_dp);
mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
@@ -1970,6 +2519,18 @@ static int mtk_dp_dt_parse(struct mtk_dp *mtk_dp,
return 0;
}
+static void mtk_dp_update_plugged_status(struct mtk_dp *mtk_dp)
+{
+ bool connected, has_audio;
+
+ mutex_lock(&mtk_dp->update_plugged_status_lock);
+ connected = mtk_dp_plug_state(mtk_dp);
+ has_audio = drm_detect_monitor_audio(mtk_dp->edid);
+ if (mtk_dp->plugged_cb && mtk_dp->codec_dev)
+ mtk_dp->plugged_cb(mtk_dp->codec_dev, connected & has_audio);
+ mutex_unlock(&mtk_dp->update_plugged_status_lock);
+}
+
static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge)
{
return connector_status_connected;
@@ -2184,6 +2745,7 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
mtk_dp_video_mute(mtk_dp, true);
+ mtk_dp_audio_mute(mtk_dp, true);
mtk_dp->state = MTK_DP_STATE_IDLE;
mtk_dp->train_state = MTK_DP_TRAIN_STATE_STARTUP;
@@ -2219,7 +2781,9 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
return;
}
+ mutex_lock(&mtk_dp->eld_lock);
memcpy(mtk_dp->connector_eld, mtk_dp->conn->eld, MAX_ELD_BYTES);
+ mutex_unlock(&mtk_dp->eld_lock);
conn_state =
drm_atomic_get_new_connector_state(old_state->base.state, mtk_dp->conn);
@@ -2386,6 +2950,104 @@ static void mtk_dp_debounce_timer(struct timer_list *t)
mtk_dp->need_debounce = true;
}
+/*
+ * HDMI audio codec callbacks
+ */
+static int mtk_dp_audio_hw_params(struct device *dev, void *data,
+ struct hdmi_codec_daifmt *daifmt,
+ struct hdmi_codec_params *params)
+{
+ struct mtk_dp *mtk_dp = dev_get_drvdata(dev);
+ struct mtk_dp_audio_cfg cfg;
+
+ if (!mtk_dp->enabled) {
+ pr_err("%s, DP is not ready!\n", __func__);
+ return -ENODEV;
+ }
+
+ cfg.channels = params->cea.channels;
+ cfg.sample_rate = params->sample_rate;
+ cfg.word_length_bits = 24;
+
+ mtk_dp_audio_setup(mtk_dp, &cfg);
+
+ return 0;
+}
+
+static int mtk_dp_audio_startup(struct device *dev, void *data)
+{
+ struct mtk_dp *mtk_dp = dev_get_drvdata(dev);
+
+ mtk_dp_audio_mute(mtk_dp, false);
+
+ return 0;
+}
+
+static void mtk_dp_audio_shutdown(struct device *dev, void *data)
+{
+ struct mtk_dp *mtk_dp = dev_get_drvdata(dev);
+
+ mtk_dp_audio_mute(mtk_dp, true);
+}
+
+static int mtk_dp_audio_get_eld(struct device *dev, void *data, uint8_t *buf,
+ size_t len)
+{
+ struct mtk_dp *mtk_dp = dev_get_drvdata(dev);
+
+ if (mtk_dp->enabled)
+ memcpy(buf, mtk_dp->connector_eld, len);
+ else
+ memset(buf, 0, len);
+
+ return 0;
+}
+
+static int mtk_dp_audio_hook_plugged_cb(struct device *dev, void *data,
+ hdmi_codec_plugged_cb fn,
+ struct device *codec_dev)
+{
+ struct mtk_dp *mtk_dp = data;
+
+ mutex_lock(&mtk_dp->update_plugged_status_lock);
+ mtk_dp->plugged_cb = fn;
+ mtk_dp->codec_dev = codec_dev;
+ mutex_unlock(&mtk_dp->update_plugged_status_lock);
+
+ mtk_dp_update_plugged_status(mtk_dp);
+
+ return 0;
+}
+
+static const struct hdmi_codec_ops mtk_dp_audio_codec_ops = {
+ .hw_params = mtk_dp_audio_hw_params,
+ .audio_startup = mtk_dp_audio_startup,
+ .audio_shutdown = mtk_dp_audio_shutdown,
+ .get_eld = mtk_dp_audio_get_eld,
+ .hook_plugged_cb = mtk_dp_audio_hook_plugged_cb,
+ .no_capture_mute = 1,
+};
+
+static int mtk_dp_register_audio_driver(struct device *dev)
+{
+ struct mtk_dp *mtk_dp = dev_get_drvdata(dev);
+ struct hdmi_codec_pdata codec_data = {
+ .ops = &mtk_dp_audio_codec_ops,
+ .max_i2s_channels = 8,
+ .i2s = 1,
+ .data = mtk_dp,
+ };
+ struct platform_device *pdev;
+
+ pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
+ PLATFORM_DEVID_AUTO, &codec_data,
+ sizeof(codec_data));
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ return 0;
+}
+
static int mtk_dp_probe(struct platform_device *pdev)
{
struct mtk_dp *mtk_dp;
@@ -2429,9 +3091,20 @@ static int mtk_dp_probe(struct platform_device *pdev)
mutex_init(&mtk_dp->dp_lock);
mutex_init(&mtk_dp->edid_lock);
+ mutex_init(&mtk_dp->eld_lock);
platform_set_drvdata(pdev, mtk_dp);
+ if (!mtk_dp_is_edp(mtk_dp)) {
+ mutex_init(&mtk_dp->update_plugged_status_lock);
+ ret = mtk_dp_register_audio_driver(dev);
+ if (ret) {
+ dev_err(dev, "Failed to register audio driver: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
mtk_dp_get_calibration_data(mtk_dp);
mtk_dp->phy = devm_phy_get(dev, "dp");
@@ -2465,6 +3138,7 @@ static int mtk_dp_remove(struct platform_device *pdev)
struct mtk_dp *mtk_dp = platform_get_drvdata(pdev);
mtk_dp_video_mute(mtk_dp, true);
+ mtk_dp_audio_mute(mtk_dp, true);
del_timer_sync(&mtk_dp->debounce_timer);
pm_runtime_disable(&pdev->dev);
--
2.34.1
Add flexibility by moving the hvsize mask to SoC specific config
Signed-off-by: Guillaume Ranquet <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index bf098f36a466..6eeda222a973 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -129,6 +129,8 @@ struct mtk_dpi_conf {
bool swap_input_support;
/* Mask used for HWIDTH, HPORCH, VSYNC_WIDTH and VSYNC_PORCH (no shift) */
u32 dimension_mask;
+ /* HSIZE and VSIZE mask (no shift) */
+ u32 hvsize_mask;
const struct mtk_dpi_yc_limit *limit;
};
@@ -243,8 +245,10 @@ static void mtk_dpi_config_interface(struct mtk_dpi *dpi, bool inter)
static void mtk_dpi_config_fb_size(struct mtk_dpi *dpi, u32 width, u32 height)
{
- mtk_dpi_mask(dpi, DPI_SIZE, width << HSIZE, HSIZE_MASK);
- mtk_dpi_mask(dpi, DPI_SIZE, height << VSIZE, VSIZE_MASK);
+ mtk_dpi_mask(dpi, DPI_SIZE, width << HSIZE,
+ dpi->conf->hvsize_mask << HSIZE);
+ mtk_dpi_mask(dpi, DPI_SIZE, height << VSIZE,
+ dpi->conf->hvsize_mask << VSIZE);
}
static void mtk_dpi_config_channel_limit(struct mtk_dpi *dpi)
@@ -816,6 +820,7 @@ static const struct mtk_dpi_conf mt8173_conf = {
.is_ck_de_pol = true,
.swap_input_support = true,
.dimension_mask = HPW_MASK,
+ .hvsize_mask = HSIZE_MASK,
.limit = &mtk_dpi_limit,
};
@@ -829,6 +834,7 @@ static const struct mtk_dpi_conf mt2701_conf = {
.is_ck_de_pol = true,
.swap_input_support = true,
.dimension_mask = HPW_MASK,
+ .hvsize_mask = HSIZE_MASK,
.limit = &mtk_dpi_limit,
};
@@ -841,6 +847,7 @@ static const struct mtk_dpi_conf mt8183_conf = {
.is_ck_de_pol = true,
.swap_input_support = true,
.dimension_mask = HPW_MASK,
+ .hvsize_mask = HSIZE_MASK,
.limit = &mtk_dpi_limit,
};
@@ -853,6 +860,7 @@ static const struct mtk_dpi_conf mt8192_conf = {
.is_ck_de_pol = true,
.swap_input_support = true,
.dimension_mask = HPW_MASK,
+ .hvsize_mask = HSIZE_MASK,
.limit = &mtk_dpi_limit,
};
--
2.34.1
From: Markus Schneider-Pargmann <[email protected]>
Similar to HDMI, DP uses audio infoframes as well which are structured
very similar to the HDMI ones.
This patch adds a helper function to pack the HDMI audio infoframe for
DP, called hdmi_audio_infoframe_pack_for_dp().
hdmi_audio_infoframe_pack_only() is split into two parts. One of them
packs the payload only and can be used for HDMI and DP.
Signed-off-by: Markus Schneider-Pargmann <[email protected]>
Signed-off-by: Guillaume Ranquet <[email protected]>
---
drivers/video/hdmi.c | 82 ++++++++++++++++++++++++++--------
include/drm/dp/drm_dp_helper.h | 2 +
include/linux/hdmi.h | 7 ++-
3 files changed, 71 insertions(+), 20 deletions(-)
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 947be761dfa4..5f50237554ed 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -21,6 +21,7 @@
* DEALINGS IN THE SOFTWARE.
*/
+#include <drm/dp/drm_dp_helper.h>
#include <linux/bitops.h>
#include <linux/bug.h>
#include <linux/errno.h>
@@ -381,12 +382,34 @@ static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *fr
*
* Returns 0 on success or a negative error code on failure.
*/
-int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
+int hdmi_audio_infoframe_check(const struct hdmi_audio_infoframe *frame)
{
return hdmi_audio_infoframe_check_only(frame);
}
EXPORT_SYMBOL(hdmi_audio_infoframe_check);
+static void
+hdmi_audio_infoframe_pack_payload(const struct hdmi_audio_infoframe *frame,
+ u8 *buffer)
+{
+ u8 channels;
+
+ if (frame->channels >= 2)
+ channels = frame->channels - 1;
+ else
+ channels = 0;
+
+ buffer[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7);
+ buffer[1] = ((frame->sample_frequency & 0x7) << 2) |
+ (frame->sample_size & 0x3);
+ buffer[2] = frame->coding_type_ext & 0x1f;
+ buffer[3] = frame->channel_allocation;
+ buffer[4] = (frame->level_shift_value & 0xf) << 3;
+
+ if (frame->downmix_inhibit)
+ buffer[4] |= BIT(7);
+}
+
/**
* hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
* @frame: HDMI audio infoframe
@@ -404,7 +427,6 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_check);
ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
void *buffer, size_t size)
{
- unsigned char channels;
u8 *ptr = buffer;
size_t length;
int ret;
@@ -420,28 +442,13 @@ ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
memset(buffer, 0, size);
- if (frame->channels >= 2)
- channels = frame->channels - 1;
- else
- channels = 0;
-
ptr[0] = frame->type;
ptr[1] = frame->version;
ptr[2] = frame->length;
ptr[3] = 0; /* checksum */
- /* start infoframe payload */
- ptr += HDMI_INFOFRAME_HEADER_SIZE;
-
- ptr[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7);
- ptr[1] = ((frame->sample_frequency & 0x7) << 2) |
- (frame->sample_size & 0x3);
- ptr[2] = frame->coding_type_ext & 0x1f;
- ptr[3] = frame->channel_allocation;
- ptr[4] = (frame->level_shift_value & 0xf) << 3;
-
- if (frame->downmix_inhibit)
- ptr[4] |= BIT(7);
+ hdmi_audio_infoframe_pack_payload(frame,
+ ptr + HDMI_INFOFRAME_HEADER_SIZE);
hdmi_infoframe_set_checksum(buffer, length);
@@ -479,6 +486,43 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
}
EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
+/**
+ * hdmi_audio_infoframe_pack_for_dp - Pack a HDMI Audio infoframe for DisplayPort
+ *
+ * @frame: HDMI Audio infoframe
+ * @sdp: secondary data packet for display port. This is filled with the
+ * appropriate: data
+ * @dp_version: Display Port version to be encoded in the header
+ *
+ * Packs a HDMI Audio Infoframe to be sent over Display Port. This function
+ * fills the secondary data packet to be used for Display Port.
+ *
+ * Return: Number of total written bytes or a negative errno on failure.
+ */
+ssize_t
+hdmi_audio_infoframe_pack_for_dp(const struct hdmi_audio_infoframe *frame,
+ struct dp_sdp *sdp, u8 dp_version)
+{
+ int ret;
+
+ ret = hdmi_audio_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ memset(sdp->db, 0, sizeof(sdp->db));
+
+ /* Secondary-data packet header */
+ sdp->sdp_header.HB0 = 0;
+ sdp->sdp_header.HB1 = frame->type;
+ sdp->sdp_header.HB2 = DP_SDP_AUDIO_INFOFRAME_HB2;
+ sdp->sdp_header.HB3 = (dp_version & 0x3f) << 2;
+
+ hdmi_audio_infoframe_pack_payload(frame, sdp->db);
+
+ return frame->length + 4;
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_pack_for_dp);
+
/**
* hdmi_vendor_infoframe_init() - initialize an HDMI vendor infoframe
* @frame: HDMI vendor infoframe
diff --git a/include/drm/dp/drm_dp_helper.h b/include/drm/dp/drm_dp_helper.h
index 51e02cf75277..d4adb479263e 100644
--- a/include/drm/dp/drm_dp_helper.h
+++ b/include/drm/dp/drm_dp_helper.h
@@ -1576,6 +1576,8 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw);
#define DP_SDP_VSC_EXT_CEA 0x21 /* DP 1.4 */
/* 0x80+ CEA-861 infoframe types */
+#define DP_SDP_AUDIO_INFOFRAME_HB2 0x1b
+
/**
* struct dp_sdp_header - DP secondary data packet header
* @HB0: Secondary Data Packet ID
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index c8ec982ff498..2f4dcc8d060e 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -336,7 +336,12 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
void *buffer, size_t size);
ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
void *buffer, size_t size);
-int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
+int hdmi_audio_infoframe_check(const struct hdmi_audio_infoframe *frame);
+
+struct dp_sdp;
+ssize_t
+hdmi_audio_infoframe_pack_for_dp(const struct hdmi_audio_infoframe *frame,
+ struct dp_sdp *sdp, u8 dp_version);
enum hdmi_3d_structure {
HDMI_3D_STRUCTURE_INVALID = -1,
--
2.34.1
On 28/03/2022 00:39, Guillaume Ranquet wrote:
> From: Markus Schneider-Pargmann <[email protected]>
>
> DP_INTF is similar to DPI but does not have the exact same feature set
> or register layouts.
>
> DP_INTF is the sink of the display pipeline that is connected to the
> DisplayPort controller and encoder unit. It takes the same clocks as
> DPI.
>
> Signed-off-by: Markus Schneider-Pargmann <[email protected]>
> Signed-off-by: Guillaume Ranquet <[email protected]>
> Reviewed-by: Rob Herring <[email protected]>
Reviewed-by: Matthias Brugger <[email protected]>
> ---
> .../bindings/display/mediatek/mediatek,dpi.yaml | 11 ++++++-----
> 1 file changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
> index dd2896a40ff0..2dba80ad3b18 100644
> --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
> +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
> @@ -4,16 +4,16 @@
> $id: http://devicetree.org/schemas/display/mediatek/mediatek,dpi.yaml#
> $schema: http://devicetree.org/meta-schemas/core.yaml#
>
> -title: mediatek DPI Controller Device Tree Bindings
> +title: mediatek DPI/DP_INTF Controller
>
> maintainers:
> - CK Hu <[email protected]>
> - Jitao shi <[email protected]>
>
> description: |
> - The Mediatek DPI function block is a sink of the display subsystem and
> - provides 8-bit RGB/YUV444 or 8/10/10-bit YUV422 pixel data on a parallel
> - output bus.
> + The Mediatek DPI and DP_INTF function blocks are a sink of the display
> + subsystem and provides 8-bit RGB/YUV444 or 8/10/10-bit YUV422 pixel data on a
> + parallel output bus.
>
> properties:
> compatible:
> @@ -23,6 +23,7 @@ properties:
> - mediatek,mt8173-dpi
> - mediatek,mt8183-dpi
> - mediatek,mt8192-dpi
> + - mediatek,mt8195-dpintf
>
> reg:
> maxItems: 1
> @@ -54,7 +55,7 @@ properties:
> $ref: /schemas/graph.yaml#/properties/port
> description:
> Output port node. This port should be connected to the input port of an
> - attached HDMI or LVDS encoder chip.
> + attached HDMI, LVDS or DisplayPort encoder chip.
>
> required:
> - compatible
On Mon, 28 Mar 2022 10:04, AngeloGioacchino Del Regno
<[email protected]> wrote:
>Il 28/03/22 00:39, Guillaume Ranquet ha scritto:
>> Signed-off-by: Guillaume Ranquet <[email protected]>
>> ---
>> include/drm/drm_edid.h | 11 ++++++++---
>> 1 file changed, 8 insertions(+), 3 deletions(-)
>>
>> diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
>> index 144c495b99c4..5d4d840b9904 100644
>> --- a/include/drm/drm_edid.h
>> +++ b/include/drm/drm_edid.h
>> @@ -359,12 +359,17 @@ struct edid {
>>
>> #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
>>
>> -/* Short Audio Descriptor */
>
>Hello Guillaume,
>
>> +/* struct cea_sad - Short Audio Descriptor.
>> + @format: See HDMI_AUDIO_CODING_TYPE_*.
>> + @channels: max number of channels - 1.
>> + @freq: See CEA_SAD_FREQ_*.
>> + @byte2: meaning depends on format.
>> +*/
>
>I appreciate the effort, but this is not valid kerneldoc.
>
>Please refer to https://docs.kernel.org/doc-guide/kernel-doc.html
>
>Regards,
>Angelo
Hello Angelo,
Thx for your review.
I'm sorry I posted this v9 in a bit of a rush...
but I promise we will get there... eventually :D
Thx,
Guillaume.
On Mon, 28 Mar 2022 10:20, AngeloGioacchino Del Regno
<[email protected]> wrote:
>Il 28/03/22 00:39, Guillaume Ranquet ha scritto:
>> From: Markus Schneider-Pargmann <[email protected]>
>>
>> This is a new driver that supports the integrated DisplayPort phy for
>> mediatek SoCs, especially the mt8195. The phy is integrated into the
>> DisplayPort controller and will be created by the mtk-dp driver. This
>> driver expects a struct regmap to be able to work on the same registers
>> as the DisplayPort controller. It sets the device data to be the struct
>> phy so that the DisplayPort controller can easily work with it.
>>
>> The driver does not have any devicetree bindings because the datasheet
>> does not list the controller and the phy as distinct units.
>>
>> The interaction with the controller can be covered by the configure
>> callback of the phy framework and its displayport parameters.
>>
>> Signed-off-by: Markus Schneider-Pargmann <[email protected]>
>> Signed-off-by: Guillaume Ranquet <[email protected]>
>> ---
>> MAINTAINERS | 1 +
>> drivers/phy/mediatek/Kconfig | 8 ++
>> drivers/phy/mediatek/Makefile | 1 +
>> drivers/phy/mediatek/phy-mtk-dp.c | 201 ++++++++++++++++++++++++++++++
>> 4 files changed, 211 insertions(+)
>> create mode 100644 drivers/phy/mediatek/phy-mtk-dp.c
>>
>
>..snip..
>
>> diff --git a/drivers/phy/mediatek/phy-mtk-dp.c b/drivers/phy/mediatek/phy-mtk-dp.c
>> new file mode 100644
>> index 000000000000..e5c5494f3636
>> --- /dev/null
>> +++ b/drivers/phy/mediatek/phy-mtk-dp.c
>
>..snip..
>
>> +
>> +static int mtk_dp_phy_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct mtk_dp_phy *dp_phy;
>> + struct phy *phy;
>> + struct regmap *regs;
>> +
>> + regs = syscon_regmap_lookup_by_phandle(dev->of_node, "mediatek,dp-syscon");
>> +
>
>Please drop this blank line
>
>> + if (IS_ERR(regs))
>> + return PTR_ERR(regs);
>> +
>> + dp_phy = devm_kzalloc(dev, sizeof(*dp_phy), GFP_KERNEL);
>> + if (!dp_phy)
>> + return -ENOMEM;
>> +
>> + dp_phy->regs = regs;
>> +
>> + phy = devm_phy_create(dev, NULL, &mtk_dp_phy_dev_ops);
>> +
>
>Same here
>
>> + if (IS_ERR(phy))
>> + return dev_err_probe(dev, PTR_ERR(phy), "Failed to create DP PHY: %ld\n", PTR_ERR(phy));
>> +
>
>Using dev_err_probe automates printing the error, so the correct usage is:
>
>return dev_err_probe(dev, PTR_ERR(phy), "Failed to create DP PHY\n");
>
>> + phy_set_drvdata(phy, dp_phy);
>> +
>> + return 0;
>> +}
>> +
>> +struct platform_driver mtk_dp_phy_driver = {
>> + .probe = mtk_dp_phy_probe,
>> + .driver = {
>> + .name = "mediatek-dp-phy",
>> + },
>> +};
>> +module_platform_driver(mtk_dp_phy_driver);
>
>Also, in your dt-binding, you mention a compatible for this driver, but I don't see
>any, here. This means that you do know what to do, so please do it.
>
Following the comments from rob [1], I'll revert back to using
platform_device_register_data() from v8.
[1] https://lore.kernel.org/linux-mediatek/YkOPB5W7uXkOc72%[email protected]/
>Regards,
>Angelo
>
>> +
>> +MODULE_AUTHOR("Markus Schneider-Pargmann <[email protected]>");
>> +MODULE_DESCRIPTION("MediaTek DP PHY Driver");
>> +MODULE_LICENSE("GPL");
>
On Tue, 29 Mar 2022 05:16, Rex-BC Chen <[email protected]> wrote:
>On Mon, 2022-03-28 at 00:39 +0200, Guillaume Ranquet wrote:
>> dpintf is the displayport interface hardware unit. This unit is
>> similar
>> to dpi and can reuse most of the code.
>>
>> This patch adds support for mt8195-dpintf to this dpi driver. Main
>> differences are:
>> - Some features/functional components are not available for dpintf
>> which are now excluded from code execution once is_dpintf is set
>> - dpintf can and needs to choose between different clockdividers
>> based
>> on the clockspeed. This is done by choosing a different clock
>> parent.
>> - There are two additional clocks that need to be managed. These are
>> only set for dpintf and will be set to NULL if not supplied. The
>> clk_* calls handle these as normal clocks then.
>> - Some register contents differ slightly between the two components.
>> To
>> work around this I added register bits/masks with a DPINTF_ prefix
>> and use them where different.
>>
>> Based on a separate driver for dpintf created by
>> Jason-JH.Lin <[email protected]>.
>>
>> Signed-off-by: Markus Schneider-Pargmann <[email protected]>
>> Signed-off-by: Guillaume Ranquet <[email protected]>
>> Reviewed-by: AngeloGioacchino Del Regno <
>> [email protected]>
>> ---
>> drivers/gpu/drm/mediatek/mtk_dpi.c | 78 ++++++++++++++++++-
>> --
>> drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 38 ++++++++++
>> drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 8 +++
>> drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 1 +
>> drivers/gpu/drm/mediatek/mtk_drm_drv.c | 5 +-
>> include/linux/soc/mediatek/mtk-mmsys.h | 2 +
>> 6 files changed, 120 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c
>> b/drivers/gpu/drm/mediatek/mtk_dpi.c
>> index eb969c5c5c2e..8198d3cf23ac 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
>> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
>> @@ -126,6 +126,7 @@ struct mtk_dpi_conf {
>> const u32 *output_fmts;
>> u32 num_output_fmts;
>> bool is_ck_de_pol;
>> + bool is_dpintf;
>> bool swap_input_support;
>> /* Mask used for HWIDTH, HPORCH, VSYNC_WIDTH and VSYNC_PORCH
>> (no shift) */
>> u32 dimension_mask;
>> @@ -498,11 +499,11 @@ static int mtk_dpi_set_display_mode(struct
>> mtk_dpi *dpi,
>>
>> vm.pixelclock = pll_rate / factor;
>> if ((dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE) ||
>> - (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE))
>> + (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE)) {
>> clk_set_rate(dpi->pixel_clk, vm.pixelclock * 2);
>> - else
>> + } else {
>> clk_set_rate(dpi->pixel_clk, vm.pixelclock);
>> -
>> + }
>>
>> vm.pixelclock = clk_get_rate(dpi->pixel_clk);
>>
>> @@ -515,9 +516,15 @@ static int mtk_dpi_set_display_mode(struct
>> mtk_dpi *dpi,
>> MTK_DPI_POLARITY_FALLING :
>> MTK_DPI_POLARITY_RISING;
>> dpi_pol.vsync_pol = vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ?
>> MTK_DPI_POLARITY_FALLING :
>> MTK_DPI_POLARITY_RISING;
>> - hsync.sync_width = vm.hsync_len;
>> - hsync.back_porch = vm.hback_porch;
>> - hsync.front_porch = vm.hfront_porch;
>> + if (dpi->conf->is_dpintf) {
>> + hsync.sync_width = vm.hsync_len / 4;
>> + hsync.back_porch = vm.hback_porch / 4;
>> + hsync.front_porch = vm.hfront_porch / 4;
>> + } else {
>> + hsync.sync_width = vm.hsync_len;
>> + hsync.back_porch = vm.hback_porch;
>> + hsync.front_porch = vm.hfront_porch;
>> + }
>> hsync.shift_half_line = false;
>> vsync_lodd.sync_width = vm.vsync_len;
>> vsync_lodd.back_porch = vm.vback_porch;
>> @@ -559,13 +566,20 @@ static int mtk_dpi_set_display_mode(struct
>> mtk_dpi *dpi,
>> mtk_dpi_config_channel_limit(dpi);
>> mtk_dpi_config_bit_num(dpi, dpi->bit_num);
>> mtk_dpi_config_channel_swap(dpi, dpi->channel_swap);
>> - mtk_dpi_config_yc_map(dpi, dpi->yc_map);
>> mtk_dpi_config_color_format(dpi, dpi->color_format);
>> - mtk_dpi_config_2n_h_fre(dpi);
>> - mtk_dpi_dual_edge(dpi);
>> - mtk_dpi_config_disable_edge(dpi);
>> + if (dpi->conf->is_dpintf) {
>> + mtk_dpi_mask(dpi, DPI_CON, DPINTF_INPUT_2P_EN,
>> + DPINTF_INPUT_2P_EN);
>> + } else {
>> + mtk_dpi_config_yc_map(dpi, dpi->yc_map);
>> + mtk_dpi_config_2n_h_fre(dpi);
>> + mtk_dpi_dual_edge(dpi);
>> + mtk_dpi_config_disable_edge(dpi);
>> + }
>> mtk_dpi_sw_reset(dpi, false);
>>
>> + mtk_dpi_enable(dpi);
>> +
>> return 0;
>> }
>>
>> @@ -642,7 +656,10 @@ static int mtk_dpi_bridge_atomic_check(struct
>> drm_bridge *bridge,
>> dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS;
>> dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB;
>> dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
>> - dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
>> + if (out_bus_format == MEDIA_BUS_FMT_YUYV8_1X16)
>> + dpi->color_format =
>> MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL;
>> + else
>> + dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
>>
>> return 0;
>> }
>> @@ -801,6 +818,16 @@ static unsigned int mt8183_calculate_factor(int
>> clock)
>> return 2;
>> }
>>
>> +static unsigned int mt8195_dpintf_calculate_factor(int clock)
>> +{
>> + if (clock < 70000)
>> + return 4;
>> + else if (clock < 200000)
>> + return 2;
>> + else
>> + return 1;
>> +}
>> +
>> static const u32 mt8173_output_fmts[] = {
>> MEDIA_BUS_FMT_RGB888_1X24,
>> };
>> @@ -810,6 +837,12 @@ static const u32 mt8183_output_fmts[] = {
>> MEDIA_BUS_FMT_RGB888_2X12_BE,
>> };
>>
>> +static const u32 mt8195_output_fmts[] = {
>> + MEDIA_BUS_FMT_RGB888_1X24,
>> + MEDIA_BUS_FMT_YUV8_1X24,
>> + MEDIA_BUS_FMT_YUYV8_1X16,
>> +};
>> +
>> static const struct mtk_dpi_yc_limit mtk_dpi_limit = {
>> .c_bottom = 0x0010,
>> .c_top = 0x0FE0,
>> @@ -817,6 +850,13 @@ static const struct mtk_dpi_yc_limit
>> mtk_dpi_limit = {
>> .y_top = 0x0FE0,
>> };
>>
>> +static const struct mtk_dpi_yc_limit mtk_dpintf_limit = {
>> + .c_bottom = 0x0000,
>> + .c_top = 0xFFF,
>> + .y_bottom = 0x0000,
>> + .y_top = 0xFFF,
>> +};
>> +
>> static const struct mtk_dpi_conf mt8173_conf = {
>> .cal_factor = mt8173_calculate_factor,
>> .reg_h_fre_con = 0xe0,
>> @@ -882,6 +922,19 @@ static const struct mtk_dpi_conf mt8192_conf = {
>> .limit = &mtk_dpi_limit,
>> };
>>
>> +static const struct mtk_dpi_conf mt8195_dpintf_conf = {
>> + .cal_factor = mt8195_dpintf_calculate_factor,
>> + .output_fmts = mt8195_output_fmts,
>> + .num_output_fmts = ARRAY_SIZE(mt8195_output_fmts),
>> + .is_dpintf = true,
>> + .dimension_mask = DPINTF_HPW_MASK,
>> + .hvsize_mask = DPINTF_HSIZE_MASK,
>> + .channel_swap_shift = DPINTF_CH_SWAP,
>> + .yuv422_en_bit = DPINTF_YUV422_EN,
>> + .csc_enable_bit = DPINTF_CSC_ENABLE,
>> + .limit = &mtk_dpintf_limit,
>> +};
>> +
>> static int mtk_dpi_probe(struct platform_device *pdev)
>> {
>> struct device *dev = &pdev->dev;
>> @@ -1004,6 +1057,9 @@ static const struct of_device_id
>> mtk_dpi_of_ids[] = {
>> { .compatible = "mediatek,mt8192-dpi",
>> .data = &mt8192_conf,
>> },
>> + { .compatible = "mediatek,mt8195-dpintf",
>> + .data = &mt8195_dpintf_conf,
>> + },
>> { },
>> };
>> MODULE_DEVICE_TABLE(of, mtk_dpi_of_ids);
>> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
>> b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
>> index 3a02fabe1662..91b32dfffced 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
>> +++ b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
>> @@ -40,10 +40,15 @@
>> #define FAKE_DE_LEVEN BIT(21)
>> #define FAKE_DE_RODD BIT(22)
>> #define FAKE_DE_REVEN BIT(23)
>> +#define DPINTF_YUV422_EN BIT(24)
>> +#define DPINTF_CSC_ENABLE BIT(26)
>> +#define DPINTF_INPUT_2P_EN BIT(29)
>>
>> #define DPI_OUTPUT_SETTING 0x14
>> #define CH_SWAP 0
>> +#define DPINTF_CH_SWAP BIT(1)
>> #define CH_SWAP_MASK (0x7 << 0)
>> +#define DPINTF_CH_SWAP_MASK (0x7 << 1)
>> #define SWAP_RGB 0x00
>> #define SWAP_GBR 0x01
>> #define SWAP_BRG 0x02
>> @@ -80,8 +85,10 @@
>> #define DPI_SIZE 0x18
>> #define HSIZE 0
>> #define HSIZE_MASK (0x1FFF << 0)
>> +#define DPINTF_HSIZE_MASK (0xFFFF << 0)
>> #define VSIZE 16
>> #define VSIZE_MASK (0x1FFF << 16)
>> +#define DPINTF_VSIZE_MASK (0xFFFF << 16)
>>
>> #define DPI_DDR_SETTING 0x1C
>> #define DDR_EN BIT(0)
>> @@ -93,24 +100,30 @@
>> #define DPI_TGEN_HWIDTH 0x20
>> #define HPW 0
>> #define HPW_MASK (0xFFF << 0)
>> +#define DPINTF_HPW_MASK (0xFFFF << 0)
>>
>> #define DPI_TGEN_HPORCH 0x24
>> #define HBP 0
>> #define HBP_MASK (0xFFF << 0)
>> +#define DPINTF_HBP_MASK (0xFFFF << 0)
>> #define HFP 16
>> #define HFP_MASK (0xFFF << 16)
>> +#define DPINTF_HFP_MASK (0xFFFF << 16)
>>
>> #define DPI_TGEN_VWIDTH 0x28
>> #define DPI_TGEN_VPORCH 0x2C
>>
>> #define VSYNC_WIDTH_SHIFT 0
>> #define VSYNC_WIDTH_MASK (0xFFF << 0)
>> +#define DPINTF_VSYNC_WIDTH_MASK (0xFFFF << 0)
>> #define VSYNC_HALF_LINE_SHIFT 16
>> #define VSYNC_HALF_LINE_MASK BIT(16)
>> #define VSYNC_BACK_PORCH_SHIFT 0
>> #define VSYNC_BACK_PORCH_MASK (0xFFF << 0)
>> +#define DPINTF_VSYNC_BACK_PORCH_MASK (0xFFFF << 0)
>> #define VSYNC_FRONT_PORCH_SHIFT 16
>> #define VSYNC_FRONT_PORCH_MASK (0xFFF << 16)
>> +#define DPINTF_VSYNC_FRONT_PORCH_MASK (0xFFFF << 16)
>>
>> #define DPI_BG_HCNTL 0x30
>> #define BG_RIGHT (0x1FFF << 0)
>> @@ -217,4 +230,29 @@
>>
>> #define EDGE_SEL_EN BIT(5)
>> #define H_FRE_2N BIT(25)
>> +
>> +#define DPI_MATRIX_SET 0xB4
>> +#define INT_MATRIX_SEL BIT(0)
>> +#define INT_MATRIX_SEL_MASK (0x1F << 0)
>> +#define RGB_TO_JPEG 0x00
>> +#define RGB_TO_FULL709 0x01
>> +#define RGB_TO_BT601 0x02
>> +#define RGB_TO_BT709 0x03
>> +#define JPEG_TO_RGB 0x04
>> +#define FULL709_TO_RGB 0x05
>> +#define BT601_TO_RGB 0x06
>> +#define BT709_TO_RGB 0x07
>> +#define JPEG_TO_BT601 0x08
>> +#define JPEG_TO_BT709 0x09
>> +#define BT601_TO_JPEG 0xA
>> +#define BT709_TO_JPEG 0xB
>> +#define BT709_TO_BT601 0xC
>> +#define BT601_TO_BT709 0xD
>> +#define JPEG_TO_CERGB 0x14
>> +#define FULL709_TO_CERGB 0x15
>> +#define BT601_TO_CERGB 0x16
>> +#define BT709_TO_CERGB 0x17
>> +#define RGB_TO_CERGB 0x1C
>> +#define MATRIX_BIT BIT(8)
>> +#define EXT_MATRIX_EN BIT(12)
>> #endif /* __MTK_DPI_REGS_H */
>> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
>> b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
>> index 2e99aee13dfe..558fc2733358 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
>> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
>> @@ -351,6 +351,11 @@ static const char * const
>> mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
>> [MTK_DISP_WDMA] = "wdma",
>> [MTK_DPI] = "dpi",
>> [MTK_DSI] = "dsi",
>> + [MTK_DP_INTF] = "dp-intf",
>> + [MTK_DISP_PWM] = "pwm",
>> + [MTK_DISP_MUTEX] = "mutex",
>> + [MTK_DISP_OD] = "od",
>> + [MTK_DISP_BLS] = "bls",
>> };
>>
>> struct mtk_ddp_comp_match {
>> @@ -369,6 +374,8 @@ static const struct mtk_ddp_comp_match
>> mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
>> [DDP_COMPONENT_DITHER] = { MTK_DISP_DITHER, 0,
>> &ddp_dither },
>> [DDP_COMPONENT_DPI0] = { MTK_DPI, 0,
>> &ddp_dpi },
>> [DDP_COMPONENT_DPI1] = { MTK_DPI, 1,
>> &ddp_dpi },
>> + [DDP_COMPONENT_DP_INTF0] = { MTK_DP_INTF, 0, &ddp_dpi
>> },
>> + [DDP_COMPONENT_DP_INTF1] = { MTK_DP_INTF, 1, &ddp_dpi
>> },
>> [DDP_COMPONENT_DSI0] = { MTK_DSI, 0,
>> &ddp_dsi },
>> [DDP_COMPONENT_DSI1] = { MTK_DSI, 1,
>> &ddp_dsi },
>> [DDP_COMPONENT_DSI2] = { MTK_DSI, 2,
>> &ddp_dsi },
>> @@ -481,6 +488,7 @@ int mtk_ddp_comp_init(struct device_node *node,
>> struct mtk_ddp_comp *comp,
>> type == MTK_DISP_PWM ||
>> type == MTK_DISP_RDMA ||
>> type == MTK_DPI ||
>> + type == MTK_DP_INTF ||
>> type == MTK_DSI)
>> return 0;
>>
>> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
>> b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
>> index ad267bb8fc9b..43ad74be509e 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
>> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
>> @@ -34,6 +34,7 @@ enum mtk_ddp_comp_type {
>> MTK_DISP_UFOE,
>> MTK_DISP_WDMA,
>> MTK_DPI,
>> + MTK_DP_INTF,
>> MTK_DSI,
>> MTK_DDP_COMP_TYPE_MAX,
>> };
>> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> index 247c6ff277ef..c8a233f609f0 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> @@ -509,6 +509,8 @@ static const struct of_device_id
>> mtk_ddp_comp_dt_ids[] = {
>> .data = (void *)MTK_DPI },
>> { .compatible = "mediatek,mt8183-dpi",
>> .data = (void *)MTK_DPI },
>> + { .compatible = "mediatek,mt8195-dpintf",
>> + .data = (void *)MTK_DP_INTF },
>> { .compatible = "mediatek,mt2701-dsi",
>> .data = (void *)MTK_DSI },
>> { .compatible = "mediatek,mt8173-dsi",
>> @@ -609,7 +611,8 @@ static int mtk_drm_probe(struct platform_device
>> *pdev)
>> comp_type == MTK_DISP_OVL_2L ||
>> comp_type == MTK_DISP_RDMA ||
>> comp_type == MTK_DPI ||
>> - comp_type == MTK_DSI) {
>> + comp_type == MTK_DPI ||
>> + comp_type == MTK_DP_INTF) {
>
>Hello Guillaume,
>
>Is this modification correct?
>MTK_DPI appears twice and MTK_DSI is removed.
>
This is not correct, I've messed up my rebase it seems.
Thx for your review.
>
>BRs,
>Rex
>
>> dev_info(dev, "Adding component match for
>> %pOF\n",
>> node);
>> drm_of_component_match_add(dev, &match,
>> component_compare_of,
>> diff --git a/include/linux/soc/mediatek/mtk-mmsys.h
>> b/include/linux/soc/mediatek/mtk-mmsys.h
>> index 4bba275e235a..56ed2fa5f59e 100644
>> --- a/include/linux/soc/mediatek/mtk-mmsys.h
>> +++ b/include/linux/soc/mediatek/mtk-mmsys.h
>> @@ -19,6 +19,8 @@ enum mtk_ddp_comp_id {
>> DDP_COMPONENT_DITHER,
>> DDP_COMPONENT_DPI0,
>> DDP_COMPONENT_DPI1,
>> + DDP_COMPONENT_DP_INTF0,
>> + DDP_COMPONENT_DP_INTF1,
>> DDP_COMPONENT_DSI0,
>> DDP_COMPONENT_DSI1,
>> DDP_COMPONENT_DSI2,
>
On Tue, 29 Mar 2022 07:41, Rex-BC Chen <[email protected]> wrote:
>Hello Guillaume,
>
>Thanks for your patch.
>I add some comments below:
>
>On Mon, 2022-03-28 at 00:39 +0200, Guillaume Ranquet wrote:
>> From: Markus Schneider-Pargmann <[email protected]>
>>
>> This patch adds a DisplayPort driver for the Mediatek mt8195 SoC.
>>
>> It supports the mt8195, the embedded DisplayPort units. It offers
>> DisplayPort 1.4 with up to 4 lanes.
>>
>> The driver shares its iomap range with the mtk-dp-phy driver using
>> the regmap/syscon facility.
>>
>> This driver is based on an initial version by
>> Jason-JH.Lin <[email protected]>.
>>
>> Signed-off-by: Markus Schneider-Pargmann <[email protected]>
>> Signed-off-by: Guillaume Ranquet <[email protected]>
>> Reported-by: kernel test robot <[email protected]>
>> ---
>> drivers/gpu/drm/mediatek/Kconfig | 8 +
>> drivers/gpu/drm/mediatek/Makefile | 2 +
>> drivers/gpu/drm/mediatek/mtk_dp.c | 2221
>> ++++++++++++++++++++++++
>> drivers/gpu/drm/mediatek/mtk_dp_reg.h | 568 ++++++
>> drivers/gpu/drm/mediatek/mtk_drm_drv.c | 1 +
>> drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
>> 6 files changed, 2801 insertions(+)
>> create mode 100644 drivers/gpu/drm/mediatek/mtk_dp.c
>> create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_reg.h
>>
>> diff --git a/drivers/gpu/drm/mediatek/Kconfig
>> b/drivers/gpu/drm/mediatek/Kconfig
>> index 2976d21e9a34..03ffa9b896c3 100644
>> --- a/drivers/gpu/drm/mediatek/Kconfig
>> +++ b/drivers/gpu/drm/mediatek/Kconfig
>> @@ -28,3 +28,11 @@ config DRM_MEDIATEK_HDMI
>> select PHY_MTK_HDMI
>> help
>> DRM/KMS HDMI driver for Mediatek SoCs
>> +
>> +config MTK_DPTX_SUPPORT
>> + tristate "DRM DPTX Support for Mediatek SoCs"
>> + depends on DRM_MEDIATEK
>> + select PHY_MTK_DP
>> + select DRM_DP_HELPER
>> + help
>> + DRM/KMS Display Port driver for Mediatek SoCs.
>> diff --git a/drivers/gpu/drm/mediatek/Makefile
>> b/drivers/gpu/drm/mediatek/Makefile
>> index 29098d7c8307..d86a6406055e 100644
>> --- a/drivers/gpu/drm/mediatek/Makefile
>> +++ b/drivers/gpu/drm/mediatek/Makefile
>> @@ -21,3 +21,5 @@ mediatek-drm-hdmi-objs := mtk_cec.o \
>> mtk_hdmi_ddc.o
>>
>> obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
>> +
>> +obj-$(CONFIG_MTK_DPTX_SUPPORT) += mtk_dp.o
>> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c
>> b/drivers/gpu/drm/mediatek/mtk_dp.c
>> new file mode 100644
>> index 000000000000..7cd8459cf719
>> --- /dev/null
>> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
>> @@ -0,0 +1,2221 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2019 MediaTek Inc.
>> + * Copyright (c) 2021 BayLibre
>> + */
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_bridge.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/dp/drm_dp_helper.h>
>> +#include <drm/drm_edid.h>
>> +#include <drm/drm_of.h>
>> +#include <drm/drm_panel.h>
>> +#include <drm/drm_print.h>
>> +#include <drm/drm_probe_helper.h>
>> +#include <linux/arm-smccc.h>
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/errno.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/nvmem-consumer.h>
>> +#include <linux/of.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/phy/phy.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/regmap.h>
>> +#include <sound/hdmi-codec.h>
>> +#include <video/videomode.h>
>> +
>> +#include "mtk_dp_reg.h"
>> +
>> +#define MTK_DP_AUX_WAIT_REPLY_COUNT 20
>> +#define MTK_DP_CHECK_SINK_CAP_TIMEOUT_COUNT 3
>> +
>> +//TODO: platform/device data or dts?
>> +#define MTK_DP_MAX_LANES 4
>> +#define MTK_DP_MAX_LINK_RATE MTK_DP_LINKRATE_HBR3
>> +
>> +#define MTK_DP_TBC_BUF_READ_START_ADDR 0x08
>> +
>> +#define MTK_DP_TRAIN_RETRY_LIMIT 8
>> +#define MTK_DP_TRAIN_MAX_ITERATIONS 5
>> +
>> +#define MTK_DP_AUX_WRITE_READ_WAIT_TIME_US 20
>> +
>> +#define MTK_DP_DP_VERSION_11 0x11
>> +
>> +enum mtk_dp_state {
>> + MTK_DP_STATE_INITIAL,
>> + MTK_DP_STATE_IDLE,
>> + MTK_DP_STATE_PREPARE,
>> + MTK_DP_STATE_NORMAL,
>> +};
>> +
>>
>
>snif...
>
>> +
>> +static int mtk_dp_msa_bypass_disable(struct mtk_dp *mtk_dp)
>> +{
>> + const u16 bits_to_set =
>> + BIT(HTOTAL_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(VTOTAL_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(HSTART_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(VSTART_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(HWIDTH_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(VHEIGHT_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(HSP_SEL_DP_ENC0_P0_SHIFT) |
>> BIT(HSW_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(VSP_SEL_DP_ENC0_P0_SHIFT) |
>> BIT(VSW_SEL_DP_ENC0_P0_SHIFT);
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3030,
>> bits_to_set,
>> + bits_to_set);
>> +}
>> +
>> +#define MTK_UPD_BITS_OR_OUT(mtk_dp, offset, val, mask, ret, label) \
>> + do {\
>> + ret = mtk_dp_update_bits(mtk_dp, offset, val, mask); \
>> + if (ret) \
>> + goto label; \
>> + } while (0)
>> +
>> +static int mtk_dp_set_msa(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> + struct mtk_dp_timings *timings = &mtk_dp->info.timings;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3010, timings-
>> >htotal,
>> + HTOTAL_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3018,
>> + timings->vm.hsync_len + timings-
>> >vm.hback_porch,
>> + HSTART_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3028,
>> + timings->vm.hsync_len <<
>> HSW_SW_DP_ENC0_P0_SHIFT,
>> + HSW_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3028, 0,
>> + HSP_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3020, timings-
>> >vm.hactive,
>> + HWIDTH_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3014, timings-
>> >vtotal,
>> + VTOTAL_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_301C,
>> + timings->vm.vsync_len + timings-
>> >vm.vback_porch,
>> + VSTART_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_302C,
>> + timings->vm.vsync_len <<
>> VSW_SW_DP_ENC0_P0_SHIFT,
>> + VSW_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_302C, 0,
>> + VSP_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3024, timings-
>> >vm.vactive,
>> + VHEIGHT_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3064, timings-
>> >vm.hactive,
>> + HDE_NUM_LAST_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3154, timings-
>> >htotal,
>> + PGEN_HTOTAL_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3158,
>> + timings->vm.hfront_porch,
>> + PGEN_HSYNC_RISING_DP_ENC0_P0_MASK, ret,
>> out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_315C, timings-
>> >vm.hsync_len,
>> + PGEN_HSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK,
>> ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3160,
>> + timings->vm.hback_porch + timings-
>> >vm.hsync_len,
>> + PGEN_HFDE_START_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3164, timings-
>> >vm.hactive,
>> + PGEN_HFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK,
>> ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3168, timings-
>> >vtotal,
>> + PGEN_VTOTAL_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_316C,
>> + timings->vm.vfront_porch,
>> + PGEN_VSYNC_RISING_DP_ENC0_P0_MASK, ret,
>> out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3170, timings-
>> >vm.vsync_len,
>> + PGEN_VSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK,
>> ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3174,
>> + timings->vm.vback_porch + timings-
>> >vm.vsync_len,
>> + PGEN_VFDE_START_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3178, timings-
>> >vm.vactive,
>> + PGEN_VFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK,
>> ret, out);
>> +
>> +out:
>
>Just like Angelo's comments.
>I think we can remove this macro.
>IMO, I think we don't need to go to out.
>The failure is caused by update registers fail, and there are error
>message in mtk_dp_update_bits().
>I think we can or all ret value and check them in last of this funtion.
>
Yes, that macro was not a great idea.
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_set_color_format(struct mtk_dp *mtk_dp,
>> + enum mtk_dp_color_format
>> color_format)
>> +{
>> + u32 val;
>> + int ret;
>> +
>> + mtk_dp->info.format = color_format;
>> +
>> + /* Update MISC0 */
>> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
>> + color_format <<
>> DP_TEST_COLOR_FORMAT_SHIFT,
>> + DP_TEST_COLOR_FORMAT_MASK);
>
>maybe the same indention with "color_format <<
>DP_TEST_COLOR_FORMAT_SHIFT," here?
>
I'll fix the indentation here.
>> +
>> + if (ret)
>> + return ret;
>> +
>> + switch (color_format) {
>> + case MTK_DP_COLOR_FORMAT_YUV_422:
>> + val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422;
>> + break;
>> + case MTK_DP_COLOR_FORMAT_YUV_420:
>> + val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR420;
>> + break;
>> + case MTK_DP_COLOR_FORMAT_YONLY:
>> + case MTK_DP_COLOR_FORMAT_RAW:
>> + case MTK_DP_COLOR_FORMAT_RESERVED:
>> + case MTK_DP_COLOR_FORMAT_UNKNOWN:
>> + drm_warn(mtk_dp->drm_dev, "Unsupported color format:
>> %d\n",
>> + color_format);
>> + fallthrough;
>> + case MTK_DP_COLOR_FORMAT_RGB_444:
>> + case MTK_DP_COLOR_FORMAT_YUV_444:
>> + val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB;
>> + break;
>> + }
>> +
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C, val,
>> + PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_set_color_depth(struct mtk_dp *mtk_dp,
>> + enum mtk_dp_color_depth color_depth)
>> +{
>> + int ret;
>> + u32 val;
>> +
>> + mtk_dp->info.depth = color_depth;
>> +
>> + /* Update MISC0 */
>> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
>> + color_depth <<
>> DP_TEST_BIT_DEPTH_SHIFT,
>> + DP_TEST_BIT_DEPTH_MASK);
>
>ditto
>
>> +
>> + if (ret)
>> + return ret;
>> +
>> + switch (color_depth) {
>> + case MTK_DP_COLOR_DEPTH_6BIT:
>> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_6BIT;
>> + break;
>> + case MTK_DP_COLOR_DEPTH_8BIT:
>> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_8BIT;
>> + break;
>> + case MTK_DP_COLOR_DEPTH_10BIT:
>> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_10BIT;
>> + break;
>> + case MTK_DP_COLOR_DEPTH_12BIT:
>> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_12BIT;
>> + break;
>> + case MTK_DP_COLOR_DEPTH_16BIT:
>> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_16BIT;
>> + break;
>> + case MTK_DP_COLOR_DEPTH_UNKNOWN:
>> + drm_warn(mtk_dp->drm_dev, "Unsupported color depth
>> %d\n",
>> + color_depth);
>> + return -EINVAL;
>> + }
>> +
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C, val,
>> + VIDEO_COLOR_DEPTH_DP_ENC0_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_mn_overwrite_disable(struct mtk_dp *mtk_dp)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004, 0,
>> + VIDEO_M_CODE_SEL_DP_ENC0_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_set_sram_read_start(struct mtk_dp *mtk_dp, u32
>> val)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
>> + val <<
>> SRAM_START_READ_THRD_DP_ENC0_P0_SHIFT,
>> + SRAM_START_READ_THRD_DP_ENC0_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_setup_encoder(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_303C,
>> + BIT(VIDEO_MN_GEN_EN_DP_ENC0_P0_SHIFT),
>> + VIDEO_MN_GEN_EN_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3040,
>> + 0x20 << SDP_DOWN_CNT_INIT_DP_ENC0_P0_SHIFT,
>> + SDP_DOWN_CNT_INIT_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3364,
>> + 0x20 <<
>> SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_SHIFT,
>> + SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_MASK,
>> ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3300,
>> + 2 << VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_SHIFT,
>> + VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3364,
>> + 4 <<
>> FIFO_READ_START_POINT_DP_ENC1_P0_SHIFT,
>> + FIFO_READ_START_POINT_DP_ENC1_P0_MASK, ret,
>> out);
>> + ret = mtk_dp_write(mtk_dp, MTK_DP_ENC1_P0_3368,
>> + 1 <<
>> VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0_SHIFT |
>> + 1 << VIDEO_STABLE_CNT_THRD_DP_ENC1_P0_SHIFT |
>> + BIT(SDP_DP13_EN_DP_ENC1_P0_SHIFT) |
>> + 1 << BS2BS_MODE_DP_ENC1_P0_SHIFT);
>
>ditto
>
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_pg_disable(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3038, 0,
>> + VIDEO_SOURCE_SEL_DP_ENC0_P0_MASK, ret,
>> out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_31B0,
>> + 4 << PGEN_PATTERN_SEL_SHIFT,
>> PGEN_PATTERN_SEL_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static bool mtk_dp_plug_state(struct mtk_dp *mtk_dp)
>> +{
>> + return !!(mtk_dp_read(mtk_dp, MTK_DP_TRANS_P0_3414) &
>> + HPD_DB_DP_TRANS_P0_MASK);
>> +}
>> +
>> +static void mtk_dp_aux_irq_clear(struct mtk_dp *mtk_dp)
>> +{
>> + mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3640,
>> + BIT(AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_SHIFT) |
>> + BIT(AUX_RX_DATA_RECV_IRQ_AUX_TX_P0_SHIFT) |
>> + BIT(AUX_RX_ADDR_RECV_IRQ_AUX_TX_P0_SHIFT) |
>> + BIT(AUX_RX_CMD_RECV_IRQ_AUX_TX_P0_SHIFT) |
>> + BIT(AUX_RX_MCCS_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT)
>> |
>> + BIT(AUX_RX_EDID_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT)
>> |
>> + BIT(AUX_RX_AUX_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT))
>> ;
>> +}
>> +
>> +static int mtk_dp_aux_set_cmd(struct mtk_dp *mtk_dp, u8 cmd, u32
>> addr)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3644, cmd,
>> + MCU_REQUEST_COMMAND_AUX_TX_P0_MASK, ret,
>> out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3648, addr,
>> + MCU_REQUEST_ADDRESS_LSB_AUX_TX_P0_MASK,
>> ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_364C, addr >> 16,
>> + MCU_REQUEST_ADDRESS_MSB_AUX_TX_P0_MASK,
>> ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_aux_cmd_complete(struct mtk_dp *mtk_dp)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3650,
>> + BIT(MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_SHIFT),
>> + MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_MASK |
>> + PHY_FIFO_RST_AUX_TX_P0_MASK |
>> + MCU_REQ_DATA_NUM_AUX_TX_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_aux_request_ready(struct mtk_dp *mtk_dp)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3630,
>> + BIT(AUX_TX_REQUEST_READY_AUX_TX_P0_SHIFT),
>> + AUX_TX_REQUEST_READY_AUX_TX_P0_MASK);
>> +}
>> +
>> +static void mtk_dp_aux_fill_write_fifo(struct mtk_dp *mtk_dp, u8
>> *buf,
>> + size_t length)
>> +{
>> + mtk_dp_bulk_16bit_write(mtk_dp, MTK_DP_AUX_P0_3708, buf,
>> length);
>> +}
>> +
>> +static int mtk_dp_aux_read_rx_fifo(struct mtk_dp *mtk_dp, u8 *buf,
>> + size_t length, int read_delay)
>> +{
>> + int ret;
>> + int read_pos;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3620, 0,
>> + AUX_RD_MODE_AUX_TX_P0_MASK, ret, out);
>> +
>> + for (read_pos = 0; read_pos < length; read_pos++) {
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3620,
>> + BIT(AUX_RX_FIFO_R_PULSE_TX_P0_SHIFT
>> ),
>> + AUX_RX_FIFO_READ_PULSE_TX_P0_MASK,
>> ret, out);
>> + usleep_range(read_delay, read_delay * 2);
>> + buf[read_pos] =
>> + (u8)(mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3620) &
>> + AUX_RX_FIFO_READ_DATA_AUX_TX_P0_MASK >>
>> + AUX_RX_FIFO_READ_DATA_AUX_TX_P0_SH
>> IFT);
>> + }
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_aux_set_length(struct mtk_dp *mtk_dp, size_t
>> length)
>> +{
>> + int ret;
>> +
>> + if (length > 0) {
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3650,
>> + (length - 1)
>> + <<
>> MCU_REQ_DATA_NUM_AUX_TX_P0_SHIFT,
>> + MCU_REQ_DATA_NUM_AUX_TX_P0_MASK,
>> ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_362C, 0,
>> + AUX_NO_LENGTH_AUX_TX_P0_MASK |
>> + AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK |
>> + AUX_RESERVED_RW_0_AUX_TX_P0_MASK,
>> ret, out);
>> + } else {
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_362C,
>> + BIT(AUX_NO_LENGTH_AUX_TX_P0_SHIFT),
>> + AUX_NO_LENGTH_AUX_TX_P0_MASK |
>> + AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK |
>> + AUX_RESERVED_RW_0_AUX_TX_P0_MASK,
>> ret, out);
>> + }
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_aux_wait_for_completion(struct mtk_dp *mtk_dp,
>> bool is_read)
>> +{
>> + int wait_reply = MTK_DP_AUX_WAIT_REPLY_COUNT;
>> +
>> + while (--wait_reply) {
>> + u32 aux_irq_status;
>> +
>> + if (is_read) {
>> + u32 fifo_status = mtk_dp_read(mtk_dp,
>> MTK_DP_AUX_P0_3618);
>> +
>> + if (fifo_status &
>> + (AUX_RX_FIFO_WRITE_POINTER_AUX_TX_P0_MASK |
>> + AUX_RX_FIFO_FULL_AUX_TX_P0_MASK)) {
>> + return 0;
>> + }
>> + }
>> +
>> + aux_irq_status = mtk_dp_read(mtk_dp,
>> MTK_DP_AUX_P0_3640);
>> + if (aux_irq_status &
>> AUX_RX_RECV_COMPLETE_IRQ_TX_P0_MASK)
>> + return 0;
>> +
>> + if (aux_irq_status &
>> AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_MASK)
>> + return -ETIMEDOUT;
>> +
>> + usleep_range(100, 500);
>> + }
>> +
>> + return -ETIMEDOUT;
>> +}
>> +
>> +static int mtk_dp_aux_do_transfer(struct mtk_dp *mtk_dp, bool
>> is_read, u8 cmd,
>> + u32 addr, u8 *buf, size_t length)
>> +{
>> + int ret;
>> + u32 reply_cmd;
>> +
>> + if (is_read && (length > DP_AUX_MAX_PAYLOAD_BYTES ||
>> + (cmd == DP_AUX_NATIVE_READ && !length)))
>> + return -EINVAL;
>> +
>> + if (!is_read) {
>> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3704,
>> + BIT(AUX_TX_FIFO_NEW_MODE_EN_AU
>> X_TX_P0_SHIFT),
>> + AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_MA
>> SK);
>
>BIT(AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_SHIFT) is very strange..
>(#define AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_SHIFT (BIT(1)))
>> +
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + mtk_dp_aux_cmd_complete(mtk_dp);
>> + mtk_dp_aux_irq_clear(mtk_dp);
>> + usleep_range(MTK_DP_AUX_WRITE_READ_WAIT_TIME_US,
>> + MTK_DP_AUX_WRITE_READ_WAIT_TIME_US * 2);
>> +
>> + mtk_dp_aux_set_cmd(mtk_dp, cmd, addr);
>> + mtk_dp_aux_set_length(mtk_dp, length);
>> +
>> + if (!is_read) {
>> + if (length)
>> + mtk_dp_aux_fill_write_fifo(mtk_dp, buf,
>> length);
>> +
>> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3704,
>> + AUX_TX_FIFO_WRITE_DATA_NEW_MOD
>> E_TOGGLE_AUX_TX_P0_MASK,
>> + AUX_TX_FIFO_WRITE_DATA_NEW_MODE_TOGG
>> LE_AUX_TX_P0_MASK);
>> +
>> + if (ret)
>> + return ret;
>> + }
>
>is this the same with previous if (!is_read) ?
>If yes, maybe we can
>extract them..
>
I plan to simplify this function as much as possible.
As previsouly stated, this can use drm_dp_dpcd_read/write()
>> +
>> + mtk_dp_aux_request_ready(mtk_dp);
>> +
>> + ret = mtk_dp_aux_wait_for_completion(mtk_dp, is_read);
>> +
>> + reply_cmd = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3624) &
>> + AUX_RX_REPLY_COMMAND_AUX_TX_P0_MASK;
>> +
>> + if (ret || reply_cmd) {
>> + u32 phy_status = mtk_dp_read(mtk_dp,
>> MTK_DP_AUX_P0_3628) &
>> + AUX_RX_PHY_STATE_AUX_TX_P0_MASK;
>> + if (phy_status != AUX_RX_PHY_STATE_AUX_TX_P0_RX_IDLE) {
>> + drm_err(mtk_dp->drm_dev,
>> + "AUX Rx Aux hang, need SW reset\n");
>> + return -EIO;
>> + }
>> +
>> + mtk_dp_aux_cmd_complete(mtk_dp);
>> + mtk_dp_aux_irq_clear(mtk_dp);
>> +
>> + usleep_range(MTK_DP_AUX_WRITE_READ_WAIT_TIME_US,
>> + MTK_DP_AUX_WRITE_READ_WAIT_TIME_US * 2);
>> + return -ETIMEDOUT;
>> + }
>> +
>> + if (!length) {
>> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_362C, 0,
>> + AUX_NO_LENGTH_AUX_TX_P0_MASK |
>> + AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK |
>> + AUX_RESERVED_RW_0_AUX_TX_P0_MASK);
>> +
>> + if (ret)
>> + return ret;
>> +
>> + } else if (is_read) {
>> + int read_delay;
>> +
>> + if (cmd == (DP_AUX_I2C_READ | DP_AUX_I2C_MOT) ||
>> + cmd == DP_AUX_I2C_READ)
>> + read_delay = 500;
>> + else
>> + read_delay = 100;
>> +
>> + mtk_dp_aux_read_rx_fifo(mtk_dp, buf, length,
>> read_delay);
>> + }
>> +
>> + mtk_dp_aux_cmd_complete(mtk_dp);
>> + mtk_dp_aux_irq_clear(mtk_dp);
>> + usleep_range(MTK_DP_AUX_WRITE_READ_WAIT_TIME_US,
>> + MTK_DP_AUX_WRITE_READ_WAIT_TIME_US * 2);
>> +
>> + return 0;
>> +}
>> +
>> +static bool mtk_dp_set_swing_pre_emphasis(struct mtk_dp *mtk_dp, int
>> lane_num,
>> + int swing_val, int
>> preemphasis)
>> +{
>> + int ret;
>> +
>> + u32 lane_shift = lane_num * DP_TX1_VOLT_SWING_SHIFT;
>> +
>> + if (lane_num < 0 || lane_num > 3)
>> + return false;
>> +
>> + dev_dbg(mtk_dp->dev,
>> + "link training swing_val= 0x%x, preemphasis = 0x%x\n",
>> + swing_val, preemphasis);
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_SWING_EMP,
>> + swing_val << (DP_TX0_VOLT_SWING_SHIFT +
>> lane_shift),
>> + DP_TX0_VOLT_SWING_MASK << lane_shift, ret,
>> out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_SWING_EMP,
>> + preemphasis << (DP_TX0_PRE_EMPH_SHIFT +
>> lane_shift),
>> + DP_TX0_PRE_EMPH_MASK << lane_shift, ret,
>> out);
>> +
>> +out:
>> + return !ret;
>
>why return !ret?
unsure... this return value is unused in the callee anyway...
I should have better error management in v10.
>
>> +}
>> +
>> +static int mtk_dp_reset_swing_pre_emphasis(struct mtk_dp *mtk_dp)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_SWING_EMP, 0,
>> + DP_TX0_VOLT_SWING_MASK |
>> DP_TX1_VOLT_SWING_MASK |
>> + DP_TX2_VOLT_SWING_MASK |
>> + DP_TX3_VOLT_SWING_MASK |
>> + DP_TX0_PRE_EMPH_MASK | DP_TX1_PRE_EMPH_MASK
>> |
>> + DP_TX2_PRE_EMPH_MASK |
>> DP_TX3_PRE_EMPH_MASK);
>> +}
>> +
>> +static int mtk_dp_fec_enable(struct mtk_dp *mtk_dp, bool enable)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3540,
>> + enable ? BIT(FEC_EN_DP_TRANS_P0_SHIFT) : 0,
>> + FEC_EN_DP_TRANS_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_hwirq_enable(struct mtk_dp *mtk_dp, bool enable)
>> +{
>> + u32 val = 0;
>> +
>> + if (!enable)
>> + val = IRQ_MASK_DP_TRANS_P0_DISC_IRQ |
>> + IRQ_MASK_DP_TRANS_P0_CONN_IRQ |
>> + IRQ_MASK_DP_TRANS_P0_INT_IRQ;
>
>I think val = enable ? ... : 0
Yes, this can be simplified :)
>
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3418, val,
>> + IRQ_MASK_DP_TRANS_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_initialize_settings(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_342C,
>> + XTAL_FREQ_DP_TRANS_P0_DEFAULT,
>> + XTAL_FREQ_DP_TRANS_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_3540,
>> + BIT(FEC_CLOCK_EN_MODE_DP_TRANS_P0_SHIFT),
>> + FEC_CLOCK_EN_MODE_DP_TRANS_P0_MASK, ret,
>> out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_31EC,
>> + BIT(AUDIO_CH_SRC_SEL_DP_ENC0_P0_SHIFT),
>> + AUDIO_CH_SRC_SEL_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_304C, 0,
>> + SDP_VSYNC_RISING_MASK_DP_ENC0_P0_MASK, ret,
>> out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_IRQ_MASK,
>> IRQ_MASK_AUX_TOP_IRQ,
>> + IRQ_MASK_AUX_TOP_IRQ, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static void mtk_dp_initialize_hpd_detect_settings(struct mtk_dp
>> *mtk_dp)
>> +{
>> + // Debounce threshold
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
>> + 8 << HPD_DEB_THD_DP_TRANS_P0_SHIFT,
>> + HPD_DEB_THD_DP_TRANS_P0_MASK);
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
>> + (HPD_INT_THD_DP_TRANS_P0_LOWER_500US |
>> + HPD_INT_THD_DP_TRANS_P0_UPPER_1100US)
>> + << HPD_INT_THD_DP_TRANS_P0_SHIFT,
>> + HPD_INT_THD_DP_TRANS_P0_MASK);
>> +
>> + // Connect threshold 1.5ms + 5 x 0.1ms = 2ms
>> + // Disconnect threshold 1.5ms + 5 x 0.1ms = 2ms
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
>> + (5 << HPD_DISC_THD_DP_TRANS_P0_SHIFT) |
>> + (5 <<
>> HPD_CONN_THD_DP_TRANS_P0_SHIFT),
>> + HPD_DISC_THD_DP_TRANS_P0_MASK |
>> + HPD_CONN_THD_DP_TRANS_P0_MASK);
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3430,
>> + HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT,
>> + HPD_INT_THD_ECO_DP_TRANS_P0_MASK);
>
>this function is not control if !ret,
>maybe we should let all functions of setting register follow the same
>rule?
>
v10 should have proper error handling throughout all the functions.
>> +}
>> +
>> +static int mtk_dp_initialize_aux_settings(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + /* modify timeout threshold = 1595 [12 : 8] */
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_360C, 0x1595,
>> + AUX_TIMEOUT_THR_AUX_TX_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3658, 0,
>> + AUX_TX_OV_EN_AUX_TX_P0_MASK, ret, out);
>> + /* 25 for 26M */
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3634,
>> + 25 <<
>> AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_SHIFT,
>> + AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_MASK, ret,
>> out);
>> + /* 13 for 26M */
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3614,
>> + 13 << AUX_RX_UI_CNT_THR_AUX_TX_P0_SHIFT,
>> + AUX_RX_UI_CNT_THR_AUX_TX_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_37C8,
>> + BIT(MTK_ATOP_EN_AUX_TX_P0_SHIFT),
>> + MTK_ATOP_EN_AUX_TX_P0_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_initialize_digital_settings(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_304C, 0,
>> + VBID_VIDEO_MUTE_DP_ENC0_P0_MASK, ret, out);
>> + mtk_dp_set_color_format(mtk_dp, MTK_DP_COLOR_FORMAT_RGB_444);
>> + mtk_dp_set_color_depth(mtk_dp, MTK_DP_COLOR_DEPTH_8BIT);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3368,
>> + 1 << BS2BS_MODE_DP_ENC1_P0_SHIFT,
>> + BS2BS_MODE_DP_ENC1_P0_MASK, ret, out);
>> +
>> + /* dp tx encoder reset all sw */
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3004,
>> + BIT(DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_SH
>> IFT),
>> + DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_MASK,
>> ret, out);
>> + usleep_range(1000, 5000);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3004, 0,
>> + DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_MASK,
>> ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_digital_sw_reset(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_340C,
>> + BIT(DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_
>> P0_SHIFT),
>> + DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_MA
>> SK, ret, out);
>> + usleep_range(1000, 5000);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_340C, 0,
>> + DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_M
>> ASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_set_lanes(struct mtk_dp *mtk_dp, int lanes)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_35F0,
>> + lanes == 0 ? 0 : BIT(3), BIT(3) | BIT(2),
>> ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3000, lanes,
>> + LANE_NUM_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_34A4,
>> + lanes << LANE_NUM_DP_TRANS_P0_SHIFT,
>> + LANE_NUM_DP_TRANS_P0_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int link_rate_to_mb_per_s(struct mtk_dp *mtk_dp,
>> + enum mtk_dp_linkrate linkrate)
>> +{
>> + switch (linkrate) {
>> + default:
>> + drm_err(mtk_dp->drm_dev,
>> + "Implementation error, unknown linkrate %d\n",
>> + linkrate);
>> + fallthrough;
>
>I think we should return 0?
>
maybe not 0, -EINVAL seemed to be a good candidate?
>> + case MTK_DP_LINKRATE_RBR:
>> + return 1620;
>> + case MTK_DP_LINKRATE_HBR:
>> + return 2700;
>> + case MTK_DP_LINKRATE_HBR2:
>> + return 5400;
>> + case MTK_DP_LINKRATE_HBR3:
>> + return 8100;
>> + }
>> +}
>> +
>> +static u32 check_cal_data_valid(u32 min, u32 max, u32 val, u32
>> default_val)
>> +{
>> + if (val < min || val > max)
>> + return default_val;
>
>maybe we should add some warning here.
Will do.
>
>> +
>> + return val;
>> +}
>> +
>> +static int mtk_dp_get_calibration_data(struct mtk_dp *mtk_dp)
>> +{
>> + struct dp_cal_data *cal_data = &mtk_dp->cal_data;
>> + struct device *dev = mtk_dp->dev;
>> + struct nvmem_cell *cell;
>> + u32 *buf;
>> + size_t len;
>> +
>> + cell = nvmem_cell_get(dev, "dp_calibration_data");
>> + if (IS_ERR(cell)) {
>> + dev_err(dev,
>> + "Error: Failed to get nvmem cell
>> dp_calibration_data\n");
>> + return PTR_ERR(cell);
>> + }
>> +
>> + buf = (u32 *)nvmem_cell_read(cell, &len);
>> + nvmem_cell_put(cell);
>> +
>> + if (IS_ERR(buf) || ((len / sizeof(u32)) != 4)) {
>> + dev_err(dev,
>> + "Error: Failed to read nvmem_cell_read fail len
>> %ld\n",
>> + (len / sizeof(u32)));
>> + return PTR_ERR(buf);
>> + }
>> +
>> + cal_data->glb_bias_trim =
>> + check_cal_data_valid(1, 0x1e, (buf[3] >> 27) & 0x1f,
>> 0xf);
>> + cal_data->clktx_impse =
>> + check_cal_data_valid(1, 0xe, (buf[0] >> 9) & 0xf, 0x8);
>> + cal_data->ln_tx_impsel_pmos[0] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 28) & 0xf,
>> 0x8);
>> + cal_data->ln_tx_impsel_nmos[0] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 24) & 0xf,
>> 0x8);
>> + cal_data->ln_tx_impsel_pmos[1] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 20) & 0xf,
>> 0x8);
>> + cal_data->ln_tx_impsel_nmos[1] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 16) & 0xf,
>> 0x8);
>> + cal_data->ln_tx_impsel_pmos[2] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 12) & 0xf,
>> 0x8);
>> + cal_data->ln_tx_impsel_nmos[2] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 8) & 0xf, 0x8);
>> + cal_data->ln_tx_impsel_pmos[3] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 4) & 0xf, 0x8);
>> + cal_data->ln_tx_impsel_nmos[3] =
>> + check_cal_data_valid(1, 0xe, buf[2] & 0xf, 0x8);
>> +
>> + kfree(buf);
>> +
>> + return 0;
>> +}
>> +
>> +static int mtk_dp_set_cal_data(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> + struct dp_cal_data *cal_data = &mtk_dp->cal_data;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_GLB_DPAUX_TX,
>> + cal_data->clktx_impse << 20,
>> RG_CKM_PT0_CKTX_IMPSEL, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_GLB_BIAS_GEN_00,
>> + cal_data->glb_bias_trim << 16,
>> + RG_XTP_GLB_BIAS_INTR_CTRL, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_0,
>> + cal_data->ln_tx_impsel_pmos[0] << 12,
>> + RG_XTP_LN0_TX_IMPSEL_PMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_0,
>> + cal_data->ln_tx_impsel_nmos[0] << 16,
>> + RG_XTP_LN0_TX_IMPSEL_NMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_1,
>> + cal_data->ln_tx_impsel_pmos[1] << 12,
>> + RG_XTP_LN1_TX_IMPSEL_PMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_1,
>> + cal_data->ln_tx_impsel_nmos[1] << 16,
>> + RG_XTP_LN1_TX_IMPSEL_NMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_2,
>> + cal_data->ln_tx_impsel_pmos[2] << 12,
>> + RG_XTP_LN2_TX_IMPSEL_PMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_2,
>> + cal_data->ln_tx_impsel_nmos[2] << 16,
>> + RG_XTP_LN2_TX_IMPSEL_NMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_3,
>> + cal_data->ln_tx_impsel_pmos[3] << 12,
>> + RG_XTP_LN3_TX_IMPSEL_PMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_3,
>> + cal_data->ln_tx_impsel_nmos[3] << 16,
>> + RG_XTP_LN3_TX_IMPSEL_NMOS, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_phy_configure(struct mtk_dp *mtk_dp,
>> + enum mtk_dp_linkrate link_rate, int
>> lane_count)
>> +{
>> + int ret;
>> + union phy_configure_opts phy_opts = {
>> + .dp = {
>> + .link_rate = link_rate_to_mb_per_s(mtk_dp,
>> link_rate),
>> + .set_rate = 1,
>> + .lanes = lane_count,
>> + .set_lanes = 1,
>> + .ssc = mtk_dp->train_info.sink_ssc,
>> + }
>> + };
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_PWR_STATE,
>> DP_PWR_STATE_BANDGAP,
>> + DP_PWR_STATE_MASK, ret, out);
>> +
>> + ret = phy_configure(mtk_dp->phy, &phy_opts);
>> +
>> + if (ret)
>> + goto out;
>> +
>> + mtk_dp_set_cal_data(mtk_dp);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_PWR_STATE,
>> + DP_PWR_STATE_BANDGAP_TPLL_LANE,
>> DP_PWR_STATE_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_set_idle_pattern(struct mtk_dp *mtk_dp, bool
>> enable)
>> +{
>> + const u32 val = POST_MISC_DATA_LANE0_OV_DP_TRANS_P0_MASK |
>> + POST_MISC_DATA_LANE1_OV_DP_TRANS_P0_MASK |
>> + POST_MISC_DATA_LANE2_OV_DP_TRANS_P0_MASK |
>> + POST_MISC_DATA_LANE3_OV_DP_TRANS_P0_MASK;
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3580, enable
>> ? val : 0, val);
>> +}
>> +
>> +//TODO: check return value in callee
>> +static int mtk_dp_train_set_pattern(struct mtk_dp *mtk_dp, int
>> pattern)
>
>maybe we can use uint8 pattern.
>So that we don't need to check the value is < 0.
Yes... and the pattern value is entirely controled within this driver anyway.
>
>> +{
>> + if (pattern < 0 || pattern > 4) {
>> + drm_err(mtk_dp->drm_dev,
>> + "Implementation error, no such pattern %d\n",
>> pattern);
>> + return -EINVAL;
>> + }
>> +
>> + if (pattern == 1) /* TPS1 */
>> + mtk_dp_set_idle_pattern(mtk_dp, false);
>> +
>> + return mtk_dp_update_bits(mtk_dp,
>> + MTK_DP_TRANS_P0_3400,
>> + pattern ? BIT(pattern - 1) <<
>> PATTERN1_EN_DP_TRANS_P0_SHIFT : 0,
>> + PATTERN1_EN_DP_TRANS_P0_MASK |
>> PATTERN2_EN_DP_TRANS_P0_MASK |
>> + PATTERN3_EN_DP_TRANS_P0_MASK |
>> + PATTERN4_EN_DP_TRANS_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_set_enhanced_frame_mode(struct mtk_dp *mtk_dp,
>> bool enable)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000,
>> + enable ?
>> BIT(ENHANCED_FRAME_EN_DP_ENC0_P0_SHIFT) : 0,
>> + ENHANCED_FRAME_EN_DP_ENC0_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_training_set_scramble(struct mtk_dp *mtk_dp, bool
>> enable)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3404,
>> + enable ? DP_SCR_EN_DP_TRANS_P0_MASK : 0,
>> + DP_SCR_EN_DP_TRANS_P0_MASK);
>> +}
>> +
>> +static void mtk_dp_video_mute(struct mtk_dp *mtk_dp, bool enable)
>> +{
>> + u32 val = BIT(VIDEO_MUTE_SEL_DP_ENC0_P0_SHIFT);
>> +
>> + if (enable)
>> + val |= BIT(VIDEO_MUTE_SW_DP_ENC0_P0_SHIFT);
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000, val,
>> + VIDEO_MUTE_SEL_DP_ENC0_P0_MASK |
>> + VIDEO_MUTE_SW_DP_ENC0_P0_MASK);
>> +
>> + mtk_dp_sip_atf_call(MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE, enable);
>> +}
>> +
>> +static int mtk_dp_power_enable(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE, 0,
>> + SW_RST_B_PHYD, ret, out);
>> + usleep_range(10, 200);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE,
>> SW_RST_B_PHYD,
>> + SW_RST_B_PHYD, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_PWR_STATE,
>> + DP_PWR_STATE_BANDGAP_TPLL,
>> + DP_PWR_STATE_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_power_disable(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + ret = mtk_dp_write(mtk_dp, MTK_DP_TOP_PWR_STATE, 0);
>> +
>> + if (ret)
>> + goto out;
>> +
>> + usleep_range(10, 200);
>> + ret = mtk_dp_write(mtk_dp, MTK_DP_0034,
>> + DA_CKM_CKTX0_EN_FORCE_EN |
>> DA_CKM_BIAS_LPF_EN_FORCE_VAL |
>> + DA_CKM_BIAS_EN_FORCE_VAL |
>> + DA_XTP_GLB_LDO_EN_FORCE_VAL |
>> + DA_XTP_GLB_AVD10_ON_FORCE_VAL);
>> +
>> + if (ret)
>> + goto out;
>> +
>> + /* Disable RX */
>> + ret = mtk_dp_write(mtk_dp, MTK_DP_1040, 0);
>> +
>> + if (ret)
>> + goto out;
>> +
>> + ret = mtk_dp_write(mtk_dp, MTK_DP_TOP_MEM_PD,
>> + 0x550 | BIT(FUSE_SEL_SHIFT) |
>> BIT(MEM_ISO_EN_SHIFT));
>> +
>> +out:
>> + return ret;
>
>If we don't do anything special here, I think we can return directly
>and no need "out" label.
Yes, I'll remove the un-needed labels whenever there's no unwraping to be done.
>
>> +}
>> +
>> +static void mtk_dp_initialize_priv_data(struct mtk_dp *mtk_dp)
>> +{
>> + mtk_dp->train_info.link_rate = MTK_DP_LINKRATE_HBR2;
>> + mtk_dp->train_info.lane_count = MTK_DP_MAX_LANES;
>> + mtk_dp->train_info.irq_status = 0;
>> + mtk_dp->train_info.cable_plugged_in = false;
>> + mtk_dp->train_info.cable_state_change = false;
>> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_STARTUP;
>> + mtk_dp->state = MTK_DP_STATE_INITIAL;
>> +
>> + mtk_dp->info.format = MTK_DP_COLOR_FORMAT_RGB_444;
>> + mtk_dp->info.depth = MTK_DP_COLOR_DEPTH_8BIT;
>> + memset(&mtk_dp->info.timings, 0, sizeof(struct
>> mtk_dp_timings));
>
>maybe re-order this.
Will do.
>
>> + mtk_dp->info.timings.frame_rate = 60;
>> +
>> + mtk_dp->has_fec = false;
>> +}
>> +
>> +static void mtk_dp_setup_tu(struct mtk_dp *mtk_dp)
>> +{
>> + u32 sram_read_start = MTK_DP_TBC_BUF_READ_START_ADDR;
>> +
>> + if (mtk_dp->train_info.lane_count > 0) {
>> + sram_read_start = min_t(u32,
>> + MTK_DP_TBC_BUF_READ_START_ADDR,
>> + mtk_dp->info.timings.vm.hactive
>> /
>> + (mtk_dp->train_info.lane_count
>> * 4 * 2 * 2));
>
>This is something magic number..
>I think we should add some comments here.
>
Will do.
>> + mtk_dp_set_sram_read_start(mtk_dp, sram_read_start);
>> + }
>> +
>> + mtk_dp_setup_encoder(mtk_dp);
>> +}
>> +
>> +static void mtk_dp_calculate_pixrate(struct mtk_dp *mtk_dp)
>> +{
>> + int target_frame_rate = 60;
>> + int target_pixel_clk;
>> +
>> + if (mtk_dp->info.timings.frame_rate > 0) {
>> + target_frame_rate = mtk_dp->info.timings.frame_rate;
>> + target_pixel_clk = (int)mtk_dp->info.timings.htotal *
>> + (int)mtk_dp->info.timings.vtotal *
>> + target_frame_rate;
>
>I think target_pixel_clk should be always >= 0?
>Can we use u32 for target_pixel_clk?
Yes, I don't see how any of the calculations could get us a negative pixel_clk.
>
>> + } else if (mtk_dp->info.timings.pix_rate_khz > 0) {
>> + target_pixel_clk = mtk_dp->info.timings.pix_rate_khz *
>> 1000;
>> + } else {
>> + target_pixel_clk = (int)mtk_dp->info.timings.htotal *
>> + (int)mtk_dp->info.timings.vtotal *
>> + target_frame_rate;
>> + }
>> +
>> + if (target_pixel_clk > 0)
>> + mtk_dp->info.timings.pix_rate_khz = target_pixel_clk /
>> 1000;
>> +}
>> +
>> +static void mtk_dp_set_tx_out(struct mtk_dp *mtk_dp)
>> +{
>> + mtk_dp_msa_bypass_disable(mtk_dp);
>> + mtk_dp_calculate_pixrate(mtk_dp);
>> + mtk_dp_pg_disable(mtk_dp);
>> + mtk_dp_setup_tu(mtk_dp);
>> +}
>> +
>> +static void mtk_dp_train_update_swing_pre(struct mtk_dp *mtk_dp, int
>> lanes,
>> + u8 dpcd_adjust_req[2])
>> +{
>> + int lane;
>> +
>> + for (lane = 0; lane < lanes; ++lane) {
>> + u8 val;
>> + u8 swing;
>> + u8 preemphasis;
>> + int index = lane / 2;
>> + int shift = lane % 2 ?
>> DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : 0;
>> +
>> + swing = (dpcd_adjust_req[index] >> shift) &
>> + DP_ADJUST_VOLTAGE_SWING_LANE0_MASK;
>> + preemphasis = ((dpcd_adjust_req[index] >> shift) &
>> + DP_ADJUST_PRE_EMPHASIS_LANE0_MASK) >>
>> + DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT;
>> + val = swing << DP_TRAIN_VOLTAGE_SWING_SHIFT |
>> + preemphasis << DP_TRAIN_PRE_EMPHASIS_SHIFT;
>> +
>> + if (swing == DP_TRAIN_VOLTAGE_SWING_LEVEL_3)
>> + val |= DP_TRAIN_MAX_SWING_REACHED;
>> + if (preemphasis == 3)
>> + val |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
>> +
>> + mtk_dp_set_swing_pre_emphasis(mtk_dp, lane, swing,
>> preemphasis);
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_TRAINING_LANE0_SET
>> + lane,
>> + val);
>> + }
>> +
>> + /* Wait for the signal to be stable enough */
>> + usleep_range(2000, 5000);
>> +}
>> +
>> +static void mtk_dp_read_link_status(struct mtk_dp *mtk_dp,
>> + u8
>> link_status[DP_LINK_STATUS_SIZE])
>> +{
>> + drm_dp_dpcd_read(&mtk_dp->aux, DP_LANE0_1_STATUS, link_status,
>> + DP_LINK_STATUS_SIZE);
>> +}
>> +
>> +static int mtk_dp_train_flow(struct mtk_dp *mtk_dp, int
>> target_link_rate,
>> + int target_lane_count)
>
>hmm..
>This function is too complicated.
>I think you can refer to this drivers in coreboot
>I have modified this before...
>
>
>https://review.coreboot.org/plugins/gitiles/coreboot/+/refs/heads/master/src/soc/mediatek/mt8195/dptx.c#770
>
Thx for the hints.
>> +{
>> + u8 link_status[DP_LINK_STATUS_SIZE] = {};
>> + u8 lane_adjust[2] = {};
>> + bool pass_tps1 = false;
>> + bool pass_tps2_3 = false;
>> + int train_retries;
>> + int status_control;
>> + int iteration_count;
>> + u8 prev_lane_adjust;
>> + u8 val;
>> +
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_LINK_BW_SET,
>> target_link_rate);
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_LANE_COUNT_SET,
>> + target_lane_count |
>> DP_LANE_COUNT_ENHANCED_FRAME_EN);
>> +
>> + if (mtk_dp->train_info.sink_ssc)
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_DOWNSPREAD_CTRL,
>> + DP_SPREAD_AMP_0_5);
>> +
>> + train_retries = 0;
>> + status_control = 0;
>> + iteration_count = 1;
>> + prev_lane_adjust = 0xFF;
>> +
>> + mtk_dp_set_lanes(mtk_dp, target_lane_count / 2);
>> + mtk_dp_phy_configure(mtk_dp, target_link_rate,
>> target_lane_count);
>> +
>> + dev_dbg(mtk_dp->dev,
>> + "Link train target_link_rate = 0x%x, target_lane_count
>> = 0x%x\n",
>> + target_link_rate, target_lane_count);
>> +
>> + do {
>> + train_retries++;
>> + if (!mtk_dp->train_info.cable_plugged_in ||
>> + ((mtk_dp->train_info.irq_status &
>> MTK_DP_HPD_DISCONNECT) !=
>> + 0x0)) {
>> + return -ENODEV;
>> + }
>> +
>> + if (mtk_dp->train_state < MTK_DP_TRAIN_STATE_TRAINING)
>> + return -EAGAIN;
>> +
>> + if (!pass_tps1) {
>> + mtk_dp_training_set_scramble(mtk_dp, false);
>> +
>> + if (status_control == 0) {
>> + status_control = 1;
>> + mtk_dp_train_set_pattern(mtk_dp, 1);
>> + val = DP_LINK_SCRAMBLING_DISABLE |
>> + DP_TRAINING_PATTERN_1;
>> + drm_dp_dpcd_writeb(&mtk_dp->aux,
>> + DP_TRAINING_PATTERN_
>> SET,
>> + DP_LINK_SCRAMBLING_D
>> ISABLE |
>> + DP_TRAINING_PATTERN_
>> 1);
>> + drm_dp_dpcd_read(&mtk_dp->aux,
>> + DP_ADJUST_REQUEST_LANE
>> 0_1,
>> + lane_adjust,
>> + sizeof(lane_adjust));
>> + iteration_count++;
>> +
>> + mtk_dp_train_update_swing_pre(mtk_dp,
>> + target_la
>> ne_count, lane_adjust);
>> + }
>> +
>> + drm_dp_link_train_clock_recovery_delay(&mtk_dp-
>> >aux,
>> + mtk_dp-
>> >rx_cap);
>> + mtk_dp_read_link_status(mtk_dp, link_status);
>> +
>> + if (drm_dp_clock_recovery_ok(link_status,
>> + target_lane_count)
>> ) {
>> + mtk_dp->train_info.cr_done = true;
>> + pass_tps1 = true;
>> + train_retries = 0;
>> + iteration_count = 1;
>> + dev_dbg(mtk_dp->dev, "Link train CR
>> pass\n");
>> + } else if (prev_lane_adjust == link_status[4])
>> {
>> + iteration_count++;
>> + if (prev_lane_adjust &
>> + DP_ADJUST_VOLTAGE_SWING_LANE0_MASK)
>> + break;
>> + } else {
>> + prev_lane_adjust = link_status[4];
>> + }
>> + dev_dbg(mtk_dp->dev, "Link train CQ fail\n");
>> + } else if (pass_tps1 && !pass_tps2_3) {
>> + if (status_control == 1) {
>> + status_control = 2;
>> + if (mtk_dp->train_info.tps4) {
>> + mtk_dp_train_set_pattern(mtk_dp
>> , 4);
>> + val = DP_TRAINING_PATTERN_4;
>> + } else if (mtk_dp->train_info.tps3) {
>> + mtk_dp_train_set_pattern(mtk_dp
>> , 3);
>> + val =
>> DP_LINK_SCRAMBLING_DISABLE |
>> + DP_TRAINING_PATTERN_3;
>> + } else {
>> + mtk_dp_train_set_pattern(mtk_dp
>> , 2);
>> + val =
>> DP_LINK_SCRAMBLING_DISABLE |
>> + DP_TRAINING_PATTERN_2;
>> + }
>> + drm_dp_dpcd_writeb(&mtk_dp->aux,
>> + DP_TRAINING_PATTERN_
>> SET,
>> + val);
>> +
>> + drm_dp_dpcd_read(&mtk_dp->aux,
>> + DP_ADJUST_REQUEST_LANE
>> 0_1,
>> + lane_adjust,
>> + sizeof(lane_adjust));
>> +
>> + iteration_count++;
>> + mtk_dp_train_update_swing_pre(mtk_dp,
>> + target_la
>> ne_count, lane_adjust);
>> + }
>> +
>> + drm_dp_link_train_channel_eq_delay(&mtk_dp-
>> >aux,
>> + mtk_dp-
>> >rx_cap);
>> +
>> + mtk_dp_read_link_status(mtk_dp, link_status);
>> +
>> + if (!drm_dp_clock_recovery_ok(link_status,
>> + target_lane_count
>> )) {
>> + mtk_dp->train_info.cr_done = false;
>> + mtk_dp->train_info.eq_done = false;
>> + dev_dbg(mtk_dp->dev, "Link train EQ
>> fail\n");
>> + break;
>> + }
>> +
>> + if (drm_dp_channel_eq_ok(link_status,
>> + target_lane_count)) {
>> + mtk_dp->train_info.eq_done = true;
>> + pass_tps2_3 = true;
>> + dev_dbg(mtk_dp->dev, "Link train EQ
>> pass\n");
>> + break;
>> + }
>> +
>> + if (prev_lane_adjust == link_status[4])
>> + iteration_count++;
>> + else
>> + prev_lane_adjust = link_status[4];
>> + }
>> +
>> + drm_dp_dpcd_read(&mtk_dp->aux,
>> DP_ADJUST_REQUEST_LANE0_1,
>> + lane_adjust, sizeof(lane_adjust));
>> + mtk_dp_train_update_swing_pre(mtk_dp,
>> target_lane_count,
>> + lane_adjust);
>> + } while (train_retries < MTK_DP_TRAIN_RETRY_LIMIT &&
>> + iteration_count < MTK_DP_TRAIN_MAX_ITERATIONS);
>> +
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_TRAINING_PATTERN_SET,
>> + DP_TRAINING_PATTERN_DISABLE);
>> + mtk_dp_train_set_pattern(mtk_dp, 0);
>> +
>> + if (!pass_tps2_3)
>> + return -ETIMEDOUT;
>> +
>> + mtk_dp->train_info.link_rate = target_link_rate;
>> + mtk_dp->train_info.lane_count = target_lane_count;
>> +
>> + mtk_dp_training_set_scramble(mtk_dp, true);
>> +
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_LANE_COUNT_SET,
>> + target_lane_count |
>> + DP_LANE_COUNT_ENHANCED_FRAME_EN);
>> + mtk_dp_set_enhanced_frame_mode(mtk_dp, true);
>> +
>> + return 0;
>> +}
>>
>
>snip..
>
>> diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
>> b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
>> new file mode 100644
>> index 000000000000..c446eef18169
>> --- /dev/null
>> +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
>
>For mtk_dp_reg.h,
>1. I think it's no need to add parnethess for BIT().
>2. Use tab to alignment for readability.
>
Will do.
Thx for your review,
Guillaume.
>BRs,
>Rex
>
>> @@ -0,0 +1,568 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (c) 2019 MediaTek Inc.
>> + * Copyright (c) 2021 BayLibre
>> + */
>> +#ifndef _MTK_DP_REG_H_
>> +#define _MTK_DP_REG_H_
>> +
>> +#define MTK_DP_SIP_CONTROL_AARCH32 (BIT(0) | BIT(1) | BIT(5) |
>> BIT(8) | BIT(10) | BIT(25) | BIT(31))
>> +#define MTK_DP_SIP_ATF_VIDEO_UNMUTE (BIT(5))
>> +#define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE (BIT(0) | BIT(5))
>> +
>> +#define DP_PHY_GLB_BIAS_GEN_00 0
>> +#define RG_XTP_GLB_BIAS_INTR_CTRL GENMASK(20, 16)
>> +
>> +#define DP_PHY_GLB_DPAUX_TX (BIT(3))
>> +#define RG_CKM_PT0_CKTX_IMPSEL GENMASK(23, 20)
>> +
>> +#define DP_PHY_LANE_TX_0 (BIT(2) | BIT(8))
>> +#define RG_XTP_LN0_TX_IMPSEL_PMOS GENMASK(15, 12)
>> +#define RG_XTP_LN0_TX_IMPSEL_NMOS GENMASK(19, 16)
>> +
>> +#define DP_PHY_LANE_TX_1 (BIT(2) | BIT(9))
>> +#define RG_XTP_LN1_TX_IMPSEL_PMOS GENMASK(15, 12)
>> +#define RG_XTP_LN1_TX_IMPSEL_NMOS GENMASK(19, 16)
>> +
>> +#define DP_PHY_LANE_TX_2 (BIT(2) | BIT(8) | BIT(9))
>> +#define RG_XTP_LN2_TX_IMPSEL_PMOS GENMASK(15, 12)
>> +#define RG_XTP_LN2_TX_IMPSEL_NMOS GENMASK(19, 16)
>> +
>> +#define DP_PHY_LANE_TX_3 (BIT(2) | BIT(10))
>> +#define RG_XTP_LN3_TX_IMPSEL_PMOS GENMASK(15, 12)
>> +#define RG_XTP_LN3_TX_IMPSEL_NMOS GENMASK(19, 16)
>> +
>> +#define TOP_OFFSET (BIT(13))
>> +#define ENC0_OFFSET GENMASK(13, 12)
>> +#define ENC1_OFFSET (BIT(9) | BIT(12) | BIT(13))
>> +#define TRANS_OFFSET (BIT(10) | BIT(12) | BIT(13))
>> +#define AUX_OFFSET (BIT(9) | BIT(10) | BIT(12) | BIT(13))
>> +#define SEC_OFFSET (BIT(14))
>> +
>> +#define MTK_DP_HPD_DISCONNECT BIT(1)
>> +#define MTK_DP_HPD_CONNECT BIT(2)
>> +#define MTK_DP_HPD_INTERRUPT BIT(3)
>> +
>> +#define MTK_DP_0034 (BIT(2) | BIT(4) | BIT(5))
>> +#define DA_XTP_GLB_CKDET_EN_FORCE_VAL BIT(15)
>> +#define DA_XTP_GLB_CKDET_EN_FORCE_EN BIT(14)
>> +#define DA_CKM_INTCKTX_EN_FORCE_VAL BIT(13)
>> +#define DA_CKM_INTCKTX_EN_FORCE_EN BIT(12)
>> +#define DA_CKM_CKTX0_EN_FORCE_VAL BIT(11)
>> +#define DA_CKM_CKTX0_EN_FORCE_EN BIT(10)
>> +#define DA_CKM_XTAL_CK_FORCE_VAL BIT(9)
>> +#define DA_CKM_XTAL_CK_FORCE_EN BIT(8)
>> +#define DA_CKM_BIAS_LPF_EN_FORCE_VAL BIT(7)
>> +#define DA_CKM_BIAS_LPF_EN_FORCE_EN BIT(6)
>> +#define DA_CKM_BIAS_EN_FORCE_VAL BIT(5)
>> +#define DA_CKM_BIAS_EN_FORCE_EN BIT(4)
>> +#define DA_XTP_GLB_AVD10_ON_FORCE_VAL BIT(3)
>> +#define DA_XTP_GLB_AVD10_ON_FORCE BIT(2)
>> +#define DA_XTP_GLB_LDO_EN_FORCE_VAL BIT(1)
>> +#define DA_XTP_GLB_LDO_EN_FORCE_EN BIT(0)
>> +
>> +#define MTK_DP_1040 (BIT(6) | BIT(12))
>> +#define RG_DPAUX_RX_VALID_DEGLITCH_EN BIT(2)
>> +#define RG_XTP_GLB_CKDET_EN BIT(1)
>> +#define RG_DPAUX_RX_EN BIT(0)
>> +
>> +#define MTK_DP_ENC0_P0_3000 (ENC0_OFFSET + 0x00)
>> +#define LANE_NUM_DP_ENC0_P0_MASK GENMASK(1, 0)
>> +#define VIDEO_MUTE_SW_DP_ENC0_P0_MASK (BIT(2))
>> +#define VIDEO_MUTE_SW_DP_ENC0_P0_SHIFT (BIT(1))
>> +#define VIDEO_MUTE_SEL_DP_ENC0_P0_MASK (BIT(3))
>> +#define VIDEO_MUTE_SEL_DP_ENC0_P0_SHIFT GENMASK(1, 0)
>> +#define ENHANCED_FRAME_EN_DP_ENC0_P0_MASK (BIT(4))
>> +#define ENHANCED_FRAME_EN_DP_ENC0_P0_SHIFT (BIT(2))
>> +
>> +#define MTK_DP_ENC0_P0_3004 (ENC0_OFFSET + 0x04)
>> +#define VIDEO_M_CODE_SEL_DP_ENC0_P0_MASK (BIT(8))
>> +#define VIDEO_M_CODE_SEL_DP_ENC0_P0_SHIFT (BIT(3))
>> +#define DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_MASK (BIT(9))
>> +#define DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_SHIFT (BIT(0) | BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_3008 (ENC0_OFFSET + 0x08)
>> +#define VIDEO_M_CODE_SW_0_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_300C (ENC0_OFFSET + 0x0C)
>> +#define VIDEO_M_CODE_SW_1_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3010 (ENC0_OFFSET + 0x10)
>> +#define HTOTAL_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3014 (ENC0_OFFSET + 0x14)
>> +#define VTOTAL_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3018 (ENC0_OFFSET + 0x18)
>> +#define HSTART_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_301C (ENC0_OFFSET + 0x1C)
>> +#define VSTART_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3020 (ENC0_OFFSET + 0x20)
>> +#define HWIDTH_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3024 (ENC0_OFFSET + 0x24)
>> +#define VHEIGHT_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3028 (ENC0_OFFSET + 0x28)
>> +#define HSW_SW_DP_ENC0_P0_MASK GENMASK(14, 0)
>> +#define HSW_SW_DP_ENC0_P0_SHIFT 0
>> +#define HSP_SW_DP_ENC0_P0_MASK (BIT(15))
>> +
>> +#define MTK_DP_ENC0_P0_302C (ENC0_OFFSET + 0x2C)
>> +#define VSW_SW_DP_ENC0_P0_MASK GENMASK(14, 0)
>> +#define VSW_SW_DP_ENC0_P0_SHIFT 0
>> +#define VSP_SW_DP_ENC0_P0_MASK (BIT(15))
>> +
>> +#define MTK_DP_ENC0_P0_3030 (ENC0_OFFSET + 0x30)
>> +#define HTOTAL_SEL_DP_ENC0_P0_SHIFT 0
>> +#define VTOTAL_SEL_DP_ENC0_P0_SHIFT (BIT(0))
>> +#define HSTART_SEL_DP_ENC0_P0_SHIFT (BIT(1))
>> +#define VSTART_SEL_DP_ENC0_P0_SHIFT GENMASK(1, 0)
>> +#define HWIDTH_SEL_DP_ENC0_P0_SHIFT (BIT(2))
>> +#define VHEIGHT_SEL_DP_ENC0_P0_SHIFT (BIT(0) | BIT(2))
>> +#define HSP_SEL_DP_ENC0_P0_SHIFT GENMASK(2, 1)
>> +#define HSW_SEL_DP_ENC0_P0_SHIFT GENMASK(2, 0)
>> +#define VSP_SEL_DP_ENC0_P0_SHIFT (BIT(3))
>> +#define VSW_SEL_DP_ENC0_P0_SHIFT (BIT(0) | BIT(3))
>> +#define VBID_AUDIO_MUTE_FLAG_SW_DP_ENC0_P0_MASK (BIT(11))
>> +#define VBID_AUDIO_MUTE_SW_DP_ENC0_P0_SHIFT (BIT(0) | BIT(1) |
>> BIT(3))
>> +#define VBID_AUDIO_MUTE_FLAG_SEL_DP_ENC0_P0_MASK (BIT(12))
>> +#define VBID_AUDIO_MUTE_SEL_DP_ENC0_P0_SHIFT GENMASK(3, 2)
>> +
>> +#define MTK_DP_ENC0_P0_3034 (ENC0_OFFSET + 0x34)
>> +
>> +#define MTK_DP_ENC0_P0_3038 (ENC0_OFFSET + 0x38)
>> +#define VIDEO_SOURCE_SEL_DP_ENC0_P0_MASK (BIT(11))
>> +#define VIDEO_SOURCE_SEL_DP_ENC0_P0_SHIFT (BIT(0) | BIT(1) | BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_303C (ENC0_OFFSET + 0x3C)
>> +#define SRAM_START_READ_THRD_DP_ENC0_P0_MASK GENMASK(5, 0)
>> +#define SRAM_START_READ_THRD_DP_ENC0_P0_SHIFT 0
>> +#define VIDEO_COLOR_DEPTH_DP_ENC0_P0_MASK GENMASK(10, 8)
>> +#define VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT (BIT(3))
>> +#define
>> VIDEO_COLOR_DEPTH_DP_ENC0_P0_16BIT
>> \
>> + (0 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
>> +#define
>> VIDEO_COLOR_DEPTH_DP_ENC0_P0_12BIT
>> \
>> + (1 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
>> +#define
>> VIDEO_COLOR_DEPTH_DP_ENC0_P0_10BIT
>> \
>> + (2 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
>> +#define
>> VIDEO_COLOR_DEPTH_DP_ENC0_P0_8BIT
>> \
>> + (3 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
>> +#define
>> VIDEO_COLOR_DEPTH_DP_ENC0_P0_6BIT
>> \
>> + (4 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
>> +#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK GENMASK(14, 12)
>> +#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_SHIFT GENMASK(3, 2)
>> +#define
>> PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB
>> \
>> + (0 << PIXEL_ENCODE_FORMAT_DP_ENC0_P0_SHIFT)
>> +#define
>> PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422
>> \
>> + (1 << PIXEL_ENCODE_FORMAT_DP_ENC0_P0_SHIFT)
>> +#define
>> PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR420
>> \
>> + (2 << PIXEL_ENCODE_FORMAT_DP_ENC0_P0_SHIFT)
>> +#define VIDEO_MN_GEN_EN_DP_ENC0_P0_MASK (BIT(15))
>> +#define VIDEO_MN_GEN_EN_DP_ENC0_P0_SHIFT GENMASK(3, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3040 (ENC0_OFFSET + 0x40)
>> +#define SDP_DOWN_CNT_INIT_DP_ENC0_P0_MASK GENMASK(11, 0)
>> +#define SDP_DOWN_CNT_INIT_DP_ENC0_P0_SHIFT 0
>> +
>> +#define MTK_DP_ENC0_P0_3044 (ENC0_OFFSET + 0x44)
>> +#define VIDEO_N_CODE_0_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3048 (ENC0_OFFSET + 0x48)
>> +#define VIDEO_N_CODE_1_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +
>> +#define MTK_DP_ENC0_P0_304C (ENC0_OFFSET + 0x4C)
>> +#define VBID_VIDEO_MUTE_DP_ENC0_P0_MASK (BIT(2))
>> +#define SDP_VSYNC_RISING_MASK_DP_ENC0_P0_MASK (BIT(8))
>> +
>> +#define MTK_DP_ENC0_P0_3050 (ENC0_OFFSET + 0x50)
>> +#define VIDEO_N_CODE_MN_GEN_0_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3054 (ENC0_OFFSET + 0x54)
>> +#define VIDEO_N_CODE_MN_GEN_1_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3064 (ENC0_OFFSET + 0x64)
>> +#define HDE_NUM_LAST_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3088 (ENC0_OFFSET + 0x88)
>> +#define AU_EN_DP_ENC0_P0_MASK (BIT(6))
>> +#define AU_EN_DP_ENC0_P0_SHIFT GENMASK(2, 1)
>> +#define AUDIO_8CH_EN_DP_ENC0_P0_MASK (BIT(7))
>> +#define AUDIO_8CH_SEL_DP_ENC0_P0_MASK (BIT(8))
>> +#define AUDIO_2CH_EN_DP_ENC0_P0_MASK (BIT(14))
>> +#define AUDIO_2CH_SEL_DP_ENC0_P0_MASK (BIT(15))
>> +
>> +#define MTK_DP_ENC0_P0_308C (ENC0_OFFSET + 0x8C)
>> +#define CH_STATUS_0_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3090 (ENC0_OFFSET + 0x90)
>> +#define CH_STATUS_1_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3094 (ENC0_OFFSET + 0x94)
>> +#define CH_STATUS_2_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +
>> +#define MTK_DP_ENC0_P0_30A0 (ENC0_OFFSET + 0xA0)
>> +
>> +#define MTK_DP_ENC0_P0_30A4 (ENC0_OFFSET + 0xA4)
>> +#define AU_TS_CFG_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +
>> +#define MTK_DP_ENC0_P0_30A8 (ENC0_OFFSET + 0xA8)
>> +
>> +#define MTK_DP_ENC0_P0_30AC (ENC0_OFFSET + 0xAC)
>> +
>> +#define MTK_DP_ENC0_P0_30B0 (ENC0_OFFSET + 0xB0)
>> +
>> +#define MTK_DP_ENC0_P0_30B4 (ENC0_OFFSET + 0xB4)
>> +#define ISRC_CFG_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +#define ISRC_CFG_DP_ENC0_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_30B8 (ENC0_OFFSET + 0xB8)
>> +
>> +#define MTK_DP_ENC0_P0_30BC (ENC0_OFFSET + 0xBC)
>> +#define ISRC_CONT_DP_ENC0_P0_MASK (BIT(0))
>> +#define ISRC_CONT_DP_ENC0_P0_SHIFT 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_SHIFT (BIT(3))
>> +#define
>> AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_2
>> \
>> + (1 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
>> +#define
>> AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_4
>> \
>> + (2 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
>> +#define
>> AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_8
>> \
>> + (3 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
>> +#define
>> AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2
>> \
>> + (5 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
>> +#define
>> AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_4
>> \
>> + (6 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
>> +#define
>> AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_8
>> \
>> + (7 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
>> +
>> +#define MTK_DP_ENC0_P0_30D8 (ENC0_OFFSET + 0xD8)
>> +
>> +#define MTK_DP_ENC0_P0_312C (ENC0_OFFSET + 0x12C)
>> +#define ASP_HB2_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +#define ASP_HB3_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +#define ASP_HB3_DP_ENC0_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_3130 (ENC0_OFFSET + 0x130)
>> +
>> +#define MTK_DP_ENC0_P0_3138 (ENC0_OFFSET + 0x138)
>> +
>> +#define MTK_DP_ENC0_P0_3154 (ENC0_OFFSET + 0x154)
>> +#define PGEN_HTOTAL_DP_ENC0_P0_MASK GENMASK(13, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3158 (ENC0_OFFSET + 0x158)
>> +#define PGEN_HSYNC_RISING_DP_ENC0_P0_MASK GENMASK(13, 0)
>> +
>> +#define MTK_DP_ENC0_P0_315C (ENC0_OFFSET + 0x15C)
>> +#define PGEN_HSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK GENMASK(13, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3160 (ENC0_OFFSET + 0x160)
>> +#define PGEN_HFDE_START_DP_ENC0_P0_MASK GENMASK(13, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3164 (ENC0_OFFSET + 0x164)
>> +#define PGEN_HFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK GENMASK(13, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3168 (ENC0_OFFSET + 0x168)
>> +#define PGEN_VTOTAL_DP_ENC0_P0_MASK GENMASK(12, 0)
>> +
>> +#define MTK_DP_ENC0_P0_316C (ENC0_OFFSET + 0x16C)
>> +#define PGEN_VSYNC_RISING_DP_ENC0_P0_MASK GENMASK(12, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3170 (ENC0_OFFSET + 0x170)
>> +#define PGEN_VSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK GENMASK(12, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3174 (ENC0_OFFSET + 0x174)
>> +#define PGEN_VFDE_START_DP_ENC0_P0_MASK GENMASK(12, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3178 (ENC0_OFFSET + 0x178)
>> +#define PGEN_VFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK GENMASK(12, 0)
>> +
>> +#define MTK_DP_ENC0_P0_31B0 (ENC0_OFFSET + 0x1B0)
>> +#define PGEN_PATTERN_SEL_SHIFT (BIT(2))
>> +#define PGEN_PATTERN_SEL_MASK GENMASK(6, 4)
>> +
>> +#define MTK_DP_ENC0_P0_31C8 (ENC0_OFFSET + 0x1C8)
>> +#define VSC_EXT_VESA_HB0_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +#define VSC_EXT_VESA_HB1_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +#define VSC_EXT_VESA_HB1_DP_ENC0_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_31CC (ENC0_OFFSET + 0x1CC)
>> +#define VSC_EXT_VESA_HB2_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +#define VSC_EXT_VESA_HB2_DP_ENC0_P0_SHIFT 0
>> +#define VSC_EXT_VESA_HB3_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +
>> +#define MTK_DP_ENC0_P0_31D0 (ENC0_OFFSET + 0x1D0)
>> +#define VSC_EXT_CEA_HB0_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +#define VSC_EXT_CEA_HB1_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +#define VSC_EXT_CEA_HB1_DP_ENC0_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_31D4 (ENC0_OFFSET + 0x1D4)
>> +#define VSC_EXT_CEA_HB2_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +#define VSC_EXT_CEA_HB2_DP_ENC0_P0_SHIFT 0
>> +#define VSC_EXT_CEA_HB3_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +
>> +#define MTK_DP_ENC0_P0_31D8 (ENC0_OFFSET + 0x1D8)
>> +#define VSC_EXT_VESA_NUM_DP_ENC0_P0_MASK GENMASK(5, 0)
>> +#define VSC_EXT_VESA_NUM_DP_ENC0_P0_SHIFT 0
>> +#define VSC_EXT_CEA_NUM_DP_ENC0_P0_MASK GENMASK(13, 8)
>> +#define VSC_EXT_CEA_NUM_DP_ENC0_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_31DC (ENC0_OFFSET + 0x1DC)
>> +#define HDR0_CFG_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +#define HDR0_CFG_DP_ENC0_P0_SHIFT 0
>> +
>> +#define MTK_DP_ENC0_P0_31E8 (ENC0_OFFSET + 0x1E8)
>> +
>> +#define MTK_DP_ENC0_P0_31EC (ENC0_OFFSET + 0x1EC)
>> +#define AUDIO_CH_SRC_SEL_DP_ENC0_P0_MASK (BIT(4))
>> +#define AUDIO_CH_SRC_SEL_DP_ENC0_P0_SHIFT (BIT(2))
>> +#define ISRC1_HB3_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +#define ISRC1_HB3_DP_ENC0_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC1_P0_3200 (ENC1_OFFSET + 0x00)
>> +
>> +#define MTK_DP_ENC1_P0_3280 (ENC1_OFFSET + 0x80)
>> +#define SDP_PACKET_TYPE_DP_ENC1_P0_MASK GENMASK(4, 0)
>> +#define SDP_PACKET_W_DP_ENC1_P0 (BIT(5))
>> +#define SDP_PACKET_W_DP_ENC1_P0_MASK (BIT(5))
>> +#define SDP_PACKET_W_DP_ENC1_P0_SHIFT (BIT(0) | BIT(2))
>> +
>> +#define MTK_DP_ENC1_P0_328C (ENC1_OFFSET + 0x8C)
>> +
>> +#define MTK_DP_ENC1_P0_3290 (ENC1_OFFSET + 0x90)
>> +
>> +#define MTK_DP_ENC1_P0_32A0 (ENC1_OFFSET + 0xA0)
>> +
>> +#define MTK_DP_ENC1_P0_32A4 (ENC1_OFFSET + 0xA4)
>> +
>> +#define MTK_DP_ENC1_P0_3300 (ENC1_OFFSET + 0x100)
>> +#define VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_MASK GENMASK(9, 8)
>> +#define VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC1_P0_3304 (ENC1_OFFSET + 0x104)
>> +#define AU_PRTY_REGEN_DP_ENC1_P0_MASK (BIT(8))
>> +#define AU_CH_STS_REGEN_DP_ENC1_P0_MASK (BIT(9))
>> +#define AUDIO_SAMPLE_PRSENT_REGEN_DP_ENC1_P0_MASK (BIT(12))
>> +
>> +#define MTK_DP_ENC1_P0_3324 (ENC1_OFFSET + 0x124)
>> +#define AUDIO_SOURCE_MUX_DP_ENC1_P0_MASK GENMASK(9, 8)
>> +#define AUDIO_SOURCE_MUX_DP_ENC1_P0_SHIFT (BIT(3))
>> +#define
>> AUDIO_SOURCE_MUX_DP_ENC1_P0_DPRX
>> \
>> + (0 << AUDIO_SOURCE_MUX_DP_ENC1_P0_SHIFT)
>> +
>> +#define MTK_DP_ENC1_P0_3364 (ENC1_OFFSET + 0x164)
>> +#define SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_MASK GENMASK(11, 0)
>> +#define SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_SHIFT 0
>> +#define FIFO_READ_START_POINT_DP_ENC1_P0_MASK GENMASK(15, 12)
>> +#define FIFO_READ_START_POINT_DP_ENC1_P0_SHIFT GENMASK(3, 2)
>> +
>> +#define MTK_DP_ENC1_P0_3368 (ENC1_OFFSET + 0x168)
>> +#define VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0_SHIFT 0
>> +#define VIDEO_STABLE_CNT_THRD_DP_ENC1_P0_SHIFT (BIT(2))
>> +#define SDP_DP13_EN_DP_ENC1_P0_SHIFT (BIT(3))
>> +#define BS2BS_MODE_DP_ENC1_P0_MASK GENMASK(13, 12)
>> +#define BS2BS_MODE_DP_ENC1_P0_SHIFT GENMASK(3, 2)
>> +
>> +#define MTK_DP_ENC1_P0_33F4 (ENC1_OFFSET + 0x1F4)
>> +
>> +#define MTK_DP_TRANS_P0_3400 (TRANS_OFFSET + 0)
>> +#define PATTERN1_EN_DP_TRANS_P0_MASK (BIT(12))
>> +#define PATTERN1_EN_DP_TRANS_P0_SHIFT GENMASK(3, 2)
>> +#define PATTERN2_EN_DP_TRANS_P0_MASK (BIT(13))
>> +#define PATTERN3_EN_DP_TRANS_P0_MASK (BIT(14))
>> +#define PATTERN4_EN_DP_TRANS_P0_MASK (BIT(15))
>> +
>> +#define MTK_DP_TRANS_P0_3404 (TRANS_OFFSET + 0x4)
>> +#define DP_SCR_EN_DP_TRANS_P0_MASK (BIT(0))
>> +
>> +#define MTK_DP_TRANS_P0_340C (TRANS_OFFSET + 0xC)
>> +#define DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_MASK (BIT(13))
>> +#define DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_SHIFT (BIT(0) |
>> BIT(2) | BIT(3))
>> +
>> +#define MTK_DP_TRANS_P0_3410 (TRANS_OFFSET + 0x10)
>> +#define HPD_DEB_THD_DP_TRANS_P0_MASK GENMASK(3, 0)
>> +#define HPD_DEB_THD_DP_TRANS_P0_SHIFT 0
>> +#define HPD_INT_THD_DP_TRANS_P0_MASK GENMASK(7, 4)
>> +#define HPD_INT_THD_DP_TRANS_P0_SHIFT (BIT(2))
>> +#define HPD_INT_THD_DP_TRANS_P0_LOWER_500US (2 <<
>> HPD_INT_THD_DP_TRANS_P0_SHIFT)
>> +#define
>> HPD_INT_THD_DP_TRANS_P0_UPPER_1100US
>> \
>> + (2 << (HPD_INT_THD_DP_TRANS_P0_SHIFT + 2))
>> +#define HPD_DISC_THD_DP_TRANS_P0_MASK GENMASK(11, 8)
>> +#define HPD_DISC_THD_DP_TRANS_P0_SHIFT (BIT(3))
>> +#define HPD_CONN_THD_DP_TRANS_P0_MASK GENMASK(15, 12)
>> +#define HPD_CONN_THD_DP_TRANS_P0_SHIFT GENMASK(3, 2)
>> +
>> +#define MTK_DP_TRANS_P0_3414 (TRANS_OFFSET + 0x14)
>> +#define HPD_DB_DP_TRANS_P0_MASK (BIT(2))
>> +
>> +#define MTK_DP_TRANS_P0_3418 (TRANS_OFFSET + 0x18)
>> +#define IRQ_CLR_DP_TRANS_P0_MASK GENMASK(3, 0)
>> +#define IRQ_MASK_DP_TRANS_P0_MASK GENMASK(7, 4)
>> +#define IRQ_MASK_DP_TRANS_P0_SHIFT (BIT(2))
>> +#define IRQ_MASK_DP_TRANS_P0_DISC_IRQ (BIT(1) <<
>> IRQ_MASK_DP_TRANS_P0_SHIFT)
>> +#define IRQ_MASK_DP_TRANS_P0_CONN_IRQ (BIT(2) <<
>> IRQ_MASK_DP_TRANS_P0_SHIFT)
>> +#define IRQ_MASK_DP_TRANS_P0_INT_IRQ (BIT(3) <<
>> IRQ_MASK_DP_TRANS_P0_SHIFT)
>> +#define IRQ_STATUS_DP_TRANS_P0_MASK GENMASK(15, 12)
>> +#define IRQ_STATUS_DP_TRANS_P0_SHIFT GENMASK(3, 2)
>> +
>> +#define MTK_DP_TRANS_P0_342C (TRANS_OFFSET + 0x2C)
>> +#define XTAL_FREQ_DP_TRANS_P0_DEFAULT (BIT(0) | BIT(3) | BIT(5) |
>> BIT(6))
>> +#define XTAL_FREQ_DP_TRANS_P0_MASK GENMASK(7, 0)
>> +
>> +#define MTK_DP_TRANS_P0_3430 (TRANS_OFFSET + 0x30)
>> +#define HPD_INT_THD_ECO_DP_TRANS_P0_MASK GENMASK(1, 0)
>> +#define HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT BIT(1)
>> +
>> +#define MTK_DP_TRANS_P0_34A4 (TRANS_OFFSET + 0xA4)
>> +#define LANE_NUM_DP_TRANS_P0_MASK GENMASK(3, 2)
>> +#define LANE_NUM_DP_TRANS_P0_SHIFT (BIT(1))
>> +
>> +#define MTK_DP_TRANS_P0_3540 (TRANS_OFFSET + 0x140)
>> +#define FEC_EN_DP_TRANS_P0_MASK (BIT(0))
>> +#define FEC_EN_DP_TRANS_P0_SHIFT 0
>> +#define FEC_CLOCK_EN_MODE_DP_TRANS_P0_MASK (BIT(3))
>> +#define FEC_CLOCK_EN_MODE_DP_TRANS_P0_SHIFT GENMASK(1, 0)
>> +
>> +#define MTK_DP_TRANS_P0_3580 (TRANS_OFFSET + 0x180)
>> +#define POST_MISC_DATA_LANE0_OV_DP_TRANS_P0_MASK (BIT(8))
>> +#define POST_MISC_DATA_LANE1_OV_DP_TRANS_P0_MASK (BIT(9))
>> +#define POST_MISC_DATA_LANE2_OV_DP_TRANS_P0_MASK (BIT(10))
>> +#define POST_MISC_DATA_LANE3_OV_DP_TRANS_P0_MASK (BIT(11))
>> +
>> +#define MTK_DP_TRANS_P0_35C4 (TRANS_OFFSET + 0x1C4)
>> +#define SW_IRQ_MASK_DP_TRANS_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_TRANS_P0_35C8 (TRANS_OFFSET + 0x1C8)
>> +#define SW_IRQ_CLR_DP_TRANS_P0_MASK GENMASK(15, 0)
>> +
>> +#define SW_IRQ_STATUS_DP_TRANS_P0_MASK GENMASK(15, 0)
>> +#define SW_IRQ_STATUS_DP_TRANS_P0_SHIFT 0
>> +
>> +#define MTK_DP_TRANS_P0_35D0 (TRANS_OFFSET + 0x1D0)
>> +#define SW_IRQ_FINAL_STATUS_DP_TRANS_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_TRANS_P0_35F0 (TRANS_OFFSET + 0x1F0)
>> +
>> +#define MTK_DP_AUX_P0_360C (AUX_OFFSET + 0xC)
>> +#define AUX_TIMEOUT_THR_AUX_TX_P0_MASK GENMASK(12, 0)
>> +
>> +#define MTK_DP_AUX_P0_3614 (AUX_OFFSET + 0x14)
>> +#define AUX_RX_UI_CNT_THR_AUX_TX_P0_MASK GENMASK(6, 0)
>> +#define AUX_RX_UI_CNT_THR_AUX_TX_P0_SHIFT 0
>> +
>> +#define MTK_DP_AUX_P0_3618 (AUX_OFFSET + 0x18)
>> +#define AUX_RX_FIFO_FULL_AUX_TX_P0_MASK (BIT(9))
>> +#define AUX_RX_FIFO_WRITE_POINTER_AUX_TX_P0_MASK GENMASK(3, 0)
>> +
>> +#define MTK_DP_AUX_P0_3620 (AUX_OFFSET + 0x20)
>> +#define AUX_RD_MODE_AUX_TX_P0_MASK (BIT(9))
>> +#define AUX_RX_FIFO_READ_PULSE_TX_P0_MASK (BIT(8))
>> +#define AUX_RX_FIFO_R_PULSE_TX_P0_SHIFT (BIT(3))
>> +#define AUX_RX_FIFO_READ_DATA_AUX_TX_P0_MASK GENMASK(7, 0)
>> +#define AUX_RX_FIFO_READ_DATA_AUX_TX_P0_SHIFT 0
>> +
>> +#define MTK_DP_AUX_P0_3624 (AUX_OFFSET + 0x24)
>> +#define AUX_RX_REPLY_COMMAND_AUX_TX_P0_MASK GENMASK(3, 0)
>> +
>> +#define MTK_DP_AUX_P0_3628 (AUX_OFFSET + 0x28)
>> +#define AUX_RX_PHY_STATE_AUX_TX_P0_MASK GENMASK(9, 0)
>> +#define AUX_RX_PHY_STATE_AUX_TX_P0_SHIFT 0
>> +#define
>> AUX_RX_PHY_STATE_AUX_TX_P0_RX_IDLE
>> \
>> + (BIT(0) << AUX_RX_PHY_STATE_AUX_TX_P0_SHIFT)
>> +
>> +#define MTK_DP_AUX_P0_362C (AUX_OFFSET + 0x2C)
>> +#define AUX_NO_LENGTH_AUX_TX_P0_MASK (BIT(0))
>> +#define AUX_NO_LENGTH_AUX_TX_P0_SHIFT 0
>> +#define AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK (BIT(1))
>> +#define AUX_RESERVED_RW_0_AUX_TX_P0_MASK GENMASK(15, 2)
>> +
>> +#define MTK_DP_AUX_P0_3630 (AUX_OFFSET + 0x30)
>> +#define AUX_TX_REQUEST_READY_AUX_TX_P0_MASK (BIT(3))
>> +#define AUX_TX_REQUEST_READY_AUX_TX_P0_SHIFT GENMASK(1, 0)
>> +
>> +#define MTK_DP_AUX_P0_3634 (AUX_OFFSET + 0x34)
>> +#define AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_MASK GENMASK(15, 8)
>> +#define AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_AUX_P0_3640 (AUX_OFFSET + 0x40)
>> +#define AUX_RX_RECV_COMPLETE_IRQ_TX_P0_MASK (BIT(6))
>> +#define AUX_RX_AUX_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT GENMASK(2, 1)
>> +#define AUX_RX_EDID_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT (BIT(0) |
>> BIT(2))
>> +#define AUX_RX_MCCS_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT (BIT(2))
>> +#define AUX_RX_CMD_RECV_IRQ_AUX_TX_P0_SHIFT GENMASK(1, 0)
>> +#define AUX_RX_ADDR_RECV_IRQ_AUX_TX_P0_SHIFT (BIT(1))
>> +#define AUX_RX_DATA_RECV_IRQ_AUX_TX_P0_SHIFT (BIT(0))
>> +#define AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_MASK (BIT(0))
>> +#define AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_SHIFT 0
>> +
>> +#define MTK_DP_AUX_P0_3644 (AUX_OFFSET + 0x44)
>> +#define MCU_REQUEST_COMMAND_AUX_TX_P0_MASK GENMASK(3, 0)
>> +
>> +#define MTK_DP_AUX_P0_3648 (AUX_OFFSET + 0x48)
>> +#define MCU_REQUEST_ADDRESS_LSB_AUX_TX_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_AUX_P0_364C (AUX_OFFSET + 0x4C)
>> +#define MCU_REQUEST_ADDRESS_MSB_AUX_TX_P0_MASK GENMASK(3, 0)
>> +
>> +#define MTK_DP_AUX_P0_3650 (AUX_OFFSET + 0x50)
>> +#define MCU_REQ_DATA_NUM_AUX_TX_P0_MASK GENMASK(15, 12)
>> +#define MCU_REQ_DATA_NUM_AUX_TX_P0_SHIFT GENMASK(3, 2)
>> +#define PHY_FIFO_RST_AUX_TX_P0_MASK (BIT(9))
>> +#define MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_MASK (BIT(8))
>> +#define MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_AUX_P0_3658 (AUX_OFFSET + 0x58)
>> +#define AUX_TX_OV_EN_AUX_TX_P0_MASK (BIT(0))
>> +
>> +#define MTK_DP_AUX_P0_3690 (AUX_OFFSET + 0x90)
>> +#define RX_REPLY_COMPLETE_MODE_AUX_TX_P0_MASK (BIT(8))
>> +#define RX_REPLY_COMPLETE_MODE_AUX_TX_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_AUX_P0_3704 (AUX_OFFSET + 0x104)
>> +#define AUX_TX_FIFO_WRITE_DATA_NEW_MODE_TOGGLE_AUX_TX_P0_MASK
>> (BIT(1))
>> +#define AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_MASK (BIT(2))
>> +#define AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_SHIFT (BIT(1))
>> +
>> +#define MTK_DP_AUX_P0_3708 (AUX_OFFSET + 0x108)
>> +
>> +#define MTK_DP_AUX_P0_37C8 (AUX_OFFSET + 0x1C8)
>> +#define MTK_ATOP_EN_AUX_TX_P0_MASK (BIT(0))
>> +#define MTK_ATOP_EN_AUX_TX_P0_SHIFT 0
>> +
>> +#define MTK_DP_TOP_PWR_STATE (TOP_OFFSET + 0x0)
>> +#define DP_PWR_STATE_MASK GENMASK(1, 0)
>> +#define DP_PWR_STATE_BANDGAP (BIT(0))
>> +#define DP_PWR_STATE_BANDGAP_TPLL (BIT(1))
>> +#define DP_PWR_STATE_BANDGAP_TPLL_LANE GENMASK(1, 0)
>> +
>> +#define MTK_DP_TOP_SWING_EMP (TOP_OFFSET + 0x4)
>> +#define DP_TX0_VOLT_SWING_MASK GENMASK(1, 0)
>> +#define DP_TX0_VOLT_SWING_SHIFT 0
>> +#define DP_TX0_PRE_EMPH_MASK GENMASK(3, 2)
>> +#define DP_TX0_PRE_EMPH_SHIFT (BIT(1))
>> +#define DP_TX1_VOLT_SWING_MASK GENMASK(9, 8)
>> +#define DP_TX1_VOLT_SWING_SHIFT (BIT(3))
>> +#define DP_TX1_PRE_EMPH_MASK GENMASK(11, 10)
>> +#define DP_TX2_VOLT_SWING_MASK GENMASK(17, 16)
>> +#define DP_TX2_PRE_EMPH_MASK GENMASK(19, 18)
>> +#define DP_TX3_VOLT_SWING_MASK GENMASK(25, 24)
>> +#define DP_TX3_PRE_EMPH_MASK GENMASK(27, 26)
>> +
>> +#define MTK_DP_TOP_RESET_AND_PROBE (TOP_OFFSET + 0x20)
>> +#define SW_RST_B_SHIFT 0
>> +#define SW_RST_B_PHYD (BIT(4) << SW_RST_B_SHIFT)
>> +
>> +#define MTK_DP_TOP_IRQ_STATUS (TOP_OFFSET + 0x28)
>> +#define RGS_IRQ_STATUS_SHIFT 0
>> +#define RGS_IRQ_STATUS_TRANSMITTER (BIT(1) << RGS_IRQ_STATUS_SHIFT)
>> +
>> +#define MTK_DP_TOP_IRQ_MASK (TOP_OFFSET + 0x2C)
>> +#define IRQ_MASK_AUX_TOP_IRQ BIT(2)
>> +
>> +#define MTK_DP_TOP_MEM_PD (TOP_OFFSET + 0x38)
>> +#define MEM_ISO_EN_SHIFT 0
>> +#define FUSE_SEL_SHIFT (BIT(1))
>> +
>> +#endif /*_MTK_DP_REG_H_*/
>> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> index c8a233f609f0..eab64d4c241b 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> @@ -709,6 +709,7 @@ static struct platform_driver * const
>> mtk_drm_drivers[] = {
>> &mtk_disp_ovl_driver,
>> &mtk_disp_rdma_driver,
>> &mtk_dpi_driver,
>> + &mtk_dp_driver,
>> &mtk_drm_platform_driver,
>> &mtk_dsi_driver,
>> };
>> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
>> b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
>> index 3e7d1e6fbe01..8926416f4419 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
>> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
>> @@ -53,6 +53,7 @@ extern struct platform_driver
>> mtk_disp_gamma_driver;
>> extern struct platform_driver mtk_disp_ovl_driver;
>> extern struct platform_driver mtk_disp_rdma_driver;
>> extern struct platform_driver mtk_dpi_driver;
>> +extern struct platform_driver mtk_dp_driver;
>> extern struct platform_driver mtk_dsi_driver;
>>
>> #endif /* MTK_DRM_DRV_H */
>
On Mon, 28 Mar 2022 10:49, Rex-BC Chen <[email protected]> wrote:
>On Mon, 2022-03-28 at 00:39 +0200, Guillaume Ranquet wrote:
>> Add a mtk_dpi_matrix_sel() helper to update the DPI_MATRIX_SET
>> register depending on the color format.
>>
>> Signed-off-by: Guillaume Ranquet <[email protected]>
>> ---
>> drivers/gpu/drm/mediatek/mtk_dpi.c | 21 +++++++++++++++++++++
>> 1 file changed, 21 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c
>> b/drivers/gpu/drm/mediatek/mtk_dpi.c
>> index 8198d3cf23ac..82f97c687652 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
>> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
>> @@ -385,6 +385,25 @@ static void mtk_dpi_config_disable_edge(struct
>> mtk_dpi *dpi)
>> mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, 0,
>> EDGE_SEL_EN);
>> }
>>
>> +static void mtk_dpi_matrix_sel(struct mtk_dpi *dpi, enum
>> mtk_dpi_out_color_format format)
>> +{
>> + u32 matrix_sel = 0;
>> +
>> + switch (format) {
>> + case MTK_DPI_COLOR_FORMAT_YCBCR_422:
>> + case MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL:
>> + case MTK_DPI_COLOR_FORMAT_YCBCR_444:
>> + case MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL:
>> + case MTK_DPI_COLOR_FORMAT_XV_YCC:
>> + if (dpi->mode.hdisplay <= 720)
>> + matrix_sel = 0x2;
>> + break;
>> + default:
>> + break;
>> + }
>> + mtk_dpi_mask(dpi, DPI_MATRIX_SET, matrix_sel,
>> INT_MATRIX_SEL_MASK);
>> +}
>> +
>> static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
>> enum mtk_dpi_out_color_format
>> format)
>> {
>> @@ -392,6 +411,7 @@ static void mtk_dpi_config_color_format(struct
>> mtk_dpi *dpi,
>> (format == MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL)) {
>> mtk_dpi_config_yuv422_enable(dpi, false);
>> mtk_dpi_config_csc_enable(dpi, true);
>> + mtk_dpi_matrix_sel(dpi, format);
>> if (dpi->conf->swap_input_support)
>> mtk_dpi_config_swap_input(dpi, false);
>> mtk_dpi_config_channel_swap(dpi,
>> MTK_DPI_OUT_CHANNEL_SWAP_BGR);
>> @@ -399,6 +419,7 @@ static void mtk_dpi_config_color_format(struct
>> mtk_dpi *dpi,
>> (format == MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL)) {
>> mtk_dpi_config_yuv422_enable(dpi, true);
>> mtk_dpi_config_csc_enable(dpi, true);
>> + mtk_dpi_matrix_sel(dpi, format);
>> if (dpi->conf->swap_input_support)
>> mtk_dpi_config_swap_input(dpi, true);
>> mtk_dpi_config_channel_swap(dpi,
>> MTK_DPI_OUT_CHANNEL_SWAP_RGB);
>
>Hello Guillaume,
>
>Thanks for your patch.
>I have one question:
>Do this setting affect the dpi for previous SoCs?
>(8183, 8192, or 8186)
>If we can confirm the original register setting for this offset in
>8183/8192/8186, I think we can clarify this question.
>
I've checked in the datasheet I have (8365/8385) that this register
and setting exists.
So yes, it will affect other platforms.
>BRs,
>Rex
>
On Mon, 28 Mar 2022 10:38, Rex-BC Chen <[email protected]> wrote:
>Hello Guillaume,
>
>Thanks for your patch, but I have some questions for this patch:
>
>On Mon, 2022-03-28 at 00:39 +0200, Guillaume Ranquet wrote:
>> dpintf is the displayport interface hardware unit. This unit is
>> similar
>> to dpi and can reuse most of the code.
>>
>> This patch adds support for mt8195-dpintf to this dpi driver. Main
>> differences are:
>> - Some features/functional components are not available for dpintf
>> which are now excluded from code execution once is_dpintf is set
>> - dpintf can and needs to choose between different clockdividers
>> based
>> on the clockspeed. This is done by choosing a different clock
>> parent.
>> - There are two additional clocks that need to be managed. These are
>> only set for dpintf and will be set to NULL if not supplied. The
>> clk_* calls handle these as normal clocks then.
>> - Some register contents differ slightly between the two components.
>> To
>> work around this I added register bits/masks with a DPINTF_ prefix
>> and use them where different.
>>
>> Based on a separate driver for dpintf created by
>> Jason-JH.Lin <[email protected]>.
>>
>> Signed-off-by: Markus Schneider-Pargmann <[email protected]>
>> Signed-off-by: Guillaume Ranquet <[email protected]>
>> Reviewed-by: AngeloGioacchino Del Regno <
>> [email protected]>
>> ---
>> drivers/gpu/drm/mediatek/mtk_dpi.c | 78 ++++++++++++++++++-
>> --
>> drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 38 ++++++++++
>> drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 8 +++
>> drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 1 +
>> drivers/gpu/drm/mediatek/mtk_drm_drv.c | 5 +-
>> include/linux/soc/mediatek/mtk-mmsys.h | 2 +
>> 6 files changed, 120 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c
>> b/drivers/gpu/drm/mediatek/mtk_dpi.c
>> index eb969c5c5c2e..8198d3cf23ac 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
>> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
>> @@ -126,6 +126,7 @@ struct mtk_dpi_conf {
>> const u32 *output_fmts;
>> u32 num_output_fmts;
>> bool is_ck_de_pol;
>> + bool is_dpintf;
>> bool swap_input_support;
>> /* Mask used for HWIDTH, HPORCH, VSYNC_WIDTH and VSYNC_PORCH
>> (no shift) */
>> u32 dimension_mask;
>> @@ -498,11 +499,11 @@ static int mtk_dpi_set_display_mode(struct
>> mtk_dpi *dpi,
>>
>> vm.pixelclock = pll_rate / factor;
>> if ((dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE) ||
>> - (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE))
>> + (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE)) {
>> clk_set_rate(dpi->pixel_clk, vm.pixelclock * 2);
>> - else
>> + } else {
>> clk_set_rate(dpi->pixel_clk, vm.pixelclock);
>> -
>> + }
>>
>> vm.pixelclock = clk_get_rate(dpi->pixel_clk);
>>
>> @@ -515,9 +516,15 @@ static int mtk_dpi_set_display_mode(struct
>> mtk_dpi *dpi,
>> MTK_DPI_POLARITY_FALLING :
>> MTK_DPI_POLARITY_RISING;
>> dpi_pol.vsync_pol = vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ?
>> MTK_DPI_POLARITY_FALLING :
>> MTK_DPI_POLARITY_RISING;
>> - hsync.sync_width = vm.hsync_len;
>> - hsync.back_porch = vm.hback_porch;
>> - hsync.front_porch = vm.hfront_porch;
>> + if (dpi->conf->is_dpintf) {
>> + hsync.sync_width = vm.hsync_len / 4;
>> + hsync.back_porch = vm.hback_porch / 4;
>> + hsync.front_porch = vm.hfront_porch / 4;
>> + } else {
>> + hsync.sync_width = vm.hsync_len;
>> + hsync.back_porch = vm.hback_porch;
>> + hsync.front_porch = vm.hfront_porch;
>> + }
>> hsync.shift_half_line = false;
>> vsync_lodd.sync_width = vm.vsync_len;
>> vsync_lodd.back_porch = vm.vback_porch;
>> @@ -559,13 +566,20 @@ static int mtk_dpi_set_display_mode(struct
>> mtk_dpi *dpi,
>> mtk_dpi_config_channel_limit(dpi);
>> mtk_dpi_config_bit_num(dpi, dpi->bit_num);
>> mtk_dpi_config_channel_swap(dpi, dpi->channel_swap);
>> - mtk_dpi_config_yc_map(dpi, dpi->yc_map);
>> mtk_dpi_config_color_format(dpi, dpi->color_format);
>> - mtk_dpi_config_2n_h_fre(dpi);
>> - mtk_dpi_dual_edge(dpi);
>> - mtk_dpi_config_disable_edge(dpi);
>> + if (dpi->conf->is_dpintf) {
>> + mtk_dpi_mask(dpi, DPI_CON, DPINTF_INPUT_2P_EN,
>> + DPINTF_INPUT_2P_EN);
>> + } else {
>> + mtk_dpi_config_yc_map(dpi, dpi->yc_map);
>> + mtk_dpi_config_2n_h_fre(dpi);
>> + mtk_dpi_dual_edge(dpi);
>> + mtk_dpi_config_disable_edge(dpi);
>> + }
>> mtk_dpi_sw_reset(dpi, false);
>>
>> + mtk_dpi_enable(dpi);
>
>Why do we need to add mtk_dpi_enable() here?
>Will this change the power on sequence?
>
I have been told that this is to avoid artifacts on screen, the
mtk_dpi_enable() is done
in mtk_dpi_set_display_mode() instead of mtk_dpi_power_on();
I will try to convey that explanation in a separate patch for v10
>BRs,
>Rex
>> +
>> return 0;
>> }
>>
>> @@ -642,7 +656,10 @@ static int mtk_dpi_bridge_atomic_check(struct
>> drm_bridge *bridge,
>> dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS;
>> dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB;
>> dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
>> - dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
>> + if (out_bus_format == MEDIA_BUS_FMT_YUYV8_1X16)
>> + dpi->color_format =
>> MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL;
>> + else
>> + dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
>>
>> return 0;
>> }
>> @@ -801,6 +818,16 @@ static unsigned int mt8183_calculate_factor(int
>> clock)
>> return 2;
>> }
>>
>> +static unsigned int mt8195_dpintf_calculate_factor(int clock)
>> +{
>> + if (clock < 70000)
>> + return 4;
>> + else if (clock < 200000)
>> + return 2;
>> + else
>> + return 1;
>> +}
>> +
>> static const u32 mt8173_output_fmts[] = {
>> MEDIA_BUS_FMT_RGB888_1X24,
>> };
>> @@ -810,6 +837,12 @@ static const u32 mt8183_output_fmts[] = {
>> MEDIA_BUS_FMT_RGB888_2X12_BE,
>> };
>>
>> +static const u32 mt8195_output_fmts[] = {
>> + MEDIA_BUS_FMT_RGB888_1X24,
>> + MEDIA_BUS_FMT_YUV8_1X24,
>> + MEDIA_BUS_FMT_YUYV8_1X16,
>> +};
>> +
>> static const struct mtk_dpi_yc_limit mtk_dpi_limit = {
>> .c_bottom = 0x0010,
>> .c_top = 0x0FE0,
>> @@ -817,6 +850,13 @@ static const struct mtk_dpi_yc_limit
>> mtk_dpi_limit = {
>> .y_top = 0x0FE0,
>> };
>>
>> +static const struct mtk_dpi_yc_limit mtk_dpintf_limit = {
>> + .c_bottom = 0x0000,
>> + .c_top = 0xFFF,
>> + .y_bottom = 0x0000,
>> + .y_top = 0xFFF,
>> +};
>> +
>> static const struct mtk_dpi_conf mt8173_conf = {
>> .cal_factor = mt8173_calculate_factor,
>> .reg_h_fre_con = 0xe0,
>> @@ -882,6 +922,19 @@ static const struct mtk_dpi_conf mt8192_conf = {
>> .limit = &mtk_dpi_limit,
>> };
>>
>> +static const struct mtk_dpi_conf mt8195_dpintf_conf = {
>> + .cal_factor = mt8195_dpintf_calculate_factor,
>> + .output_fmts = mt8195_output_fmts,
>> + .num_output_fmts = ARRAY_SIZE(mt8195_output_fmts),
>> + .is_dpintf = true,
>> + .dimension_mask = DPINTF_HPW_MASK,
>> + .hvsize_mask = DPINTF_HSIZE_MASK,
>> + .channel_swap_shift = DPINTF_CH_SWAP,
>> + .yuv422_en_bit = DPINTF_YUV422_EN,
>> + .csc_enable_bit = DPINTF_CSC_ENABLE,
>> + .limit = &mtk_dpintf_limit,
>> +};
>> +
>> static int mtk_dpi_probe(struct platform_device *pdev)
>> {
>> struct device *dev = &pdev->dev;
>> @@ -1004,6 +1057,9 @@ static const struct of_device_id
>> mtk_dpi_of_ids[] = {
>> { .compatible = "mediatek,mt8192-dpi",
>> .data = &mt8192_conf,
>> },
>> + { .compatible = "mediatek,mt8195-dpintf",
>> + .data = &mt8195_dpintf_conf,
>> + },
>> { },
>> };
>> MODULE_DEVICE_TABLE(of, mtk_dpi_of_ids);
>> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
>> b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
>> index 3a02fabe1662..91b32dfffced 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
>> +++ b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
>> @@ -40,10 +40,15 @@
>> #define FAKE_DE_LEVEN BIT(21)
>> #define FAKE_DE_RODD BIT(22)
>> #define FAKE_DE_REVEN BIT(23)
>> +#define DPINTF_YUV422_EN BIT(24)
>> +#define DPINTF_CSC_ENABLE BIT(26)
>> +#define DPINTF_INPUT_2P_EN BIT(29)
>>
>> #define DPI_OUTPUT_SETTING 0x14
>> #define CH_SWAP 0
>> +#define DPINTF_CH_SWAP BIT(1)
>> #define CH_SWAP_MASK (0x7 << 0)
>> +#define DPINTF_CH_SWAP_MASK (0x7 << 1)
>> #define SWAP_RGB 0x00
>> #define SWAP_GBR 0x01
>> #define SWAP_BRG 0x02
>> @@ -80,8 +85,10 @@
>> #define DPI_SIZE 0x18
>> #define HSIZE 0
>> #define HSIZE_MASK (0x1FFF << 0)
>> +#define DPINTF_HSIZE_MASK (0xFFFF << 0)
>> #define VSIZE 16
>> #define VSIZE_MASK (0x1FFF << 16)
>> +#define DPINTF_VSIZE_MASK (0xFFFF << 16)
>>
>> #define DPI_DDR_SETTING 0x1C
>> #define DDR_EN BIT(0)
>> @@ -93,24 +100,30 @@
>> #define DPI_TGEN_HWIDTH 0x20
>> #define HPW 0
>> #define HPW_MASK (0xFFF << 0)
>> +#define DPINTF_HPW_MASK (0xFFFF << 0)
>>
>> #define DPI_TGEN_HPORCH 0x24
>> #define HBP 0
>> #define HBP_MASK (0xFFF << 0)
>> +#define DPINTF_HBP_MASK (0xFFFF << 0)
>> #define HFP 16
>> #define HFP_MASK (0xFFF << 16)
>> +#define DPINTF_HFP_MASK (0xFFFF << 16)
>>
>> #define DPI_TGEN_VWIDTH 0x28
>> #define DPI_TGEN_VPORCH 0x2C
>>
>> #define VSYNC_WIDTH_SHIFT 0
>> #define VSYNC_WIDTH_MASK (0xFFF << 0)
>> +#define DPINTF_VSYNC_WIDTH_MASK (0xFFFF << 0)
>> #define VSYNC_HALF_LINE_SHIFT 16
>> #define VSYNC_HALF_LINE_MASK BIT(16)
>> #define VSYNC_BACK_PORCH_SHIFT 0
>> #define VSYNC_BACK_PORCH_MASK (0xFFF << 0)
>> +#define DPINTF_VSYNC_BACK_PORCH_MASK (0xFFFF << 0)
>> #define VSYNC_FRONT_PORCH_SHIFT 16
>> #define VSYNC_FRONT_PORCH_MASK (0xFFF << 16)
>> +#define DPINTF_VSYNC_FRONT_PORCH_MASK (0xFFFF << 16)
>>
>> #define DPI_BG_HCNTL 0x30
>> #define BG_RIGHT (0x1FFF << 0)
>> @@ -217,4 +230,29 @@
>>
>> #define EDGE_SEL_EN BIT(5)
>> #define H_FRE_2N BIT(25)
>> +
>> +#define DPI_MATRIX_SET 0xB4
>> +#define INT_MATRIX_SEL BIT(0)
>> +#define INT_MATRIX_SEL_MASK (0x1F << 0)
>> +#define RGB_TO_JPEG 0x00
>> +#define RGB_TO_FULL709 0x01
>> +#define RGB_TO_BT601 0x02
>> +#define RGB_TO_BT709 0x03
>> +#define JPEG_TO_RGB 0x04
>> +#define FULL709_TO_RGB 0x05
>> +#define BT601_TO_RGB 0x06
>> +#define BT709_TO_RGB 0x07
>> +#define JPEG_TO_BT601 0x08
>> +#define JPEG_TO_BT709 0x09
>> +#define BT601_TO_JPEG 0xA
>> +#define BT709_TO_JPEG 0xB
>> +#define BT709_TO_BT601 0xC
>> +#define BT601_TO_BT709 0xD
>> +#define JPEG_TO_CERGB 0x14
>> +#define FULL709_TO_CERGB 0x15
>> +#define BT601_TO_CERGB 0x16
>> +#define BT709_TO_CERGB 0x17
>> +#define RGB_TO_CERGB 0x1C
>> +#define MATRIX_BIT BIT(8)
>> +#define EXT_MATRIX_EN BIT(12)
>> #endif /* __MTK_DPI_REGS_H */
>> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
>> b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
>> index 2e99aee13dfe..558fc2733358 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
>> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
>> @@ -351,6 +351,11 @@ static const char * const
>> mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
>> [MTK_DISP_WDMA] = "wdma",
>> [MTK_DPI] = "dpi",
>> [MTK_DSI] = "dsi",
>> + [MTK_DP_INTF] = "dp-intf",
>> + [MTK_DISP_PWM] = "pwm",
>> + [MTK_DISP_MUTEX] = "mutex",
>> + [MTK_DISP_OD] = "od",
>> + [MTK_DISP_BLS] = "bls",
>> };
>>
>> struct mtk_ddp_comp_match {
>> @@ -369,6 +374,8 @@ static const struct mtk_ddp_comp_match
>> mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
>> [DDP_COMPONENT_DITHER] = { MTK_DISP_DITHER, 0,
>> &ddp_dither },
>> [DDP_COMPONENT_DPI0] = { MTK_DPI, 0,
>> &ddp_dpi },
>> [DDP_COMPONENT_DPI1] = { MTK_DPI, 1,
>> &ddp_dpi },
>> + [DDP_COMPONENT_DP_INTF0] = { MTK_DP_INTF, 0, &ddp_dpi
>> },
>> + [DDP_COMPONENT_DP_INTF1] = { MTK_DP_INTF, 1, &ddp_dpi
>> },
>> [DDP_COMPONENT_DSI0] = { MTK_DSI, 0,
>> &ddp_dsi },
>> [DDP_COMPONENT_DSI1] = { MTK_DSI, 1,
>> &ddp_dsi },
>> [DDP_COMPONENT_DSI2] = { MTK_DSI, 2,
>> &ddp_dsi },
>> @@ -481,6 +488,7 @@ int mtk_ddp_comp_init(struct device_node *node,
>> struct mtk_ddp_comp *comp,
>> type == MTK_DISP_PWM ||
>> type == MTK_DISP_RDMA ||
>> type == MTK_DPI ||
>> + type == MTK_DP_INTF ||
>> type == MTK_DSI)
>> return 0;
>>
>> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
>> b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
>> index ad267bb8fc9b..43ad74be509e 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
>> +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
>> @@ -34,6 +34,7 @@ enum mtk_ddp_comp_type {
>> MTK_DISP_UFOE,
>> MTK_DISP_WDMA,
>> MTK_DPI,
>> + MTK_DP_INTF,
>> MTK_DSI,
>> MTK_DDP_COMP_TYPE_MAX,
>> };
>> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> index 247c6ff277ef..c8a233f609f0 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> @@ -509,6 +509,8 @@ static const struct of_device_id
>> mtk_ddp_comp_dt_ids[] = {
>> .data = (void *)MTK_DPI },
>> { .compatible = "mediatek,mt8183-dpi",
>> .data = (void *)MTK_DPI },
>> + { .compatible = "mediatek,mt8195-dpintf",
>> + .data = (void *)MTK_DP_INTF },
>> { .compatible = "mediatek,mt2701-dsi",
>> .data = (void *)MTK_DSI },
>> { .compatible = "mediatek,mt8173-dsi",
>> @@ -609,7 +611,8 @@ static int mtk_drm_probe(struct platform_device
>> *pdev)
>> comp_type == MTK_DISP_OVL_2L ||
>> comp_type == MTK_DISP_RDMA ||
>> comp_type == MTK_DPI ||
>> - comp_type == MTK_DSI) {
>> + comp_type == MTK_DPI ||
>> + comp_type == MTK_DP_INTF) {
>> dev_info(dev, "Adding component match for
>> %pOF\n",
>> node);
>> drm_of_component_match_add(dev, &match,
>> component_compare_of,
>> diff --git a/include/linux/soc/mediatek/mtk-mmsys.h
>> b/include/linux/soc/mediatek/mtk-mmsys.h
>> index 4bba275e235a..56ed2fa5f59e 100644
>> --- a/include/linux/soc/mediatek/mtk-mmsys.h
>> +++ b/include/linux/soc/mediatek/mtk-mmsys.h
>> @@ -19,6 +19,8 @@ enum mtk_ddp_comp_id {
>> DDP_COMPONENT_DITHER,
>> DDP_COMPONENT_DPI0,
>> DDP_COMPONENT_DPI1,
>> + DDP_COMPONENT_DP_INTF0,
>> + DDP_COMPONENT_DP_INTF1,
>> DDP_COMPONENT_DSI0,
>> DDP_COMPONENT_DSI1,
>> DDP_COMPONENT_DSI2,
>
On Tue, 29 Mar 2022 05:34, Rex-BC Chen <[email protected]> wrote:
>On Mon, 2022-03-28 at 00:39 +0200, Guillaume Ranquet wrote:
>> From: Markus Schneider-Pargmann <[email protected]>
>>
>> This patch adds a DisplayPort driver for the Mediatek mt8195 SoC.
>>
>> It supports the mt8195, the embedded DisplayPort units. It offers
>> DisplayPort 1.4 with up to 4 lanes.
>>
>> The driver shares its iomap range with the mtk-dp-phy driver using
>> the regmap/syscon facility.
>>
>> This driver is based on an initial version by
>> Jason-JH.Lin <[email protected]>.
>>
>> Signed-off-by: Markus Schneider-Pargmann <[email protected]>
>> Signed-off-by: Guillaume Ranquet <[email protected]>
>> Reported-by: kernel test robot <[email protected]>
>> ---
>> drivers/gpu/drm/mediatek/Kconfig | 8 +
>> drivers/gpu/drm/mediatek/Makefile | 2 +
>> drivers/gpu/drm/mediatek/mtk_dp.c | 2221
>> ++++++++++++++++++++++++
>> drivers/gpu/drm/mediatek/mtk_dp_reg.h | 568 ++++++
>> drivers/gpu/drm/mediatek/mtk_drm_drv.c | 1 +
>> drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
>> 6 files changed, 2801 insertions(+)
>> create mode 100644 drivers/gpu/drm/mediatek/mtk_dp.c
>> create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_reg.h
>>
>> diff --git a/drivers/gpu/drm/mediatek/Kconfig
>> b/drivers/gpu/drm/mediatek/Kconfig
>> index 2976d21e9a34..03ffa9b896c3 100644
>> --- a/drivers/gpu/drm/mediatek/Kconfig
>> +++ b/drivers/gpu/drm/mediatek/Kconfig
>> @@ -28,3 +28,11 @@ config DRM_MEDIATEK_HDMI
>> select PHY_MTK_HDMI
>> help
>> DRM/KMS HDMI driver for Mediatek SoCs
>> +
>> +config MTK_DPTX_SUPPORT
>> + tristate "DRM DPTX Support for Mediatek SoCs"
>> + depends on DRM_MEDIATEK
>> + select PHY_MTK_DP
>> + select DRM_DP_HELPER
>> + help
>> + DRM/KMS Display Port driver for Mediatek SoCs.
>> diff --git a/drivers/gpu/drm/mediatek/Makefile
>> b/drivers/gpu/drm/mediatek/Makefile
>> index 29098d7c8307..d86a6406055e 100644
>> --- a/drivers/gpu/drm/mediatek/Makefile
>> +++ b/drivers/gpu/drm/mediatek/Makefile
>> @@ -21,3 +21,5 @@ mediatek-drm-hdmi-objs := mtk_cec.o \
>> mtk_hdmi_ddc.o
>>
>> obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
>> +
>> +obj-$(CONFIG_MTK_DPTX_SUPPORT) += mtk_dp.o
>> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c
>> b/drivers/gpu/drm/mediatek/mtk_dp.c
>> new file mode 100644
>> index 000000000000..7cd8459cf719
>> --- /dev/null
>> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
>> @@ -0,0 +1,2221 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2019 MediaTek Inc.
>> + * Copyright (c) 2021 BayLibre
>> + */
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_bridge.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/dp/drm_dp_helper.h>
>> +#include <drm/drm_edid.h>
>> +#include <drm/drm_of.h>
>> +#include <drm/drm_panel.h>
>> +#include <drm/drm_print.h>
>> +#include <drm/drm_probe_helper.h>
>> +#include <linux/arm-smccc.h>
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/errno.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/nvmem-consumer.h>
>> +#include <linux/of.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/phy/phy.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/regmap.h>
>> +#include <sound/hdmi-codec.h>
>> +#include <video/videomode.h>
>> +
>>
>
>...snip...
>
>> +
>> +static SIMPLE_DEV_PM_OPS(mtk_dp_pm_ops, mtk_dp_suspend,
>> mtk_dp_resume);
>> +
>> +static const struct of_device_id mtk_dp_of_match[] = {
>> + { .compatible = "mediatek,mt8195-edp-tx", },
>> + {},
>> +};
>> +MODULE_DEVICE_TABLE(of, mtk_dp_of_match);
>> +
>> +struct platform_driver mtk_dp_driver = {
>> + .probe = mtk_dp_probe,
>> + .remove = mtk_dp_remove,
>> + .driver = {
>> + .name = "mediatek-drm-dp",
>> + .of_match_table = mtk_dp_of_match,
>> + .pm = &mtk_dp_pm_ops,
>> + },
>> +};
>> +
>> +MODULE_AUTHOR("Jason-JH.Lin <[email protected]>");
>
>Hello Guillaume,
>
>I think the module author is not Jason-JH Lin.
>He is the owner of 8195 DRM.
>The owner should be Jitao Shi <[email protected]>
>
>BRs,
>Rex
Hi Rex,
We kept the original author from the vendor tree.
I'll update for v10.
Thx,
Guillaume.
>> +MODULE_AUTHOR("Markus Schneider-Pargmann <[email protected]>");
>> +MODULE_DESCRIPTION("MediaTek DisplayPort Driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
>> b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
>> new file mode 100644
>> index 000000000000..c446eef18169
>> --- /dev/null
>> +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
>> @@ -0,0 +1,568 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (c) 2019 MediaTek Inc.
>> + * Copyright (c) 2021 BayLibre
>> + */
>> +#ifndef _MTK_DP_REG_H_
>> +#define _MTK_DP_REG_H_
>> +
>> +#define MTK_DP_SIP_CONTROL_AARCH32 (BIT(0) | BIT(1) | BIT(5) |
>> BIT(8) | BIT(10) | BIT(25) | BIT(31))
>> +#define MTK_DP_SIP_ATF_VIDEO_UNMUTE (BIT(5))
>> +#define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE (BIT(0) | BIT(5))
>> +
>> +#define DP_PHY_GLB_BIAS_GEN_00 0
>> +#define RG_XTP_GLB_BIAS_INTR_CTRL GENMASK(20, 16)
>> +
>> +#define DP_PHY_GLB_DPAUX_TX (BIT(3))
>> +#define RG_CKM_PT0_CKTX_IMPSEL GENMASK(23, 20)
>> +
>> +#define DP_PHY_LANE_TX_0 (BIT(2) | BIT(8))
>> +#define RG_XTP_LN0_TX_IMPSEL_PMOS GENMASK(15, 12)
>> +#define RG_XTP_LN0_TX_IMPSEL_NMOS GENMASK(19, 16)
>> +
>> +#define DP_PHY_LANE_TX_1 (BIT(2) | BIT(9))
>> +#define RG_XTP_LN1_TX_IMPSEL_PMOS GENMASK(15, 12)
>> +#define RG_XTP_LN1_TX_IMPSEL_NMOS GENMASK(19, 16)
>> +
>> +#define DP_PHY_LANE_TX_2 (BIT(2) | BIT(8) | BIT(9))
>> +#define RG_XTP_LN2_TX_IMPSEL_PMOS GENMASK(15, 12)
>> +#define RG_XTP_LN2_TX_IMPSEL_NMOS GENMASK(19, 16)
>> +
>> +#define DP_PHY_LANE_TX_3 (BIT(2) | BIT(10))
>> +#define RG_XTP_LN3_TX_IMPSEL_PMOS GENMASK(15, 12)
>> +#define RG_XTP_LN3_TX_IMPSEL_NMOS GENMASK(19, 16)
>> +
>> +#define TOP_OFFSET (BIT(13))
>> +#define ENC0_OFFSET GENMASK(13, 12)
>> +#define ENC1_OFFSET (BIT(9) | BIT(12) | BIT(13))
>> +#define TRANS_OFFSET (BIT(10) | BIT(12) | BIT(13))
>> +#define AUX_OFFSET (BIT(9) | BIT(10) | BIT(12) | BIT(13))
>> +#define SEC_OFFSET (BIT(14))
>> +
>> +#define MTK_DP_HPD_DISCONNECT BIT(1)
>> +#define MTK_DP_HPD_CONNECT BIT(2)
>> +#define MTK_DP_HPD_INTERRUPT BIT(3)
>> +
>> +#define MTK_DP_0034 (BIT(2) | BIT(4) | BIT(5))
>> +#define DA_XTP_GLB_CKDET_EN_FORCE_VAL BIT(15)
>> +#define DA_XTP_GLB_CKDET_EN_FORCE_EN BIT(14)
>> +#define DA_CKM_INTCKTX_EN_FORCE_VAL BIT(13)
>> +#define DA_CKM_INTCKTX_EN_FORCE_EN BIT(12)
>> +#define DA_CKM_CKTX0_EN_FORCE_VAL BIT(11)
>> +#define DA_CKM_CKTX0_EN_FORCE_EN BIT(10)
>> +#define DA_CKM_XTAL_CK_FORCE_VAL BIT(9)
>> +#define DA_CKM_XTAL_CK_FORCE_EN BIT(8)
>> +#define DA_CKM_BIAS_LPF_EN_FORCE_VAL BIT(7)
>> +#define DA_CKM_BIAS_LPF_EN_FORCE_EN BIT(6)
>> +#define DA_CKM_BIAS_EN_FORCE_VAL BIT(5)
>> +#define DA_CKM_BIAS_EN_FORCE_EN BIT(4)
>> +#define DA_XTP_GLB_AVD10_ON_FORCE_VAL BIT(3)
>> +#define DA_XTP_GLB_AVD10_ON_FORCE BIT(2)
>> +#define DA_XTP_GLB_LDO_EN_FORCE_VAL BIT(1)
>> +#define DA_XTP_GLB_LDO_EN_FORCE_EN BIT(0)
>> +
>> +#define MTK_DP_1040 (BIT(6) | BIT(12))
>> +#define RG_DPAUX_RX_VALID_DEGLITCH_EN BIT(2)
>> +#define RG_XTP_GLB_CKDET_EN BIT(1)
>> +#define RG_DPAUX_RX_EN BIT(0)
>> +
>> +#define MTK_DP_ENC0_P0_3000 (ENC0_OFFSET + 0x00)
>> +#define LANE_NUM_DP_ENC0_P0_MASK GENMASK(1, 0)
>> +#define VIDEO_MUTE_SW_DP_ENC0_P0_MASK (BIT(2))
>> +#define VIDEO_MUTE_SW_DP_ENC0_P0_SHIFT (BIT(1))
>> +#define VIDEO_MUTE_SEL_DP_ENC0_P0_MASK (BIT(3))
>> +#define VIDEO_MUTE_SEL_DP_ENC0_P0_SHIFT GENMASK(1, 0)
>> +#define ENHANCED_FRAME_EN_DP_ENC0_P0_MASK (BIT(4))
>> +#define ENHANCED_FRAME_EN_DP_ENC0_P0_SHIFT (BIT(2))
>> +
>> +#define MTK_DP_ENC0_P0_3004 (ENC0_OFFSET + 0x04)
>> +#define VIDEO_M_CODE_SEL_DP_ENC0_P0_MASK (BIT(8))
>> +#define VIDEO_M_CODE_SEL_DP_ENC0_P0_SHIFT (BIT(3))
>> +#define DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_MASK (BIT(9))
>> +#define DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_SHIFT (BIT(0) | BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_3008 (ENC0_OFFSET + 0x08)
>> +#define VIDEO_M_CODE_SW_0_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_300C (ENC0_OFFSET + 0x0C)
>> +#define VIDEO_M_CODE_SW_1_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3010 (ENC0_OFFSET + 0x10)
>> +#define HTOTAL_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3014 (ENC0_OFFSET + 0x14)
>> +#define VTOTAL_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3018 (ENC0_OFFSET + 0x18)
>> +#define HSTART_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_301C (ENC0_OFFSET + 0x1C)
>> +#define VSTART_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3020 (ENC0_OFFSET + 0x20)
>> +#define HWIDTH_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3024 (ENC0_OFFSET + 0x24)
>> +#define VHEIGHT_SW_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3028 (ENC0_OFFSET + 0x28)
>> +#define HSW_SW_DP_ENC0_P0_MASK GENMASK(14, 0)
>> +#define HSW_SW_DP_ENC0_P0_SHIFT 0
>> +#define HSP_SW_DP_ENC0_P0_MASK (BIT(15))
>> +
>> +#define MTK_DP_ENC0_P0_302C (ENC0_OFFSET + 0x2C)
>> +#define VSW_SW_DP_ENC0_P0_MASK GENMASK(14, 0)
>> +#define VSW_SW_DP_ENC0_P0_SHIFT 0
>> +#define VSP_SW_DP_ENC0_P0_MASK (BIT(15))
>> +
>> +#define MTK_DP_ENC0_P0_3030 (ENC0_OFFSET + 0x30)
>> +#define HTOTAL_SEL_DP_ENC0_P0_SHIFT 0
>> +#define VTOTAL_SEL_DP_ENC0_P0_SHIFT (BIT(0))
>> +#define HSTART_SEL_DP_ENC0_P0_SHIFT (BIT(1))
>> +#define VSTART_SEL_DP_ENC0_P0_SHIFT GENMASK(1, 0)
>> +#define HWIDTH_SEL_DP_ENC0_P0_SHIFT (BIT(2))
>> +#define VHEIGHT_SEL_DP_ENC0_P0_SHIFT (BIT(0) | BIT(2))
>> +#define HSP_SEL_DP_ENC0_P0_SHIFT GENMASK(2, 1)
>> +#define HSW_SEL_DP_ENC0_P0_SHIFT GENMASK(2, 0)
>> +#define VSP_SEL_DP_ENC0_P0_SHIFT (BIT(3))
>> +#define VSW_SEL_DP_ENC0_P0_SHIFT (BIT(0) | BIT(3))
>> +#define VBID_AUDIO_MUTE_FLAG_SW_DP_ENC0_P0_MASK (BIT(11))
>> +#define VBID_AUDIO_MUTE_SW_DP_ENC0_P0_SHIFT (BIT(0) | BIT(1) |
>> BIT(3))
>> +#define VBID_AUDIO_MUTE_FLAG_SEL_DP_ENC0_P0_MASK (BIT(12))
>> +#define VBID_AUDIO_MUTE_SEL_DP_ENC0_P0_SHIFT GENMASK(3, 2)
>> +
>> +#define MTK_DP_ENC0_P0_3034 (ENC0_OFFSET + 0x34)
>> +
>> +#define MTK_DP_ENC0_P0_3038 (ENC0_OFFSET + 0x38)
>> +#define VIDEO_SOURCE_SEL_DP_ENC0_P0_MASK (BIT(11))
>> +#define VIDEO_SOURCE_SEL_DP_ENC0_P0_SHIFT (BIT(0) | BIT(1) | BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_303C (ENC0_OFFSET + 0x3C)
>> +#define SRAM_START_READ_THRD_DP_ENC0_P0_MASK GENMASK(5, 0)
>> +#define SRAM_START_READ_THRD_DP_ENC0_P0_SHIFT 0
>> +#define VIDEO_COLOR_DEPTH_DP_ENC0_P0_MASK GENMASK(10, 8)
>> +#define VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT (BIT(3))
>> +#define
>> VIDEO_COLOR_DEPTH_DP_ENC0_P0_16BIT
>> \
>> + (0 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
>> +#define
>> VIDEO_COLOR_DEPTH_DP_ENC0_P0_12BIT
>> \
>> + (1 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
>> +#define
>> VIDEO_COLOR_DEPTH_DP_ENC0_P0_10BIT
>> \
>> + (2 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
>> +#define
>> VIDEO_COLOR_DEPTH_DP_ENC0_P0_8BIT
>> \
>> + (3 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
>> +#define
>> VIDEO_COLOR_DEPTH_DP_ENC0_P0_6BIT
>> \
>> + (4 << VIDEO_COLOR_DEPTH_DP_ENC0_P0_SHIFT)
>> +#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK GENMASK(14, 12)
>> +#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_SHIFT GENMASK(3, 2)
>> +#define
>> PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB
>> \
>> + (0 << PIXEL_ENCODE_FORMAT_DP_ENC0_P0_SHIFT)
>> +#define
>> PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422
>> \
>> + (1 << PIXEL_ENCODE_FORMAT_DP_ENC0_P0_SHIFT)
>> +#define
>> PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR420
>> \
>> + (2 << PIXEL_ENCODE_FORMAT_DP_ENC0_P0_SHIFT)
>> +#define VIDEO_MN_GEN_EN_DP_ENC0_P0_MASK (BIT(15))
>> +#define VIDEO_MN_GEN_EN_DP_ENC0_P0_SHIFT GENMASK(3, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3040 (ENC0_OFFSET + 0x40)
>> +#define SDP_DOWN_CNT_INIT_DP_ENC0_P0_MASK GENMASK(11, 0)
>> +#define SDP_DOWN_CNT_INIT_DP_ENC0_P0_SHIFT 0
>> +
>> +#define MTK_DP_ENC0_P0_3044 (ENC0_OFFSET + 0x44)
>> +#define VIDEO_N_CODE_0_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3048 (ENC0_OFFSET + 0x48)
>> +#define VIDEO_N_CODE_1_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +
>> +#define MTK_DP_ENC0_P0_304C (ENC0_OFFSET + 0x4C)
>> +#define VBID_VIDEO_MUTE_DP_ENC0_P0_MASK (BIT(2))
>> +#define SDP_VSYNC_RISING_MASK_DP_ENC0_P0_MASK (BIT(8))
>> +
>> +#define MTK_DP_ENC0_P0_3050 (ENC0_OFFSET + 0x50)
>> +#define VIDEO_N_CODE_MN_GEN_0_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3054 (ENC0_OFFSET + 0x54)
>> +#define VIDEO_N_CODE_MN_GEN_1_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3064 (ENC0_OFFSET + 0x64)
>> +#define HDE_NUM_LAST_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3088 (ENC0_OFFSET + 0x88)
>> +#define AU_EN_DP_ENC0_P0_MASK (BIT(6))
>> +#define AU_EN_DP_ENC0_P0_SHIFT GENMASK(2, 1)
>> +#define AUDIO_8CH_EN_DP_ENC0_P0_MASK (BIT(7))
>> +#define AUDIO_8CH_SEL_DP_ENC0_P0_MASK (BIT(8))
>> +#define AUDIO_2CH_EN_DP_ENC0_P0_MASK (BIT(14))
>> +#define AUDIO_2CH_SEL_DP_ENC0_P0_MASK (BIT(15))
>> +
>> +#define MTK_DP_ENC0_P0_308C (ENC0_OFFSET + 0x8C)
>> +#define CH_STATUS_0_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3090 (ENC0_OFFSET + 0x90)
>> +#define CH_STATUS_1_DP_ENC0_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3094 (ENC0_OFFSET + 0x94)
>> +#define CH_STATUS_2_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +
>> +#define MTK_DP_ENC0_P0_30A0 (ENC0_OFFSET + 0xA0)
>> +
>> +#define MTK_DP_ENC0_P0_30A4 (ENC0_OFFSET + 0xA4)
>> +#define AU_TS_CFG_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +
>> +#define MTK_DP_ENC0_P0_30A8 (ENC0_OFFSET + 0xA8)
>> +
>> +#define MTK_DP_ENC0_P0_30AC (ENC0_OFFSET + 0xAC)
>> +
>> +#define MTK_DP_ENC0_P0_30B0 (ENC0_OFFSET + 0xB0)
>> +
>> +#define MTK_DP_ENC0_P0_30B4 (ENC0_OFFSET + 0xB4)
>> +#define ISRC_CFG_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +#define ISRC_CFG_DP_ENC0_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_30B8 (ENC0_OFFSET + 0xB8)
>> +
>> +#define MTK_DP_ENC0_P0_30BC (ENC0_OFFSET + 0xBC)
>> +#define ISRC_CONT_DP_ENC0_P0_MASK (BIT(0))
>> +#define ISRC_CONT_DP_ENC0_P0_SHIFT 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_SHIFT (BIT(3))
>> +#define
>> AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_2
>> \
>> + (1 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
>> +#define
>> AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_4
>> \
>> + (2 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
>> +#define
>> AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_8
>> \
>> + (3 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
>> +#define
>> AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2
>> \
>> + (5 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
>> +#define
>> AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_4
>> \
>> + (6 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
>> +#define
>> AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_8
>> \
>> + (7 << AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_SHIFT)
>> +
>> +#define MTK_DP_ENC0_P0_30D8 (ENC0_OFFSET + 0xD8)
>> +
>> +#define MTK_DP_ENC0_P0_312C (ENC0_OFFSET + 0x12C)
>> +#define ASP_HB2_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +#define ASP_HB3_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +#define ASP_HB3_DP_ENC0_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_3130 (ENC0_OFFSET + 0x130)
>> +
>> +#define MTK_DP_ENC0_P0_3138 (ENC0_OFFSET + 0x138)
>> +
>> +#define MTK_DP_ENC0_P0_3154 (ENC0_OFFSET + 0x154)
>> +#define PGEN_HTOTAL_DP_ENC0_P0_MASK GENMASK(13, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3158 (ENC0_OFFSET + 0x158)
>> +#define PGEN_HSYNC_RISING_DP_ENC0_P0_MASK GENMASK(13, 0)
>> +
>> +#define MTK_DP_ENC0_P0_315C (ENC0_OFFSET + 0x15C)
>> +#define PGEN_HSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK GENMASK(13, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3160 (ENC0_OFFSET + 0x160)
>> +#define PGEN_HFDE_START_DP_ENC0_P0_MASK GENMASK(13, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3164 (ENC0_OFFSET + 0x164)
>> +#define PGEN_HFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK GENMASK(13, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3168 (ENC0_OFFSET + 0x168)
>> +#define PGEN_VTOTAL_DP_ENC0_P0_MASK GENMASK(12, 0)
>> +
>> +#define MTK_DP_ENC0_P0_316C (ENC0_OFFSET + 0x16C)
>> +#define PGEN_VSYNC_RISING_DP_ENC0_P0_MASK GENMASK(12, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3170 (ENC0_OFFSET + 0x170)
>> +#define PGEN_VSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK GENMASK(12, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3174 (ENC0_OFFSET + 0x174)
>> +#define PGEN_VFDE_START_DP_ENC0_P0_MASK GENMASK(12, 0)
>> +
>> +#define MTK_DP_ENC0_P0_3178 (ENC0_OFFSET + 0x178)
>> +#define PGEN_VFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK GENMASK(12, 0)
>> +
>> +#define MTK_DP_ENC0_P0_31B0 (ENC0_OFFSET + 0x1B0)
>> +#define PGEN_PATTERN_SEL_SHIFT (BIT(2))
>> +#define PGEN_PATTERN_SEL_MASK GENMASK(6, 4)
>> +
>> +#define MTK_DP_ENC0_P0_31C8 (ENC0_OFFSET + 0x1C8)
>> +#define VSC_EXT_VESA_HB0_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +#define VSC_EXT_VESA_HB1_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +#define VSC_EXT_VESA_HB1_DP_ENC0_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_31CC (ENC0_OFFSET + 0x1CC)
>> +#define VSC_EXT_VESA_HB2_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +#define VSC_EXT_VESA_HB2_DP_ENC0_P0_SHIFT 0
>> +#define VSC_EXT_VESA_HB3_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +
>> +#define MTK_DP_ENC0_P0_31D0 (ENC0_OFFSET + 0x1D0)
>> +#define VSC_EXT_CEA_HB0_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +#define VSC_EXT_CEA_HB1_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +#define VSC_EXT_CEA_HB1_DP_ENC0_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_31D4 (ENC0_OFFSET + 0x1D4)
>> +#define VSC_EXT_CEA_HB2_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +#define VSC_EXT_CEA_HB2_DP_ENC0_P0_SHIFT 0
>> +#define VSC_EXT_CEA_HB3_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +
>> +#define MTK_DP_ENC0_P0_31D8 (ENC0_OFFSET + 0x1D8)
>> +#define VSC_EXT_VESA_NUM_DP_ENC0_P0_MASK GENMASK(5, 0)
>> +#define VSC_EXT_VESA_NUM_DP_ENC0_P0_SHIFT 0
>> +#define VSC_EXT_CEA_NUM_DP_ENC0_P0_MASK GENMASK(13, 8)
>> +#define VSC_EXT_CEA_NUM_DP_ENC0_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC0_P0_31DC (ENC0_OFFSET + 0x1DC)
>> +#define HDR0_CFG_DP_ENC0_P0_MASK GENMASK(7, 0)
>> +#define HDR0_CFG_DP_ENC0_P0_SHIFT 0
>> +
>> +#define MTK_DP_ENC0_P0_31E8 (ENC0_OFFSET + 0x1E8)
>> +
>> +#define MTK_DP_ENC0_P0_31EC (ENC0_OFFSET + 0x1EC)
>> +#define AUDIO_CH_SRC_SEL_DP_ENC0_P0_MASK (BIT(4))
>> +#define AUDIO_CH_SRC_SEL_DP_ENC0_P0_SHIFT (BIT(2))
>> +#define ISRC1_HB3_DP_ENC0_P0_MASK GENMASK(15, 8)
>> +#define ISRC1_HB3_DP_ENC0_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC1_P0_3200 (ENC1_OFFSET + 0x00)
>> +
>> +#define MTK_DP_ENC1_P0_3280 (ENC1_OFFSET + 0x80)
>> +#define SDP_PACKET_TYPE_DP_ENC1_P0_MASK GENMASK(4, 0)
>> +#define SDP_PACKET_W_DP_ENC1_P0 (BIT(5))
>> +#define SDP_PACKET_W_DP_ENC1_P0_MASK (BIT(5))
>> +#define SDP_PACKET_W_DP_ENC1_P0_SHIFT (BIT(0) | BIT(2))
>> +
>> +#define MTK_DP_ENC1_P0_328C (ENC1_OFFSET + 0x8C)
>> +
>> +#define MTK_DP_ENC1_P0_3290 (ENC1_OFFSET + 0x90)
>> +
>> +#define MTK_DP_ENC1_P0_32A0 (ENC1_OFFSET + 0xA0)
>> +
>> +#define MTK_DP_ENC1_P0_32A4 (ENC1_OFFSET + 0xA4)
>> +
>> +#define MTK_DP_ENC1_P0_3300 (ENC1_OFFSET + 0x100)
>> +#define VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_MASK GENMASK(9, 8)
>> +#define VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_ENC1_P0_3304 (ENC1_OFFSET + 0x104)
>> +#define AU_PRTY_REGEN_DP_ENC1_P0_MASK (BIT(8))
>> +#define AU_CH_STS_REGEN_DP_ENC1_P0_MASK (BIT(9))
>> +#define AUDIO_SAMPLE_PRSENT_REGEN_DP_ENC1_P0_MASK (BIT(12))
>> +
>> +#define MTK_DP_ENC1_P0_3324 (ENC1_OFFSET + 0x124)
>> +#define AUDIO_SOURCE_MUX_DP_ENC1_P0_MASK GENMASK(9, 8)
>> +#define AUDIO_SOURCE_MUX_DP_ENC1_P0_SHIFT (BIT(3))
>> +#define
>> AUDIO_SOURCE_MUX_DP_ENC1_P0_DPRX
>> \
>> + (0 << AUDIO_SOURCE_MUX_DP_ENC1_P0_SHIFT)
>> +
>> +#define MTK_DP_ENC1_P0_3364 (ENC1_OFFSET + 0x164)
>> +#define SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_MASK GENMASK(11, 0)
>> +#define SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_SHIFT 0
>> +#define FIFO_READ_START_POINT_DP_ENC1_P0_MASK GENMASK(15, 12)
>> +#define FIFO_READ_START_POINT_DP_ENC1_P0_SHIFT GENMASK(3, 2)
>> +
>> +#define MTK_DP_ENC1_P0_3368 (ENC1_OFFSET + 0x168)
>> +#define VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0_SHIFT 0
>> +#define VIDEO_STABLE_CNT_THRD_DP_ENC1_P0_SHIFT (BIT(2))
>> +#define SDP_DP13_EN_DP_ENC1_P0_SHIFT (BIT(3))
>> +#define BS2BS_MODE_DP_ENC1_P0_MASK GENMASK(13, 12)
>> +#define BS2BS_MODE_DP_ENC1_P0_SHIFT GENMASK(3, 2)
>> +
>> +#define MTK_DP_ENC1_P0_33F4 (ENC1_OFFSET + 0x1F4)
>> +
>> +#define MTK_DP_TRANS_P0_3400 (TRANS_OFFSET + 0)
>> +#define PATTERN1_EN_DP_TRANS_P0_MASK (BIT(12))
>> +#define PATTERN1_EN_DP_TRANS_P0_SHIFT GENMASK(3, 2)
>> +#define PATTERN2_EN_DP_TRANS_P0_MASK (BIT(13))
>> +#define PATTERN3_EN_DP_TRANS_P0_MASK (BIT(14))
>> +#define PATTERN4_EN_DP_TRANS_P0_MASK (BIT(15))
>> +
>> +#define MTK_DP_TRANS_P0_3404 (TRANS_OFFSET + 0x4)
>> +#define DP_SCR_EN_DP_TRANS_P0_MASK (BIT(0))
>> +
>> +#define MTK_DP_TRANS_P0_340C (TRANS_OFFSET + 0xC)
>> +#define DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_MASK (BIT(13))
>> +#define DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_SHIFT (BIT(0) |
>> BIT(2) | BIT(3))
>> +
>> +#define MTK_DP_TRANS_P0_3410 (TRANS_OFFSET + 0x10)
>> +#define HPD_DEB_THD_DP_TRANS_P0_MASK GENMASK(3, 0)
>> +#define HPD_DEB_THD_DP_TRANS_P0_SHIFT 0
>> +#define HPD_INT_THD_DP_TRANS_P0_MASK GENMASK(7, 4)
>> +#define HPD_INT_THD_DP_TRANS_P0_SHIFT (BIT(2))
>> +#define HPD_INT_THD_DP_TRANS_P0_LOWER_500US (2 <<
>> HPD_INT_THD_DP_TRANS_P0_SHIFT)
>> +#define
>> HPD_INT_THD_DP_TRANS_P0_UPPER_1100US
>> \
>> + (2 << (HPD_INT_THD_DP_TRANS_P0_SHIFT + 2))
>> +#define HPD_DISC_THD_DP_TRANS_P0_MASK GENMASK(11, 8)
>> +#define HPD_DISC_THD_DP_TRANS_P0_SHIFT (BIT(3))
>> +#define HPD_CONN_THD_DP_TRANS_P0_MASK GENMASK(15, 12)
>> +#define HPD_CONN_THD_DP_TRANS_P0_SHIFT GENMASK(3, 2)
>> +
>> +#define MTK_DP_TRANS_P0_3414 (TRANS_OFFSET + 0x14)
>> +#define HPD_DB_DP_TRANS_P0_MASK (BIT(2))
>> +
>> +#define MTK_DP_TRANS_P0_3418 (TRANS_OFFSET + 0x18)
>> +#define IRQ_CLR_DP_TRANS_P0_MASK GENMASK(3, 0)
>> +#define IRQ_MASK_DP_TRANS_P0_MASK GENMASK(7, 4)
>> +#define IRQ_MASK_DP_TRANS_P0_SHIFT (BIT(2))
>> +#define IRQ_MASK_DP_TRANS_P0_DISC_IRQ (BIT(1) <<
>> IRQ_MASK_DP_TRANS_P0_SHIFT)
>> +#define IRQ_MASK_DP_TRANS_P0_CONN_IRQ (BIT(2) <<
>> IRQ_MASK_DP_TRANS_P0_SHIFT)
>> +#define IRQ_MASK_DP_TRANS_P0_INT_IRQ (BIT(3) <<
>> IRQ_MASK_DP_TRANS_P0_SHIFT)
>> +#define IRQ_STATUS_DP_TRANS_P0_MASK GENMASK(15, 12)
>> +#define IRQ_STATUS_DP_TRANS_P0_SHIFT GENMASK(3, 2)
>> +
>> +#define MTK_DP_TRANS_P0_342C (TRANS_OFFSET + 0x2C)
>> +#define XTAL_FREQ_DP_TRANS_P0_DEFAULT (BIT(0) | BIT(3) | BIT(5) |
>> BIT(6))
>> +#define XTAL_FREQ_DP_TRANS_P0_MASK GENMASK(7, 0)
>> +
>> +#define MTK_DP_TRANS_P0_3430 (TRANS_OFFSET + 0x30)
>> +#define HPD_INT_THD_ECO_DP_TRANS_P0_MASK GENMASK(1, 0)
>> +#define HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT BIT(1)
>> +
>> +#define MTK_DP_TRANS_P0_34A4 (TRANS_OFFSET + 0xA4)
>> +#define LANE_NUM_DP_TRANS_P0_MASK GENMASK(3, 2)
>> +#define LANE_NUM_DP_TRANS_P0_SHIFT (BIT(1))
>> +
>> +#define MTK_DP_TRANS_P0_3540 (TRANS_OFFSET + 0x140)
>> +#define FEC_EN_DP_TRANS_P0_MASK (BIT(0))
>> +#define FEC_EN_DP_TRANS_P0_SHIFT 0
>> +#define FEC_CLOCK_EN_MODE_DP_TRANS_P0_MASK (BIT(3))
>> +#define FEC_CLOCK_EN_MODE_DP_TRANS_P0_SHIFT GENMASK(1, 0)
>> +
>> +#define MTK_DP_TRANS_P0_3580 (TRANS_OFFSET + 0x180)
>> +#define POST_MISC_DATA_LANE0_OV_DP_TRANS_P0_MASK (BIT(8))
>> +#define POST_MISC_DATA_LANE1_OV_DP_TRANS_P0_MASK (BIT(9))
>> +#define POST_MISC_DATA_LANE2_OV_DP_TRANS_P0_MASK (BIT(10))
>> +#define POST_MISC_DATA_LANE3_OV_DP_TRANS_P0_MASK (BIT(11))
>> +
>> +#define MTK_DP_TRANS_P0_35C4 (TRANS_OFFSET + 0x1C4)
>> +#define SW_IRQ_MASK_DP_TRANS_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_TRANS_P0_35C8 (TRANS_OFFSET + 0x1C8)
>> +#define SW_IRQ_CLR_DP_TRANS_P0_MASK GENMASK(15, 0)
>> +
>> +#define SW_IRQ_STATUS_DP_TRANS_P0_MASK GENMASK(15, 0)
>> +#define SW_IRQ_STATUS_DP_TRANS_P0_SHIFT 0
>> +
>> +#define MTK_DP_TRANS_P0_35D0 (TRANS_OFFSET + 0x1D0)
>> +#define SW_IRQ_FINAL_STATUS_DP_TRANS_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_TRANS_P0_35F0 (TRANS_OFFSET + 0x1F0)
>> +
>> +#define MTK_DP_AUX_P0_360C (AUX_OFFSET + 0xC)
>> +#define AUX_TIMEOUT_THR_AUX_TX_P0_MASK GENMASK(12, 0)
>> +
>> +#define MTK_DP_AUX_P0_3614 (AUX_OFFSET + 0x14)
>> +#define AUX_RX_UI_CNT_THR_AUX_TX_P0_MASK GENMASK(6, 0)
>> +#define AUX_RX_UI_CNT_THR_AUX_TX_P0_SHIFT 0
>> +
>> +#define MTK_DP_AUX_P0_3618 (AUX_OFFSET + 0x18)
>> +#define AUX_RX_FIFO_FULL_AUX_TX_P0_MASK (BIT(9))
>> +#define AUX_RX_FIFO_WRITE_POINTER_AUX_TX_P0_MASK GENMASK(3, 0)
>> +
>> +#define MTK_DP_AUX_P0_3620 (AUX_OFFSET + 0x20)
>> +#define AUX_RD_MODE_AUX_TX_P0_MASK (BIT(9))
>> +#define AUX_RX_FIFO_READ_PULSE_TX_P0_MASK (BIT(8))
>> +#define AUX_RX_FIFO_R_PULSE_TX_P0_SHIFT (BIT(3))
>> +#define AUX_RX_FIFO_READ_DATA_AUX_TX_P0_MASK GENMASK(7, 0)
>> +#define AUX_RX_FIFO_READ_DATA_AUX_TX_P0_SHIFT 0
>> +
>> +#define MTK_DP_AUX_P0_3624 (AUX_OFFSET + 0x24)
>> +#define AUX_RX_REPLY_COMMAND_AUX_TX_P0_MASK GENMASK(3, 0)
>> +
>> +#define MTK_DP_AUX_P0_3628 (AUX_OFFSET + 0x28)
>> +#define AUX_RX_PHY_STATE_AUX_TX_P0_MASK GENMASK(9, 0)
>> +#define AUX_RX_PHY_STATE_AUX_TX_P0_SHIFT 0
>> +#define
>> AUX_RX_PHY_STATE_AUX_TX_P0_RX_IDLE
>> \
>> + (BIT(0) << AUX_RX_PHY_STATE_AUX_TX_P0_SHIFT)
>> +
>> +#define MTK_DP_AUX_P0_362C (AUX_OFFSET + 0x2C)
>> +#define AUX_NO_LENGTH_AUX_TX_P0_MASK (BIT(0))
>> +#define AUX_NO_LENGTH_AUX_TX_P0_SHIFT 0
>> +#define AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK (BIT(1))
>> +#define AUX_RESERVED_RW_0_AUX_TX_P0_MASK GENMASK(15, 2)
>> +
>> +#define MTK_DP_AUX_P0_3630 (AUX_OFFSET + 0x30)
>> +#define AUX_TX_REQUEST_READY_AUX_TX_P0_MASK (BIT(3))
>> +#define AUX_TX_REQUEST_READY_AUX_TX_P0_SHIFT GENMASK(1, 0)
>> +
>> +#define MTK_DP_AUX_P0_3634 (AUX_OFFSET + 0x34)
>> +#define AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_MASK GENMASK(15, 8)
>> +#define AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_AUX_P0_3640 (AUX_OFFSET + 0x40)
>> +#define AUX_RX_RECV_COMPLETE_IRQ_TX_P0_MASK (BIT(6))
>> +#define AUX_RX_AUX_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT GENMASK(2, 1)
>> +#define AUX_RX_EDID_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT (BIT(0) |
>> BIT(2))
>> +#define AUX_RX_MCCS_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT (BIT(2))
>> +#define AUX_RX_CMD_RECV_IRQ_AUX_TX_P0_SHIFT GENMASK(1, 0)
>> +#define AUX_RX_ADDR_RECV_IRQ_AUX_TX_P0_SHIFT (BIT(1))
>> +#define AUX_RX_DATA_RECV_IRQ_AUX_TX_P0_SHIFT (BIT(0))
>> +#define AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_MASK (BIT(0))
>> +#define AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_SHIFT 0
>> +
>> +#define MTK_DP_AUX_P0_3644 (AUX_OFFSET + 0x44)
>> +#define MCU_REQUEST_COMMAND_AUX_TX_P0_MASK GENMASK(3, 0)
>> +
>> +#define MTK_DP_AUX_P0_3648 (AUX_OFFSET + 0x48)
>> +#define MCU_REQUEST_ADDRESS_LSB_AUX_TX_P0_MASK GENMASK(15, 0)
>> +
>> +#define MTK_DP_AUX_P0_364C (AUX_OFFSET + 0x4C)
>> +#define MCU_REQUEST_ADDRESS_MSB_AUX_TX_P0_MASK GENMASK(3, 0)
>> +
>> +#define MTK_DP_AUX_P0_3650 (AUX_OFFSET + 0x50)
>> +#define MCU_REQ_DATA_NUM_AUX_TX_P0_MASK GENMASK(15, 12)
>> +#define MCU_REQ_DATA_NUM_AUX_TX_P0_SHIFT GENMASK(3, 2)
>> +#define PHY_FIFO_RST_AUX_TX_P0_MASK (BIT(9))
>> +#define MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_MASK (BIT(8))
>> +#define MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_AUX_P0_3658 (AUX_OFFSET + 0x58)
>> +#define AUX_TX_OV_EN_AUX_TX_P0_MASK (BIT(0))
>> +
>> +#define MTK_DP_AUX_P0_3690 (AUX_OFFSET + 0x90)
>> +#define RX_REPLY_COMPLETE_MODE_AUX_TX_P0_MASK (BIT(8))
>> +#define RX_REPLY_COMPLETE_MODE_AUX_TX_P0_SHIFT (BIT(3))
>> +
>> +#define MTK_DP_AUX_P0_3704 (AUX_OFFSET + 0x104)
>> +#define AUX_TX_FIFO_WRITE_DATA_NEW_MODE_TOGGLE_AUX_TX_P0_MASK
>> (BIT(1))
>> +#define AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_MASK (BIT(2))
>> +#define AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_SHIFT (BIT(1))
>> +
>> +#define MTK_DP_AUX_P0_3708 (AUX_OFFSET + 0x108)
>> +
>> +#define MTK_DP_AUX_P0_37C8 (AUX_OFFSET + 0x1C8)
>> +#define MTK_ATOP_EN_AUX_TX_P0_MASK (BIT(0))
>> +#define MTK_ATOP_EN_AUX_TX_P0_SHIFT 0
>> +
>> +#define MTK_DP_TOP_PWR_STATE (TOP_OFFSET + 0x0)
>> +#define DP_PWR_STATE_MASK GENMASK(1, 0)
>> +#define DP_PWR_STATE_BANDGAP (BIT(0))
>> +#define DP_PWR_STATE_BANDGAP_TPLL (BIT(1))
>> +#define DP_PWR_STATE_BANDGAP_TPLL_LANE GENMASK(1, 0)
>> +
>> +#define MTK_DP_TOP_SWING_EMP (TOP_OFFSET + 0x4)
>> +#define DP_TX0_VOLT_SWING_MASK GENMASK(1, 0)
>> +#define DP_TX0_VOLT_SWING_SHIFT 0
>> +#define DP_TX0_PRE_EMPH_MASK GENMASK(3, 2)
>> +#define DP_TX0_PRE_EMPH_SHIFT (BIT(1))
>> +#define DP_TX1_VOLT_SWING_MASK GENMASK(9, 8)
>> +#define DP_TX1_VOLT_SWING_SHIFT (BIT(3))
>> +#define DP_TX1_PRE_EMPH_MASK GENMASK(11, 10)
>> +#define DP_TX2_VOLT_SWING_MASK GENMASK(17, 16)
>> +#define DP_TX2_PRE_EMPH_MASK GENMASK(19, 18)
>> +#define DP_TX3_VOLT_SWING_MASK GENMASK(25, 24)
>> +#define DP_TX3_PRE_EMPH_MASK GENMASK(27, 26)
>> +
>> +#define MTK_DP_TOP_RESET_AND_PROBE (TOP_OFFSET + 0x20)
>> +#define SW_RST_B_SHIFT 0
>> +#define SW_RST_B_PHYD (BIT(4) << SW_RST_B_SHIFT)
>> +
>> +#define MTK_DP_TOP_IRQ_STATUS (TOP_OFFSET + 0x28)
>> +#define RGS_IRQ_STATUS_SHIFT 0
>> +#define RGS_IRQ_STATUS_TRANSMITTER (BIT(1) << RGS_IRQ_STATUS_SHIFT)
>> +
>> +#define MTK_DP_TOP_IRQ_MASK (TOP_OFFSET + 0x2C)
>> +#define IRQ_MASK_AUX_TOP_IRQ BIT(2)
>> +
>> +#define MTK_DP_TOP_MEM_PD (TOP_OFFSET + 0x38)
>> +#define MEM_ISO_EN_SHIFT 0
>> +#define FUSE_SEL_SHIFT (BIT(1))
>> +
>> +#endif /*_MTK_DP_REG_H_*/
>> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> index c8a233f609f0..eab64d4c241b 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
>> @@ -709,6 +709,7 @@ static struct platform_driver * const
>> mtk_drm_drivers[] = {
>> &mtk_disp_ovl_driver,
>> &mtk_disp_rdma_driver,
>> &mtk_dpi_driver,
>> + &mtk_dp_driver,
>> &mtk_drm_platform_driver,
>> &mtk_dsi_driver,
>> };
>> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
>> b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
>> index 3e7d1e6fbe01..8926416f4419 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
>> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
>> @@ -53,6 +53,7 @@ extern struct platform_driver
>> mtk_disp_gamma_driver;
>> extern struct platform_driver mtk_disp_ovl_driver;
>> extern struct platform_driver mtk_disp_rdma_driver;
>> extern struct platform_driver mtk_dpi_driver;
>> +extern struct platform_driver mtk_dp_driver;
>> extern struct platform_driver mtk_dsi_driver;
>>
>> #endif /* MTK_DRM_DRV_H */
>
Hi,
On Mon, Mar 28, 2022 at 12:39:06AM +0200, Guillaume Ranquet wrote:
> From: Markus Schneider-Pargmann <[email protected]>
>
> DP_INTF is similar to DPI but does not have the exact same feature set
> or register layouts.
>
> DP_INTF is the sink of the display pipeline that is connected to the
> DisplayPort controller and encoder unit. It takes the same clocks as
> DPI.
>
> Signed-off-by: Markus Schneider-Pargmann <[email protected]>
> Signed-off-by: Guillaume Ranquet <[email protected]>
> Reviewed-by: Rob Herring <[email protected]>
> ---
> .../bindings/display/mediatek/mediatek,dpi.yaml | 11 ++++++-----
> 1 file changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
> index dd2896a40ff0..2dba80ad3b18 100644
> --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
> +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
> @@ -4,16 +4,16 @@
> $id: http://devicetree.org/schemas/display/mediatek/mediatek,dpi.yaml#
> $schema: http://devicetree.org/meta-schemas/core.yaml#
>
> -title: mediatek DPI Controller Device Tree Bindings
> +title: mediatek DPI/DP_INTF Controller
>
> maintainers:
> - CK Hu <[email protected]>
> - Jitao shi <[email protected]>
>
> description: |
> - The Mediatek DPI function block is a sink of the display subsystem and
> - provides 8-bit RGB/YUV444 or 8/10/10-bit YUV422 pixel data on a parallel
> - output bus.
> + The Mediatek DPI and DP_INTF function blocks are a sink of the display
> + subsystem and provides 8-bit RGB/YUV444 or 8/10/10-bit YUV422 pixel data on a
> + parallel output bus.
>
> properties:
> compatible:
> @@ -23,6 +23,7 @@ properties:
> - mediatek,mt8173-dpi
> - mediatek,mt8183-dpi
> - mediatek,mt8192-dpi
> + - mediatek,mt8195-dpintf
It seems a bit weird to have all instances of DP_INTF with a separator
but the compatible doesn't have one?
Is there a reason to not use dp-intf?
Maxime
Hi Guillaume,
On Mon, Mar 28, 2022 at 12:39:23AM +0200, Guillaume Ranquet wrote:
> From: Markus Schneider-Pargmann <[email protected]>
>
> This patch adds a DisplayPort driver for the Mediatek mt8195 SoC.
>
> It supports the mt8195, the embedded DisplayPort units. It offers
> DisplayPort 1.4 with up to 4 lanes.
>
> The driver shares its iomap range with the mtk-dp-phy driver using
> the regmap/syscon facility.
>
> This driver is based on an initial version by
> Jason-JH.Lin <[email protected]>.
>
> Signed-off-by: Markus Schneider-Pargmann <[email protected]>
> Signed-off-by: Guillaume Ranquet <[email protected]>
> Reported-by: kernel test robot <[email protected]>
You don't need to set Reported-by on a patch introducing a new driver.
That would be typically done for a fix.
> ---
> drivers/gpu/drm/mediatek/Kconfig | 8 +
> drivers/gpu/drm/mediatek/Makefile | 2 +
> drivers/gpu/drm/mediatek/mtk_dp.c | 2221 ++++++++++++++++++++++++
> drivers/gpu/drm/mediatek/mtk_dp_reg.h | 568 ++++++
> drivers/gpu/drm/mediatek/mtk_drm_drv.c | 1 +
> drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
> 6 files changed, 2801 insertions(+)
> create mode 100644 drivers/gpu/drm/mediatek/mtk_dp.c
> create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_reg.h
>
> diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig
> index 2976d21e9a34..03ffa9b896c3 100644
> --- a/drivers/gpu/drm/mediatek/Kconfig
> +++ b/drivers/gpu/drm/mediatek/Kconfig
> @@ -28,3 +28,11 @@ config DRM_MEDIATEK_HDMI
> select PHY_MTK_HDMI
> help
> DRM/KMS HDMI driver for Mediatek SoCs
> +
> +config MTK_DPTX_SUPPORT
> + tristate "DRM DPTX Support for Mediatek SoCs"
> + depends on DRM_MEDIATEK
> + select PHY_MTK_DP
> + select DRM_DP_HELPER
> + help
> + DRM/KMS Display Port driver for Mediatek SoCs.
> diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
> index 29098d7c8307..d86a6406055e 100644
> --- a/drivers/gpu/drm/mediatek/Makefile
> +++ b/drivers/gpu/drm/mediatek/Makefile
> @@ -21,3 +21,5 @@ mediatek-drm-hdmi-objs := mtk_cec.o \
> mtk_hdmi_ddc.o
>
> obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
> +
> +obj-$(CONFIG_MTK_DPTX_SUPPORT) += mtk_dp.o
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> new file mode 100644
> index 000000000000..7cd8459cf719
> --- /dev/null
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> @@ -0,0 +1,2221 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2019 MediaTek Inc.
> + * Copyright (c) 2021 BayLibre
2022?
> + */
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/dp/drm_dp_helper.h>
> +#include <drm/drm_edid.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_print.h>
> +#include <drm/drm_probe_helper.h>
> +#include <linux/arm-smccc.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/nvmem-consumer.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <sound/hdmi-codec.h>
> +#include <video/videomode.h>
> +
> +#include "mtk_dp_reg.h"
> +
> +#define MTK_DP_AUX_WAIT_REPLY_COUNT 20
> +#define MTK_DP_CHECK_SINK_CAP_TIMEOUT_COUNT 3
> +
> +//TODO: platform/device data or dts?
DTS :)
> +#define MTK_DP_MAX_LANES 4
> +#define MTK_DP_MAX_LINK_RATE MTK_DP_LINKRATE_HBR3
> +
> +#define MTK_DP_TBC_BUF_READ_START_ADDR 0x08
> +
> +#define MTK_DP_TRAIN_RETRY_LIMIT 8
> +#define MTK_DP_TRAIN_MAX_ITERATIONS 5
> +
> +#define MTK_DP_AUX_WRITE_READ_WAIT_TIME_US 20
> +
> +#define MTK_DP_DP_VERSION_11 0x11
> +
> +enum mtk_dp_state {
> + MTK_DP_STATE_INITIAL,
> + MTK_DP_STATE_IDLE,
> + MTK_DP_STATE_PREPARE,
> + MTK_DP_STATE_NORMAL,
> +};
> +
> +enum mtk_dp_train_state {
> + MTK_DP_TRAIN_STATE_STARTUP = 0,
> + MTK_DP_TRAIN_STATE_CHECKCAP,
> + MTK_DP_TRAIN_STATE_CHECKEDID,
> + MTK_DP_TRAIN_STATE_TRAINING_PRE,
> + MTK_DP_TRAIN_STATE_TRAINING,
> + MTK_DP_TRAIN_STATE_NORMAL,
> + MTK_DP_TRAIN_STATE_DPIDLE,
> +};
> +
> +struct mtk_dp_timings {
> + struct videomode vm;
> +
> + u16 htotal;
> + u16 vtotal;
> + u8 frame_rate;
> + u32 pix_rate_khz;
> +};
> +
> +struct mtk_dp_train_info {
> + bool tps3;
> + bool tps4;
> + bool sink_ssc;
> + bool cable_plugged_in;
> + bool cable_state_change;
> + bool cr_done;
> + bool eq_done;
> +
> + /* link_rate is in multiple of 0.27Gbps */
> + int link_rate;
> + int lane_count;
> +
> + u8 irq_status;
> + int check_cap_count;
> +};
> +
> +/* Same values as used by the DP Spec for MISC0 bits 1 and 2 */
> +enum mtk_dp_color_format {
> + MTK_DP_COLOR_FORMAT_RGB_444 = 0,
> + MTK_DP_COLOR_FORMAT_YUV_422 = 1,
> + MTK_DP_COLOR_FORMAT_YUV_444 = 2,
> + MTK_DP_COLOR_FORMAT_YUV_420 = 3,
> + MTK_DP_COLOR_FORMAT_YONLY = 4,
> + MTK_DP_COLOR_FORMAT_RAW = 5,
> + MTK_DP_COLOR_FORMAT_RESERVED = 6,
> + MTK_DP_COLOR_FORMAT_DEFAULT = MTK_DP_COLOR_FORMAT_RGB_444,
> + MTK_DP_COLOR_FORMAT_UNKNOWN = 15,
> +};
Isn't that redundant with DP_MSA_MISC_COLOR_* ?
> +/* Multiple of 0.27Gbps */
> +enum mtk_dp_linkrate {
> + MTK_DP_LINKRATE_RBR = 0x6,
> + MTK_DP_LINKRATE_HBR = 0xA,
> + MTK_DP_LINKRATE_HBR2 = 0x14,
> + MTK_DP_LINKRATE_HBR25 = 0x19,
> + MTK_DP_LINKRATE_HBR3 = 0x1E,
> +};
> +
> +/* Same values as used for DP Spec MISC0 bits 5,6,7 */
> +enum mtk_dp_color_depth {
> + MTK_DP_COLOR_DEPTH_6BIT = 0,
> + MTK_DP_COLOR_DEPTH_8BIT = 1,
> + MTK_DP_COLOR_DEPTH_10BIT = 2,
> + MTK_DP_COLOR_DEPTH_12BIT = 3,
> + MTK_DP_COLOR_DEPTH_16BIT = 4,
> + MTK_DP_COLOR_DEPTH_UNKNOWN = 5,
> +};
DP_MSA_MISC_*_BPC?
> +struct mtk_dp_info {
> + enum mtk_dp_color_depth depth;
> + enum mtk_dp_color_format format;
> + struct mtk_dp_timings timings;
> +};
> +
> +struct dp_cal_data {
> + unsigned int glb_bias_trim;
> + unsigned int clktx_impse;
> +
> + //TODO: see above with MTK_DP_MAX_LANES, make it SoC specific
> + unsigned int ln_tx_impsel_pmos[MTK_DP_MAX_LANES];
> + unsigned int ln_tx_impsel_nmos[MTK_DP_MAX_LANES];
> +};
> +
> +struct mtk_dp {
> + struct device *dev;
> + struct phy *phy;
> + struct dp_cal_data cal_data;
> +
> + struct drm_device *drm_dev;
> + struct drm_bridge bridge;
> + struct drm_bridge *next_bridge;
> + struct drm_dp_aux aux;
> +
> + /* Protects edid as it is used in both bridge ops and IRQ handler */
> + struct mutex edid_lock;
> + struct edid *edid;
> +
> + u8 rx_cap[DP_RECEIVER_CAP_SIZE];
> +
> + struct mtk_dp_info info;
> + enum mtk_dp_state state;
> +
> + struct mtk_dp_train_info train_info;
> + enum mtk_dp_train_state train_state;
> + unsigned int input_fmt;
> +
> + struct regmap *regs;
> + struct clk *dp_tx_clk;
> +
> + bool enabled;
> +
> + bool has_fec;
> + /* Protects the mtk_dp struct */
> + struct mutex dp_lock;
> +
> + hdmi_codec_plugged_cb plugged_cb;
> + struct device *codec_dev;
> + u8 connector_eld[MAX_ELD_BYTES];
> + struct drm_connector *conn;
> +};
> +
> +static struct mtk_dp *mtk_dp_from_bridge(struct drm_bridge *b)
> +{
> + return container_of(b, struct mtk_dp, bridge);
> +}
> +
> +static u32 mtk_dp_read(struct mtk_dp *mtk_dp, u32 offset)
> +{
> + u32 read_val;
> + int ret;
> +
> + ret = regmap_read(mtk_dp->regs, offset, &read_val);
> + if (ret) {
> + dev_err(mtk_dp->dev, "Failed to read register 0x%x: %d\n",
> + offset, ret);
> + return 0;
> + }
> +
> + return read_val;
> +}
> +
> +static int mtk_dp_write(struct mtk_dp *mtk_dp, u32 offset, u32 val)
> +{
> + int ret;
> +
> + ret = regmap_write(mtk_dp->regs, offset, val);
> + if (ret)
> + dev_err(mtk_dp->dev,
> + "Failed to write register 0x%x with value 0x%x: %d\n",
> + offset, val, ret);
> + return ret;
> +}
> +
> +static int mtk_dp_update_bits(struct mtk_dp *mtk_dp, u32 offset, u32 val,
> + u32 mask)
> +{
> + int ret;
> +
> + ret = regmap_update_bits(mtk_dp->regs, offset, mask, val);
> + if (ret)
> + dev_err(mtk_dp->dev,
> + "Failed to update register 0x%x with value 0x%x, mask 0x%x: %d\n",
> + offset, val, mask, ret);
> + return ret;
> +}
> +
> +static int mtk_dp_bulk_16bit_write(struct mtk_dp *mtk_dp, u32 offset, u8 *buf,
> + size_t length)
> +{
> + int i;
> + int ret = 0;
> + int num_regs = (length + 1) / 2;
> +
> + /* 2 bytes per register */
> + for (i = 0; i < num_regs; i++) {
> + u32 val = buf[i * 2] |
> + (i * 2 + 1 < length ? buf[i * 2 + 1] << 8 : 0);
> +
> + ret = mtk_dp_write(mtk_dp, offset + i * 4, val);
> + if (ret)
> + goto out;
> + }
> +
> +out:
> + return ret;
> +}
> +
> +static unsigned long mtk_dp_sip_atf_call(unsigned int cmd, unsigned int para)
> +{
> + struct arm_smccc_res res;
> +
> + arm_smccc_smc(MTK_DP_SIP_CONTROL_AARCH32, cmd, para, 0, 0, 0, 0, 0,
> + &res);
> +
> + pr_debug("[DPTX]%s cmd 0x%x, p1 0x%x, ret 0x%lx-0x%lx", __func__, cmd,
> + para, res.a0, res.a1);
> + return res.a1;
> +}
> +
> +static int mtk_dp_msa_bypass_disable(struct mtk_dp *mtk_dp)
> +{
> + const u16 bits_to_set =
> + BIT(HTOTAL_SEL_DP_ENC0_P0_SHIFT) |
> + BIT(VTOTAL_SEL_DP_ENC0_P0_SHIFT) |
> + BIT(HSTART_SEL_DP_ENC0_P0_SHIFT) |
> + BIT(VSTART_SEL_DP_ENC0_P0_SHIFT) |
> + BIT(HWIDTH_SEL_DP_ENC0_P0_SHIFT) |
> + BIT(VHEIGHT_SEL_DP_ENC0_P0_SHIFT) |
> + BIT(HSP_SEL_DP_ENC0_P0_SHIFT) | BIT(HSW_SEL_DP_ENC0_P0_SHIFT) |
> + BIT(VSP_SEL_DP_ENC0_P0_SHIFT) | BIT(VSW_SEL_DP_ENC0_P0_SHIFT);
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3030, bits_to_set,
> + bits_to_set);
> +}
> +
> +#define MTK_UPD_BITS_OR_OUT(mtk_dp, offset, val, mask, ret, label) \
> + do {\
> + ret = mtk_dp_update_bits(mtk_dp, offset, val, mask); \
> + if (ret) \
> + goto label; \
> + } while (0)
> +
> +static int mtk_dp_set_msa(struct mtk_dp *mtk_dp)
> +{
> + int ret;
> + struct mtk_dp_timings *timings = &mtk_dp->info.timings;
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3010, timings->htotal,
> + HTOTAL_SW_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3018,
> + timings->vm.hsync_len + timings->vm.hback_porch,
> + HSTART_SW_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3028,
> + timings->vm.hsync_len << HSW_SW_DP_ENC0_P0_SHIFT,
> + HSW_SW_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3028, 0,
> + HSP_SW_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3020, timings->vm.hactive,
> + HWIDTH_SW_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3014, timings->vtotal,
> + VTOTAL_SW_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_301C,
> + timings->vm.vsync_len + timings->vm.vback_porch,
> + VSTART_SW_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_302C,
> + timings->vm.vsync_len << VSW_SW_DP_ENC0_P0_SHIFT,
> + VSW_SW_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_302C, 0,
> + VSP_SW_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3024, timings->vm.vactive,
> + VHEIGHT_SW_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3064, timings->vm.hactive,
> + HDE_NUM_LAST_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3154, timings->htotal,
> + PGEN_HTOTAL_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3158,
> + timings->vm.hfront_porch,
> + PGEN_HSYNC_RISING_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_315C, timings->vm.hsync_len,
> + PGEN_HSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3160,
> + timings->vm.hback_porch + timings->vm.hsync_len,
> + PGEN_HFDE_START_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3164, timings->vm.hactive,
> + PGEN_HFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3168, timings->vtotal,
> + PGEN_VTOTAL_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_316C,
> + timings->vm.vfront_porch,
> + PGEN_VSYNC_RISING_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3170, timings->vm.vsync_len,
> + PGEN_VSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3174,
> + timings->vm.vback_porch + timings->vm.vsync_len,
> + PGEN_VFDE_START_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3178, timings->vm.vactive,
> + PGEN_VFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK, ret, out);
> +
> +out:
> + return ret;
> +}
> +
> +static int mtk_dp_set_color_format(struct mtk_dp *mtk_dp,
> + enum mtk_dp_color_format color_format)
> +{
> + u32 val;
> + int ret;
> +
> + mtk_dp->info.format = color_format;
> +
> + /* Update MISC0 */
> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
> + color_format << DP_TEST_COLOR_FORMAT_SHIFT,
> + DP_TEST_COLOR_FORMAT_MASK);
> +
> + if (ret)
> + return ret;
> +
> + switch (color_format) {
> + case MTK_DP_COLOR_FORMAT_YUV_422:
> + val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422;
> + break;
> + case MTK_DP_COLOR_FORMAT_YUV_420:
> + val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR420;
> + break;
> + case MTK_DP_COLOR_FORMAT_YONLY:
> + case MTK_DP_COLOR_FORMAT_RAW:
> + case MTK_DP_COLOR_FORMAT_RESERVED:
> + case MTK_DP_COLOR_FORMAT_UNKNOWN:
> + drm_warn(mtk_dp->drm_dev, "Unsupported color format: %d\n",
> + color_format);
> + fallthrough;
> + case MTK_DP_COLOR_FORMAT_RGB_444:
> + case MTK_DP_COLOR_FORMAT_YUV_444:
> + val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB;
> + break;
> + }
> +
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C, val,
> + PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK);
> +}
> +
> +static int mtk_dp_set_color_depth(struct mtk_dp *mtk_dp,
> + enum mtk_dp_color_depth color_depth)
> +{
> + int ret;
> + u32 val;
> +
> + mtk_dp->info.depth = color_depth;
> +
> + /* Update MISC0 */
> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
> + color_depth << DP_TEST_BIT_DEPTH_SHIFT,
> + DP_TEST_BIT_DEPTH_MASK);
> +
> + if (ret)
> + return ret;
> +
> + switch (color_depth) {
> + case MTK_DP_COLOR_DEPTH_6BIT:
> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_6BIT;
> + break;
> + case MTK_DP_COLOR_DEPTH_8BIT:
> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_8BIT;
> + break;
> + case MTK_DP_COLOR_DEPTH_10BIT:
> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_10BIT;
> + break;
> + case MTK_DP_COLOR_DEPTH_12BIT:
> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_12BIT;
> + break;
> + case MTK_DP_COLOR_DEPTH_16BIT:
> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_16BIT;
> + break;
> + case MTK_DP_COLOR_DEPTH_UNKNOWN:
> + drm_warn(mtk_dp->drm_dev, "Unsupported color depth %d\n",
> + color_depth);
> + return -EINVAL;
> + }
> +
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C, val,
> + VIDEO_COLOR_DEPTH_DP_ENC0_P0_MASK);
> +}
> +
> +static int mtk_dp_mn_overwrite_disable(struct mtk_dp *mtk_dp)
> +{
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004, 0,
> + VIDEO_M_CODE_SEL_DP_ENC0_P0_MASK);
> +}
> +
> +static int mtk_dp_set_sram_read_start(struct mtk_dp *mtk_dp, u32 val)
> +{
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
> + val << SRAM_START_READ_THRD_DP_ENC0_P0_SHIFT,
> + SRAM_START_READ_THRD_DP_ENC0_P0_MASK);
> +}
> +
> +static int mtk_dp_setup_encoder(struct mtk_dp *mtk_dp)
> +{
> + int ret;
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_303C,
> + BIT(VIDEO_MN_GEN_EN_DP_ENC0_P0_SHIFT),
> + VIDEO_MN_GEN_EN_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3040,
> + 0x20 << SDP_DOWN_CNT_INIT_DP_ENC0_P0_SHIFT,
> + SDP_DOWN_CNT_INIT_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3364,
> + 0x20 << SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_SHIFT,
> + SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3300,
> + 2 << VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_SHIFT,
> + VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3364,
> + 4 << FIFO_READ_START_POINT_DP_ENC1_P0_SHIFT,
> + FIFO_READ_START_POINT_DP_ENC1_P0_MASK, ret, out);
> + ret = mtk_dp_write(mtk_dp, MTK_DP_ENC1_P0_3368,
> + 1 << VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0_SHIFT |
> + 1 << VIDEO_STABLE_CNT_THRD_DP_ENC1_P0_SHIFT |
> + BIT(SDP_DP13_EN_DP_ENC1_P0_SHIFT) |
> + 1 << BS2BS_MODE_DP_ENC1_P0_SHIFT);
> +
> +out:
> + return ret;
> +}
> +
> +static int mtk_dp_pg_disable(struct mtk_dp *mtk_dp)
> +{
> + int ret;
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3038, 0,
> + VIDEO_SOURCE_SEL_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_31B0,
> + 4 << PGEN_PATTERN_SEL_SHIFT, PGEN_PATTERN_SEL_MASK, ret, out);
> +
> +out:
> + return ret;
> +}
> +
> +static bool mtk_dp_plug_state(struct mtk_dp *mtk_dp)
> +{
> + return !!(mtk_dp_read(mtk_dp, MTK_DP_TRANS_P0_3414) &
> + HPD_DB_DP_TRANS_P0_MASK);
> +}
> +
> +static void mtk_dp_aux_irq_clear(struct mtk_dp *mtk_dp)
> +{
> + mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3640,
> + BIT(AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_SHIFT) |
> + BIT(AUX_RX_DATA_RECV_IRQ_AUX_TX_P0_SHIFT) |
> + BIT(AUX_RX_ADDR_RECV_IRQ_AUX_TX_P0_SHIFT) |
> + BIT(AUX_RX_CMD_RECV_IRQ_AUX_TX_P0_SHIFT) |
> + BIT(AUX_RX_MCCS_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT) |
> + BIT(AUX_RX_EDID_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT) |
> + BIT(AUX_RX_AUX_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT));
> +}
> +
> +static int mtk_dp_aux_set_cmd(struct mtk_dp *mtk_dp, u8 cmd, u32 addr)
> +{
> + int ret;
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3644, cmd,
> + MCU_REQUEST_COMMAND_AUX_TX_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3648, addr,
> + MCU_REQUEST_ADDRESS_LSB_AUX_TX_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_364C, addr >> 16,
> + MCU_REQUEST_ADDRESS_MSB_AUX_TX_P0_MASK, ret, out);
> +
> +out:
> + return ret;
> +}
> +
> +static int mtk_dp_aux_cmd_complete(struct mtk_dp *mtk_dp)
> +{
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3650,
> + BIT(MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_SHIFT),
> + MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_MASK |
> + PHY_FIFO_RST_AUX_TX_P0_MASK |
> + MCU_REQ_DATA_NUM_AUX_TX_P0_MASK);
> +}
> +
> +static int mtk_dp_aux_request_ready(struct mtk_dp *mtk_dp)
> +{
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3630,
> + BIT(AUX_TX_REQUEST_READY_AUX_TX_P0_SHIFT),
> + AUX_TX_REQUEST_READY_AUX_TX_P0_MASK);
> +}
> +
> +static void mtk_dp_aux_fill_write_fifo(struct mtk_dp *mtk_dp, u8 *buf,
> + size_t length)
> +{
> + mtk_dp_bulk_16bit_write(mtk_dp, MTK_DP_AUX_P0_3708, buf, length);
> +}
> +
> +static int mtk_dp_aux_read_rx_fifo(struct mtk_dp *mtk_dp, u8 *buf,
> + size_t length, int read_delay)
> +{
> + int ret;
> + int read_pos;
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3620, 0,
> + AUX_RD_MODE_AUX_TX_P0_MASK, ret, out);
> +
> + for (read_pos = 0; read_pos < length; read_pos++) {
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3620,
> + BIT(AUX_RX_FIFO_R_PULSE_TX_P0_SHIFT),
> + AUX_RX_FIFO_READ_PULSE_TX_P0_MASK, ret, out);
> + usleep_range(read_delay, read_delay * 2);
> + buf[read_pos] =
> + (u8)(mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3620) &
> + AUX_RX_FIFO_READ_DATA_AUX_TX_P0_MASK >>
> + AUX_RX_FIFO_READ_DATA_AUX_TX_P0_SHIFT);
> + }
> +
> +out:
> + return ret;
> +}
> +
> +static int mtk_dp_aux_set_length(struct mtk_dp *mtk_dp, size_t length)
> +{
> + int ret;
> +
> + if (length > 0) {
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3650,
> + (length - 1)
> + << MCU_REQ_DATA_NUM_AUX_TX_P0_SHIFT,
> + MCU_REQ_DATA_NUM_AUX_TX_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_362C, 0,
> + AUX_NO_LENGTH_AUX_TX_P0_MASK |
> + AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK |
> + AUX_RESERVED_RW_0_AUX_TX_P0_MASK, ret, out);
> + } else {
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_362C,
> + BIT(AUX_NO_LENGTH_AUX_TX_P0_SHIFT),
> + AUX_NO_LENGTH_AUX_TX_P0_MASK |
> + AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK |
> + AUX_RESERVED_RW_0_AUX_TX_P0_MASK, ret, out);
> + }
> +
> +out:
> + return ret;
> +}
> +
> +static int mtk_dp_aux_wait_for_completion(struct mtk_dp *mtk_dp, bool is_read)
> +{
> + int wait_reply = MTK_DP_AUX_WAIT_REPLY_COUNT;
> +
> + while (--wait_reply) {
> + u32 aux_irq_status;
> +
> + if (is_read) {
> + u32 fifo_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3618);
> +
> + if (fifo_status &
> + (AUX_RX_FIFO_WRITE_POINTER_AUX_TX_P0_MASK |
> + AUX_RX_FIFO_FULL_AUX_TX_P0_MASK)) {
> + return 0;
> + }
> + }
> +
> + aux_irq_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3640);
> + if (aux_irq_status & AUX_RX_RECV_COMPLETE_IRQ_TX_P0_MASK)
> + return 0;
> +
> + if (aux_irq_status & AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_MASK)
> + return -ETIMEDOUT;
> +
> + usleep_range(100, 500);
> + }
> +
> + return -ETIMEDOUT;
> +}
> +
> +static int mtk_dp_aux_do_transfer(struct mtk_dp *mtk_dp, bool is_read, u8 cmd,
> + u32 addr, u8 *buf, size_t length)
> +{
> + int ret;
> + u32 reply_cmd;
> +
> + if (is_read && (length > DP_AUX_MAX_PAYLOAD_BYTES ||
> + (cmd == DP_AUX_NATIVE_READ && !length)))
> + return -EINVAL;
> +
> + if (!is_read) {
> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3704,
> + BIT(AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_SHIFT),
> + AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_MASK);
> +
> + if (ret)
> + return ret;
> + }
> +
> + mtk_dp_aux_cmd_complete(mtk_dp);
> + mtk_dp_aux_irq_clear(mtk_dp);
> + usleep_range(MTK_DP_AUX_WRITE_READ_WAIT_TIME_US,
> + MTK_DP_AUX_WRITE_READ_WAIT_TIME_US * 2);
> +
> + mtk_dp_aux_set_cmd(mtk_dp, cmd, addr);
> + mtk_dp_aux_set_length(mtk_dp, length);
> +
> + if (!is_read) {
> + if (length)
> + mtk_dp_aux_fill_write_fifo(mtk_dp, buf, length);
> +
> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3704,
> + AUX_TX_FIFO_WRITE_DATA_NEW_MODE_TOGGLE_AUX_TX_P0_MASK,
> + AUX_TX_FIFO_WRITE_DATA_NEW_MODE_TOGGLE_AUX_TX_P0_MASK);
> +
> + if (ret)
> + return ret;
> + }
> +
> + mtk_dp_aux_request_ready(mtk_dp);
> +
> + ret = mtk_dp_aux_wait_for_completion(mtk_dp, is_read);
> +
> + reply_cmd = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3624) &
> + AUX_RX_REPLY_COMMAND_AUX_TX_P0_MASK;
> +
> + if (ret || reply_cmd) {
> + u32 phy_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3628) &
> + AUX_RX_PHY_STATE_AUX_TX_P0_MASK;
> + if (phy_status != AUX_RX_PHY_STATE_AUX_TX_P0_RX_IDLE) {
> + drm_err(mtk_dp->drm_dev,
> + "AUX Rx Aux hang, need SW reset\n");
> + return -EIO;
> + }
> +
> + mtk_dp_aux_cmd_complete(mtk_dp);
> + mtk_dp_aux_irq_clear(mtk_dp);
> +
> + usleep_range(MTK_DP_AUX_WRITE_READ_WAIT_TIME_US,
> + MTK_DP_AUX_WRITE_READ_WAIT_TIME_US * 2);
> + return -ETIMEDOUT;
> + }
> +
> + if (!length) {
> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_362C, 0,
> + AUX_NO_LENGTH_AUX_TX_P0_MASK |
> + AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK |
> + AUX_RESERVED_RW_0_AUX_TX_P0_MASK);
> +
> + if (ret)
> + return ret;
> +
> + } else if (is_read) {
> + int read_delay;
> +
> + if (cmd == (DP_AUX_I2C_READ | DP_AUX_I2C_MOT) ||
> + cmd == DP_AUX_I2C_READ)
> + read_delay = 500;
> + else
> + read_delay = 100;
> +
> + mtk_dp_aux_read_rx_fifo(mtk_dp, buf, length, read_delay);
> + }
> +
> + mtk_dp_aux_cmd_complete(mtk_dp);
> + mtk_dp_aux_irq_clear(mtk_dp);
> + usleep_range(MTK_DP_AUX_WRITE_READ_WAIT_TIME_US,
> + MTK_DP_AUX_WRITE_READ_WAIT_TIME_US * 2);
> +
> + return 0;
> +}
> +
> +static bool mtk_dp_set_swing_pre_emphasis(struct mtk_dp *mtk_dp, int lane_num,
> + int swing_val, int preemphasis)
> +{
> + int ret;
> +
> + u32 lane_shift = lane_num * DP_TX1_VOLT_SWING_SHIFT;
> +
> + if (lane_num < 0 || lane_num > 3)
> + return false;
> +
> + dev_dbg(mtk_dp->dev,
> + "link training swing_val= 0x%x, preemphasis = 0x%x\n",
> + swing_val, preemphasis);
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_SWING_EMP,
> + swing_val << (DP_TX0_VOLT_SWING_SHIFT + lane_shift),
> + DP_TX0_VOLT_SWING_MASK << lane_shift, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_SWING_EMP,
> + preemphasis << (DP_TX0_PRE_EMPH_SHIFT + lane_shift),
> + DP_TX0_PRE_EMPH_MASK << lane_shift, ret, out);
> +
> +out:
> + return !ret;
> +}
> +
> +static int mtk_dp_reset_swing_pre_emphasis(struct mtk_dp *mtk_dp)
> +{
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_SWING_EMP, 0,
> + DP_TX0_VOLT_SWING_MASK | DP_TX1_VOLT_SWING_MASK |
> + DP_TX2_VOLT_SWING_MASK |
> + DP_TX3_VOLT_SWING_MASK |
> + DP_TX0_PRE_EMPH_MASK | DP_TX1_PRE_EMPH_MASK |
> + DP_TX2_PRE_EMPH_MASK | DP_TX3_PRE_EMPH_MASK);
> +}
> +
> +static int mtk_dp_fec_enable(struct mtk_dp *mtk_dp, bool enable)
> +{
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3540,
> + enable ? BIT(FEC_EN_DP_TRANS_P0_SHIFT) : 0,
> + FEC_EN_DP_TRANS_P0_MASK);
> +}
> +
> +static int mtk_dp_hwirq_enable(struct mtk_dp *mtk_dp, bool enable)
> +{
> + u32 val = 0;
> +
> + if (!enable)
> + val = IRQ_MASK_DP_TRANS_P0_DISC_IRQ |
> + IRQ_MASK_DP_TRANS_P0_CONN_IRQ |
> + IRQ_MASK_DP_TRANS_P0_INT_IRQ;
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3418, val,
> + IRQ_MASK_DP_TRANS_P0_MASK);
> +}
> +
> +static int mtk_dp_initialize_settings(struct mtk_dp *mtk_dp)
> +{
> + int ret;
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_342C,
> + XTAL_FREQ_DP_TRANS_P0_DEFAULT,
> + XTAL_FREQ_DP_TRANS_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_3540,
> + BIT(FEC_CLOCK_EN_MODE_DP_TRANS_P0_SHIFT),
> + FEC_CLOCK_EN_MODE_DP_TRANS_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_31EC,
> + BIT(AUDIO_CH_SRC_SEL_DP_ENC0_P0_SHIFT),
> + AUDIO_CH_SRC_SEL_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_304C, 0,
> + SDP_VSYNC_RISING_MASK_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_IRQ_MASK, IRQ_MASK_AUX_TOP_IRQ,
> + IRQ_MASK_AUX_TOP_IRQ, ret, out);
> +
> +out:
> + return ret;
> +}
> +
> +static void mtk_dp_initialize_hpd_detect_settings(struct mtk_dp *mtk_dp)
> +{
> + // Debounce threshold
> + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
> + 8 << HPD_DEB_THD_DP_TRANS_P0_SHIFT,
> + HPD_DEB_THD_DP_TRANS_P0_MASK);
> + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
> + (HPD_INT_THD_DP_TRANS_P0_LOWER_500US |
> + HPD_INT_THD_DP_TRANS_P0_UPPER_1100US)
> + << HPD_INT_THD_DP_TRANS_P0_SHIFT,
> + HPD_INT_THD_DP_TRANS_P0_MASK);
> +
> + // Connect threshold 1.5ms + 5 x 0.1ms = 2ms
> + // Disconnect threshold 1.5ms + 5 x 0.1ms = 2ms
> + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
> + (5 << HPD_DISC_THD_DP_TRANS_P0_SHIFT) |
> + (5 << HPD_CONN_THD_DP_TRANS_P0_SHIFT),
> + HPD_DISC_THD_DP_TRANS_P0_MASK |
> + HPD_CONN_THD_DP_TRANS_P0_MASK);
> + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3430,
> + HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT,
> + HPD_INT_THD_ECO_DP_TRANS_P0_MASK);
> +}
> +
> +static int mtk_dp_initialize_aux_settings(struct mtk_dp *mtk_dp)
> +{
> + int ret;
> +
> + /* modify timeout threshold = 1595 [12 : 8] */
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_360C, 0x1595,
> + AUX_TIMEOUT_THR_AUX_TX_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3658, 0,
> + AUX_TX_OV_EN_AUX_TX_P0_MASK, ret, out);
> + /* 25 for 26M */
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3634,
> + 25 << AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_SHIFT,
> + AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_MASK, ret, out);
> + /* 13 for 26M */
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3614,
> + 13 << AUX_RX_UI_CNT_THR_AUX_TX_P0_SHIFT,
> + AUX_RX_UI_CNT_THR_AUX_TX_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_37C8,
> + BIT(MTK_ATOP_EN_AUX_TX_P0_SHIFT),
> + MTK_ATOP_EN_AUX_TX_P0_MASK, ret, out);
> +
> +out:
> + return ret;
> +}
> +
> +static int mtk_dp_initialize_digital_settings(struct mtk_dp *mtk_dp)
> +{
> + int ret;
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_304C, 0,
> + VBID_VIDEO_MUTE_DP_ENC0_P0_MASK, ret, out);
> + mtk_dp_set_color_format(mtk_dp, MTK_DP_COLOR_FORMAT_RGB_444);
> + mtk_dp_set_color_depth(mtk_dp, MTK_DP_COLOR_DEPTH_8BIT);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3368,
> + 1 << BS2BS_MODE_DP_ENC1_P0_SHIFT,
> + BS2BS_MODE_DP_ENC1_P0_MASK, ret, out);
> +
> + /* dp tx encoder reset all sw */
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3004,
> + BIT(DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_SHIFT),
> + DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_MASK, ret, out);
> + usleep_range(1000, 5000);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3004, 0,
> + DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_MASK, ret, out);
> +
> +out:
> + return ret;
> +}
> +
> +static int mtk_dp_digital_sw_reset(struct mtk_dp *mtk_dp)
> +{
> + int ret;
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_340C,
> + BIT(DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_SHIFT),
> + DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_MASK, ret, out);
> + usleep_range(1000, 5000);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_340C, 0,
> + DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_MASK, ret, out);
> +
> +out:
> + return ret;
> +}
> +
> +static int mtk_dp_set_lanes(struct mtk_dp *mtk_dp, int lanes)
> +{
> + int ret;
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_35F0,
> + lanes == 0 ? 0 : BIT(3), BIT(3) | BIT(2), ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3000, lanes,
> + LANE_NUM_DP_ENC0_P0_MASK, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_34A4,
> + lanes << LANE_NUM_DP_TRANS_P0_SHIFT,
> + LANE_NUM_DP_TRANS_P0_MASK, ret, out);
> +
> +out:
> + return ret;
> +}
> +
> +static int link_rate_to_mb_per_s(struct mtk_dp *mtk_dp,
> + enum mtk_dp_linkrate linkrate)
> +{
> + switch (linkrate) {
> + default:
> + drm_err(mtk_dp->drm_dev,
> + "Implementation error, unknown linkrate %d\n",
> + linkrate);
> + fallthrough;
> + case MTK_DP_LINKRATE_RBR:
> + return 1620;
> + case MTK_DP_LINKRATE_HBR:
> + return 2700;
> + case MTK_DP_LINKRATE_HBR2:
> + return 5400;
> + case MTK_DP_LINKRATE_HBR3:
> + return 8100;
> + }
> +}
> +
> +static u32 check_cal_data_valid(u32 min, u32 max, u32 val, u32 default_val)
> +{
> + if (val < min || val > max)
> + return default_val;
> +
> + return val;
> +}
> +
> +static int mtk_dp_get_calibration_data(struct mtk_dp *mtk_dp)
> +{
> + struct dp_cal_data *cal_data = &mtk_dp->cal_data;
> + struct device *dev = mtk_dp->dev;
> + struct nvmem_cell *cell;
> + u32 *buf;
> + size_t len;
> +
> + cell = nvmem_cell_get(dev, "dp_calibration_data");
> + if (IS_ERR(cell)) {
> + dev_err(dev,
> + "Error: Failed to get nvmem cell dp_calibration_data\n");
> + return PTR_ERR(cell);
> + }
> +
> + buf = (u32 *)nvmem_cell_read(cell, &len);
> + nvmem_cell_put(cell);
> +
> + if (IS_ERR(buf) || ((len / sizeof(u32)) != 4)) {
> + dev_err(dev,
> + "Error: Failed to read nvmem_cell_read fail len %ld\n",
> + (len / sizeof(u32)));
> + return PTR_ERR(buf);
> + }
> +
> + cal_data->glb_bias_trim =
> + check_cal_data_valid(1, 0x1e, (buf[3] >> 27) & 0x1f, 0xf);
> + cal_data->clktx_impse =
> + check_cal_data_valid(1, 0xe, (buf[0] >> 9) & 0xf, 0x8);
> + cal_data->ln_tx_impsel_pmos[0] =
> + check_cal_data_valid(1, 0xe, (buf[2] >> 28) & 0xf, 0x8);
> + cal_data->ln_tx_impsel_nmos[0] =
> + check_cal_data_valid(1, 0xe, (buf[2] >> 24) & 0xf, 0x8);
> + cal_data->ln_tx_impsel_pmos[1] =
> + check_cal_data_valid(1, 0xe, (buf[2] >> 20) & 0xf, 0x8);
> + cal_data->ln_tx_impsel_nmos[1] =
> + check_cal_data_valid(1, 0xe, (buf[2] >> 16) & 0xf, 0x8);
> + cal_data->ln_tx_impsel_pmos[2] =
> + check_cal_data_valid(1, 0xe, (buf[2] >> 12) & 0xf, 0x8);
> + cal_data->ln_tx_impsel_nmos[2] =
> + check_cal_data_valid(1, 0xe, (buf[2] >> 8) & 0xf, 0x8);
> + cal_data->ln_tx_impsel_pmos[3] =
> + check_cal_data_valid(1, 0xe, (buf[2] >> 4) & 0xf, 0x8);
> + cal_data->ln_tx_impsel_nmos[3] =
> + check_cal_data_valid(1, 0xe, buf[2] & 0xf, 0x8);
> +
> + kfree(buf);
> +
> + return 0;
> +}
> +
> +static int mtk_dp_set_cal_data(struct mtk_dp *mtk_dp)
> +{
> + int ret;
> + struct dp_cal_data *cal_data = &mtk_dp->cal_data;
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_GLB_DPAUX_TX,
> + cal_data->clktx_impse << 20, RG_CKM_PT0_CKTX_IMPSEL, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_GLB_BIAS_GEN_00,
> + cal_data->glb_bias_trim << 16,
> + RG_XTP_GLB_BIAS_INTR_CTRL, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_0,
> + cal_data->ln_tx_impsel_pmos[0] << 12,
> + RG_XTP_LN0_TX_IMPSEL_PMOS, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_0,
> + cal_data->ln_tx_impsel_nmos[0] << 16,
> + RG_XTP_LN0_TX_IMPSEL_NMOS, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_1,
> + cal_data->ln_tx_impsel_pmos[1] << 12,
> + RG_XTP_LN1_TX_IMPSEL_PMOS, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_1,
> + cal_data->ln_tx_impsel_nmos[1] << 16,
> + RG_XTP_LN1_TX_IMPSEL_NMOS, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_2,
> + cal_data->ln_tx_impsel_pmos[2] << 12,
> + RG_XTP_LN2_TX_IMPSEL_PMOS, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_2,
> + cal_data->ln_tx_impsel_nmos[2] << 16,
> + RG_XTP_LN2_TX_IMPSEL_NMOS, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_3,
> + cal_data->ln_tx_impsel_pmos[3] << 12,
> + RG_XTP_LN3_TX_IMPSEL_PMOS, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_3,
> + cal_data->ln_tx_impsel_nmos[3] << 16,
> + RG_XTP_LN3_TX_IMPSEL_NMOS, ret, out);
> +
> +out:
> + return ret;
> +}
> +
> +static int mtk_dp_phy_configure(struct mtk_dp *mtk_dp,
> + enum mtk_dp_linkrate link_rate, int lane_count)
> +{
> + int ret;
> + union phy_configure_opts phy_opts = {
> + .dp = {
> + .link_rate = link_rate_to_mb_per_s(mtk_dp, link_rate),
> + .set_rate = 1,
> + .lanes = lane_count,
> + .set_lanes = 1,
> + .ssc = mtk_dp->train_info.sink_ssc,
> + }
> + };
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_PWR_STATE, DP_PWR_STATE_BANDGAP,
> + DP_PWR_STATE_MASK, ret, out);
> +
> + ret = phy_configure(mtk_dp->phy, &phy_opts);
> +
> + if (ret)
> + goto out;
> +
> + mtk_dp_set_cal_data(mtk_dp);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_PWR_STATE,
> + DP_PWR_STATE_BANDGAP_TPLL_LANE, DP_PWR_STATE_MASK, ret, out);
> +
> +out:
> + return ret;
> +}
> +
> +static int mtk_dp_set_idle_pattern(struct mtk_dp *mtk_dp, bool enable)
> +{
> + const u32 val = POST_MISC_DATA_LANE0_OV_DP_TRANS_P0_MASK |
> + POST_MISC_DATA_LANE1_OV_DP_TRANS_P0_MASK |
> + POST_MISC_DATA_LANE2_OV_DP_TRANS_P0_MASK |
> + POST_MISC_DATA_LANE3_OV_DP_TRANS_P0_MASK;
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3580, enable ? val : 0, val);
> +}
> +
> +//TODO: check return value in callee
> +static int mtk_dp_train_set_pattern(struct mtk_dp *mtk_dp, int pattern)
> +{
> + if (pattern < 0 || pattern > 4) {
> + drm_err(mtk_dp->drm_dev,
> + "Implementation error, no such pattern %d\n", pattern);
> + return -EINVAL;
> + }
> +
> + if (pattern == 1) /* TPS1 */
> + mtk_dp_set_idle_pattern(mtk_dp, false);
> +
> + return mtk_dp_update_bits(mtk_dp,
> + MTK_DP_TRANS_P0_3400,
> + pattern ? BIT(pattern - 1) << PATTERN1_EN_DP_TRANS_P0_SHIFT : 0,
> + PATTERN1_EN_DP_TRANS_P0_MASK | PATTERN2_EN_DP_TRANS_P0_MASK |
> + PATTERN3_EN_DP_TRANS_P0_MASK |
> + PATTERN4_EN_DP_TRANS_P0_MASK);
> +}
> +
> +static int mtk_dp_set_enhanced_frame_mode(struct mtk_dp *mtk_dp, bool enable)
> +{
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000,
> + enable ? BIT(ENHANCED_FRAME_EN_DP_ENC0_P0_SHIFT) : 0,
> + ENHANCED_FRAME_EN_DP_ENC0_P0_MASK);
> +}
> +
> +static int mtk_dp_training_set_scramble(struct mtk_dp *mtk_dp, bool enable)
> +{
> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3404,
> + enable ? DP_SCR_EN_DP_TRANS_P0_MASK : 0,
> + DP_SCR_EN_DP_TRANS_P0_MASK);
> +}
> +
> +static void mtk_dp_video_mute(struct mtk_dp *mtk_dp, bool enable)
> +{
> + u32 val = BIT(VIDEO_MUTE_SEL_DP_ENC0_P0_SHIFT);
> +
> + if (enable)
> + val |= BIT(VIDEO_MUTE_SW_DP_ENC0_P0_SHIFT);
> + mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000, val,
> + VIDEO_MUTE_SEL_DP_ENC0_P0_MASK |
> + VIDEO_MUTE_SW_DP_ENC0_P0_MASK);
> +
> + mtk_dp_sip_atf_call(MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE, enable);
> +}
> +
> +static int mtk_dp_power_enable(struct mtk_dp *mtk_dp)
> +{
> + int ret;
> +
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE, 0,
> + SW_RST_B_PHYD, ret, out);
> + usleep_range(10, 200);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE, SW_RST_B_PHYD,
> + SW_RST_B_PHYD, ret, out);
> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_PWR_STATE,
> + DP_PWR_STATE_BANDGAP_TPLL,
> + DP_PWR_STATE_MASK, ret, out);
> +
> +out:
> + return ret;
> +}
> +
> +static int mtk_dp_power_disable(struct mtk_dp *mtk_dp)
> +{
> + int ret;
> +
> + ret = mtk_dp_write(mtk_dp, MTK_DP_TOP_PWR_STATE, 0);
> +
> + if (ret)
> + goto out;
> +
> + usleep_range(10, 200);
> + ret = mtk_dp_write(mtk_dp, MTK_DP_0034,
> + DA_CKM_CKTX0_EN_FORCE_EN | DA_CKM_BIAS_LPF_EN_FORCE_VAL |
> + DA_CKM_BIAS_EN_FORCE_VAL |
> + DA_XTP_GLB_LDO_EN_FORCE_VAL |
> + DA_XTP_GLB_AVD10_ON_FORCE_VAL);
> +
> + if (ret)
> + goto out;
> +
> + /* Disable RX */
> + ret = mtk_dp_write(mtk_dp, MTK_DP_1040, 0);
> +
> + if (ret)
> + goto out;
> +
> + ret = mtk_dp_write(mtk_dp, MTK_DP_TOP_MEM_PD,
> + 0x550 | BIT(FUSE_SEL_SHIFT) | BIT(MEM_ISO_EN_SHIFT));
> +
> +out:
> + return ret;
> +}
> +
> +static void mtk_dp_initialize_priv_data(struct mtk_dp *mtk_dp)
> +{
> + mtk_dp->train_info.link_rate = MTK_DP_LINKRATE_HBR2;
> + mtk_dp->train_info.lane_count = MTK_DP_MAX_LANES;
> + mtk_dp->train_info.irq_status = 0;
> + mtk_dp->train_info.cable_plugged_in = false;
> + mtk_dp->train_info.cable_state_change = false;
> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_STARTUP;
> + mtk_dp->state = MTK_DP_STATE_INITIAL;
> +
> + mtk_dp->info.format = MTK_DP_COLOR_FORMAT_RGB_444;
> + mtk_dp->info.depth = MTK_DP_COLOR_DEPTH_8BIT;
> + memset(&mtk_dp->info.timings, 0, sizeof(struct mtk_dp_timings));
> + mtk_dp->info.timings.frame_rate = 60;
> +
> + mtk_dp->has_fec = false;
> +}
> +
> +static void mtk_dp_setup_tu(struct mtk_dp *mtk_dp)
> +{
> + u32 sram_read_start = MTK_DP_TBC_BUF_READ_START_ADDR;
> +
> + if (mtk_dp->train_info.lane_count > 0) {
> + sram_read_start = min_t(u32,
> + MTK_DP_TBC_BUF_READ_START_ADDR,
> + mtk_dp->info.timings.vm.hactive /
> + (mtk_dp->train_info.lane_count * 4 * 2 * 2));
> + mtk_dp_set_sram_read_start(mtk_dp, sram_read_start);
> + }
> +
> + mtk_dp_setup_encoder(mtk_dp);
> +}
> +
> +static void mtk_dp_calculate_pixrate(struct mtk_dp *mtk_dp)
> +{
> + int target_frame_rate = 60;
> + int target_pixel_clk;
> +
> + if (mtk_dp->info.timings.frame_rate > 0) {
> + target_frame_rate = mtk_dp->info.timings.frame_rate;
> + target_pixel_clk = (int)mtk_dp->info.timings.htotal *
> + (int)mtk_dp->info.timings.vtotal *
> + target_frame_rate;
> + } else if (mtk_dp->info.timings.pix_rate_khz > 0) {
> + target_pixel_clk = mtk_dp->info.timings.pix_rate_khz * 1000;
> + } else {
> + target_pixel_clk = (int)mtk_dp->info.timings.htotal *
> + (int)mtk_dp->info.timings.vtotal *
> + target_frame_rate;
> + }
> +
> + if (target_pixel_clk > 0)
> + mtk_dp->info.timings.pix_rate_khz = target_pixel_clk / 1000;
> +}
> +
> +static void mtk_dp_set_tx_out(struct mtk_dp *mtk_dp)
> +{
> + mtk_dp_msa_bypass_disable(mtk_dp);
> + mtk_dp_calculate_pixrate(mtk_dp);
> + mtk_dp_pg_disable(mtk_dp);
> + mtk_dp_setup_tu(mtk_dp);
> +}
> +
> +static void mtk_dp_train_update_swing_pre(struct mtk_dp *mtk_dp, int lanes,
> + u8 dpcd_adjust_req[2])
> +{
> + int lane;
> +
> + for (lane = 0; lane < lanes; ++lane) {
> + u8 val;
> + u8 swing;
> + u8 preemphasis;
> + int index = lane / 2;
> + int shift = lane % 2 ? DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : 0;
> +
> + swing = (dpcd_adjust_req[index] >> shift) &
> + DP_ADJUST_VOLTAGE_SWING_LANE0_MASK;
> + preemphasis = ((dpcd_adjust_req[index] >> shift) &
> + DP_ADJUST_PRE_EMPHASIS_LANE0_MASK) >>
> + DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT;
> + val = swing << DP_TRAIN_VOLTAGE_SWING_SHIFT |
> + preemphasis << DP_TRAIN_PRE_EMPHASIS_SHIFT;
> +
> + if (swing == DP_TRAIN_VOLTAGE_SWING_LEVEL_3)
> + val |= DP_TRAIN_MAX_SWING_REACHED;
> + if (preemphasis == 3)
> + val |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
> +
> + mtk_dp_set_swing_pre_emphasis(mtk_dp, lane, swing, preemphasis);
> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_TRAINING_LANE0_SET + lane,
> + val);
> + }
> +
> + /* Wait for the signal to be stable enough */
> + usleep_range(2000, 5000);
> +}
> +
> +static void mtk_dp_read_link_status(struct mtk_dp *mtk_dp,
> + u8 link_status[DP_LINK_STATUS_SIZE])
> +{
> + drm_dp_dpcd_read(&mtk_dp->aux, DP_LANE0_1_STATUS, link_status,
> + DP_LINK_STATUS_SIZE);
> +}
> +
> +static int mtk_dp_train_flow(struct mtk_dp *mtk_dp, int target_link_rate,
> + int target_lane_count)
> +{
> + u8 link_status[DP_LINK_STATUS_SIZE] = {};
> + u8 lane_adjust[2] = {};
> + bool pass_tps1 = false;
> + bool pass_tps2_3 = false;
> + int train_retries;
> + int status_control;
> + int iteration_count;
> + u8 prev_lane_adjust;
> + u8 val;
> +
> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_LINK_BW_SET, target_link_rate);
> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_LANE_COUNT_SET,
> + target_lane_count | DP_LANE_COUNT_ENHANCED_FRAME_EN);
> +
> + if (mtk_dp->train_info.sink_ssc)
> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_DOWNSPREAD_CTRL,
> + DP_SPREAD_AMP_0_5);
> +
> + train_retries = 0;
> + status_control = 0;
> + iteration_count = 1;
> + prev_lane_adjust = 0xFF;
> +
> + mtk_dp_set_lanes(mtk_dp, target_lane_count / 2);
> + mtk_dp_phy_configure(mtk_dp, target_link_rate, target_lane_count);
> +
> + dev_dbg(mtk_dp->dev,
> + "Link train target_link_rate = 0x%x, target_lane_count = 0x%x\n",
> + target_link_rate, target_lane_count);
> +
> + do {
> + train_retries++;
> + if (!mtk_dp->train_info.cable_plugged_in ||
> + ((mtk_dp->train_info.irq_status & MTK_DP_HPD_DISCONNECT) !=
> + 0x0)) {
> + return -ENODEV;
> + }
> +
> + if (mtk_dp->train_state < MTK_DP_TRAIN_STATE_TRAINING)
> + return -EAGAIN;
> +
> + if (!pass_tps1) {
> + mtk_dp_training_set_scramble(mtk_dp, false);
> +
> + if (status_control == 0) {
> + status_control = 1;
> + mtk_dp_train_set_pattern(mtk_dp, 1);
> + val = DP_LINK_SCRAMBLING_DISABLE |
> + DP_TRAINING_PATTERN_1;
> + drm_dp_dpcd_writeb(&mtk_dp->aux,
> + DP_TRAINING_PATTERN_SET,
> + DP_LINK_SCRAMBLING_DISABLE |
> + DP_TRAINING_PATTERN_1);
> + drm_dp_dpcd_read(&mtk_dp->aux,
> + DP_ADJUST_REQUEST_LANE0_1,
> + lane_adjust,
> + sizeof(lane_adjust));
> + iteration_count++;
> +
> + mtk_dp_train_update_swing_pre(mtk_dp,
> + target_lane_count, lane_adjust);
> + }
> +
> + drm_dp_link_train_clock_recovery_delay(&mtk_dp->aux,
> + mtk_dp->rx_cap);
> + mtk_dp_read_link_status(mtk_dp, link_status);
> +
> + if (drm_dp_clock_recovery_ok(link_status,
> + target_lane_count)) {
> + mtk_dp->train_info.cr_done = true;
> + pass_tps1 = true;
> + train_retries = 0;
> + iteration_count = 1;
> + dev_dbg(mtk_dp->dev, "Link train CR pass\n");
> + } else if (prev_lane_adjust == link_status[4]) {
> + iteration_count++;
> + if (prev_lane_adjust &
> + DP_ADJUST_VOLTAGE_SWING_LANE0_MASK)
> + break;
> + } else {
> + prev_lane_adjust = link_status[4];
> + }
> + dev_dbg(mtk_dp->dev, "Link train CQ fail\n");
> + } else if (pass_tps1 && !pass_tps2_3) {
> + if (status_control == 1) {
> + status_control = 2;
> + if (mtk_dp->train_info.tps4) {
> + mtk_dp_train_set_pattern(mtk_dp, 4);
> + val = DP_TRAINING_PATTERN_4;
> + } else if (mtk_dp->train_info.tps3) {
> + mtk_dp_train_set_pattern(mtk_dp, 3);
> + val = DP_LINK_SCRAMBLING_DISABLE |
> + DP_TRAINING_PATTERN_3;
> + } else {
> + mtk_dp_train_set_pattern(mtk_dp, 2);
> + val = DP_LINK_SCRAMBLING_DISABLE |
> + DP_TRAINING_PATTERN_2;
> + }
> + drm_dp_dpcd_writeb(&mtk_dp->aux,
> + DP_TRAINING_PATTERN_SET,
> + val);
> +
> + drm_dp_dpcd_read(&mtk_dp->aux,
> + DP_ADJUST_REQUEST_LANE0_1,
> + lane_adjust,
> + sizeof(lane_adjust));
> +
> + iteration_count++;
> + mtk_dp_train_update_swing_pre(mtk_dp,
> + target_lane_count, lane_adjust);
> + }
> +
> + drm_dp_link_train_channel_eq_delay(&mtk_dp->aux,
> + mtk_dp->rx_cap);
> +
> + mtk_dp_read_link_status(mtk_dp, link_status);
> +
> + if (!drm_dp_clock_recovery_ok(link_status,
> + target_lane_count)) {
> + mtk_dp->train_info.cr_done = false;
> + mtk_dp->train_info.eq_done = false;
> + dev_dbg(mtk_dp->dev, "Link train EQ fail\n");
> + break;
> + }
> +
> + if (drm_dp_channel_eq_ok(link_status,
> + target_lane_count)) {
> + mtk_dp->train_info.eq_done = true;
> + pass_tps2_3 = true;
> + dev_dbg(mtk_dp->dev, "Link train EQ pass\n");
> + break;
> + }
> +
> + if (prev_lane_adjust == link_status[4])
> + iteration_count++;
> + else
> + prev_lane_adjust = link_status[4];
> + }
> +
> + drm_dp_dpcd_read(&mtk_dp->aux, DP_ADJUST_REQUEST_LANE0_1,
> + lane_adjust, sizeof(lane_adjust));
> + mtk_dp_train_update_swing_pre(mtk_dp, target_lane_count,
> + lane_adjust);
> + } while (train_retries < MTK_DP_TRAIN_RETRY_LIMIT &&
> + iteration_count < MTK_DP_TRAIN_MAX_ITERATIONS);
> +
> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_TRAINING_PATTERN_SET,
> + DP_TRAINING_PATTERN_DISABLE);
> + mtk_dp_train_set_pattern(mtk_dp, 0);
> +
> + if (!pass_tps2_3)
> + return -ETIMEDOUT;
> +
> + mtk_dp->train_info.link_rate = target_link_rate;
> + mtk_dp->train_info.lane_count = target_lane_count;
> +
> + mtk_dp_training_set_scramble(mtk_dp, true);
> +
> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_LANE_COUNT_SET,
> + target_lane_count |
> + DP_LANE_COUNT_ENHANCED_FRAME_EN);
> + mtk_dp_set_enhanced_frame_mode(mtk_dp, true);
> +
> + return 0;
> +}
> +
> +static bool mtk_dp_parse_capabilities(struct mtk_dp *mtk_dp)
> +{
> + u8 buf[DP_RECEIVER_CAP_SIZE] = {};
> + u8 val;
> + struct mtk_dp_train_info *train_info = &mtk_dp->train_info;
> +
> + if (!mtk_dp_plug_state(mtk_dp))
> + return false;
> +
> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
> + usleep_range(2000, 5000);
> +
> + drm_dp_read_dpcd_caps(&mtk_dp->aux, buf);
> +
> + memcpy(mtk_dp->rx_cap, buf, min(sizeof(mtk_dp->rx_cap), sizeof(buf)));
> + mtk_dp->rx_cap[DP_TRAINING_AUX_RD_INTERVAL] &= DP_TRAINING_AUX_RD_MASK;
> +
> + train_info->link_rate =
> + min_t(int, MTK_DP_MAX_LINK_RATE, buf[DP_MAX_LINK_RATE]);
> + train_info->lane_count =
> + min_t(int, MTK_DP_MAX_LANES, drm_dp_max_lane_count(buf));
> +
> + train_info->tps3 = drm_dp_tps3_supported(buf);
> + train_info->tps4 = drm_dp_tps4_supported(buf);
> +
> + train_info->sink_ssc =
> + !!(buf[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5);
> +
> + train_info->sink_ssc = false;
> +
> + drm_dp_dpcd_readb(&mtk_dp->aux, DP_MSTM_CAP, &val);
> + if (val & DP_MST_CAP) {
> + /* Clear DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 */
> + drm_dp_dpcd_readb(&mtk_dp->aux,
> + DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0, &val);
> + if (val)
> + drm_dp_dpcd_writeb(&mtk_dp->aux,
> + DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0,
> + val);
> + }
> +
> + return true;
> +}
> +
> +static void mtk_dp_train_change_mode(struct mtk_dp *mtk_dp)
> +{
> + phy_reset(mtk_dp->phy);
> + mtk_dp_reset_swing_pre_emphasis(mtk_dp);
> +
> + usleep_range(2000, 5000);
> +}
> +
> +static int mtk_dp_train_start(struct mtk_dp *mtk_dp)
> +{
> + int ret = 0;
> + int lane_count;
> + int link_rate;
> + int train_limit;
> + int max_link_rate;
> + int plug_wait;
> +
> + for (plug_wait = 7; !mtk_dp_plug_state(mtk_dp) && plug_wait > 0;
> + --plug_wait)
> + usleep_range(1000, 5000);
> + if (plug_wait == 0) {
> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_DPIDLE;
> + return -ENODEV;
> + }
> +
> + link_rate = mtk_dp->rx_cap[1];
> + lane_count = mtk_dp->rx_cap[2] & 0x1F;
> +
> + mtk_dp->train_info.link_rate = min(MTK_DP_MAX_LINK_RATE, link_rate);
> + mtk_dp->train_info.lane_count = min(MTK_DP_MAX_LANES, lane_count);
> + link_rate = mtk_dp->train_info.link_rate;
> + lane_count = mtk_dp->train_info.lane_count;
> +
> + switch (link_rate) {
> + case MTK_DP_LINKRATE_RBR:
> + case MTK_DP_LINKRATE_HBR:
> + case MTK_DP_LINKRATE_HBR2:
> + case MTK_DP_LINKRATE_HBR25:
> + case MTK_DP_LINKRATE_HBR3:
> + break;
> + default:
> + mtk_dp->train_info.link_rate = MTK_DP_LINKRATE_HBR3;
> + break;
> + };
>+
> + max_link_rate = link_rate;
> + for (train_limit = 6; train_limit > 0; train_limit--) {
> + mtk_dp->train_info.cr_done = false;
> + mtk_dp->train_info.eq_done = false;
> +
> + mtk_dp_train_change_mode(mtk_dp);
> + ret = mtk_dp_train_flow(mtk_dp, link_rate, lane_count);
> + if (ret)
> + return ret;
> +
> + if (!mtk_dp->train_info.cr_done) {
> + switch (link_rate) {
> + case MTK_DP_LINKRATE_RBR:
> + lane_count = lane_count / 2;
> + link_rate = max_link_rate;
> + if (lane_count == 0) {
> + mtk_dp->train_state =
> + MTK_DP_TRAIN_STATE_DPIDLE;
> + return -EIO;
> + }
> + break;
> + case MTK_DP_LINKRATE_HBR:
> + link_rate = MTK_DP_LINKRATE_RBR;
> + break;
> + case MTK_DP_LINKRATE_HBR2:
> + link_rate = MTK_DP_LINKRATE_HBR;
> + break;
> + case MTK_DP_LINKRATE_HBR3:
> + link_rate = MTK_DP_LINKRATE_HBR2;
> + break;
> + default:
> + return -EINVAL;
> + };
> + } else if (!mtk_dp->train_info.eq_done) {
> + if (lane_count == 0)
> + return -EIO;
> +
> + lane_count /= 2;
> + } else {
> + break;
> + }
> + }
> +
> + if (train_limit == 0)
> + return -ETIMEDOUT;
> +
> + return 0;
> +}
> +
> +static int mtk_dp_train_handler(struct mtk_dp *mtk_dp)
> +{
> + int ret = 0;
> + int i = 50;
> +
> + for (; ret && i; i--) {
> + if (mtk_dp->train_state == MTK_DP_TRAIN_STATE_NORMAL)
> + continue;
> +
> + switch (mtk_dp->train_state) {
> + case MTK_DP_TRAIN_STATE_STARTUP:
> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_CHECKCAP;
> + break;
> +
> + case MTK_DP_TRAIN_STATE_CHECKCAP:
> + if (mtk_dp_parse_capabilities(mtk_dp)) {
> + mtk_dp->train_info.check_cap_count = 0;
> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_CHECKEDID;
> + } else {
> + mtk_dp->train_info.check_cap_count++;
> +
> + if (mtk_dp->train_info.check_cap_count >
> + MTK_DP_CHECK_SINK_CAP_TIMEOUT_COUNT) {
> + mtk_dp->train_info.check_cap_count = 0;
> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_DPIDLE;
> + ret = -ETIMEDOUT;
> + }
> + }
> + break;
> +
> + case MTK_DP_TRAIN_STATE_CHECKEDID:
> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_TRAINING_PRE;
> + break;
> +
> + case MTK_DP_TRAIN_STATE_TRAINING_PRE:
> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_TRAINING;
> + break;
> +
> + case MTK_DP_TRAIN_STATE_TRAINING:
> + ret = mtk_dp_train_start(mtk_dp);
> + if (!ret) {
> + mtk_dp_video_mute(mtk_dp, true);
> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_NORMAL;
> + mtk_dp_fec_enable(mtk_dp, mtk_dp->has_fec);
> + } else if (ret != -EAGAIN) {
> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_DPIDLE;
> + }
> +
> + ret = 0;
> + break;
> +
> + case MTK_DP_TRAIN_STATE_NORMAL:
> + break;
> + case MTK_DP_TRAIN_STATE_DPIDLE:
> + break;
> + default:
> + break;
> + }
> + }
> +
> + if (ret)
> + drm_err(mtk_dp->drm_dev, "Train handler failed %d\n", ret);
> +
> + return ret;
> +}
I'm not really familiar with displayport, but it looks like you're
hand-rolling a significant part of what the drm_dp_* helpers provide.
> +static void mtk_dp_video_enable(struct mtk_dp *mtk_dp, bool enable)
> +{
> + if (enable) {
> + mtk_dp_set_tx_out(mtk_dp);
> + mtk_dp_video_mute(mtk_dp, false);
> + } else {
> + mtk_dp_video_mute(mtk_dp, true);
> + }
> +}
> +
> +static void mtk_dp_video_config(struct mtk_dp *mtk_dp)
> +{
> + mtk_dp_mn_overwrite_disable(mtk_dp);
> +
> + mtk_dp_set_msa(mtk_dp);
> +
> + mtk_dp_set_color_depth(mtk_dp, mtk_dp->info.depth);
> + mtk_dp_set_color_format(mtk_dp, mtk_dp->info.format);
> +}
> +
> +static void mtk_dp_state_handler(struct mtk_dp *mtk_dp)
> +{
> + switch (mtk_dp->state) {
> + case MTK_DP_STATE_INITIAL:
> + mtk_dp_video_mute(mtk_dp, true);
> + mtk_dp->state = MTK_DP_STATE_IDLE;
> + break;
> +
> + case MTK_DP_STATE_IDLE:
> + if (mtk_dp->train_state == MTK_DP_TRAIN_STATE_NORMAL)
> + mtk_dp->state = MTK_DP_STATE_PREPARE;
> + break;
> +
> + case MTK_DP_STATE_PREPARE:
> + mtk_dp_video_config(mtk_dp);
> + mtk_dp_video_enable(mtk_dp, true);
> +
> + mtk_dp->state = MTK_DP_STATE_NORMAL;
> + break;
> +
> + case MTK_DP_STATE_NORMAL:
> + if (mtk_dp->train_state != MTK_DP_TRAIN_STATE_NORMAL) {
> + mtk_dp_video_mute(mtk_dp, true);
> + mtk_dp->state = MTK_DP_STATE_IDLE;
> + }
> + break;
> +
> + default:
> + break;
> + }
> +}
> +
> +static void mtk_dp_init_port(struct mtk_dp *mtk_dp)
> +{
> + mtk_dp_set_idle_pattern(mtk_dp, true);
> + mtk_dp_initialize_priv_data(mtk_dp);
> +
> + mtk_dp_initialize_settings(mtk_dp);
> + mtk_dp_initialize_aux_settings(mtk_dp);
> + mtk_dp_initialize_digital_settings(mtk_dp);
> + mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3690,
> + BIT(RX_REPLY_COMPLETE_MODE_AUX_TX_P0_SHIFT),
> + RX_REPLY_COMPLETE_MODE_AUX_TX_P0_MASK);
> + mtk_dp_initialize_hpd_detect_settings(mtk_dp);
> +
> + mtk_dp_digital_sw_reset(mtk_dp);
> +}
> +
> +static int mtk_dp_dt_parse(struct mtk_dp *mtk_dp,
> + struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + int ret = 0;
> + void __iomem *base;
> +
> + base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + mtk_dp->regs = syscon_node_to_regmap(dev->of_node);
> + if (IS_ERR(mtk_dp->regs))
> + return PTR_ERR(mtk_dp->regs);
> +
> + //TODO: optional clock?
> + mtk_dp->dp_tx_clk = devm_clk_get(dev, "faxi");
> + if (IS_ERR(mtk_dp->dp_tx_clk)) {
> + ret = PTR_ERR(mtk_dp->dp_tx_clk);
> + dev_info(dev, "Failed to get dptx clock: %d\n", ret);
> + mtk_dp->dp_tx_clk = NULL;
> + }
> +
> + return 0;
> +}
> +
> +static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge)
> +{
> + return connector_status_connected;
> +}
I'm not quite sure what's going on there. You seem to have some support
for HPD interrupts above, but you always report the display as
connected?
I'd assume that either you don't have HPD support and then always report
it as connected, or you have HPD support and report the current status
in detect, but that combination seems weird.
> +static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
> + struct drm_connector *connector)
> +{
> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
> + bool enabled = mtk_dp->enabled;
> + struct edid *new_edid = NULL;
> +
> + if (!enabled)
> + drm_bridge_chain_pre_enable(bridge);
> +
> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
> + usleep_range(2000, 5000);
> +
> + if (mtk_dp_plug_state(mtk_dp))
> + new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
> +
> + if (!enabled)
> + drm_bridge_chain_post_disable(bridge);
Are you sure we can't get a mode set while get_edid is called?
If we can, then you could end up disabling the device while it's being
powered on.
> + mutex_lock(&mtk_dp->edid_lock);
> + kfree(mtk_dp->edid);
> + mtk_dp->edid = NULL;
> +
> + if (!new_edid) {
> + mutex_unlock(&mtk_dp->edid_lock);
> + return NULL;
> + }
> +
> + mtk_dp->edid = drm_edid_duplicate(new_edid);
> + mutex_unlock(&mtk_dp->edid_lock);
Why do you need a copy of the edid there?
> + return new_edid;
> +}
> +
> +static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux,
> + struct drm_dp_aux_msg *msg)
> +{
> + struct mtk_dp *mtk_dp;
> + bool is_read;
> + u8 request;
> + size_t accessed_bytes = 0;
> + int retry = 3, ret = 0;
> +
> + mtk_dp = container_of(mtk_aux, struct mtk_dp, aux);
> +
> + if (!mtk_dp->train_info.cable_plugged_in ||
> + mtk_dp->train_info.irq_status & MTK_DP_HPD_DISCONNECT) {
> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_CHECKCAP;
> + ret = -EAGAIN;
> + goto err;
> + }
> +
> + switch (msg->request) {
> + case DP_AUX_I2C_MOT:
> + case DP_AUX_I2C_WRITE:
> + case DP_AUX_NATIVE_WRITE:
> + case DP_AUX_I2C_WRITE_STATUS_UPDATE:
> + case DP_AUX_I2C_WRITE_STATUS_UPDATE | DP_AUX_I2C_MOT:
> + request = msg->request & ~DP_AUX_I2C_WRITE_STATUS_UPDATE;
> + is_read = false;
> + break;
> + case DP_AUX_I2C_READ:
> + case DP_AUX_NATIVE_READ:
> + case DP_AUX_I2C_READ | DP_AUX_I2C_MOT:
> + request = msg->request;
> + is_read = true;
> + break;
> + default:
> + drm_err(mtk_aux->drm_dev, "invalid aux cmd = %d\n",
> + msg->request);
> + ret = -EINVAL;
> + goto err;
> + }
> +
> + if (msg->size == 0) {
> + ret = mtk_dp_aux_do_transfer(mtk_dp, is_read, request,
> + msg->address + accessed_bytes,
> + msg->buffer + accessed_bytes, 0);
> + } else {
> + while (accessed_bytes < msg->size) {
> + size_t to_access =
> + min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES,
> + msg->size - accessed_bytes);
> + while (retry--) {
> + ret = mtk_dp_aux_do_transfer(mtk_dp,
> + is_read, request,
> + msg->address + accessed_bytes,
> + msg->buffer + accessed_bytes,
> + to_access);
> + if (ret == 0)
> + break;
> + usleep_range(50, 100);
> + }
> + if (!retry || ret) {
> + drm_info(mtk_dp->drm_dev,
> + "Failed to do AUX transfer: %d\n",
> + ret);
> + break;
> + }
> + accessed_bytes += to_access;
> + }
> + }
> +err:
> + if (ret) {
> + msg->reply = DP_AUX_NATIVE_REPLY_NACK | DP_AUX_I2C_REPLY_NACK;
> + return ret;
> + }
> +
> + msg->reply = DP_AUX_NATIVE_REPLY_ACK | DP_AUX_I2C_REPLY_ACK;
> + return msg->size;
> +}
> +
> +static void mtk_dp_poweroff(struct mtk_dp *mtk_dp)
> +{
> + mutex_lock(&mtk_dp->dp_lock);
> +
> + mtk_dp_hwirq_enable(mtk_dp, false);
> + mtk_dp_power_disable(mtk_dp);
> + phy_exit(mtk_dp->phy);
> + clk_disable_unprepare(mtk_dp->dp_tx_clk);
> +
> + mutex_unlock(&mtk_dp->dp_lock);
> +}
> +
> +static int mtk_dp_poweron(struct mtk_dp *mtk_dp)
> +{
> + int ret = 0;
> +
> + mutex_lock(&mtk_dp->dp_lock);
> +
> + ret = clk_prepare_enable(mtk_dp->dp_tx_clk);
> + if (ret < 0) {
> + dev_err(mtk_dp->dev, "Fail to enable clock: %d\n", ret);
> + goto err;
> + }
> + ret = phy_init(mtk_dp->phy);
> + if (ret) {
> + dev_err(mtk_dp->dev, "Failed to initialize phy: %d\n", ret);
> + goto err_phy_init;
> + }
> + ret = mtk_dp_phy_configure(mtk_dp, MTK_DP_LINKRATE_RBR, 1);
> + if (ret) {
> + dev_err(mtk_dp->dev, "Failed to configure phy: %d\n", ret);
> + goto err_phy_config;
> + }
> +
> + mtk_dp_init_port(mtk_dp);
> + mtk_dp_power_enable(mtk_dp);
> + mtk_dp_hwirq_enable(mtk_dp, true);
> +
> +err_phy_config:
> + phy_exit(mtk_dp->phy);
> +err_phy_init:
> + clk_disable_unprepare(mtk_dp->dp_tx_clk);
> +err:
> + mutex_unlock(&mtk_dp->dp_lock);
> + return ret;
> +}
> +
> +static int mtk_dp_bridge_attach(struct drm_bridge *bridge,
> + enum drm_bridge_attach_flags flags)
> +{
> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
> + int ret;
> +
> + ret = mtk_dp_poweron(mtk_dp);
> + if (ret)
> + return ret;
> +
> + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> + dev_err(mtk_dp->dev, "Driver does not provide a connector!");
> + return -EINVAL;
> + }
> +
> + if (mtk_dp->next_bridge) {
> + ret = drm_bridge_attach(bridge->encoder, mtk_dp->next_bridge,
> + &mtk_dp->bridge, flags);
> + if (ret) {
> + drm_warn(mtk_dp->drm_dev,
> + "Failed to attach external bridge: %d\n", ret);
> + return ret;
> + }
> + }
> +
> + mtk_dp->drm_dev = bridge->dev;
> +
> + return 0;
> +}
> +
> +static void mtk_dp_bridge_detach(struct drm_bridge *bridge)
> +{
> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
> +
> + mtk_dp->drm_dev = NULL;
> +}
> +
> +static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
> + struct drm_bridge_state *old_state)
> +{
> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
> +
> + mtk_dp_video_mute(mtk_dp, true);
> + mtk_dp->state = MTK_DP_STATE_IDLE;
> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_STARTUP;
> +
> + mtk_dp->enabled = false;
> + msleep(100);
> + mtk_dp_poweroff(mtk_dp);
> +}
> +
> +static void mtk_dp_parse_drm_mode_timings(struct mtk_dp *mtk_dp,
> + struct drm_display_mode *mode)
> +{
> + struct mtk_dp_timings *timings = &mtk_dp->info.timings;
> +
> + drm_display_mode_to_videomode(mode, &timings->vm);
> + timings->frame_rate = mode->clock * 1000 / mode->htotal / mode->vtotal;
drm_mode_vrefresh()
> + timings->htotal = mode->htotal;
> + timings->vtotal = mode->vtotal;
> +}
It's not really clear to me why you need to duplicate drm_display_mode
here?
> +static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
> + struct drm_bridge_state *old_state)
> +{
> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
> + struct drm_connector_state *conn_state;
> + struct drm_crtc *crtc;
> + struct drm_crtc_state *crtc_state;
> +
> + mtk_dp->conn = drm_atomic_get_new_connector_for_encoder(old_state->base.state,
> + bridge->encoder);
> + if (!mtk_dp->conn) {
> + drm_err(mtk_dp->drm_dev,
> + "Can't enable bridge as connector is missing\n");
> + return;
> + }
> +
> + memcpy(mtk_dp->connector_eld, mtk_dp->conn->eld, MAX_ELD_BYTES);
> +
> + conn_state =
> + drm_atomic_get_new_connector_state(old_state->base.state, mtk_dp->conn);
> + if (!conn_state) {
> + drm_err(mtk_dp->drm_dev,
> + "Can't enable bridge as connector state is missing\n");
> + return;
> + }
> +
> + crtc = conn_state->crtc;
> + if (!crtc) {
> + drm_err(mtk_dp->drm_dev,
> + "Can't enable bridge as connector state doesn't have a crtc\n");
> + return;
> + }
> +
> + crtc_state = drm_atomic_get_new_crtc_state(old_state->base.state, crtc);
> + if (!crtc_state) {
> + drm_err(mtk_dp->drm_dev,
> + "Can't enable bridge as crtc state is missing\n");
> + return;
> + }
> +
> + mtk_dp_parse_drm_mode_timings(mtk_dp, &crtc_state->adjusted_mode);
> + if (!mtk_dp_parse_capabilities(mtk_dp)) {
> + drm_err(mtk_dp->drm_dev,
> + "Can't enable bridge as nothing is plugged in\n");
> + return;
> + }
All this needs to be done in atomic_check. You aren't allowed to fail in
atomic_enable.
Maxime
On Fri, 22 Apr 2022 12:57, Maxime Ripard <[email protected]> wrote:
>Hi,
>
>On Mon, Mar 28, 2022 at 12:39:06AM +0200, Guillaume Ranquet wrote:
>> From: Markus Schneider-Pargmann <[email protected]>
>>
>> DP_INTF is similar to DPI but does not have the exact same feature set
>> or register layouts.
>>
>> DP_INTF is the sink of the display pipeline that is connected to the
>> DisplayPort controller and encoder unit. It takes the same clocks as
>> DPI.
>>
>> Signed-off-by: Markus Schneider-Pargmann <[email protected]>
>> Signed-off-by: Guillaume Ranquet <[email protected]>
>> Reviewed-by: Rob Herring <[email protected]>
>> ---
>> .../bindings/display/mediatek/mediatek,dpi.yaml | 11 ++++++-----
>> 1 file changed, 6 insertions(+), 5 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
>> index dd2896a40ff0..2dba80ad3b18 100644
>> --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
>> +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
>> @@ -4,16 +4,16 @@
>> $id: http://devicetree.org/schemas/display/mediatek/mediatek,dpi.yaml#
>> $schema: http://devicetree.org/meta-schemas/core.yaml#
>>
>> -title: mediatek DPI Controller Device Tree Bindings
>> +title: mediatek DPI/DP_INTF Controller
>>
>> maintainers:
>> - CK Hu <[email protected]>
>> - Jitao shi <[email protected]>
>>
>> description: |
>> - The Mediatek DPI function block is a sink of the display subsystem and
>> - provides 8-bit RGB/YUV444 or 8/10/10-bit YUV422 pixel data on a parallel
>> - output bus.
>> + The Mediatek DPI and DP_INTF function blocks are a sink of the display
>> + subsystem and provides 8-bit RGB/YUV444 or 8/10/10-bit YUV422 pixel data on a
>> + parallel output bus.
>>
>> properties:
>> compatible:
>> @@ -23,6 +23,7 @@ properties:
>> - mediatek,mt8173-dpi
>> - mediatek,mt8183-dpi
>> - mediatek,mt8192-dpi
>> + - mediatek,mt8195-dpintf
>
>It seems a bit weird to have all instances of DP_INTF with a separator
>but the compatible doesn't have one?
>
>Is there a reason to not use dp-intf?
None that I know of, It was taken as is from the vendor tree.
I'll use dp-intf in v10 for the sake of consistency.
Thx,
Guillaume.
>
>Maxime
On Fri, 29 Apr 2022 10:39, Maxime Ripard <[email protected]> wrote:
>Hi Guillaume,
>
Hi Maxime, Thx for your review.
>On Mon, Mar 28, 2022 at 12:39:23AM +0200, Guillaume Ranquet wrote:
>> From: Markus Schneider-Pargmann <[email protected]>
>>
>> This patch adds a DisplayPort driver for the Mediatek mt8195 SoC.
>>
>> It supports the mt8195, the embedded DisplayPort units. It offers
>> DisplayPort 1.4 with up to 4 lanes.
>>
>> The driver shares its iomap range with the mtk-dp-phy driver using
>> the regmap/syscon facility.
>>
>> This driver is based on an initial version by
>> Jason-JH.Lin <[email protected]>.
>>
>> Signed-off-by: Markus Schneider-Pargmann <[email protected]>
>> Signed-off-by: Guillaume Ranquet <[email protected]>
>> Reported-by: kernel test robot <[email protected]>
>
>You don't need to set Reported-by on a patch introducing a new driver.
>That would be typically done for a fix.
>
Ok.
>> ---
>> drivers/gpu/drm/mediatek/Kconfig | 8 +
>> drivers/gpu/drm/mediatek/Makefile | 2 +
>> drivers/gpu/drm/mediatek/mtk_dp.c | 2221 ++++++++++++++++++++++++
>> drivers/gpu/drm/mediatek/mtk_dp_reg.h | 568 ++++++
>> drivers/gpu/drm/mediatek/mtk_drm_drv.c | 1 +
>> drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
>> 6 files changed, 2801 insertions(+)
>> create mode 100644 drivers/gpu/drm/mediatek/mtk_dp.c
>> create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_reg.h
>>
>> diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig
>> index 2976d21e9a34..03ffa9b896c3 100644
>> --- a/drivers/gpu/drm/mediatek/Kconfig
>> +++ b/drivers/gpu/drm/mediatek/Kconfig
>> @@ -28,3 +28,11 @@ config DRM_MEDIATEK_HDMI
>> select PHY_MTK_HDMI
>> help
>> DRM/KMS HDMI driver for Mediatek SoCs
>> +
>> +config MTK_DPTX_SUPPORT
>> + tristate "DRM DPTX Support for Mediatek SoCs"
>> + depends on DRM_MEDIATEK
>> + select PHY_MTK_DP
>> + select DRM_DP_HELPER
>> + help
>> + DRM/KMS Display Port driver for Mediatek SoCs.
>> diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
>> index 29098d7c8307..d86a6406055e 100644
>> --- a/drivers/gpu/drm/mediatek/Makefile
>> +++ b/drivers/gpu/drm/mediatek/Makefile
>> @@ -21,3 +21,5 @@ mediatek-drm-hdmi-objs := mtk_cec.o \
>> mtk_hdmi_ddc.o
>>
>> obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
>> +
>> +obj-$(CONFIG_MTK_DPTX_SUPPORT) += mtk_dp.o
>> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
>> new file mode 100644
>> index 000000000000..7cd8459cf719
>> --- /dev/null
>> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
>> @@ -0,0 +1,2221 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2019 MediaTek Inc.
>> + * Copyright (c) 2021 BayLibre
>
>2022?
right.
>
>> + */
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_bridge.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/dp/drm_dp_helper.h>
>> +#include <drm/drm_edid.h>
>> +#include <drm/drm_of.h>
>> +#include <drm/drm_panel.h>
>> +#include <drm/drm_print.h>
>> +#include <drm/drm_probe_helper.h>
>> +#include <linux/arm-smccc.h>
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/errno.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/nvmem-consumer.h>
>> +#include <linux/of.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/phy/phy.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/regmap.h>
>> +#include <sound/hdmi-codec.h>
>> +#include <video/videomode.h>
>> +
>> +#include "mtk_dp_reg.h"
>> +
>> +#define MTK_DP_AUX_WAIT_REPLY_COUNT 20
>> +#define MTK_DP_CHECK_SINK_CAP_TIMEOUT_COUNT 3
>> +
>> +//TODO: platform/device data or dts?
>
>DTS :)
It's probably going to be a platform_data struct for v10...
If I have time, I'll change it to a dts property for v10.
>
>> +#define MTK_DP_MAX_LANES 4
>> +#define MTK_DP_MAX_LINK_RATE MTK_DP_LINKRATE_HBR3
>> +
>> +#define MTK_DP_TBC_BUF_READ_START_ADDR 0x08
>> +
>> +#define MTK_DP_TRAIN_RETRY_LIMIT 8
>> +#define MTK_DP_TRAIN_MAX_ITERATIONS 5
>> +
>> +#define MTK_DP_AUX_WRITE_READ_WAIT_TIME_US 20
>> +
>> +#define MTK_DP_DP_VERSION_11 0x11
>> +
>> +enum mtk_dp_state {
>> + MTK_DP_STATE_INITIAL,
>> + MTK_DP_STATE_IDLE,
>> + MTK_DP_STATE_PREPARE,
>> + MTK_DP_STATE_NORMAL,
>> +};
>> +
>> +enum mtk_dp_train_state {
>> + MTK_DP_TRAIN_STATE_STARTUP = 0,
>> + MTK_DP_TRAIN_STATE_CHECKCAP,
>> + MTK_DP_TRAIN_STATE_CHECKEDID,
>> + MTK_DP_TRAIN_STATE_TRAINING_PRE,
>> + MTK_DP_TRAIN_STATE_TRAINING,
>> + MTK_DP_TRAIN_STATE_NORMAL,
>> + MTK_DP_TRAIN_STATE_DPIDLE,
>> +};
>> +
>> +struct mtk_dp_timings {
>> + struct videomode vm;
>> +
>> + u16 htotal;
>> + u16 vtotal;
>> + u8 frame_rate;
>> + u32 pix_rate_khz;
>> +};
>> +
>> +struct mtk_dp_train_info {
>> + bool tps3;
>> + bool tps4;
>> + bool sink_ssc;
>> + bool cable_plugged_in;
>> + bool cable_state_change;
>> + bool cr_done;
>> + bool eq_done;
>> +
>> + /* link_rate is in multiple of 0.27Gbps */
>> + int link_rate;
>> + int lane_count;
>> +
>> + u8 irq_status;
>> + int check_cap_count;
>> +};
>> +
>> +/* Same values as used by the DP Spec for MISC0 bits 1 and 2 */
>> +enum mtk_dp_color_format {
>> + MTK_DP_COLOR_FORMAT_RGB_444 = 0,
>> + MTK_DP_COLOR_FORMAT_YUV_422 = 1,
>> + MTK_DP_COLOR_FORMAT_YUV_444 = 2,
>> + MTK_DP_COLOR_FORMAT_YUV_420 = 3,
>> + MTK_DP_COLOR_FORMAT_YONLY = 4,
>> + MTK_DP_COLOR_FORMAT_RAW = 5,
>> + MTK_DP_COLOR_FORMAT_RESERVED = 6,
>> + MTK_DP_COLOR_FORMAT_DEFAULT = MTK_DP_COLOR_FORMAT_RGB_444,
>> + MTK_DP_COLOR_FORMAT_UNKNOWN = 15,
>> +};
>
>Isn't that redundant with DP_MSA_MISC_COLOR_* ?
Not exactly DP_MSA_MISC_COLOR_*...
as we actually don't care about the values of these enums...
It's only used internally in a switch/case and has no link to the DP Spec...
Not sure why the original author defined it this way.
I've used instead the enum defined in the drm_dp_helper dp_pixelformat.
>
>> +/* Multiple of 0.27Gbps */
>> +enum mtk_dp_linkrate {
>> + MTK_DP_LINKRATE_RBR = 0x6,
>> + MTK_DP_LINKRATE_HBR = 0xA,
>> + MTK_DP_LINKRATE_HBR2 = 0x14,
>> + MTK_DP_LINKRATE_HBR25 = 0x19,
>> + MTK_DP_LINKRATE_HBR3 = 0x1E,
>> +};
>> +
>> +/* Same values as used for DP Spec MISC0 bits 5,6,7 */
>> +enum mtk_dp_color_depth {
>> + MTK_DP_COLOR_DEPTH_6BIT = 0,
>> + MTK_DP_COLOR_DEPTH_8BIT = 1,
>> + MTK_DP_COLOR_DEPTH_10BIT = 2,
>> + MTK_DP_COLOR_DEPTH_12BIT = 3,
>> + MTK_DP_COLOR_DEPTH_16BIT = 4,
>> + MTK_DP_COLOR_DEPTH_UNKNOWN = 5,
>> +};
>
>DP_MSA_MISC_*_BPC?
Same thing for this enum, the value of these are of no importance.
but I couldn't find anything equivalent in the drm_dp_helper.
I'll keep searching if there's anything worth switching to.
>
>> +struct mtk_dp_info {
>> + enum mtk_dp_color_depth depth;
>> + enum mtk_dp_color_format format;
>> + struct mtk_dp_timings timings;
>> +};
>> +
>> +struct dp_cal_data {
>> + unsigned int glb_bias_trim;
>> + unsigned int clktx_impse;
>> +
>> + //TODO: see above with MTK_DP_MAX_LANES, make it SoC specific
>> + unsigned int ln_tx_impsel_pmos[MTK_DP_MAX_LANES];
>> + unsigned int ln_tx_impsel_nmos[MTK_DP_MAX_LANES];
>> +};
>> +
>> +struct mtk_dp {
>> + struct device *dev;
>> + struct phy *phy;
>> + struct dp_cal_data cal_data;
>> +
>> + struct drm_device *drm_dev;
>> + struct drm_bridge bridge;
>> + struct drm_bridge *next_bridge;
>> + struct drm_dp_aux aux;
>> +
>> + /* Protects edid as it is used in both bridge ops and IRQ handler */
>> + struct mutex edid_lock;
>> + struct edid *edid;
>> +
>> + u8 rx_cap[DP_RECEIVER_CAP_SIZE];
>> +
>> + struct mtk_dp_info info;
>> + enum mtk_dp_state state;
>> +
>> + struct mtk_dp_train_info train_info;
>> + enum mtk_dp_train_state train_state;
>> + unsigned int input_fmt;
>> +
>> + struct regmap *regs;
>> + struct clk *dp_tx_clk;
>> +
>> + bool enabled;
>> +
>> + bool has_fec;
>> + /* Protects the mtk_dp struct */
>> + struct mutex dp_lock;
>> +
>> + hdmi_codec_plugged_cb plugged_cb;
>> + struct device *codec_dev;
>> + u8 connector_eld[MAX_ELD_BYTES];
>> + struct drm_connector *conn;
>> +};
>> +
>> +static struct mtk_dp *mtk_dp_from_bridge(struct drm_bridge *b)
>> +{
>> + return container_of(b, struct mtk_dp, bridge);
>> +}
>> +
>> +static u32 mtk_dp_read(struct mtk_dp *mtk_dp, u32 offset)
>> +{
>> + u32 read_val;
>> + int ret;
>> +
>> + ret = regmap_read(mtk_dp->regs, offset, &read_val);
>> + if (ret) {
>> + dev_err(mtk_dp->dev, "Failed to read register 0x%x: %d\n",
>> + offset, ret);
>> + return 0;
>> + }
>> +
>> + return read_val;
>> +}
>> +
>> +static int mtk_dp_write(struct mtk_dp *mtk_dp, u32 offset, u32 val)
>> +{
>> + int ret;
>> +
>> + ret = regmap_write(mtk_dp->regs, offset, val);
>> + if (ret)
>> + dev_err(mtk_dp->dev,
>> + "Failed to write register 0x%x with value 0x%x: %d\n",
>> + offset, val, ret);
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_update_bits(struct mtk_dp *mtk_dp, u32 offset, u32 val,
>> + u32 mask)
>> +{
>> + int ret;
>> +
>> + ret = regmap_update_bits(mtk_dp->regs, offset, mask, val);
>> + if (ret)
>> + dev_err(mtk_dp->dev,
>> + "Failed to update register 0x%x with value 0x%x, mask 0x%x: %d\n",
>> + offset, val, mask, ret);
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_bulk_16bit_write(struct mtk_dp *mtk_dp, u32 offset, u8 *buf,
>> + size_t length)
>> +{
>> + int i;
>> + int ret = 0;
>> + int num_regs = (length + 1) / 2;
>> +
>> + /* 2 bytes per register */
>> + for (i = 0; i < num_regs; i++) {
>> + u32 val = buf[i * 2] |
>> + (i * 2 + 1 < length ? buf[i * 2 + 1] << 8 : 0);
>> +
>> + ret = mtk_dp_write(mtk_dp, offset + i * 4, val);
>> + if (ret)
>> + goto out;
>> + }
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static unsigned long mtk_dp_sip_atf_call(unsigned int cmd, unsigned int para)
>> +{
>> + struct arm_smccc_res res;
>> +
>> + arm_smccc_smc(MTK_DP_SIP_CONTROL_AARCH32, cmd, para, 0, 0, 0, 0, 0,
>> + &res);
>> +
>> + pr_debug("[DPTX]%s cmd 0x%x, p1 0x%x, ret 0x%lx-0x%lx", __func__, cmd,
>> + para, res.a0, res.a1);
>> + return res.a1;
>> +}
>> +
>> +static int mtk_dp_msa_bypass_disable(struct mtk_dp *mtk_dp)
>> +{
>> + const u16 bits_to_set =
>> + BIT(HTOTAL_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(VTOTAL_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(HSTART_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(VSTART_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(HWIDTH_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(VHEIGHT_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(HSP_SEL_DP_ENC0_P0_SHIFT) | BIT(HSW_SEL_DP_ENC0_P0_SHIFT) |
>> + BIT(VSP_SEL_DP_ENC0_P0_SHIFT) | BIT(VSW_SEL_DP_ENC0_P0_SHIFT);
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3030, bits_to_set,
>> + bits_to_set);
>> +}
>> +
>> +#define MTK_UPD_BITS_OR_OUT(mtk_dp, offset, val, mask, ret, label) \
>> + do {\
>> + ret = mtk_dp_update_bits(mtk_dp, offset, val, mask); \
>> + if (ret) \
>> + goto label; \
>> + } while (0)
>> +
>> +static int mtk_dp_set_msa(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> + struct mtk_dp_timings *timings = &mtk_dp->info.timings;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3010, timings->htotal,
>> + HTOTAL_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3018,
>> + timings->vm.hsync_len + timings->vm.hback_porch,
>> + HSTART_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3028,
>> + timings->vm.hsync_len << HSW_SW_DP_ENC0_P0_SHIFT,
>> + HSW_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3028, 0,
>> + HSP_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3020, timings->vm.hactive,
>> + HWIDTH_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3014, timings->vtotal,
>> + VTOTAL_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_301C,
>> + timings->vm.vsync_len + timings->vm.vback_porch,
>> + VSTART_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_302C,
>> + timings->vm.vsync_len << VSW_SW_DP_ENC0_P0_SHIFT,
>> + VSW_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_302C, 0,
>> + VSP_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3024, timings->vm.vactive,
>> + VHEIGHT_SW_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3064, timings->vm.hactive,
>> + HDE_NUM_LAST_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3154, timings->htotal,
>> + PGEN_HTOTAL_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3158,
>> + timings->vm.hfront_porch,
>> + PGEN_HSYNC_RISING_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_315C, timings->vm.hsync_len,
>> + PGEN_HSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3160,
>> + timings->vm.hback_porch + timings->vm.hsync_len,
>> + PGEN_HFDE_START_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3164, timings->vm.hactive,
>> + PGEN_HFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3168, timings->vtotal,
>> + PGEN_VTOTAL_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_316C,
>> + timings->vm.vfront_porch,
>> + PGEN_VSYNC_RISING_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3170, timings->vm.vsync_len,
>> + PGEN_VSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3174,
>> + timings->vm.vback_porch + timings->vm.vsync_len,
>> + PGEN_VFDE_START_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3178, timings->vm.vactive,
>> + PGEN_VFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_set_color_format(struct mtk_dp *mtk_dp,
>> + enum mtk_dp_color_format color_format)
>> +{
>> + u32 val;
>> + int ret;
>> +
>> + mtk_dp->info.format = color_format;
>> +
>> + /* Update MISC0 */
>> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
>> + color_format << DP_TEST_COLOR_FORMAT_SHIFT,
>> + DP_TEST_COLOR_FORMAT_MASK);
>> +
>> + if (ret)
>> + return ret;
>> +
>> + switch (color_format) {
>> + case MTK_DP_COLOR_FORMAT_YUV_422:
>> + val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422;
>> + break;
>> + case MTK_DP_COLOR_FORMAT_YUV_420:
>> + val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR420;
>> + break;
>> + case MTK_DP_COLOR_FORMAT_YONLY:
>> + case MTK_DP_COLOR_FORMAT_RAW:
>> + case MTK_DP_COLOR_FORMAT_RESERVED:
>> + case MTK_DP_COLOR_FORMAT_UNKNOWN:
>> + drm_warn(mtk_dp->drm_dev, "Unsupported color format: %d\n",
>> + color_format);
>> + fallthrough;
>> + case MTK_DP_COLOR_FORMAT_RGB_444:
>> + case MTK_DP_COLOR_FORMAT_YUV_444:
>> + val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB;
>> + break;
>> + }
>> +
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C, val,
>> + PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_set_color_depth(struct mtk_dp *mtk_dp,
>> + enum mtk_dp_color_depth color_depth)
>> +{
>> + int ret;
>> + u32 val;
>> +
>> + mtk_dp->info.depth = color_depth;
>> +
>> + /* Update MISC0 */
>> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
>> + color_depth << DP_TEST_BIT_DEPTH_SHIFT,
>> + DP_TEST_BIT_DEPTH_MASK);
>> +
>> + if (ret)
>> + return ret;
>> +
>> + switch (color_depth) {
>> + case MTK_DP_COLOR_DEPTH_6BIT:
>> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_6BIT;
>> + break;
>> + case MTK_DP_COLOR_DEPTH_8BIT:
>> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_8BIT;
>> + break;
>> + case MTK_DP_COLOR_DEPTH_10BIT:
>> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_10BIT;
>> + break;
>> + case MTK_DP_COLOR_DEPTH_12BIT:
>> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_12BIT;
>> + break;
>> + case MTK_DP_COLOR_DEPTH_16BIT:
>> + val = VIDEO_COLOR_DEPTH_DP_ENC0_P0_16BIT;
>> + break;
>> + case MTK_DP_COLOR_DEPTH_UNKNOWN:
>> + drm_warn(mtk_dp->drm_dev, "Unsupported color depth %d\n",
>> + color_depth);
>> + return -EINVAL;
>> + }
>> +
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C, val,
>> + VIDEO_COLOR_DEPTH_DP_ENC0_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_mn_overwrite_disable(struct mtk_dp *mtk_dp)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004, 0,
>> + VIDEO_M_CODE_SEL_DP_ENC0_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_set_sram_read_start(struct mtk_dp *mtk_dp, u32 val)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
>> + val << SRAM_START_READ_THRD_DP_ENC0_P0_SHIFT,
>> + SRAM_START_READ_THRD_DP_ENC0_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_setup_encoder(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_303C,
>> + BIT(VIDEO_MN_GEN_EN_DP_ENC0_P0_SHIFT),
>> + VIDEO_MN_GEN_EN_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3040,
>> + 0x20 << SDP_DOWN_CNT_INIT_DP_ENC0_P0_SHIFT,
>> + SDP_DOWN_CNT_INIT_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3364,
>> + 0x20 << SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_SHIFT,
>> + SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3300,
>> + 2 << VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_SHIFT,
>> + VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3364,
>> + 4 << FIFO_READ_START_POINT_DP_ENC1_P0_SHIFT,
>> + FIFO_READ_START_POINT_DP_ENC1_P0_MASK, ret, out);
>> + ret = mtk_dp_write(mtk_dp, MTK_DP_ENC1_P0_3368,
>> + 1 << VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0_SHIFT |
>> + 1 << VIDEO_STABLE_CNT_THRD_DP_ENC1_P0_SHIFT |
>> + BIT(SDP_DP13_EN_DP_ENC1_P0_SHIFT) |
>> + 1 << BS2BS_MODE_DP_ENC1_P0_SHIFT);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_pg_disable(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3038, 0,
>> + VIDEO_SOURCE_SEL_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_31B0,
>> + 4 << PGEN_PATTERN_SEL_SHIFT, PGEN_PATTERN_SEL_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static bool mtk_dp_plug_state(struct mtk_dp *mtk_dp)
>> +{
>> + return !!(mtk_dp_read(mtk_dp, MTK_DP_TRANS_P0_3414) &
>> + HPD_DB_DP_TRANS_P0_MASK);
>> +}
>> +
>> +static void mtk_dp_aux_irq_clear(struct mtk_dp *mtk_dp)
>> +{
>> + mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3640,
>> + BIT(AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_SHIFT) |
>> + BIT(AUX_RX_DATA_RECV_IRQ_AUX_TX_P0_SHIFT) |
>> + BIT(AUX_RX_ADDR_RECV_IRQ_AUX_TX_P0_SHIFT) |
>> + BIT(AUX_RX_CMD_RECV_IRQ_AUX_TX_P0_SHIFT) |
>> + BIT(AUX_RX_MCCS_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT) |
>> + BIT(AUX_RX_EDID_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT) |
>> + BIT(AUX_RX_AUX_RECV_COMPLETE_IRQ_AUX_TX_P0_SHIFT));
>> +}
>> +
>> +static int mtk_dp_aux_set_cmd(struct mtk_dp *mtk_dp, u8 cmd, u32 addr)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3644, cmd,
>> + MCU_REQUEST_COMMAND_AUX_TX_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3648, addr,
>> + MCU_REQUEST_ADDRESS_LSB_AUX_TX_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_364C, addr >> 16,
>> + MCU_REQUEST_ADDRESS_MSB_AUX_TX_P0_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_aux_cmd_complete(struct mtk_dp *mtk_dp)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3650,
>> + BIT(MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_SHIFT),
>> + MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_MASK |
>> + PHY_FIFO_RST_AUX_TX_P0_MASK |
>> + MCU_REQ_DATA_NUM_AUX_TX_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_aux_request_ready(struct mtk_dp *mtk_dp)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3630,
>> + BIT(AUX_TX_REQUEST_READY_AUX_TX_P0_SHIFT),
>> + AUX_TX_REQUEST_READY_AUX_TX_P0_MASK);
>> +}
>> +
>> +static void mtk_dp_aux_fill_write_fifo(struct mtk_dp *mtk_dp, u8 *buf,
>> + size_t length)
>> +{
>> + mtk_dp_bulk_16bit_write(mtk_dp, MTK_DP_AUX_P0_3708, buf, length);
>> +}
>> +
>> +static int mtk_dp_aux_read_rx_fifo(struct mtk_dp *mtk_dp, u8 *buf,
>> + size_t length, int read_delay)
>> +{
>> + int ret;
>> + int read_pos;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3620, 0,
>> + AUX_RD_MODE_AUX_TX_P0_MASK, ret, out);
>> +
>> + for (read_pos = 0; read_pos < length; read_pos++) {
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3620,
>> + BIT(AUX_RX_FIFO_R_PULSE_TX_P0_SHIFT),
>> + AUX_RX_FIFO_READ_PULSE_TX_P0_MASK, ret, out);
>> + usleep_range(read_delay, read_delay * 2);
>> + buf[read_pos] =
>> + (u8)(mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3620) &
>> + AUX_RX_FIFO_READ_DATA_AUX_TX_P0_MASK >>
>> + AUX_RX_FIFO_READ_DATA_AUX_TX_P0_SHIFT);
>> + }
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_aux_set_length(struct mtk_dp *mtk_dp, size_t length)
>> +{
>> + int ret;
>> +
>> + if (length > 0) {
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3650,
>> + (length - 1)
>> + << MCU_REQ_DATA_NUM_AUX_TX_P0_SHIFT,
>> + MCU_REQ_DATA_NUM_AUX_TX_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_362C, 0,
>> + AUX_NO_LENGTH_AUX_TX_P0_MASK |
>> + AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK |
>> + AUX_RESERVED_RW_0_AUX_TX_P0_MASK, ret, out);
>> + } else {
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_362C,
>> + BIT(AUX_NO_LENGTH_AUX_TX_P0_SHIFT),
>> + AUX_NO_LENGTH_AUX_TX_P0_MASK |
>> + AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK |
>> + AUX_RESERVED_RW_0_AUX_TX_P0_MASK, ret, out);
>> + }
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_aux_wait_for_completion(struct mtk_dp *mtk_dp, bool is_read)
>> +{
>> + int wait_reply = MTK_DP_AUX_WAIT_REPLY_COUNT;
>> +
>> + while (--wait_reply) {
>> + u32 aux_irq_status;
>> +
>> + if (is_read) {
>> + u32 fifo_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3618);
>> +
>> + if (fifo_status &
>> + (AUX_RX_FIFO_WRITE_POINTER_AUX_TX_P0_MASK |
>> + AUX_RX_FIFO_FULL_AUX_TX_P0_MASK)) {
>> + return 0;
>> + }
>> + }
>> +
>> + aux_irq_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3640);
>> + if (aux_irq_status & AUX_RX_RECV_COMPLETE_IRQ_TX_P0_MASK)
>> + return 0;
>> +
>> + if (aux_irq_status & AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_MASK)
>> + return -ETIMEDOUT;
>> +
>> + usleep_range(100, 500);
>> + }
>> +
>> + return -ETIMEDOUT;
>> +}
>> +
>> +static int mtk_dp_aux_do_transfer(struct mtk_dp *mtk_dp, bool is_read, u8 cmd,
>> + u32 addr, u8 *buf, size_t length)
>> +{
>> + int ret;
>> + u32 reply_cmd;
>> +
>> + if (is_read && (length > DP_AUX_MAX_PAYLOAD_BYTES ||
>> + (cmd == DP_AUX_NATIVE_READ && !length)))
>> + return -EINVAL;
>> +
>> + if (!is_read) {
>> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3704,
>> + BIT(AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_SHIFT),
>> + AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_MASK);
>> +
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + mtk_dp_aux_cmd_complete(mtk_dp);
>> + mtk_dp_aux_irq_clear(mtk_dp);
>> + usleep_range(MTK_DP_AUX_WRITE_READ_WAIT_TIME_US,
>> + MTK_DP_AUX_WRITE_READ_WAIT_TIME_US * 2);
>> +
>> + mtk_dp_aux_set_cmd(mtk_dp, cmd, addr);
>> + mtk_dp_aux_set_length(mtk_dp, length);
>> +
>> + if (!is_read) {
>> + if (length)
>> + mtk_dp_aux_fill_write_fifo(mtk_dp, buf, length);
>> +
>> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3704,
>> + AUX_TX_FIFO_WRITE_DATA_NEW_MODE_TOGGLE_AUX_TX_P0_MASK,
>> + AUX_TX_FIFO_WRITE_DATA_NEW_MODE_TOGGLE_AUX_TX_P0_MASK);
>> +
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + mtk_dp_aux_request_ready(mtk_dp);
>> +
>> + ret = mtk_dp_aux_wait_for_completion(mtk_dp, is_read);
>> +
>> + reply_cmd = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3624) &
>> + AUX_RX_REPLY_COMMAND_AUX_TX_P0_MASK;
>> +
>> + if (ret || reply_cmd) {
>> + u32 phy_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3628) &
>> + AUX_RX_PHY_STATE_AUX_TX_P0_MASK;
>> + if (phy_status != AUX_RX_PHY_STATE_AUX_TX_P0_RX_IDLE) {
>> + drm_err(mtk_dp->drm_dev,
>> + "AUX Rx Aux hang, need SW reset\n");
>> + return -EIO;
>> + }
>> +
>> + mtk_dp_aux_cmd_complete(mtk_dp);
>> + mtk_dp_aux_irq_clear(mtk_dp);
>> +
>> + usleep_range(MTK_DP_AUX_WRITE_READ_WAIT_TIME_US,
>> + MTK_DP_AUX_WRITE_READ_WAIT_TIME_US * 2);
>> + return -ETIMEDOUT;
>> + }
>> +
>> + if (!length) {
>> + ret = mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_362C, 0,
>> + AUX_NO_LENGTH_AUX_TX_P0_MASK |
>> + AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK |
>> + AUX_RESERVED_RW_0_AUX_TX_P0_MASK);
>> +
>> + if (ret)
>> + return ret;
>> +
>> + } else if (is_read) {
>> + int read_delay;
>> +
>> + if (cmd == (DP_AUX_I2C_READ | DP_AUX_I2C_MOT) ||
>> + cmd == DP_AUX_I2C_READ)
>> + read_delay = 500;
>> + else
>> + read_delay = 100;
>> +
>> + mtk_dp_aux_read_rx_fifo(mtk_dp, buf, length, read_delay);
>> + }
>> +
>> + mtk_dp_aux_cmd_complete(mtk_dp);
>> + mtk_dp_aux_irq_clear(mtk_dp);
>> + usleep_range(MTK_DP_AUX_WRITE_READ_WAIT_TIME_US,
>> + MTK_DP_AUX_WRITE_READ_WAIT_TIME_US * 2);
>> +
>> + return 0;
>> +}
>> +
>> +static bool mtk_dp_set_swing_pre_emphasis(struct mtk_dp *mtk_dp, int lane_num,
>> + int swing_val, int preemphasis)
>> +{
>> + int ret;
>> +
>> + u32 lane_shift = lane_num * DP_TX1_VOLT_SWING_SHIFT;
>> +
>> + if (lane_num < 0 || lane_num > 3)
>> + return false;
>> +
>> + dev_dbg(mtk_dp->dev,
>> + "link training swing_val= 0x%x, preemphasis = 0x%x\n",
>> + swing_val, preemphasis);
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_SWING_EMP,
>> + swing_val << (DP_TX0_VOLT_SWING_SHIFT + lane_shift),
>> + DP_TX0_VOLT_SWING_MASK << lane_shift, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_SWING_EMP,
>> + preemphasis << (DP_TX0_PRE_EMPH_SHIFT + lane_shift),
>> + DP_TX0_PRE_EMPH_MASK << lane_shift, ret, out);
>> +
>> +out:
>> + return !ret;
>> +}
>> +
>> +static int mtk_dp_reset_swing_pre_emphasis(struct mtk_dp *mtk_dp)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_SWING_EMP, 0,
>> + DP_TX0_VOLT_SWING_MASK | DP_TX1_VOLT_SWING_MASK |
>> + DP_TX2_VOLT_SWING_MASK |
>> + DP_TX3_VOLT_SWING_MASK |
>> + DP_TX0_PRE_EMPH_MASK | DP_TX1_PRE_EMPH_MASK |
>> + DP_TX2_PRE_EMPH_MASK | DP_TX3_PRE_EMPH_MASK);
>> +}
>> +
>> +static int mtk_dp_fec_enable(struct mtk_dp *mtk_dp, bool enable)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3540,
>> + enable ? BIT(FEC_EN_DP_TRANS_P0_SHIFT) : 0,
>> + FEC_EN_DP_TRANS_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_hwirq_enable(struct mtk_dp *mtk_dp, bool enable)
>> +{
>> + u32 val = 0;
>> +
>> + if (!enable)
>> + val = IRQ_MASK_DP_TRANS_P0_DISC_IRQ |
>> + IRQ_MASK_DP_TRANS_P0_CONN_IRQ |
>> + IRQ_MASK_DP_TRANS_P0_INT_IRQ;
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3418, val,
>> + IRQ_MASK_DP_TRANS_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_initialize_settings(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_342C,
>> + XTAL_FREQ_DP_TRANS_P0_DEFAULT,
>> + XTAL_FREQ_DP_TRANS_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_3540,
>> + BIT(FEC_CLOCK_EN_MODE_DP_TRANS_P0_SHIFT),
>> + FEC_CLOCK_EN_MODE_DP_TRANS_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_31EC,
>> + BIT(AUDIO_CH_SRC_SEL_DP_ENC0_P0_SHIFT),
>> + AUDIO_CH_SRC_SEL_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_304C, 0,
>> + SDP_VSYNC_RISING_MASK_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_IRQ_MASK, IRQ_MASK_AUX_TOP_IRQ,
>> + IRQ_MASK_AUX_TOP_IRQ, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static void mtk_dp_initialize_hpd_detect_settings(struct mtk_dp *mtk_dp)
>> +{
>> + // Debounce threshold
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
>> + 8 << HPD_DEB_THD_DP_TRANS_P0_SHIFT,
>> + HPD_DEB_THD_DP_TRANS_P0_MASK);
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
>> + (HPD_INT_THD_DP_TRANS_P0_LOWER_500US |
>> + HPD_INT_THD_DP_TRANS_P0_UPPER_1100US)
>> + << HPD_INT_THD_DP_TRANS_P0_SHIFT,
>> + HPD_INT_THD_DP_TRANS_P0_MASK);
>> +
>> + // Connect threshold 1.5ms + 5 x 0.1ms = 2ms
>> + // Disconnect threshold 1.5ms + 5 x 0.1ms = 2ms
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
>> + (5 << HPD_DISC_THD_DP_TRANS_P0_SHIFT) |
>> + (5 << HPD_CONN_THD_DP_TRANS_P0_SHIFT),
>> + HPD_DISC_THD_DP_TRANS_P0_MASK |
>> + HPD_CONN_THD_DP_TRANS_P0_MASK);
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3430,
>> + HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT,
>> + HPD_INT_THD_ECO_DP_TRANS_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_initialize_aux_settings(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + /* modify timeout threshold = 1595 [12 : 8] */
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_360C, 0x1595,
>> + AUX_TIMEOUT_THR_AUX_TX_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3658, 0,
>> + AUX_TX_OV_EN_AUX_TX_P0_MASK, ret, out);
>> + /* 25 for 26M */
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3634,
>> + 25 << AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_SHIFT,
>> + AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_MASK, ret, out);
>> + /* 13 for 26M */
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_3614,
>> + 13 << AUX_RX_UI_CNT_THR_AUX_TX_P0_SHIFT,
>> + AUX_RX_UI_CNT_THR_AUX_TX_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_AUX_P0_37C8,
>> + BIT(MTK_ATOP_EN_AUX_TX_P0_SHIFT),
>> + MTK_ATOP_EN_AUX_TX_P0_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_initialize_digital_settings(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_304C, 0,
>> + VBID_VIDEO_MUTE_DP_ENC0_P0_MASK, ret, out);
>> + mtk_dp_set_color_format(mtk_dp, MTK_DP_COLOR_FORMAT_RGB_444);
>> + mtk_dp_set_color_depth(mtk_dp, MTK_DP_COLOR_DEPTH_8BIT);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC1_P0_3368,
>> + 1 << BS2BS_MODE_DP_ENC1_P0_SHIFT,
>> + BS2BS_MODE_DP_ENC1_P0_MASK, ret, out);
>> +
>> + /* dp tx encoder reset all sw */
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3004,
>> + BIT(DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_SHIFT),
>> + DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_MASK, ret, out);
>> + usleep_range(1000, 5000);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3004, 0,
>> + DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_digital_sw_reset(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_340C,
>> + BIT(DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_SHIFT),
>> + DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_MASK, ret, out);
>> + usleep_range(1000, 5000);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_340C, 0,
>> + DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_set_lanes(struct mtk_dp *mtk_dp, int lanes)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_35F0,
>> + lanes == 0 ? 0 : BIT(3), BIT(3) | BIT(2), ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_ENC0_P0_3000, lanes,
>> + LANE_NUM_DP_ENC0_P0_MASK, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TRANS_P0_34A4,
>> + lanes << LANE_NUM_DP_TRANS_P0_SHIFT,
>> + LANE_NUM_DP_TRANS_P0_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int link_rate_to_mb_per_s(struct mtk_dp *mtk_dp,
>> + enum mtk_dp_linkrate linkrate)
>> +{
>> + switch (linkrate) {
>> + default:
>> + drm_err(mtk_dp->drm_dev,
>> + "Implementation error, unknown linkrate %d\n",
>> + linkrate);
>> + fallthrough;
>> + case MTK_DP_LINKRATE_RBR:
>> + return 1620;
>> + case MTK_DP_LINKRATE_HBR:
>> + return 2700;
>> + case MTK_DP_LINKRATE_HBR2:
>> + return 5400;
>> + case MTK_DP_LINKRATE_HBR3:
>> + return 8100;
>> + }
>> +}
>> +
>> +static u32 check_cal_data_valid(u32 min, u32 max, u32 val, u32 default_val)
>> +{
>> + if (val < min || val > max)
>> + return default_val;
>> +
>> + return val;
>> +}
>> +
>> +static int mtk_dp_get_calibration_data(struct mtk_dp *mtk_dp)
>> +{
>> + struct dp_cal_data *cal_data = &mtk_dp->cal_data;
>> + struct device *dev = mtk_dp->dev;
>> + struct nvmem_cell *cell;
>> + u32 *buf;
>> + size_t len;
>> +
>> + cell = nvmem_cell_get(dev, "dp_calibration_data");
>> + if (IS_ERR(cell)) {
>> + dev_err(dev,
>> + "Error: Failed to get nvmem cell dp_calibration_data\n");
>> + return PTR_ERR(cell);
>> + }
>> +
>> + buf = (u32 *)nvmem_cell_read(cell, &len);
>> + nvmem_cell_put(cell);
>> +
>> + if (IS_ERR(buf) || ((len / sizeof(u32)) != 4)) {
>> + dev_err(dev,
>> + "Error: Failed to read nvmem_cell_read fail len %ld\n",
>> + (len / sizeof(u32)));
>> + return PTR_ERR(buf);
>> + }
>> +
>> + cal_data->glb_bias_trim =
>> + check_cal_data_valid(1, 0x1e, (buf[3] >> 27) & 0x1f, 0xf);
>> + cal_data->clktx_impse =
>> + check_cal_data_valid(1, 0xe, (buf[0] >> 9) & 0xf, 0x8);
>> + cal_data->ln_tx_impsel_pmos[0] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 28) & 0xf, 0x8);
>> + cal_data->ln_tx_impsel_nmos[0] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 24) & 0xf, 0x8);
>> + cal_data->ln_tx_impsel_pmos[1] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 20) & 0xf, 0x8);
>> + cal_data->ln_tx_impsel_nmos[1] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 16) & 0xf, 0x8);
>> + cal_data->ln_tx_impsel_pmos[2] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 12) & 0xf, 0x8);
>> + cal_data->ln_tx_impsel_nmos[2] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 8) & 0xf, 0x8);
>> + cal_data->ln_tx_impsel_pmos[3] =
>> + check_cal_data_valid(1, 0xe, (buf[2] >> 4) & 0xf, 0x8);
>> + cal_data->ln_tx_impsel_nmos[3] =
>> + check_cal_data_valid(1, 0xe, buf[2] & 0xf, 0x8);
>> +
>> + kfree(buf);
>> +
>> + return 0;
>> +}
>> +
>> +static int mtk_dp_set_cal_data(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> + struct dp_cal_data *cal_data = &mtk_dp->cal_data;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_GLB_DPAUX_TX,
>> + cal_data->clktx_impse << 20, RG_CKM_PT0_CKTX_IMPSEL, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_GLB_BIAS_GEN_00,
>> + cal_data->glb_bias_trim << 16,
>> + RG_XTP_GLB_BIAS_INTR_CTRL, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_0,
>> + cal_data->ln_tx_impsel_pmos[0] << 12,
>> + RG_XTP_LN0_TX_IMPSEL_PMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_0,
>> + cal_data->ln_tx_impsel_nmos[0] << 16,
>> + RG_XTP_LN0_TX_IMPSEL_NMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_1,
>> + cal_data->ln_tx_impsel_pmos[1] << 12,
>> + RG_XTP_LN1_TX_IMPSEL_PMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_1,
>> + cal_data->ln_tx_impsel_nmos[1] << 16,
>> + RG_XTP_LN1_TX_IMPSEL_NMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_2,
>> + cal_data->ln_tx_impsel_pmos[2] << 12,
>> + RG_XTP_LN2_TX_IMPSEL_PMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_2,
>> + cal_data->ln_tx_impsel_nmos[2] << 16,
>> + RG_XTP_LN2_TX_IMPSEL_NMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_3,
>> + cal_data->ln_tx_impsel_pmos[3] << 12,
>> + RG_XTP_LN3_TX_IMPSEL_PMOS, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, DP_PHY_LANE_TX_3,
>> + cal_data->ln_tx_impsel_nmos[3] << 16,
>> + RG_XTP_LN3_TX_IMPSEL_NMOS, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_phy_configure(struct mtk_dp *mtk_dp,
>> + enum mtk_dp_linkrate link_rate, int lane_count)
>> +{
>> + int ret;
>> + union phy_configure_opts phy_opts = {
>> + .dp = {
>> + .link_rate = link_rate_to_mb_per_s(mtk_dp, link_rate),
>> + .set_rate = 1,
>> + .lanes = lane_count,
>> + .set_lanes = 1,
>> + .ssc = mtk_dp->train_info.sink_ssc,
>> + }
>> + };
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_PWR_STATE, DP_PWR_STATE_BANDGAP,
>> + DP_PWR_STATE_MASK, ret, out);
>> +
>> + ret = phy_configure(mtk_dp->phy, &phy_opts);
>> +
>> + if (ret)
>> + goto out;
>> +
>> + mtk_dp_set_cal_data(mtk_dp);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_PWR_STATE,
>> + DP_PWR_STATE_BANDGAP_TPLL_LANE, DP_PWR_STATE_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_set_idle_pattern(struct mtk_dp *mtk_dp, bool enable)
>> +{
>> + const u32 val = POST_MISC_DATA_LANE0_OV_DP_TRANS_P0_MASK |
>> + POST_MISC_DATA_LANE1_OV_DP_TRANS_P0_MASK |
>> + POST_MISC_DATA_LANE2_OV_DP_TRANS_P0_MASK |
>> + POST_MISC_DATA_LANE3_OV_DP_TRANS_P0_MASK;
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3580, enable ? val : 0, val);
>> +}
>> +
>> +//TODO: check return value in callee
>> +static int mtk_dp_train_set_pattern(struct mtk_dp *mtk_dp, int pattern)
>> +{
>> + if (pattern < 0 || pattern > 4) {
>> + drm_err(mtk_dp->drm_dev,
>> + "Implementation error, no such pattern %d\n", pattern);
>> + return -EINVAL;
>> + }
>> +
>> + if (pattern == 1) /* TPS1 */
>> + mtk_dp_set_idle_pattern(mtk_dp, false);
>> +
>> + return mtk_dp_update_bits(mtk_dp,
>> + MTK_DP_TRANS_P0_3400,
>> + pattern ? BIT(pattern - 1) << PATTERN1_EN_DP_TRANS_P0_SHIFT : 0,
>> + PATTERN1_EN_DP_TRANS_P0_MASK | PATTERN2_EN_DP_TRANS_P0_MASK |
>> + PATTERN3_EN_DP_TRANS_P0_MASK |
>> + PATTERN4_EN_DP_TRANS_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_set_enhanced_frame_mode(struct mtk_dp *mtk_dp, bool enable)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000,
>> + enable ? BIT(ENHANCED_FRAME_EN_DP_ENC0_P0_SHIFT) : 0,
>> + ENHANCED_FRAME_EN_DP_ENC0_P0_MASK);
>> +}
>> +
>> +static int mtk_dp_training_set_scramble(struct mtk_dp *mtk_dp, bool enable)
>> +{
>> + return mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3404,
>> + enable ? DP_SCR_EN_DP_TRANS_P0_MASK : 0,
>> + DP_SCR_EN_DP_TRANS_P0_MASK);
>> +}
>> +
>> +static void mtk_dp_video_mute(struct mtk_dp *mtk_dp, bool enable)
>> +{
>> + u32 val = BIT(VIDEO_MUTE_SEL_DP_ENC0_P0_SHIFT);
>> +
>> + if (enable)
>> + val |= BIT(VIDEO_MUTE_SW_DP_ENC0_P0_SHIFT);
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000, val,
>> + VIDEO_MUTE_SEL_DP_ENC0_P0_MASK |
>> + VIDEO_MUTE_SW_DP_ENC0_P0_MASK);
>> +
>> + mtk_dp_sip_atf_call(MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE, enable);
>> +}
>> +
>> +static int mtk_dp_power_enable(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE, 0,
>> + SW_RST_B_PHYD, ret, out);
>> + usleep_range(10, 200);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE, SW_RST_B_PHYD,
>> + SW_RST_B_PHYD, ret, out);
>> + MTK_UPD_BITS_OR_OUT(mtk_dp, MTK_DP_TOP_PWR_STATE,
>> + DP_PWR_STATE_BANDGAP_TPLL,
>> + DP_PWR_STATE_MASK, ret, out);
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_power_disable(struct mtk_dp *mtk_dp)
>> +{
>> + int ret;
>> +
>> + ret = mtk_dp_write(mtk_dp, MTK_DP_TOP_PWR_STATE, 0);
>> +
>> + if (ret)
>> + goto out;
>> +
>> + usleep_range(10, 200);
>> + ret = mtk_dp_write(mtk_dp, MTK_DP_0034,
>> + DA_CKM_CKTX0_EN_FORCE_EN | DA_CKM_BIAS_LPF_EN_FORCE_VAL |
>> + DA_CKM_BIAS_EN_FORCE_VAL |
>> + DA_XTP_GLB_LDO_EN_FORCE_VAL |
>> + DA_XTP_GLB_AVD10_ON_FORCE_VAL);
>> +
>> + if (ret)
>> + goto out;
>> +
>> + /* Disable RX */
>> + ret = mtk_dp_write(mtk_dp, MTK_DP_1040, 0);
>> +
>> + if (ret)
>> + goto out;
>> +
>> + ret = mtk_dp_write(mtk_dp, MTK_DP_TOP_MEM_PD,
>> + 0x550 | BIT(FUSE_SEL_SHIFT) | BIT(MEM_ISO_EN_SHIFT));
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static void mtk_dp_initialize_priv_data(struct mtk_dp *mtk_dp)
>> +{
>> + mtk_dp->train_info.link_rate = MTK_DP_LINKRATE_HBR2;
>> + mtk_dp->train_info.lane_count = MTK_DP_MAX_LANES;
>> + mtk_dp->train_info.irq_status = 0;
>> + mtk_dp->train_info.cable_plugged_in = false;
>> + mtk_dp->train_info.cable_state_change = false;
>> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_STARTUP;
>> + mtk_dp->state = MTK_DP_STATE_INITIAL;
>> +
>> + mtk_dp->info.format = MTK_DP_COLOR_FORMAT_RGB_444;
>> + mtk_dp->info.depth = MTK_DP_COLOR_DEPTH_8BIT;
>> + memset(&mtk_dp->info.timings, 0, sizeof(struct mtk_dp_timings));
>> + mtk_dp->info.timings.frame_rate = 60;
>> +
>> + mtk_dp->has_fec = false;
>> +}
>> +
>> +static void mtk_dp_setup_tu(struct mtk_dp *mtk_dp)
>> +{
>> + u32 sram_read_start = MTK_DP_TBC_BUF_READ_START_ADDR;
>> +
>> + if (mtk_dp->train_info.lane_count > 0) {
>> + sram_read_start = min_t(u32,
>> + MTK_DP_TBC_BUF_READ_START_ADDR,
>> + mtk_dp->info.timings.vm.hactive /
>> + (mtk_dp->train_info.lane_count * 4 * 2 * 2));
>> + mtk_dp_set_sram_read_start(mtk_dp, sram_read_start);
>> + }
>> +
>> + mtk_dp_setup_encoder(mtk_dp);
>> +}
>> +
>> +static void mtk_dp_calculate_pixrate(struct mtk_dp *mtk_dp)
>> +{
>> + int target_frame_rate = 60;
>> + int target_pixel_clk;
>> +
>> + if (mtk_dp->info.timings.frame_rate > 0) {
>> + target_frame_rate = mtk_dp->info.timings.frame_rate;
>> + target_pixel_clk = (int)mtk_dp->info.timings.htotal *
>> + (int)mtk_dp->info.timings.vtotal *
>> + target_frame_rate;
>> + } else if (mtk_dp->info.timings.pix_rate_khz > 0) {
>> + target_pixel_clk = mtk_dp->info.timings.pix_rate_khz * 1000;
>> + } else {
>> + target_pixel_clk = (int)mtk_dp->info.timings.htotal *
>> + (int)mtk_dp->info.timings.vtotal *
>> + target_frame_rate;
>> + }
>> +
>> + if (target_pixel_clk > 0)
>> + mtk_dp->info.timings.pix_rate_khz = target_pixel_clk / 1000;
>> +}
>> +
>> +static void mtk_dp_set_tx_out(struct mtk_dp *mtk_dp)
>> +{
>> + mtk_dp_msa_bypass_disable(mtk_dp);
>> + mtk_dp_calculate_pixrate(mtk_dp);
>> + mtk_dp_pg_disable(mtk_dp);
>> + mtk_dp_setup_tu(mtk_dp);
>> +}
>> +
>> +static void mtk_dp_train_update_swing_pre(struct mtk_dp *mtk_dp, int lanes,
>> + u8 dpcd_adjust_req[2])
>> +{
>> + int lane;
>> +
>> + for (lane = 0; lane < lanes; ++lane) {
>> + u8 val;
>> + u8 swing;
>> + u8 preemphasis;
>> + int index = lane / 2;
>> + int shift = lane % 2 ? DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : 0;
>> +
>> + swing = (dpcd_adjust_req[index] >> shift) &
>> + DP_ADJUST_VOLTAGE_SWING_LANE0_MASK;
>> + preemphasis = ((dpcd_adjust_req[index] >> shift) &
>> + DP_ADJUST_PRE_EMPHASIS_LANE0_MASK) >>
>> + DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT;
>> + val = swing << DP_TRAIN_VOLTAGE_SWING_SHIFT |
>> + preemphasis << DP_TRAIN_PRE_EMPHASIS_SHIFT;
>> +
>> + if (swing == DP_TRAIN_VOLTAGE_SWING_LEVEL_3)
>> + val |= DP_TRAIN_MAX_SWING_REACHED;
>> + if (preemphasis == 3)
>> + val |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
>> +
>> + mtk_dp_set_swing_pre_emphasis(mtk_dp, lane, swing, preemphasis);
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_TRAINING_LANE0_SET + lane,
>> + val);
>> + }
>> +
>> + /* Wait for the signal to be stable enough */
>> + usleep_range(2000, 5000);
>> +}
>> +
>> +static void mtk_dp_read_link_status(struct mtk_dp *mtk_dp,
>> + u8 link_status[DP_LINK_STATUS_SIZE])
>> +{
>> + drm_dp_dpcd_read(&mtk_dp->aux, DP_LANE0_1_STATUS, link_status,
>> + DP_LINK_STATUS_SIZE);
>> +}
>> +
>> +static int mtk_dp_train_flow(struct mtk_dp *mtk_dp, int target_link_rate,
>> + int target_lane_count)
>> +{
>> + u8 link_status[DP_LINK_STATUS_SIZE] = {};
>> + u8 lane_adjust[2] = {};
>> + bool pass_tps1 = false;
>> + bool pass_tps2_3 = false;
>> + int train_retries;
>> + int status_control;
>> + int iteration_count;
>> + u8 prev_lane_adjust;
>> + u8 val;
>> +
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_LINK_BW_SET, target_link_rate);
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_LANE_COUNT_SET,
>> + target_lane_count | DP_LANE_COUNT_ENHANCED_FRAME_EN);
>> +
>> + if (mtk_dp->train_info.sink_ssc)
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_DOWNSPREAD_CTRL,
>> + DP_SPREAD_AMP_0_5);
>> +
>> + train_retries = 0;
>> + status_control = 0;
>> + iteration_count = 1;
>> + prev_lane_adjust = 0xFF;
>> +
>> + mtk_dp_set_lanes(mtk_dp, target_lane_count / 2);
>> + mtk_dp_phy_configure(mtk_dp, target_link_rate, target_lane_count);
>> +
>> + dev_dbg(mtk_dp->dev,
>> + "Link train target_link_rate = 0x%x, target_lane_count = 0x%x\n",
>> + target_link_rate, target_lane_count);
>> +
>> + do {
>> + train_retries++;
>> + if (!mtk_dp->train_info.cable_plugged_in ||
>> + ((mtk_dp->train_info.irq_status & MTK_DP_HPD_DISCONNECT) !=
>> + 0x0)) {
>> + return -ENODEV;
>> + }
>> +
>> + if (mtk_dp->train_state < MTK_DP_TRAIN_STATE_TRAINING)
>> + return -EAGAIN;
>> +
>> + if (!pass_tps1) {
>> + mtk_dp_training_set_scramble(mtk_dp, false);
>> +
>> + if (status_control == 0) {
>> + status_control = 1;
>> + mtk_dp_train_set_pattern(mtk_dp, 1);
>> + val = DP_LINK_SCRAMBLING_DISABLE |
>> + DP_TRAINING_PATTERN_1;
>> + drm_dp_dpcd_writeb(&mtk_dp->aux,
>> + DP_TRAINING_PATTERN_SET,
>> + DP_LINK_SCRAMBLING_DISABLE |
>> + DP_TRAINING_PATTERN_1);
>> + drm_dp_dpcd_read(&mtk_dp->aux,
>> + DP_ADJUST_REQUEST_LANE0_1,
>> + lane_adjust,
>> + sizeof(lane_adjust));
>> + iteration_count++;
>> +
>> + mtk_dp_train_update_swing_pre(mtk_dp,
>> + target_lane_count, lane_adjust);
>> + }
>> +
>> + drm_dp_link_train_clock_recovery_delay(&mtk_dp->aux,
>> + mtk_dp->rx_cap);
>> + mtk_dp_read_link_status(mtk_dp, link_status);
>> +
>> + if (drm_dp_clock_recovery_ok(link_status,
>> + target_lane_count)) {
>> + mtk_dp->train_info.cr_done = true;
>> + pass_tps1 = true;
>> + train_retries = 0;
>> + iteration_count = 1;
>> + dev_dbg(mtk_dp->dev, "Link train CR pass\n");
>> + } else if (prev_lane_adjust == link_status[4]) {
>> + iteration_count++;
>> + if (prev_lane_adjust &
>> + DP_ADJUST_VOLTAGE_SWING_LANE0_MASK)
>> + break;
>> + } else {
>> + prev_lane_adjust = link_status[4];
>> + }
>> + dev_dbg(mtk_dp->dev, "Link train CQ fail\n");
>> + } else if (pass_tps1 && !pass_tps2_3) {
>> + if (status_control == 1) {
>> + status_control = 2;
>> + if (mtk_dp->train_info.tps4) {
>> + mtk_dp_train_set_pattern(mtk_dp, 4);
>> + val = DP_TRAINING_PATTERN_4;
>> + } else if (mtk_dp->train_info.tps3) {
>> + mtk_dp_train_set_pattern(mtk_dp, 3);
>> + val = DP_LINK_SCRAMBLING_DISABLE |
>> + DP_TRAINING_PATTERN_3;
>> + } else {
>> + mtk_dp_train_set_pattern(mtk_dp, 2);
>> + val = DP_LINK_SCRAMBLING_DISABLE |
>> + DP_TRAINING_PATTERN_2;
>> + }
>> + drm_dp_dpcd_writeb(&mtk_dp->aux,
>> + DP_TRAINING_PATTERN_SET,
>> + val);
>> +
>> + drm_dp_dpcd_read(&mtk_dp->aux,
>> + DP_ADJUST_REQUEST_LANE0_1,
>> + lane_adjust,
>> + sizeof(lane_adjust));
>> +
>> + iteration_count++;
>> + mtk_dp_train_update_swing_pre(mtk_dp,
>> + target_lane_count, lane_adjust);
>> + }
>> +
>> + drm_dp_link_train_channel_eq_delay(&mtk_dp->aux,
>> + mtk_dp->rx_cap);
>> +
>> + mtk_dp_read_link_status(mtk_dp, link_status);
>> +
>> + if (!drm_dp_clock_recovery_ok(link_status,
>> + target_lane_count)) {
>> + mtk_dp->train_info.cr_done = false;
>> + mtk_dp->train_info.eq_done = false;
>> + dev_dbg(mtk_dp->dev, "Link train EQ fail\n");
>> + break;
>> + }
>> +
>> + if (drm_dp_channel_eq_ok(link_status,
>> + target_lane_count)) {
>> + mtk_dp->train_info.eq_done = true;
>> + pass_tps2_3 = true;
>> + dev_dbg(mtk_dp->dev, "Link train EQ pass\n");
>> + break;
>> + }
>> +
>> + if (prev_lane_adjust == link_status[4])
>> + iteration_count++;
>> + else
>> + prev_lane_adjust = link_status[4];
>> + }
>> +
>> + drm_dp_dpcd_read(&mtk_dp->aux, DP_ADJUST_REQUEST_LANE0_1,
>> + lane_adjust, sizeof(lane_adjust));
>> + mtk_dp_train_update_swing_pre(mtk_dp, target_lane_count,
>> + lane_adjust);
>> + } while (train_retries < MTK_DP_TRAIN_RETRY_LIMIT &&
>> + iteration_count < MTK_DP_TRAIN_MAX_ITERATIONS);
>> +
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_TRAINING_PATTERN_SET,
>> + DP_TRAINING_PATTERN_DISABLE);
>> + mtk_dp_train_set_pattern(mtk_dp, 0);
>> +
>> + if (!pass_tps2_3)
>> + return -ETIMEDOUT;
>> +
>> + mtk_dp->train_info.link_rate = target_link_rate;
>> + mtk_dp->train_info.lane_count = target_lane_count;
>> +
>> + mtk_dp_training_set_scramble(mtk_dp, true);
>> +
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_LANE_COUNT_SET,
>> + target_lane_count |
>> + DP_LANE_COUNT_ENHANCED_FRAME_EN);
>> + mtk_dp_set_enhanced_frame_mode(mtk_dp, true);
>> +
>> + return 0;
>> +}
>> +
>> +static bool mtk_dp_parse_capabilities(struct mtk_dp *mtk_dp)
>> +{
>> + u8 buf[DP_RECEIVER_CAP_SIZE] = {};
>> + u8 val;
>> + struct mtk_dp_train_info *train_info = &mtk_dp->train_info;
>> +
>> + if (!mtk_dp_plug_state(mtk_dp))
>> + return false;
>> +
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
>> + usleep_range(2000, 5000);
>> +
>> + drm_dp_read_dpcd_caps(&mtk_dp->aux, buf);
>> +
>> + memcpy(mtk_dp->rx_cap, buf, min(sizeof(mtk_dp->rx_cap), sizeof(buf)));
>> + mtk_dp->rx_cap[DP_TRAINING_AUX_RD_INTERVAL] &= DP_TRAINING_AUX_RD_MASK;
>> +
>> + train_info->link_rate =
>> + min_t(int, MTK_DP_MAX_LINK_RATE, buf[DP_MAX_LINK_RATE]);
>> + train_info->lane_count =
>> + min_t(int, MTK_DP_MAX_LANES, drm_dp_max_lane_count(buf));
>> +
>> + train_info->tps3 = drm_dp_tps3_supported(buf);
>> + train_info->tps4 = drm_dp_tps4_supported(buf);
>> +
>> + train_info->sink_ssc =
>> + !!(buf[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5);
>> +
>> + train_info->sink_ssc = false;
>> +
>> + drm_dp_dpcd_readb(&mtk_dp->aux, DP_MSTM_CAP, &val);
>> + if (val & DP_MST_CAP) {
>> + /* Clear DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 */
>> + drm_dp_dpcd_readb(&mtk_dp->aux,
>> + DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0, &val);
>> + if (val)
>> + drm_dp_dpcd_writeb(&mtk_dp->aux,
>> + DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0,
>> + val);
>> + }
>> +
>> + return true;
>> +}
>> +
>> +static void mtk_dp_train_change_mode(struct mtk_dp *mtk_dp)
>> +{
>> + phy_reset(mtk_dp->phy);
>> + mtk_dp_reset_swing_pre_emphasis(mtk_dp);
>> +
>> + usleep_range(2000, 5000);
>> +}
>> +
>> +static int mtk_dp_train_start(struct mtk_dp *mtk_dp)
>> +{
>> + int ret = 0;
>> + int lane_count;
>> + int link_rate;
>> + int train_limit;
>> + int max_link_rate;
>> + int plug_wait;
>> +
>> + for (plug_wait = 7; !mtk_dp_plug_state(mtk_dp) && plug_wait > 0;
>> + --plug_wait)
>> + usleep_range(1000, 5000);
>> + if (plug_wait == 0) {
>> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_DPIDLE;
>> + return -ENODEV;
>> + }
>> +
>> + link_rate = mtk_dp->rx_cap[1];
>> + lane_count = mtk_dp->rx_cap[2] & 0x1F;
>> +
>> + mtk_dp->train_info.link_rate = min(MTK_DP_MAX_LINK_RATE, link_rate);
>> + mtk_dp->train_info.lane_count = min(MTK_DP_MAX_LANES, lane_count);
>> + link_rate = mtk_dp->train_info.link_rate;
>> + lane_count = mtk_dp->train_info.lane_count;
>> +
>> + switch (link_rate) {
>> + case MTK_DP_LINKRATE_RBR:
>> + case MTK_DP_LINKRATE_HBR:
>> + case MTK_DP_LINKRATE_HBR2:
>> + case MTK_DP_LINKRATE_HBR25:
>> + case MTK_DP_LINKRATE_HBR3:
>> + break;
>> + default:
>> + mtk_dp->train_info.link_rate = MTK_DP_LINKRATE_HBR3;
>> + break;
>> + };
>>+
>> + max_link_rate = link_rate;
>> + for (train_limit = 6; train_limit > 0; train_limit--) {
>> + mtk_dp->train_info.cr_done = false;
>> + mtk_dp->train_info.eq_done = false;
>> +
>> + mtk_dp_train_change_mode(mtk_dp);
>> + ret = mtk_dp_train_flow(mtk_dp, link_rate, lane_count);
>> + if (ret)
>> + return ret;
>> +
>> + if (!mtk_dp->train_info.cr_done) {
>> + switch (link_rate) {
>> + case MTK_DP_LINKRATE_RBR:
>> + lane_count = lane_count / 2;
>> + link_rate = max_link_rate;
>> + if (lane_count == 0) {
>> + mtk_dp->train_state =
>> + MTK_DP_TRAIN_STATE_DPIDLE;
>> + return -EIO;
>> + }
>> + break;
>> + case MTK_DP_LINKRATE_HBR:
>> + link_rate = MTK_DP_LINKRATE_RBR;
>> + break;
>> + case MTK_DP_LINKRATE_HBR2:
>> + link_rate = MTK_DP_LINKRATE_HBR;
>> + break;
>> + case MTK_DP_LINKRATE_HBR3:
>> + link_rate = MTK_DP_LINKRATE_HBR2;
>> + break;
>> + default:
>> + return -EINVAL;
>> + };
>> + } else if (!mtk_dp->train_info.eq_done) {
>> + if (lane_count == 0)
>> + return -EIO;
>> +
>> + lane_count /= 2;
>> + } else {
>> + break;
>> + }
>> + }
>> +
>> + if (train_limit == 0)
>> + return -ETIMEDOUT;
>> +
>> + return 0;
>> +}
>> +
>> +static int mtk_dp_train_handler(struct mtk_dp *mtk_dp)
>> +{
>> + int ret = 0;
>> + int i = 50;
>> +
>> + for (; ret && i; i--) {
>> + if (mtk_dp->train_state == MTK_DP_TRAIN_STATE_NORMAL)
>> + continue;
>> +
>> + switch (mtk_dp->train_state) {
>> + case MTK_DP_TRAIN_STATE_STARTUP:
>> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_CHECKCAP;
>> + break;
>> +
>> + case MTK_DP_TRAIN_STATE_CHECKCAP:
>> + if (mtk_dp_parse_capabilities(mtk_dp)) {
>> + mtk_dp->train_info.check_cap_count = 0;
>> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_CHECKEDID;
>> + } else {
>> + mtk_dp->train_info.check_cap_count++;
>> +
>> + if (mtk_dp->train_info.check_cap_count >
>> + MTK_DP_CHECK_SINK_CAP_TIMEOUT_COUNT) {
>> + mtk_dp->train_info.check_cap_count = 0;
>> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_DPIDLE;
>> + ret = -ETIMEDOUT;
>> + }
>> + }
>> + break;
>> +
>> + case MTK_DP_TRAIN_STATE_CHECKEDID:
>> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_TRAINING_PRE;
>> + break;
>> +
>> + case MTK_DP_TRAIN_STATE_TRAINING_PRE:
>> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_TRAINING;
>> + break;
>> +
>> + case MTK_DP_TRAIN_STATE_TRAINING:
>> + ret = mtk_dp_train_start(mtk_dp);
>> + if (!ret) {
>> + mtk_dp_video_mute(mtk_dp, true);
>> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_NORMAL;
>> + mtk_dp_fec_enable(mtk_dp, mtk_dp->has_fec);
>> + } else if (ret != -EAGAIN) {
>> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_DPIDLE;
>> + }
>> +
>> + ret = 0;
>> + break;
>> +
>> + case MTK_DP_TRAIN_STATE_NORMAL:
>> + break;
>> + case MTK_DP_TRAIN_STATE_DPIDLE:
>> + break;
>> + default:
>> + break;
>> + }
>> + }
>> +
>> + if (ret)
>> + drm_err(mtk_dp->drm_dev, "Train handler failed %d\n", ret);
>> +
>> + return ret;
>> +}
>
>I'm not really familiar with displayport, but it looks like you're
>hand-rolling a significant part of what the drm_dp_* helpers provide.
That's very probable, I'll go shopping and see what I can remove from
this driver.
Thanks for the hint.
>
>> +static void mtk_dp_video_enable(struct mtk_dp *mtk_dp, bool enable)
>> +{
>> + if (enable) {
>> + mtk_dp_set_tx_out(mtk_dp);
>> + mtk_dp_video_mute(mtk_dp, false);
>> + } else {
>> + mtk_dp_video_mute(mtk_dp, true);
>> + }
>> +}
>> +
>> +static void mtk_dp_video_config(struct mtk_dp *mtk_dp)
>> +{
>> + mtk_dp_mn_overwrite_disable(mtk_dp);
>> +
>> + mtk_dp_set_msa(mtk_dp);
>> +
>> + mtk_dp_set_color_depth(mtk_dp, mtk_dp->info.depth);
>> + mtk_dp_set_color_format(mtk_dp, mtk_dp->info.format);
>> +}
>> +
>> +static void mtk_dp_state_handler(struct mtk_dp *mtk_dp)
>> +{
>> + switch (mtk_dp->state) {
>> + case MTK_DP_STATE_INITIAL:
>> + mtk_dp_video_mute(mtk_dp, true);
>> + mtk_dp->state = MTK_DP_STATE_IDLE;
>> + break;
>> +
>> + case MTK_DP_STATE_IDLE:
>> + if (mtk_dp->train_state == MTK_DP_TRAIN_STATE_NORMAL)
>> + mtk_dp->state = MTK_DP_STATE_PREPARE;
>> + break;
>> +
>> + case MTK_DP_STATE_PREPARE:
>> + mtk_dp_video_config(mtk_dp);
>> + mtk_dp_video_enable(mtk_dp, true);
>> +
>> + mtk_dp->state = MTK_DP_STATE_NORMAL;
>> + break;
>> +
>> + case MTK_DP_STATE_NORMAL:
>> + if (mtk_dp->train_state != MTK_DP_TRAIN_STATE_NORMAL) {
>> + mtk_dp_video_mute(mtk_dp, true);
>> + mtk_dp->state = MTK_DP_STATE_IDLE;
>> + }
>> + break;
>> +
>> + default:
>> + break;
>> + }
>> +}
>> +
>> +static void mtk_dp_init_port(struct mtk_dp *mtk_dp)
>> +{
>> + mtk_dp_set_idle_pattern(mtk_dp, true);
>> + mtk_dp_initialize_priv_data(mtk_dp);
>> +
>> + mtk_dp_initialize_settings(mtk_dp);
>> + mtk_dp_initialize_aux_settings(mtk_dp);
>> + mtk_dp_initialize_digital_settings(mtk_dp);
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3690,
>> + BIT(RX_REPLY_COMPLETE_MODE_AUX_TX_P0_SHIFT),
>> + RX_REPLY_COMPLETE_MODE_AUX_TX_P0_MASK);
>> + mtk_dp_initialize_hpd_detect_settings(mtk_dp);
>> +
>> + mtk_dp_digital_sw_reset(mtk_dp);
>> +}
>> +
>> +static int mtk_dp_dt_parse(struct mtk_dp *mtk_dp,
>> + struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + int ret = 0;
>> + void __iomem *base;
>> +
>> + base = devm_platform_ioremap_resource(pdev, 0);
>> + if (IS_ERR(base))
>> + return PTR_ERR(base);
>> +
>> + mtk_dp->regs = syscon_node_to_regmap(dev->of_node);
>> + if (IS_ERR(mtk_dp->regs))
>> + return PTR_ERR(mtk_dp->regs);
>> +
>> + //TODO: optional clock?
>> + mtk_dp->dp_tx_clk = devm_clk_get(dev, "faxi");
>> + if (IS_ERR(mtk_dp->dp_tx_clk)) {
>> + ret = PTR_ERR(mtk_dp->dp_tx_clk);
>> + dev_info(dev, "Failed to get dptx clock: %d\n", ret);
>> + mtk_dp->dp_tx_clk = NULL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge)
>> +{
>> + return connector_status_connected;
>> +}
>
>I'm not quite sure what's going on there. You seem to have some support
>for HPD interrupts above, but you always report the display as
>connected?
>
>I'd assume that either you don't have HPD support and then always report
>it as connected, or you have HPD support and report the current status
>in detect, but that combination seems weird.
The HPD logic needs more work, some things have been broken when I split
the driver into three patches eDP - DP - Audio
The assumption at first was that eDP didn't need any HPD handling... but it
seems I was wrong and the eDP driver needs to be reworked.
>
>> +static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
>> + struct drm_connector *connector)
>> +{
>> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
>> + bool enabled = mtk_dp->enabled;
>> + struct edid *new_edid = NULL;
>> +
>> + if (!enabled)
>> + drm_bridge_chain_pre_enable(bridge);
>> +
>> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
>> + usleep_range(2000, 5000);
>> +
>> + if (mtk_dp_plug_state(mtk_dp))
>> + new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
>> +
>> + if (!enabled)
>> + drm_bridge_chain_post_disable(bridge);
>
>Are you sure we can't get a mode set while get_edid is called?
>
>If we can, then you could end up disabling the device while it's being
>powered on.
I'm a bit unsure, I need to spend more time in the drm stack to make sure.
I'll get back to you when I have a definitive answer.
>
>> + mutex_lock(&mtk_dp->edid_lock);
>> + kfree(mtk_dp->edid);
>> + mtk_dp->edid = NULL;
>> +
>> + if (!new_edid) {
>> + mutex_unlock(&mtk_dp->edid_lock);
>> + return NULL;
>> + }
>> +
>> + mtk_dp->edid = drm_edid_duplicate(new_edid);
>> + mutex_unlock(&mtk_dp->edid_lock);
>
>Why do you need a copy of the edid there?
It seems to be leftover from the split of the driver into 3 patches.
This will be removed from the eDP implementation.
>
>> + return new_edid;
>> +}
>> +
>> +static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux,
>> + struct drm_dp_aux_msg *msg)
>> +{
>> + struct mtk_dp *mtk_dp;
>> + bool is_read;
>> + u8 request;
>> + size_t accessed_bytes = 0;
>> + int retry = 3, ret = 0;
>> +
>> + mtk_dp = container_of(mtk_aux, struct mtk_dp, aux);
>> +
>> + if (!mtk_dp->train_info.cable_plugged_in ||
>> + mtk_dp->train_info.irq_status & MTK_DP_HPD_DISCONNECT) {
>> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_CHECKCAP;
>> + ret = -EAGAIN;
>> + goto err;
>> + }
>> +
>> + switch (msg->request) {
>> + case DP_AUX_I2C_MOT:
>> + case DP_AUX_I2C_WRITE:
>> + case DP_AUX_NATIVE_WRITE:
>> + case DP_AUX_I2C_WRITE_STATUS_UPDATE:
>> + case DP_AUX_I2C_WRITE_STATUS_UPDATE | DP_AUX_I2C_MOT:
>> + request = msg->request & ~DP_AUX_I2C_WRITE_STATUS_UPDATE;
>> + is_read = false;
>> + break;
>> + case DP_AUX_I2C_READ:
>> + case DP_AUX_NATIVE_READ:
>> + case DP_AUX_I2C_READ | DP_AUX_I2C_MOT:
>> + request = msg->request;
>> + is_read = true;
>> + break;
>> + default:
>> + drm_err(mtk_aux->drm_dev, "invalid aux cmd = %d\n",
>> + msg->request);
>> + ret = -EINVAL;
>> + goto err;
>> + }
>> +
>> + if (msg->size == 0) {
>> + ret = mtk_dp_aux_do_transfer(mtk_dp, is_read, request,
>> + msg->address + accessed_bytes,
>> + msg->buffer + accessed_bytes, 0);
>> + } else {
>> + while (accessed_bytes < msg->size) {
>> + size_t to_access =
>> + min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES,
>> + msg->size - accessed_bytes);
>> + while (retry--) {
>> + ret = mtk_dp_aux_do_transfer(mtk_dp,
>> + is_read, request,
>> + msg->address + accessed_bytes,
>> + msg->buffer + accessed_bytes,
>> + to_access);
>> + if (ret == 0)
>> + break;
>> + usleep_range(50, 100);
>> + }
>> + if (!retry || ret) {
>> + drm_info(mtk_dp->drm_dev,
>> + "Failed to do AUX transfer: %d\n",
>> + ret);
>> + break;
>> + }
>> + accessed_bytes += to_access;
>> + }
>> + }
>> +err:
>> + if (ret) {
>> + msg->reply = DP_AUX_NATIVE_REPLY_NACK | DP_AUX_I2C_REPLY_NACK;
>> + return ret;
>> + }
>> +
>> + msg->reply = DP_AUX_NATIVE_REPLY_ACK | DP_AUX_I2C_REPLY_ACK;
>> + return msg->size;
>> +}
>> +
>> +static void mtk_dp_poweroff(struct mtk_dp *mtk_dp)
>> +{
>> + mutex_lock(&mtk_dp->dp_lock);
>> +
>> + mtk_dp_hwirq_enable(mtk_dp, false);
>> + mtk_dp_power_disable(mtk_dp);
>> + phy_exit(mtk_dp->phy);
>> + clk_disable_unprepare(mtk_dp->dp_tx_clk);
>> +
>> + mutex_unlock(&mtk_dp->dp_lock);
>> +}
>> +
>> +static int mtk_dp_poweron(struct mtk_dp *mtk_dp)
>> +{
>> + int ret = 0;
>> +
>> + mutex_lock(&mtk_dp->dp_lock);
>> +
>> + ret = clk_prepare_enable(mtk_dp->dp_tx_clk);
>> + if (ret < 0) {
>> + dev_err(mtk_dp->dev, "Fail to enable clock: %d\n", ret);
>> + goto err;
>> + }
>> + ret = phy_init(mtk_dp->phy);
>> + if (ret) {
>> + dev_err(mtk_dp->dev, "Failed to initialize phy: %d\n", ret);
>> + goto err_phy_init;
>> + }
>> + ret = mtk_dp_phy_configure(mtk_dp, MTK_DP_LINKRATE_RBR, 1);
>> + if (ret) {
>> + dev_err(mtk_dp->dev, "Failed to configure phy: %d\n", ret);
>> + goto err_phy_config;
>> + }
>> +
>> + mtk_dp_init_port(mtk_dp);
>> + mtk_dp_power_enable(mtk_dp);
>> + mtk_dp_hwirq_enable(mtk_dp, true);
>> +
>> +err_phy_config:
>> + phy_exit(mtk_dp->phy);
>> +err_phy_init:
>> + clk_disable_unprepare(mtk_dp->dp_tx_clk);
>> +err:
>> + mutex_unlock(&mtk_dp->dp_lock);
>> + return ret;
>> +}
>> +
>> +static int mtk_dp_bridge_attach(struct drm_bridge *bridge,
>> + enum drm_bridge_attach_flags flags)
>> +{
>> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
>> + int ret;
>> +
>> + ret = mtk_dp_poweron(mtk_dp);
>> + if (ret)
>> + return ret;
>> +
>> + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
>> + dev_err(mtk_dp->dev, "Driver does not provide a connector!");
>> + return -EINVAL;
>> + }
>> +
>> + if (mtk_dp->next_bridge) {
>> + ret = drm_bridge_attach(bridge->encoder, mtk_dp->next_bridge,
>> + &mtk_dp->bridge, flags);
>> + if (ret) {
>> + drm_warn(mtk_dp->drm_dev,
>> + "Failed to attach external bridge: %d\n", ret);
>> + return ret;
>> + }
>> + }
>> +
>> + mtk_dp->drm_dev = bridge->dev;
>> +
>> + return 0;
>> +}
>> +
>> +static void mtk_dp_bridge_detach(struct drm_bridge *bridge)
>> +{
>> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
>> +
>> + mtk_dp->drm_dev = NULL;
>> +}
>> +
>> +static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
>> + struct drm_bridge_state *old_state)
>> +{
>> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
>> +
>> + mtk_dp_video_mute(mtk_dp, true);
>> + mtk_dp->state = MTK_DP_STATE_IDLE;
>> + mtk_dp->train_state = MTK_DP_TRAIN_STATE_STARTUP;
>> +
>> + mtk_dp->enabled = false;
>> + msleep(100);
>> + mtk_dp_poweroff(mtk_dp);
>> +}
>> +
>> +static void mtk_dp_parse_drm_mode_timings(struct mtk_dp *mtk_dp,
>> + struct drm_display_mode *mode)
>> +{
>> + struct mtk_dp_timings *timings = &mtk_dp->info.timings;
>> +
>> + drm_display_mode_to_videomode(mode, &timings->vm);
>> + timings->frame_rate = mode->clock * 1000 / mode->htotal / mode->vtotal;
>
>drm_mode_vrefresh()
>
>> + timings->htotal = mode->htotal;
>> + timings->vtotal = mode->vtotal;
>> +}
>
>It's not really clear to me why you need to duplicate drm_display_mode
>here?
>
It's saved to be re-used in mtk_dp_set_msa().
It's not ideal, I'll check if I can get the mode directly from mtk_dp_set_msa()
>> +static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
>> + struct drm_bridge_state *old_state)
>> +{
>> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
>> + struct drm_connector_state *conn_state;
>> + struct drm_crtc *crtc;
>> + struct drm_crtc_state *crtc_state;
>> +
>> + mtk_dp->conn = drm_atomic_get_new_connector_for_encoder(old_state->base.state,
>> + bridge->encoder);
>> + if (!mtk_dp->conn) {
>> + drm_err(mtk_dp->drm_dev,
>> + "Can't enable bridge as connector is missing\n");
>> + return;
>> + }
>> +
>> + memcpy(mtk_dp->connector_eld, mtk_dp->conn->eld, MAX_ELD_BYTES);
>> +
>> + conn_state =
>> + drm_atomic_get_new_connector_state(old_state->base.state, mtk_dp->conn);
>> + if (!conn_state) {
>> + drm_err(mtk_dp->drm_dev,
>> + "Can't enable bridge as connector state is missing\n");
>> + return;
>> + }
>> +
>> + crtc = conn_state->crtc;
>> + if (!crtc) {
>> + drm_err(mtk_dp->drm_dev,
>> + "Can't enable bridge as connector state doesn't have a crtc\n");
>> + return;
>> + }
>> +
>> + crtc_state = drm_atomic_get_new_crtc_state(old_state->base.state, crtc);
>> + if (!crtc_state) {
>> + drm_err(mtk_dp->drm_dev,
>> + "Can't enable bridge as crtc state is missing\n");
>> + return;
>> + }
>> +
>> + mtk_dp_parse_drm_mode_timings(mtk_dp, &crtc_state->adjusted_mode);
>> + if (!mtk_dp_parse_capabilities(mtk_dp)) {
>> + drm_err(mtk_dp->drm_dev,
>> + "Can't enable bridge as nothing is plugged in\n");
>> + return;
>> + }
>
>All this needs to be done in atomic_check. You aren't allowed to fail in
>atomic_enable.
Good to know, I'll move everything that can fail in atomic_check.
>
>Maxime
Thx,
Guillaume.
Hi,
On Wed, May 11, 2022 at 05:59:13AM -0700, Guillaume Ranquet wrote:
> >> +#include <drm/drm_atomic_helper.h>
> >> +#include <drm/drm_bridge.h>
> >> +#include <drm/drm_crtc.h>
> >> +#include <drm/dp/drm_dp_helper.h>
> >> +#include <drm/drm_edid.h>
> >> +#include <drm/drm_of.h>
> >> +#include <drm/drm_panel.h>
> >> +#include <drm/drm_print.h>
> >> +#include <drm/drm_probe_helper.h>
> >> +#include <linux/arm-smccc.h>
> >> +#include <linux/clk.h>
> >> +#include <linux/delay.h>
> >> +#include <linux/errno.h>
> >> +#include <linux/kernel.h>
> >> +#include <linux/mfd/syscon.h>
> >> +#include <linux/nvmem-consumer.h>
> >> +#include <linux/of.h>
> >> +#include <linux/of_irq.h>
> >> +#include <linux/of_platform.h>
> >> +#include <linux/phy/phy.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/pm_runtime.h>
> >> +#include <linux/regmap.h>
> >> +#include <sound/hdmi-codec.h>
> >> +#include <video/videomode.h>
> >> +
> >> +#include "mtk_dp_reg.h"
> >> +
> >> +#define MTK_DP_AUX_WAIT_REPLY_COUNT 20
> >> +#define MTK_DP_CHECK_SINK_CAP_TIMEOUT_COUNT 3
> >> +
> >> +//TODO: platform/device data or dts?
> >
> >DTS :)
>
> It's probably going to be a platform_data struct for v10...
> If I have time, I'll change it to a dts property for v10.
I can't really imagine a case where we would need platform_data
nowadays. If you have a device tree, then it should be part of the
binding.
What issue would you like to address by using a platform_data?
> >> +static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge)
> >> +{
> >> + return connector_status_connected;
> >> +}
> >
> >I'm not quite sure what's going on there. You seem to have some support
> >for HPD interrupts above, but you always report the display as
> >connected?
> >
> >I'd assume that either you don't have HPD support and then always report
> >it as connected, or you have HPD support and report the current status
> >in detect, but that combination seems weird.
>
> The HPD logic needs more work, some things have been broken when I split
> the driver into three patches eDP - DP - Audio
> The assumption at first was that eDP didn't need any HPD handling... but it
> seems I was wrong and the eDP driver needs to be reworked.
That can be made into a patch of its own if you prefer.
You first introduce the driver without status reporting (always
returning connected or unknown), and then add the needed bits for HPD.
However, that first patch shouldn't contain the interrupt plumbing and
so on, it's just confusing.
> >> +static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
> >> + struct drm_connector *connector)
> >> +{
> >> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
> >> + bool enabled = mtk_dp->enabled;
> >> + struct edid *new_edid = NULL;
> >> +
> >> + if (!enabled)
> >> + drm_bridge_chain_pre_enable(bridge);
> >> +
> >> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
> >> + usleep_range(2000, 5000);
> >> +
> >> + if (mtk_dp_plug_state(mtk_dp))
> >> + new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
> >> +
> >> + if (!enabled)
> >> + drm_bridge_chain_post_disable(bridge);
> >
> >Are you sure we can't get a mode set while get_edid is called?
> >
> >If we can, then you could end up disabling the device while it's being
> >powered on.
>
> I'm a bit unsure, I need to spend more time in the drm stack to make sure.
> I'll get back to you when I have a definitive answer.
So, it looks like it's ok.
get_edid is your implementation of get_modes, which is called by
drm_helper_probe_single_connector_modes
https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_probe_helper.c#L416
This is the standard implemantion of fill_modes, which is called
whenever the get_connector ioctl is called (or similar paths, like
drm_client_modeset_probe)
drm_helper_probe_single_connector_modes is under the assumption that the
mode_config.mutex is held though, and that the big lock. So it should be
serialized there.
Just for future proofing though, it would be better to use refcounting
there. Would runtime_pm work for you there?
> >> +static void mtk_dp_parse_drm_mode_timings(struct mtk_dp *mtk_dp,
> >> + struct drm_display_mode *mode)
> >> +{
> >> + struct mtk_dp_timings *timings = &mtk_dp->info.timings;
> >> +
> >> + drm_display_mode_to_videomode(mode, &timings->vm);
> >> + timings->frame_rate = mode->clock * 1000 / mode->htotal / mode->vtotal;
> >
> >drm_mode_vrefresh()
> >
> >> + timings->htotal = mode->htotal;
> >> + timings->vtotal = mode->vtotal;
> >> +}
> >
> >It's not really clear to me why you need to duplicate drm_display_mode
> >here?
> >
> It's saved to be re-used in mtk_dp_set_msa().
> It's not ideal, I'll check if I can get the mode directly from mtk_dp_set_msa()
Yeah, it looks like mtk_dp_set_msa() uses fairly straightforward values,
this will be just as easy with drm_display_mode.
Maxime
On Thu, 12 May 2022 09:44, Maxime Ripard <[email protected]> wrote:
>Hi,
>
>On Wed, May 11, 2022 at 05:59:13AM -0700, Guillaume Ranquet wrote:
>> >> +#include <drm/drm_atomic_helper.h>
>> >> +#include <drm/drm_bridge.h>
>> >> +#include <drm/drm_crtc.h>
>> >> +#include <drm/dp/drm_dp_helper.h>
>> >> +#include <drm/drm_edid.h>
>> >> +#include <drm/drm_of.h>
>> >> +#include <drm/drm_panel.h>
>> >> +#include <drm/drm_print.h>
>> >> +#include <drm/drm_probe_helper.h>
>> >> +#include <linux/arm-smccc.h>
>> >> +#include <linux/clk.h>
>> >> +#include <linux/delay.h>
>> >> +#include <linux/errno.h>
>> >> +#include <linux/kernel.h>
>> >> +#include <linux/mfd/syscon.h>
>> >> +#include <linux/nvmem-consumer.h>
>> >> +#include <linux/of.h>
>> >> +#include <linux/of_irq.h>
>> >> +#include <linux/of_platform.h>
>> >> +#include <linux/phy/phy.h>
>> >> +#include <linux/platform_device.h>
>> >> +#include <linux/pm_runtime.h>
>> >> +#include <linux/regmap.h>
>> >> +#include <sound/hdmi-codec.h>
>> >> +#include <video/videomode.h>
>> >> +
>> >> +#include "mtk_dp_reg.h"
>> >> +
>> >> +#define MTK_DP_AUX_WAIT_REPLY_COUNT 20
>> >> +#define MTK_DP_CHECK_SINK_CAP_TIMEOUT_COUNT 3
>> >> +
>> >> +//TODO: platform/device data or dts?
>> >
>> >DTS :)
>>
>> It's probably going to be a platform_data struct for v10...
>> If I have time, I'll change it to a dts property for v10.
>
>I can't really imagine a case where we would need platform_data
>nowadays. If you have a device tree, then it should be part of the
>binding.
>
>What issue would you like to address by using a platform_data?
>
Ok, I'll migrate to dt then. I didn't realize platform_data were depreciated.
Angelo wants the MAX_LINRATE and MAX_LANES defines to be configurable.
I imagined platform_data would be more appropriate as (per my understanding) the
limitation is associated with a specific SoC.
>> >> +static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge)
>> >> +{
>> >> + return connector_status_connected;
>> >> +}
>> >
>> >I'm not quite sure what's going on there. You seem to have some support
>> >for HPD interrupts above, but you always report the display as
>> >connected?
>> >
>> >I'd assume that either you don't have HPD support and then always report
>> >it as connected, or you have HPD support and report the current status
>> >in detect, but that combination seems weird.
>>
>> The HPD logic needs more work, some things have been broken when I split
>> the driver into three patches eDP - DP - Audio
>> The assumption at first was that eDP didn't need any HPD handling... but it
>> seems I was wrong and the eDP driver needs to be reworked.
>
>That can be made into a patch of its own if you prefer.
>
>You first introduce the driver without status reporting (always
>returning connected or unknown), and then add the needed bits for HPD.
>
>However, that first patch shouldn't contain the interrupt plumbing and
>so on, it's just confusing.
>
After discussing a while with Mediatek, it appears that hot plug detection
needs to be handled even for eDP... (which is always connected).
So I'll revert to the split I made earlier in v8 where hot plug detection was
part of the eDP patch the addition of the External display port was a
trivial patch [1].
>> >> +static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
>> >> + struct drm_connector *connector)
>> >> +{
>> >> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
>> >> + bool enabled = mtk_dp->enabled;
>> >> + struct edid *new_edid = NULL;
>> >> +
>> >> + if (!enabled)
>> >> + drm_bridge_chain_pre_enable(bridge);
>> >> +
>> >> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
>> >> + usleep_range(2000, 5000);
>> >> +
>> >> + if (mtk_dp_plug_state(mtk_dp))
>> >> + new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
>> >> +
>> >> + if (!enabled)
>> >> + drm_bridge_chain_post_disable(bridge);
>> >
>> >Are you sure we can't get a mode set while get_edid is called?
>> >
>> >If we can, then you could end up disabling the device while it's being
>> >powered on.
>>
>> I'm a bit unsure, I need to spend more time in the drm stack to make sure.
>> I'll get back to you when I have a definitive answer.
>
>So, it looks like it's ok.
>
>get_edid is your implementation of get_modes, which is called by
>drm_helper_probe_single_connector_modes
>
>https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_probe_helper.c#L416
>
>This is the standard implemantion of fill_modes, which is called
>whenever the get_connector ioctl is called (or similar paths, like
>drm_client_modeset_probe)
>
>drm_helper_probe_single_connector_modes is under the assumption that the
>mode_config.mutex is held though, and that the big lock. So it should be
>serialized there.
>
>Just for future proofing though, it would be better to use refcounting
>there. Would runtime_pm work for you there?
>
Thx for looking into this for me.
Not sure runtime_pm works here as it would only refcount if compiled
with CONFIG_PM?
I'd rather use the enabled field as a refcounter instead of a boolean.
Unless I'm totally missing your point?
Thx,
Guillaume.
>> >> +static void mtk_dp_parse_drm_mode_timings(struct mtk_dp *mtk_dp,
>> >> + struct drm_display_mode *mode)
>> >> +{
>> >> + struct mtk_dp_timings *timings = &mtk_dp->info.timings;
>> >> +
>> >> + drm_display_mode_to_videomode(mode, &timings->vm);
>> >> + timings->frame_rate = mode->clock * 1000 / mode->htotal / mode->vtotal;
>> >
>> >drm_mode_vrefresh()
>> >
>> >> + timings->htotal = mode->htotal;
>> >> + timings->vtotal = mode->vtotal;
>> >> +}
>> >
>> >It's not really clear to me why you need to duplicate drm_display_mode
>> >here?
>> >
>> It's saved to be re-used in mtk_dp_set_msa().
>> It's not ideal, I'll check if I can get the mode directly from mtk_dp_set_msa()
>
>Yeah, it looks like mtk_dp_set_msa() uses fairly straightforward values,
>this will be just as easy with drm_display_mode.
>
>Maxime
[1] https://patchwork.kernel.org/project/linux-mediatek/patch/[email protected]/
On Thu, May 19, 2022 at 09:26:59AM -0700, Guillaume Ranquet wrote:
> On Thu, 12 May 2022 09:44, Maxime Ripard <[email protected]> wrote:
> >Hi,
> >
> >On Wed, May 11, 2022 at 05:59:13AM -0700, Guillaume Ranquet wrote:
> >> >> +#include <drm/drm_atomic_helper.h>
> >> >> +#include <drm/drm_bridge.h>
> >> >> +#include <drm/drm_crtc.h>
> >> >> +#include <drm/dp/drm_dp_helper.h>
> >> >> +#include <drm/drm_edid.h>
> >> >> +#include <drm/drm_of.h>
> >> >> +#include <drm/drm_panel.h>
> >> >> +#include <drm/drm_print.h>
> >> >> +#include <drm/drm_probe_helper.h>
> >> >> +#include <linux/arm-smccc.h>
> >> >> +#include <linux/clk.h>
> >> >> +#include <linux/delay.h>
> >> >> +#include <linux/errno.h>
> >> >> +#include <linux/kernel.h>
> >> >> +#include <linux/mfd/syscon.h>
> >> >> +#include <linux/nvmem-consumer.h>
> >> >> +#include <linux/of.h>
> >> >> +#include <linux/of_irq.h>
> >> >> +#include <linux/of_platform.h>
> >> >> +#include <linux/phy/phy.h>
> >> >> +#include <linux/platform_device.h>
> >> >> +#include <linux/pm_runtime.h>
> >> >> +#include <linux/regmap.h>
> >> >> +#include <sound/hdmi-codec.h>
> >> >> +#include <video/videomode.h>
> >> >> +
> >> >> +#include "mtk_dp_reg.h"
> >> >> +
> >> >> +#define MTK_DP_AUX_WAIT_REPLY_COUNT 20
> >> >> +#define MTK_DP_CHECK_SINK_CAP_TIMEOUT_COUNT 3
> >> >> +
> >> >> +//TODO: platform/device data or dts?
> >> >
> >> >DTS :)
> >>
> >> It's probably going to be a platform_data struct for v10...
> >> If I have time, I'll change it to a dts property for v10.
> >
> >I can't really imagine a case where we would need platform_data
> >nowadays. If you have a device tree, then it should be part of the
> >binding.
> >
> >What issue would you like to address by using a platform_data?
> >
>
> Ok, I'll migrate to dt then. I didn't realize platform_data were depreciated.
>
> Angelo wants the MAX_LINRATE and MAX_LANES defines to be configurable.
> I imagined platform_data would be more appropriate as (per my understanding) the
> limitation is associated with a specific SoC.
The entire device tree is nothing but a collection of data associated to
a specific SoC though :)
> >> >> +static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
> >> >> + struct drm_connector *connector)
> >> >> +{
> >> >> + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
> >> >> + bool enabled = mtk_dp->enabled;
> >> >> + struct edid *new_edid = NULL;
> >> >> +
> >> >> + if (!enabled)
> >> >> + drm_bridge_chain_pre_enable(bridge);
> >> >> +
> >> >> + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
> >> >> + usleep_range(2000, 5000);
> >> >> +
> >> >> + if (mtk_dp_plug_state(mtk_dp))
> >> >> + new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
> >> >> +
> >> >> + if (!enabled)
> >> >> + drm_bridge_chain_post_disable(bridge);
> >> >
> >> >Are you sure we can't get a mode set while get_edid is called?
> >> >
> >> >If we can, then you could end up disabling the device while it's being
> >> >powered on.
> >>
> >> I'm a bit unsure, I need to spend more time in the drm stack to make sure.
> >> I'll get back to you when I have a definitive answer.
> >
> >So, it looks like it's ok.
> >
> >get_edid is your implementation of get_modes, which is called by
> >drm_helper_probe_single_connector_modes
> >
> >https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_probe_helper.c#L416
> >
> >This is the standard implemantion of fill_modes, which is called
> >whenever the get_connector ioctl is called (or similar paths, like
> >drm_client_modeset_probe)
> >
> >drm_helper_probe_single_connector_modes is under the assumption that the
> >mode_config.mutex is held though, and that the big lock. So it should be
> >serialized there.
> >
> >Just for future proofing though, it would be better to use refcounting
> >there. Would runtime_pm work for you there?
> >
>
> Thx for looking into this for me.
> Not sure runtime_pm works here as it would only refcount if compiled
> with CONFIG_PM?
It should be enabled in most configurations these days, and you can
always depend on it in your Kconfig option.
> I'd rather use the enabled field as a refcounter instead of a boolean.
It's a bit more ad-hoc, but that would work too. Make sure to use a lock
or atomic operations though
Maxime