linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v14 00/10] drm/mediatek: Add MT8195 DisplayPort driver
@ 2022-07-12 11:12 Bo-Chen Chen
  2022-07-12 11:12 ` [PATCH v14 01/10] dt-bindings: mediatek,dp: Add Display Port binding Bo-Chen Chen
                   ` (9 more replies)
  0 siblings, 10 replies; 50+ messages in thread
From: Bo-Chen Chen @ 2022-07-12 11:12 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, daniel, robh+dt, krzysztof.kozlowski+dt,
	mripard, tzimmermann, matthias.bgg, deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	ck.hu, liangxu.xu, dri-devel, linux-mediatek, devicetree,
	linux-kernel, linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group, Bo-Chen Chen

This patch is separated from v10 which is including dp driver, phy driver
and dpintf driver. This series is only contained the DisplayPort driver.

This series can be tested using 5.19-rc2 kernel and I test it in MT8195
Tomato Chromebook. Modetest these modes:

for eDP:
  #0 2256x1504 60.00 2256 2304 2336 2536 1504 1507 1513 1549 235690 flags: phsync, nvsync; type: preferred, driver
  #1 2256x1504 48.00 2256 2304 2336 2536 1504 1507 1513 1549 188550 flags: phsync, nvsync; type: driver

for DP:
  #0 1920x1080 60.00 1920 2008 2052 2200 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: preferred, driver
  #1 1920x1080 59.94 1920 2008 2052 2200 1080 1084 1089 1125 148352 flags: phsync, pvsync; type: driver
  #2 1920x1080 50.00 1920 2448 2492 2640 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: driver
  #3 1680x1050 59.95 1680 1784 1960 2240 1050 1053 1059 1089 146250 flags: nhsync, pvsync; type: driver
  #4 1600x900 60.00 1600 1624 1704 1800 900 901 904 1000 108000 flags: phsync, pvsync; type: driver
  #5 1280x1024 60.02 1280 1328 1440 1688 1024 1025 1028 1066 108000 flags: phsync, pvsync; type: driver
  #6 1280x800 59.81 1280 1352 1480 1680 800 803 809 831 83500 flags: nhsync, pvsync; type: driver
  #7 1280x720 60.00 1280 1390 1430 1650 720 725 730 750 74250 flags: phsync, pvsync; type: driver
  #8 1280x720 59.94 1280 1390 1430 1650 720 725 730 750 74176 flags: phsync, pvsync; type: driver
  #9 1280x720 50.00 1280 1720 1760 1980 720 725 730 750 74250 flags: phsync, pvsync; type: driver
  #10 1024x768 60.00 1024 1048 1184 1344 768 771 777 806 65000 flags: nhsync, nvsync; type: driver
  #11 800x600 60.32 800 840 968 1056 600 601 605 628 40000 flags: phsync, pvsync; type: driver
  #12 720x576 50.00 720 732 796 864 576 581 586 625 27000 flags: nhsync, nvsync; type: driver
  #13 720x480 60.00 720 736 798 858 480 489 495 525 27027 flags: nhsync, nvsync; type: driver
  #14 720x480 59.94 720 736 798 858 480 489 495 525 27000 flags: nhsync, nvsync; type: driver
  #15 640x480 60.00 640 656 752 800 480 490 492 525 25200 flags: nhsync, nvsync; type: driver
  #16 640x480 59.94 640 656 752 800 480 490 492 525 25175 flags: nhsync, nvsync; type: driver

Changes from v13 for dp driver:
dt-binding:
  - Move data-lanes to port.
dp drivers:
  - Reporting for data-lanes using port.
  - Remove unnecessary drivers.
  - Refine mtk_dp_aux_transfer().
  - Refine mtk_dp_hpd_isr_handler().
  - Remove fec related drivers.

Changes from v12 for dp driver:
dt-binding:
  - Fix build error.
embedded dp drivers:
  - Revise Kconfig to let this driver independent.
  - Drop some unused/redundant drivers.
  - Move some features to patches of external dp and audio.
  - Refine format error control flow.
  - Add error control of write register functions.
  - Use mtk sip common definitions.

Changes from v11 for dp driver:
dt-binding:
  - Use data-lanes to determine the max supported lane numbers.
  - Add mhz to max-linkrate to show the units.
embedded dp drivers:
  - Modify Makefile.
  - Drop some unused/redundant drivers.
  - Move some features to patches of external dp and audio.
  - Modify break condition of training loop to control cr/eq fail.
  - Replace some function/definition with ones of common drm drivers.
  - Remove dp_lock mutex because it's only locked in power_on/off.
  - Add drm_dp_aux_(un)register in mtk_dp_bridge_(de)attach.

Changes from v10 for dp driver:
- Drop return value for write registers to make code more clear.
- Refine training state.
- Add property for dt-binding.
- Add new bug fix patches for audio and suspend.
- Rebase to v5.19-rc1.

Changes from v9:
- The DP-Phy is back to being a child device of the DP driver (as in v8)
- hot plug detection has been added back to Embedded Display Port... as
  after discussing with mediatek experts, this is needed eventhough the
  Embedded Display port is not un-pluggable
- rebased on linux-next
- simplified/split train_handler function, as suggested by Rex
- added comments on the sleep/delays present in the code
- removed previous patch introducing retries when receiving AUX_DEFER as
  this is already handled in the dp_aux framework
- added max-lane and max-linkrate device tree u8 properties instead of
  hardcoded #defines

Older revisions:
RFC - https://lore.kernel.org/linux-mediatek/20210816192523.1739365-1-msp@baylibre.com/
v1  - https://lore.kernel.org/linux-mediatek/20210906193529.718845-1-msp@baylibre.com/
v2  - https://lore.kernel.org/linux-mediatek/20210920084424.231825-1-msp@baylibre.com/
v3  - https://lore.kernel.org/linux-mediatek/20211001094443.2770169-1-msp@baylibre.com/
v4  - https://lore.kernel.org/linux-mediatek/20211011094624.3416029-1-msp@baylibre.com/
v5  - https://lore.kernel.org/all/20211021092707.3562523-1-msp@baylibre.com/
v6  - https://lore.kernel.org/linux-mediatek/20211110130623.20553-1-granquet@baylibre.com/
v7  - https://lore.kernel.org/linux-mediatek/20211217150854.2081-1-granquet@baylibre.com/
v8  - https://lore.kernel.org/linux-mediatek/20220218145437.18563-1-granquet@baylibre.com/
v9  - https://lore.kernel.org/all/20220327223927.20848-1-granquet@baylibre.com/
v10 - https://lore.kernel.org/all/20220523104758.29531-1-granquet@baylibre.com/
v11 - https://lore.kernel.org/r/20220610105522.13449-1-rex-bc.chen@mediatek.com
v12 - https://lore.kernel.org/all/20220627080341.5087-1-rex-bc.chen@mediatek.com/
v13 - https://lore.kernel.org/all/20220701062808.18596-1-rex-bc.chen@mediatek.com/

Bo-Chen Chen (2):
  drm/mediatek: set monitor to DP_SET_POWER_D3 to avoid garbage
  drm/mediatek: Use cached audio config when changing resolution

Guillaume Ranquet (4):
  drm/edid: Convert cea_sad helper struct to kernelDoc
  drm/edid: Add cea_sad helpers for freq/length
  drm/mediatek: Add MT8195 External DisplayPort support
  drm/mediatek: DP audio support for MT8195

Jitao Shi (1):
  drm/mediatek: add hpd debounce

Markus Schneider-Pargmann (3):
  dt-bindings: mediatek,dp: Add Display Port binding
  video/hdmi: Add audio_infoframe packing for DP
  drm/mediatek: Add MT8195 Embedded DisplayPort driver

 .../display/mediatek/mediatek,dp.yaml         |  115 +
 drivers/gpu/drm/drm_edid.c                    |   73 +
 drivers/gpu/drm/mediatek/Kconfig              |    9 +
 drivers/gpu/drm/mediatek/Makefile             |    2 +
 drivers/gpu/drm/mediatek/mtk_dp.c             | 2951 +++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_dp_reg.h         |  545 +++
 drivers/video/hdmi.c                          |   82 +-
 include/drm/display/drm_dp.h                  |    2 +
 include/drm/drm_edid.h                        |   26 +-
 include/linux/hdmi.h                          |    7 +-
 10 files changed, 3789 insertions(+), 23 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dp.c
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_reg.h

-- 
2.18.0


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH v14 01/10] dt-bindings: mediatek,dp: Add Display Port binding
  2022-07-12 11:12 [PATCH v14 00/10] drm/mediatek: Add MT8195 DisplayPort driver Bo-Chen Chen
@ 2022-07-12 11:12 ` Bo-Chen Chen
  2022-07-13  7:56   ` CK Hu
  2022-07-18 20:21   ` Rob Herring
  2022-07-12 11:12 ` [PATCH v14 02/10] drm/edid: Convert cea_sad helper struct to kernelDoc Bo-Chen Chen
                   ` (8 subsequent siblings)
  9 siblings, 2 replies; 50+ messages in thread
From: Bo-Chen Chen @ 2022-07-12 11:12 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, daniel, robh+dt, krzysztof.kozlowski+dt,
	mripard, tzimmermann, matthias.bgg, deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	ck.hu, liangxu.xu, dri-devel, linux-mediatek, devicetree,
	linux-kernel, linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group, Bo-Chen Chen

From: Markus Schneider-Pargmann <msp@baylibre.com>

This controller is present on several mediatek hardware. Currently
mt8195 and mt8395 have this controller without a functional difference,
so only one compatible field is added.

The controller can have two forms, as a normal display port and as an
embedded display port.

Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
---
 .../display/mediatek/mediatek,dp.yaml         | 115 ++++++++++++++++++
 1 file changed, 115 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml

diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
new file mode 100644
index 000000000000..e2d6cb314297
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
@@ -0,0 +1,115 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/mediatek/mediatek,dp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Display Port Controller
+
+maintainers:
+  - Chun-Kuang Hu <chunkuang.hu@kernel.org>
+  - Jitao shi <jitao.shi@mediatek.com>
+
+description: |
+  Device tree bindings for the MediaTek display port TX (DP) and
+  embedded display port TX (eDP) controller present on some MediaTek SoCs.
+  MediaTek DP and eDP are different hardwares and they have different
+  base address for registers, so we need two different compatibles to
+  separate them.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt8195-dp-tx
+      - mediatek,mt8195-edp-tx
+
+  reg:
+    maxItems: 1
+
+  nvmem-cells:
+    maxItems: 1
+    description: efuse data for display port calibration
+
+  nvmem-cell-names:
+    const: dp_calibration_data
+
+  power-domains:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+    properties:
+      port@0:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Input endpoint of the controller, usually dp_intf
+
+      port@1:
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
+        description: Output endpoint of the controller
+        properties:
+          endpoint:
+            $ref: /schemas/media/video-interfaces.yaml#
+            unevaluatedProperties: false
+            properties:
+              data-lanes:
+                description: |
+                  number of lanes supported by the hardware.
+                  The possible values:
+                  0       - For 1 lane enabled in IP.
+                  0 1     - For 2 lanes enabled in IP.
+                  0 1 2 3 - For 4 lanes enabled in IP.
+                minItems: 1
+                maxItems: 4
+            required:
+              - data-lanes
+
+    required:
+      - port@0
+      - port@1
+
+  max-linkrate-mhz:
+    enum: [ 1620, 2700, 5400, 8100 ]
+    description: maximum link rate supported by the hardware.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - ports
+  - max-linkrate-mhz
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/power/mt8195-power.h>
+    dp_tx@1c600000 {
+        compatible = "mediatek,mt8195-dp-tx";
+        reg = <0x1c600000 0x8000>;
+        power-domains = <&spm MT8195_POWER_DOMAIN_DP_TX>;
+        interrupts = <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH 0>;
+        max-linkrate-mhz = <8100>;
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            port@0 {
+                reg = <0>;
+                dptx_in: endpoint {
+                    remote-endpoint = <&dp_intf0_out>;
+                };
+            };
+            port@1 {
+                reg = <1>;
+                dptx_out: endpoint {
+                    data-lanes = <0 1 2 3>;
+                };
+            };
+        };
+    };
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v14 02/10] drm/edid: Convert cea_sad helper struct to kernelDoc
  2022-07-12 11:12 [PATCH v14 00/10] drm/mediatek: Add MT8195 DisplayPort driver Bo-Chen Chen
  2022-07-12 11:12 ` [PATCH v14 01/10] dt-bindings: mediatek,dp: Add Display Port binding Bo-Chen Chen
@ 2022-07-12 11:12 ` Bo-Chen Chen
  2022-07-12 11:12 ` [PATCH v14 03/10] drm/edid: Add cea_sad helpers for freq/length Bo-Chen Chen
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 50+ messages in thread
From: Bo-Chen Chen @ 2022-07-12 11:12 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, daniel, robh+dt, krzysztof.kozlowski+dt,
	mripard, tzimmermann, matthias.bgg, deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	ck.hu, liangxu.xu, dri-devel, linux-mediatek, devicetree,
	linux-kernel, linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group, Bo-Chen Chen

From: Guillaume Ranquet <granquet@baylibre.com>

To illustrate the cea_sad helper struct more clear, we convert the
driver comments to kernelDoc.

Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 include/drm/drm_edid.h | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index b2756753370b..c2c43a4af681 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -359,12 +359,18 @@ struct edid {
 
 #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
 
-/* Short Audio Descriptor */
+/**
+ * struct cea_sad - CEA 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.18.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v14 03/10] drm/edid: Add cea_sad helpers for freq/length
  2022-07-12 11:12 [PATCH v14 00/10] drm/mediatek: Add MT8195 DisplayPort driver Bo-Chen Chen
  2022-07-12 11:12 ` [PATCH v14 01/10] dt-bindings: mediatek,dp: Add Display Port binding Bo-Chen Chen
  2022-07-12 11:12 ` [PATCH v14 02/10] drm/edid: Convert cea_sad helper struct to kernelDoc Bo-Chen Chen
@ 2022-07-12 11:12 ` Bo-Chen Chen
  2022-07-14 11:12   ` AngeloGioacchino Del Regno
  2022-07-12 11:12 ` [PATCH v14 04/10] video/hdmi: Add audio_infoframe packing for DP Bo-Chen Chen
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 50+ messages in thread
From: Bo-Chen Chen @ 2022-07-12 11:12 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, daniel, robh+dt, krzysztof.kozlowski+dt,
	mripard, tzimmermann, matthias.bgg, deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	ck.hu, liangxu.xu, dri-devel, linux-mediatek, devicetree,
	linux-kernel, linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group, Bo-Chen Chen

From: Guillaume Ranquet <granquet@baylibre.com>

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 <msp@baylibre.com>
Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
---
 drivers/gpu/drm/drm_edid.c | 73 ++++++++++++++++++++++++++++++++++++++
 include/drm/drm_edid.h     | 14 ++++++++
 2 files changed, 87 insertions(+)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index bc43e1b32092..79316d7f1fd8 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -4916,6 +4916,79 @@ int drm_edid_to_speaker_allocation(const 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_pcm(const struct cea_sad *sad)
+{
+	switch (sad->format) {
+	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_pcm(sad)) {
+		DRM_WARN("Unable to get the uncompressed word length for 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 c2c43a4af681..779b710aed40 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -373,6 +373,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;
@@ -380,6 +392,8 @@ struct drm_display_mode;
 
 int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads);
 int drm_edid_to_speaker_allocation(const 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.18.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v14 04/10] video/hdmi: Add audio_infoframe packing for DP
  2022-07-12 11:12 [PATCH v14 00/10] drm/mediatek: Add MT8195 DisplayPort driver Bo-Chen Chen
                   ` (2 preceding siblings ...)
  2022-07-12 11:12 ` [PATCH v14 03/10] drm/edid: Add cea_sad helpers for freq/length Bo-Chen Chen
@ 2022-07-12 11:12 ` Bo-Chen Chen
  2022-07-14 11:26   ` AngeloGioacchino Del Regno
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 50+ messages in thread
From: Bo-Chen Chen @ 2022-07-12 11:12 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, daniel, robh+dt, krzysztof.kozlowski+dt,
	mripard, tzimmermann, matthias.bgg, deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	ck.hu, liangxu.xu, dri-devel, linux-mediatek, devicetree,
	linux-kernel, linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group, Bo-Chen Chen

From: Markus Schneider-Pargmann <msp@baylibre.com>

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.

Also constify the frame parameter in hdmi_audio_infoframe_check() as
it is passed to hdmi_audio_infoframe_check_only() which expects a const.

Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
---
 drivers/video/hdmi.c         | 82 +++++++++++++++++++++++++++---------
 include/drm/display/drm_dp.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..86805d77cc86 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -21,6 +21,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include <drm/display/drm_dp.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/display/drm_dp.h b/include/drm/display/drm_dp.h
index 9e3aff7e68bb..6c0871164771 100644
--- a/include/drm/display/drm_dp.h
+++ b/include/drm/display/drm_dp.h
@@ -1536,6 +1536,8 @@ enum drm_dp_phy {
 #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.18.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 [PATCH v14 00/10] drm/mediatek: Add MT8195 DisplayPort driver Bo-Chen Chen
                   ` (3 preceding siblings ...)
  2022-07-12 11:12 ` [PATCH v14 04/10] video/hdmi: Add audio_infoframe packing for DP Bo-Chen Chen
@ 2022-07-12 11:12 ` Bo-Chen Chen
  2022-07-13  8:03   ` CK Hu
                     ` (16 more replies)
  2022-07-12 11:12 ` [PATCH v14 06/10] drm/mediatek: Add MT8195 External DisplayPort support Bo-Chen Chen
                   ` (4 subsequent siblings)
  9 siblings, 17 replies; 50+ messages in thread
From: Bo-Chen Chen @ 2022-07-12 11:12 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, daniel, robh+dt, krzysztof.kozlowski+dt,
	mripard, tzimmermann, matthias.bgg, deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	ck.hu, liangxu.xu, dri-devel, linux-mediatek, devicetree,
	linux-kernel, linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group, Bo-Chen Chen

From: Markus Schneider-Pargmann <msp@baylibre.com>

This patch adds a embedded 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 creates a child device for the phy. The child device will
never exist without the parent being active. As they are sharing a
register range, the parent passes a regmap pointer to the child so that
both can work with the same register range. The phy driver sets device
data that is read by the parent to get the phy device that can be used
to control the phy properties.

This driver is based on an initial version by
Jitao shi <jitao.shi@mediatek.com>

Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
---
 drivers/gpu/drm/mediatek/Kconfig      |    9 +
 drivers/gpu/drm/mediatek/Makefile     |    2 +
 drivers/gpu/drm/mediatek/mtk_dp.c     | 2109 +++++++++++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_dp_reg.h |  542 +++++++
 4 files changed, 2662 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..e66f4a3b6be0 100644
--- a/drivers/gpu/drm/mediatek/Kconfig
+++ b/drivers/gpu/drm/mediatek/Kconfig
@@ -21,6 +21,15 @@ config DRM_MEDIATEK
 	  This driver provides kernel mode setting and
 	  buffer management to userspace.
 
+config DRM_MEDIATEK_DP
+	tristate "DRM DPTX Support for MediaTek SoCs"
+	depends on DRM_MEDIATEK
+	select PHY_MTK_DP
+	select DRM_DISPLAY_HELPER
+	select DRM_DISPLAY_DP_HELPER
+	help
+	  DRM/KMS Display Port driver for MediaTek SoCs.
+
 config DRM_MEDIATEK_HDMI
 	tristate "DRM HDMI Support for Mediatek SoCs"
 	depends on DRM_MEDIATEK
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index 29098d7c8307..17f89ef65b57 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_DRM_MEDIATEK_DP) += 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..eb61a8810ea2
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -0,0 +1,2109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019-2022 MediaTek Inc.
+ * Copyright (c) 2022 BayLibre
+ */
+
+#include <drm/display/drm_dp.h>
+#include <drm/display/drm_dp_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_crtc.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/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/soc/mediatek/mtk_sip_svc.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_SIP_CONTROL_AARCH32 MTK_SIP_SMC_CMD(0x523)
+
+#define MTK_VDOSYS1_MAX_FRAMERATE 60
+#define MTK_DP_4P1T 4
+#define MTK_DP_HDE 2
+#define MTK_DP_PIX_PER_ADDR 2
+#define MTK_DP_AUX_WAIT_REPLY_COUNT 20
+#define MTK_DP_CHECK_SINK_CAP_TIMEOUT_COUNT 3
+#define MTK_DP_TBC_BUF_READ_START_ADDR 0x08
+#define MTK_DP_TRAIN_RETRY_LIMIT 8
+#define MTK_DP_TRAIN_MAX_ITERATIONS 5
+
+struct mtk_dp_timings {
+	struct videomode vm;
+};
+
+struct mtk_dp_irq_sta {
+	bool hpd_inerrupt;
+};
+
+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;
+	struct mtk_dp_irq_sta irq_sta;
+};
+
+struct mtk_dp_info {
+	u32 depth;
+	enum dp_pixelformat format;
+	struct mtk_dp_timings timings;
+};
+
+struct dp_cal_data {
+	unsigned int glb_bias_trim;
+	unsigned int clktx_impse;
+
+	unsigned int ln_tx_impsel_pmos[4];
+	unsigned int ln_tx_impsel_nmos[4];
+};
+
+struct mtk_dp {
+	struct device *dev;
+	struct platform_device *phy_dev;
+	struct phy *phy;
+	struct dp_cal_data cal_data;
+	u8 max_lanes;
+	u8 max_linkrate;
+
+	struct drm_device *drm_dev;
+	struct drm_bridge bridge;
+	struct drm_bridge *next_bridge;
+	struct drm_dp_aux aux;
+
+	u8 rx_cap[DP_RECEIVER_CAP_SIZE];
+
+	struct mtk_dp_info info;
+
+	struct mtk_dp_train_info train_info;
+
+	struct regmap *regs;
+
+	bool enabled;
+
+	struct drm_connector *conn;
+};
+
+static struct regmap_config mtk_dp_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.max_register = SEC_OFFSET + 0x90,
+	.name = "mtk-dp-registers",
+};
+
+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 = regmap_write(mtk_dp->regs, offset, val);
+
+	if (ret)
+		dev_err(mtk_dp->dev,
+			"Failed to write register 0x%x with value 0x%x\n",
+			offset, val);
+	return ret;
+}
+
+static int mtk_dp_update_bits(struct mtk_dp *mtk_dp, u32 offset,
+			      u32 val, u32 mask)
+{
+	int 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\n",
+			offset, val, mask);
+	return ret;
+}
+
+static void mtk_dp_bulk_16bit_write(struct mtk_dp *mtk_dp, u32 offset, u8 *buf,
+				    size_t length)
+{
+	int i;
+	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);
+
+		if (mtk_dp_write(mtk_dp, offset + i * 4, val))
+			return;
+	}
+}
+
+static void mtk_dp_sip_atf_call(struct mtk_dp *mtk_dp,
+				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);
+
+	dev_dbg(mtk_dp->dev, "sip cmd 0x%x, p1 0x%x, ret 0x%lx-0x%lx",
+		cmd, para, res.a0, res.a1);
+}
+
+static void mtk_dp_msa_bypass_enable(struct mtk_dp *mtk_dp, bool enable)
+{
+	u32 mask = 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);
+	u32 val = enable ? 0 : mask;
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3030, val, mask);
+}
+
+static void mtk_dp_set_msa(struct mtk_dp *mtk_dp)
+{
+	struct drm_display_mode mode;
+	struct mtk_dp_timings *timings = &mtk_dp->info.timings;
+
+	drm_display_mode_from_videomode(&timings->vm, &mode);
+
+	/* horizontal */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3010,
+			   mode.htotal, HTOTAL_SW_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3018,
+			   timings->vm.hsync_len + timings->vm.hback_porch,
+			   HSTART_SW_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3028,
+			   timings->vm.hsync_len << HSW_SW_DP_ENC0_P0_SHIFT,
+			   HSW_SW_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3028,
+			   0, HSP_SW_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3020,
+			   timings->vm.hactive, HWIDTH_SW_DP_ENC0_P0_MASK);
+
+	/* vertical */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3014,
+			   mode.vtotal, VTOTAL_SW_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_301C,
+			   timings->vm.vsync_len + timings->vm.vback_porch,
+			   VSTART_SW_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_302C,
+			   timings->vm.vsync_len << VSW_SW_DP_ENC0_P0_SHIFT,
+			   VSW_SW_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_302C,
+			   0, VSP_SW_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3024,
+			   timings->vm.vactive, VHEIGHT_SW_DP_ENC0_P0_MASK);
+
+	/* horizontal */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3064,
+			   timings->vm.hactive, HDE_NUM_LAST_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3154,
+			   mode.htotal, PGEN_HTOTAL_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3158,
+			   timings->vm.hfront_porch,
+			   PGEN_HSYNC_RISING_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_315C,
+			   timings->vm.hsync_len,
+			   PGEN_HSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3160,
+			   timings->vm.hback_porch + timings->vm.hsync_len,
+			   PGEN_HFDE_START_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3164,
+			   timings->vm.hactive,
+			   PGEN_HFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK);
+
+	/* vertical */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3168,
+			   mode.vtotal,
+			   PGEN_VTOTAL_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_316C,
+			   timings->vm.vfront_porch,
+			   PGEN_VSYNC_RISING_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3170,
+			   timings->vm.vsync_len,
+			   PGEN_VSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3174,
+			   timings->vm.vback_porch + timings->vm.vsync_len,
+			   PGEN_VFDE_START_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3178,
+			   timings->vm.vactive,
+			   PGEN_VFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK);
+}
+
+static int mtk_dp_set_color_format(struct mtk_dp *mtk_dp,
+				   enum dp_pixelformat color_format)
+{
+	u32 val;
+
+	/* update MISC0 */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
+			   color_format << DP_TEST_COLOR_FORMAT_SHIFT,
+			   DP_TEST_COLOR_FORMAT_MASK);
+
+	switch (color_format) {
+	case DP_PIXELFORMAT_YUV422:
+		val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422;
+		break;
+	case DP_PIXELFORMAT_RGB:
+		val = PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB;
+		break;
+	default:
+		drm_warn(mtk_dp->drm_dev, "Unsupported color format: %d\n",
+			 color_format);
+		return -EINVAL;
+	}
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
+			   val, PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK);
+	return 0;
+}
+
+static int mtk_dp_set_color_depth(struct mtk_dp *mtk_dp)
+{
+	/* Only support 8 bits currently */
+	mtk_dp->info.depth = DP_MSA_MISC_8_BPC;
+
+	/* Update MISC0 */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
+			   DP_MSA_MISC_8_BPC, DP_TEST_BIT_DEPTH_MASK);
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
+			   VIDEO_COLOR_DEPTH_DP_ENC0_P0_8BIT,
+			   VIDEO_COLOR_DEPTH_DP_ENC0_P0_MASK);
+	return 0;
+}
+
+static void mtk_dp_mn_overwrite_disable(struct mtk_dp *mtk_dp)
+{
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004,
+			   0, VIDEO_M_CODE_SEL_DP_ENC0_P0_MASK);
+}
+
+static void mtk_dp_set_sram_read_start(struct mtk_dp *mtk_dp, u32 val)
+{
+	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 void mtk_dp_setup_encoder(struct mtk_dp *mtk_dp)
+{
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
+			   BIT(VIDEO_MN_GEN_EN_DP_ENC0_P0_SHIFT),
+			   VIDEO_MN_GEN_EN_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3040,
+			   0x20 << SDP_DOWN_CNT_INIT_DP_ENC0_P0_SHIFT,
+			   SDP_DOWN_CNT_INIT_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(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);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3300,
+			   2 << VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_SHIFT,
+			   VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3364,
+			   4 << FIFO_READ_START_POINT_DP_ENC1_P0_SHIFT,
+			   FIFO_READ_START_POINT_DP_ENC1_P0_MASK);
+	mtk_dp_write(mtk_dp, MTK_DP_ENC1_P0_3368,
+		     BIT(VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0_SHIFT) |
+		     BIT(VIDEO_STABLE_CNT_THRD_DP_ENC1_P0_SHIFT) |
+		     BIT(SDP_DP13_EN_DP_ENC1_P0_SHIFT) |
+		     BIT(BS2BS_MODE_DP_ENC1_P0_SHIFT));
+}
+
+static void mtk_dp_pg_enable(struct mtk_dp *mtk_dp, bool enable)
+{
+	u32 en = enable ? VIDEO_SOURCE_SEL_DP_ENC0_P0_MASK : 0;
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3038,
+			   en, VIDEO_SOURCE_SEL_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_31B0,
+			   4 << PGEN_PATTERN_SEL_SHIFT, PGEN_PATTERN_SEL_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)
+{
+	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 void mtk_dp_aux_set_cmd(struct mtk_dp *mtk_dp, u8 cmd, u32 addr)
+{
+	mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3644,
+			   cmd, MCU_REQUEST_COMMAND_AUX_TX_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3648,
+			   addr, MCU_REQUEST_ADDRESS_LSB_AUX_TX_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_364C,
+			   addr >> 16, MCU_REQUEST_ADDRESS_MSB_AUX_TX_P0_MASK);
+}
+
+static void mtk_dp_aux_cmd_complete(struct mtk_dp *mtk_dp)
+{
+	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 void mtk_dp_aux_request_ready(struct mtk_dp *mtk_dp)
+{
+	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 void mtk_dp_aux_read_rx_fifo(struct mtk_dp *mtk_dp, u8 *buf,
+				    size_t length, int read_delay)
+{
+	int read_pos;
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3620,
+			   0, AUX_RD_MODE_AUX_TX_P0_MASK);
+
+	for (read_pos = 0; read_pos < length; read_pos++) {
+		mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3620,
+				   BIT(AUX_RX_FIFO_R_PULSE_TX_P0_SHIFT),
+				   AUX_RX_FIFO_READ_PULSE_TX_P0_MASK);
+
+		/* Hardware needs time to update the data */
+		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);
+	}
+}
+
+static void mtk_dp_aux_set_length(struct mtk_dp *mtk_dp, size_t length)
+{
+	if (length > 0) {
+		mtk_dp_update_bits(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);
+		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);
+	} else {
+		mtk_dp_update_bits(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);
+	}
+}
+
+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;
+
+		/* Give the hardware a chance to reach completion before retrying */
+		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)
+		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);
+
+	mtk_dp_aux_cmd_complete(mtk_dp);
+	mtk_dp_aux_irq_clear(mtk_dp);
+
+	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);
+
+		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);
+	}
+
+	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);
+
+		return -ETIMEDOUT;
+	}
+
+	if (!length) {
+		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);
+	} 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);
+
+	return 0;
+}
+
+static void mtk_dp_set_swing_pre_emphasis(struct mtk_dp *mtk_dp, int lane_num,
+					  int swing_val, int preemphasis)
+{
+	u32 lane_shift = lane_num * DP_TX1_VOLT_SWING_SHIFT;
+
+	dev_dbg(mtk_dp->dev,
+		"link training: swing_val = 0x%x, pre-emphasis = 0x%x\n",
+		swing_val, preemphasis);
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_SWING_EMP,
+			   swing_val << (DP_TX0_VOLT_SWING_SHIFT + lane_shift),
+			   DP_TX0_VOLT_SWING_MASK << lane_shift);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_SWING_EMP,
+			   preemphasis << (DP_TX0_PRE_EMPH_SHIFT + lane_shift),
+			   DP_TX0_PRE_EMPH_MASK << lane_shift);
+}
+
+static void mtk_dp_reset_swing_pre_emphasis(struct mtk_dp *mtk_dp)
+{
+	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 u32 mtk_dp_swirq_get_clear(struct mtk_dp *mtk_dp)
+{
+	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_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_35C8,
+				   irq_status, SW_IRQ_CLR_DP_TRANS_P0_MASK);
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_35C8,
+				   0, SW_IRQ_CLR_DP_TRANS_P0_MASK);
+	}
+
+	return irq_status;
+}
+
+static u32 mtk_dp_hwirq_get_clear(struct mtk_dp *mtk_dp)
+{
+	u32 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_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3418,
+				   irq_status, IRQ_CLR_DP_TRANS_P0_MASK);
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3418,
+				   0, IRQ_CLR_DP_TRANS_P0_MASK);
+	}
+
+	return irq_status;
+}
+
+static void mtk_dp_hwirq_enable(struct mtk_dp *mtk_dp, bool enable)
+{
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3418,
+			   enable ? 0 :
+			   IRQ_MASK_DP_TRANS_P0_DISC_IRQ |
+			   IRQ_MASK_DP_TRANS_P0_CONN_IRQ |
+			   IRQ_MASK_DP_TRANS_P0_INT_IRQ,
+			   IRQ_MASK_DP_TRANS_P0_MASK);
+}
+
+static void mtk_dp_initialize_settings(struct mtk_dp *mtk_dp)
+{
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_342C,
+			   XTAL_FREQ_DP_TRANS_P0_DEFAULT,
+			   XTAL_FREQ_DP_TRANS_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3540,
+			   BIT(FEC_CLOCK_EN_MODE_DP_TRANS_P0_SHIFT),
+			   FEC_CLOCK_EN_MODE_DP_TRANS_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_31EC,
+			   BIT(AUDIO_CH_SRC_SEL_DP_ENC0_P0_SHIFT),
+			   AUDIO_CH_SRC_SEL_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_304C,
+			   0, SDP_VSYNC_RISING_MASK_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_IRQ_MASK,
+			   IRQ_MASK_AUX_TOP_IRQ, IRQ_MASK_AUX_TOP_IRQ);
+}
+
+static void mtk_dp_initialize_hpd_detect_settings(struct mtk_dp *mtk_dp)
+{
+	u32 val;
+	/* 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);
+
+	val = (HPD_INT_THD_DP_TRANS_P0_LOWER_500US |
+	       HPD_INT_THD_DP_TRANS_P0_UPPER_1100US)
+	      << HPD_INT_THD_DP_TRANS_P0_SHIFT;
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
+			   val, 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
+	 */
+	val = (5 << HPD_DISC_THD_DP_TRANS_P0_SHIFT) |
+	      (5 << HPD_CONN_THD_DP_TRANS_P0_SHIFT);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
+			   val,
+			   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 void mtk_dp_initialize_aux_settings(struct mtk_dp *mtk_dp)
+{
+	/* modify timeout threshold = 0x1595 */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_360C,
+			   0x1595, AUX_TIMEOUT_THR_AUX_TX_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3658, 0,
+			   AUX_TX_OV_EN_AUX_TX_P0_MASK);
+	/* 25 for 26M */
+	mtk_dp_update_bits(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);
+	/* 13 for 26M */
+	mtk_dp_update_bits(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);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_37C8,
+			   BIT(MTK_ATOP_EN_AUX_TX_P0_SHIFT),
+			   MTK_ATOP_EN_AUX_TX_P0_MASK);
+}
+
+static int mtk_dp_initialize_digital_settings(struct mtk_dp *mtk_dp)
+{
+	int ret;
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_304C,
+			   0, VBID_VIDEO_MUTE_DP_ENC0_P0_MASK);
+
+	ret = mtk_dp_set_color_format(mtk_dp, DP_PIXELFORMAT_RGB);
+	if (ret)
+		return ret;
+
+	ret = mtk_dp_set_color_depth(mtk_dp);
+	if (ret)
+		return ret;
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3368,
+			   1 << BS2BS_MODE_DP_ENC1_P0_SHIFT,
+			   BS2BS_MODE_DP_ENC1_P0_MASK);
+
+	/* dp tx encoder reset all sw */
+	mtk_dp_update_bits(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);
+
+	/* Wait for sw reset to complete */
+	usleep_range(1000, 5000);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004,
+			   0, DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0_MASK);
+	return 0;
+}
+
+static void mtk_dp_digital_sw_reset(struct mtk_dp *mtk_dp)
+{
+	mtk_dp_update_bits(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);
+
+	/* Wait for sw reset to complete */
+	usleep_range(1000, 5000);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_340C,
+			   0, DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0_MASK);
+}
+
+static void mtk_dp_set_lanes(struct mtk_dp *mtk_dp, int lanes)
+{
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_35F0,
+			   lanes == 0 ? 0 : BIT(3), BIT(3) | BIT(2));
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000,
+			   lanes, LANE_NUM_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_34A4,
+			   lanes << LANE_NUM_DP_TRANS_P0_SHIFT,
+			   LANE_NUM_DP_TRANS_P0_MASK);
+}
+
+static void use_cal_default_val(struct mtk_dp *mtk_dp)
+{
+	struct dp_cal_data *cal_data = &mtk_dp->cal_data;
+	int i;
+
+	dev_warn(mtk_dp->dev, "Use default calibration data\n");
+
+	cal_data->glb_bias_trim = 0xf;
+	cal_data->clktx_impse = 0x8;
+
+	for (i = 0; i < 4; i++) {
+		cal_data->ln_tx_impsel_pmos[i] = 0x8;
+		cal_data->ln_tx_impsel_nmos[i] = 0x8;
+	}
+}
+
+static u32 check_cal_data_valid(struct mtk_dp *mtk_dp, u32 min, u32 max,
+				u32 val, u32 default_val)
+{
+	if (val < min || val > max) {
+		dev_warn(mtk_dp->dev,
+			 "invalid calibration data: %d, use value: %d\n",
+			 val, default_val);
+		return default_val;
+	}
+
+	return val;
+}
+
+static void 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_warn(dev,
+			 "Error: Failed to get nvmem cell dp_calibration_data\n");
+		use_cal_default_val(mtk_dp);
+		return;
+	}
+
+	buf = (u32 *)nvmem_cell_read(cell, &len);
+	nvmem_cell_put(cell);
+
+	if (IS_ERR(buf) || ((len / sizeof(u32)) != 4)) {
+		dev_warn(dev, "Failed to read nvmem_cell_read\n");
+		use_cal_default_val(mtk_dp);
+		return;
+	}
+
+	cal_data->glb_bias_trim =
+		check_cal_data_valid(mtk_dp, 1, 0x1e,
+				     (buf[3] >> 27) & 0x1f, 0xf);
+	cal_data->clktx_impse =
+		check_cal_data_valid(mtk_dp, 1, 0xe,
+				     (buf[0] >> 9) & 0xf, 0x8);
+	cal_data->ln_tx_impsel_pmos[0] =
+		check_cal_data_valid(mtk_dp, 1, 0xe,
+				     (buf[2] >> 28) & 0xf, 0x8);
+	cal_data->ln_tx_impsel_nmos[0] =
+		check_cal_data_valid(mtk_dp, 1, 0xe,
+				     (buf[2] >> 24) & 0xf, 0x8);
+	cal_data->ln_tx_impsel_pmos[1] =
+		check_cal_data_valid(mtk_dp, 1, 0xe,
+				     (buf[2] >> 20) & 0xf, 0x8);
+	cal_data->ln_tx_impsel_nmos[1] =
+		check_cal_data_valid(mtk_dp, 1, 0xe,
+				     (buf[2] >> 16) & 0xf, 0x8);
+	cal_data->ln_tx_impsel_pmos[2] =
+		check_cal_data_valid(mtk_dp, 1, 0xe,
+				     (buf[2] >> 12) & 0xf, 0x8);
+	cal_data->ln_tx_impsel_nmos[2] =
+		check_cal_data_valid(mtk_dp, 1, 0xe,
+				     (buf[2] >> 8) & 0xf, 0x8);
+	cal_data->ln_tx_impsel_pmos[3] =
+		check_cal_data_valid(mtk_dp, 1, 0xe,
+				     (buf[2] >> 4) & 0xf, 0x8);
+	cal_data->ln_tx_impsel_nmos[3] =
+		check_cal_data_valid(mtk_dp, 1, 0xe, buf[2] & 0xf, 0x8);
+
+	kfree(buf);
+}
+
+static void mtk_dp_set_cal_data(struct mtk_dp *mtk_dp)
+{
+	struct dp_cal_data *cal_data = &mtk_dp->cal_data;
+
+	mtk_dp_update_bits(mtk_dp, DP_PHY_GLB_DPAUX_TX,
+			   cal_data->clktx_impse << 20, RG_CKM_PT0_CKTX_IMPSEL);
+	mtk_dp_update_bits(mtk_dp, DP_PHY_GLB_BIAS_GEN_00,
+			   cal_data->glb_bias_trim << 16,
+			   RG_XTP_GLB_BIAS_INTR_CTRL);
+	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_0,
+			   cal_data->ln_tx_impsel_pmos[0] << 12,
+			   RG_XTP_LN0_TX_IMPSEL_PMOS);
+	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_0,
+			   cal_data->ln_tx_impsel_nmos[0] << 16,
+			   RG_XTP_LN0_TX_IMPSEL_NMOS);
+	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_1,
+			   cal_data->ln_tx_impsel_pmos[1] << 12,
+			   RG_XTP_LN1_TX_IMPSEL_PMOS);
+	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_1,
+			   cal_data->ln_tx_impsel_nmos[1] << 16,
+			   RG_XTP_LN1_TX_IMPSEL_NMOS);
+	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_2,
+			   cal_data->ln_tx_impsel_pmos[2] << 12,
+			   RG_XTP_LN2_TX_IMPSEL_PMOS);
+	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_2,
+			   cal_data->ln_tx_impsel_nmos[2] << 16,
+			   RG_XTP_LN2_TX_IMPSEL_NMOS);
+	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_3,
+			   cal_data->ln_tx_impsel_pmos[3] << 12,
+			   RG_XTP_LN3_TX_IMPSEL_PMOS);
+	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_3,
+			   cal_data->ln_tx_impsel_nmos[3] << 16,
+			   RG_XTP_LN3_TX_IMPSEL_NMOS);
+}
+
+static int mtk_dp_phy_configure(struct mtk_dp *mtk_dp,
+				u32 link_rate, int lane_count)
+{
+	int ret;
+	union phy_configure_opts phy_opts = {
+		.dp = {
+			.link_rate = drm_dp_bw_code_to_link_rate(link_rate) / 100,
+			.set_rate = 1,
+			.lanes = lane_count,
+			.set_lanes = 1,
+			.ssc = mtk_dp->train_info.sink_ssc,
+		}
+	};
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE, DP_PWR_STATE_BANDGAP,
+			   DP_PWR_STATE_MASK);
+
+	ret = phy_configure(mtk_dp->phy, &phy_opts);
+	if (ret)
+		return ret;
+
+	mtk_dp_set_cal_data(mtk_dp);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
+			   DP_PWR_STATE_BANDGAP_TPLL_LANE, DP_PWR_STATE_MASK);
+
+	return 0;
+}
+
+static void mtk_dp_set_idle_pattern(struct mtk_dp *mtk_dp, bool enable)
+{
+	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;
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3580,
+			   enable ? val : 0, val);
+}
+
+static void mtk_dp_train_set_pattern(struct mtk_dp *mtk_dp, int pattern)
+{
+	/* TPS1 */
+	if (pattern == 1)
+		mtk_dp_set_idle_pattern(mtk_dp, false);
+
+	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 void mtk_dp_set_enhanced_frame_mode(struct mtk_dp *mtk_dp, bool enable)
+{
+	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 void mtk_dp_training_set_scramble(struct mtk_dp *mtk_dp, bool enable)
+{
+	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) |
+		  (enable ? BIT(VIDEO_MUTE_SW_DP_ENC0_P0_SHIFT) : 0);
+
+	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, MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE, enable);
+}
+
+static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
+{
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE,
+			   0, SW_RST_B_PHYD);
+
+	/* Wait for power enable */
+	usleep_range(10, 200);
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE,
+			   SW_RST_B_PHYD, SW_RST_B_PHYD);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
+			   DP_PWR_STATE_BANDGAP_TPLL, DP_PWR_STATE_MASK);
+	mtk_dp_write(mtk_dp, MTK_DP_1040,
+		     RG_DPAUX_RX_VALID_DEGLITCH_EN | RG_XTP_GLB_CKDET_EN |
+		     RG_DPAUX_RX_EN);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_0034, 0, DA_CKM_CKTX0_EN_FORCE_EN);
+}
+
+static void mtk_dp_power_disable(struct mtk_dp *mtk_dp)
+{
+	mtk_dp_write(mtk_dp, MTK_DP_TOP_PWR_STATE, 0);
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_0034,
+			   DA_CKM_CKTX0_EN_FORCE_EN, DA_CKM_CKTX0_EN_FORCE_EN);
+
+	/* Disable RX */
+	mtk_dp_write(mtk_dp, MTK_DP_1040, 0);
+	mtk_dp_write(mtk_dp, MTK_DP_TOP_MEM_PD,
+		     0x550 | BIT(FUSE_SEL_SHIFT) | BIT(MEM_ISO_EN_SHIFT));
+}
+
+static void mtk_dp_initialize_priv_data(struct mtk_dp *mtk_dp)
+{
+	mtk_dp->train_info.link_rate = DP_LINK_BW_5_4;
+	mtk_dp->train_info.lane_count = mtk_dp->max_lanes;
+	mtk_dp->train_info.cable_plugged_in = false;
+	mtk_dp->train_info.cable_state_change = false;
+	memset(&mtk_dp->train_info.irq_sta, 0, sizeof(struct mtk_dp_irq_sta));
+
+	mtk_dp->info.format = DP_PIXELFORMAT_RGB;
+	mtk_dp->info.depth = DP_MSA_MISC_8_BPC;
+	memset(&mtk_dp->info.timings, 0, sizeof(struct mtk_dp_timings));
+}
+
+static void mtk_dp_setup_tu(struct mtk_dp *mtk_dp)
+{
+	u32 sram_read_start = min_t(u32, MTK_DP_TBC_BUF_READ_START_ADDR,
+				    mtk_dp->info.timings.vm.hactive /
+				    mtk_dp->train_info.lane_count /
+				    MTK_DP_4P1T / MTK_DP_HDE /
+				    MTK_DP_PIX_PER_ADDR);
+	mtk_dp_set_sram_read_start(mtk_dp, sram_read_start);
+	mtk_dp_setup_encoder(mtk_dp);
+}
+
+static void mtk_dp_set_tx_out(struct mtk_dp *mtk_dp)
+{
+	mtk_dp_setup_tu(mtk_dp);
+}
+
+static void mtk_dp_hpd_sink_event(struct mtk_dp *mtk_dp)
+{
+	ssize_t ret;
+	u8 sink_count;
+	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 < 1) {
+		drm_err(mtk_dp->drm_dev, "Read sink count failed\n");
+		return;
+	}
+
+	drm_dbg(mtk_dp->drm_dev,
+		"read sink count from dpcd: %d\n", sink_count);
+
+	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\n");
+		return;
+	}
+
+	if (!drm_dp_channel_eq_ok(link_status, mtk_dp->train_info.lane_count)) {
+		drm_err(mtk_dp->drm_dev, "Channel EQ failed\n");
+		return;
+	}
+
+	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);
+}
+
+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);
+	}
+}
+
+static int mtk_dp_train_tps_1(struct mtk_dp *mtk_dp, u8 target_lane_count,
+			      int *iteration_count, u8 *lane_adjust,
+			      int *status_control, u8 *prev_lane_adjust)
+{
+	u8 val;
+	u8 link_status[DP_LINK_STATUS_SIZE] = {};
+
+	mtk_dp_training_set_scramble(mtk_dp, false);
+
+	if (*status_control == 0) {
+		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) * 2);
+
+		mtk_dp_train_update_swing_pre(mtk_dp,
+					      target_lane_count, lane_adjust);
+		*status_control = 1;
+		(*iteration_count)++;
+	}
+
+	drm_dp_link_train_clock_recovery_delay(&mtk_dp->aux, mtk_dp->rx_cap);
+	drm_dp_dpcd_read_link_status(&mtk_dp->aux, link_status);
+
+	if (drm_dp_clock_recovery_ok(link_status,
+				     target_lane_count)) {
+		mtk_dp->train_info.cr_done = true;
+		*iteration_count = 1;
+		dev_dbg(mtk_dp->dev, "Link train CR pass\n");
+		return 0;
+	} else if (*prev_lane_adjust == link_status[4]) {
+		(*iteration_count)++;
+		if (*prev_lane_adjust & DP_ADJUST_VOLTAGE_SWING_LANE0_MASK) {
+			dev_dbg(mtk_dp->dev, "Link train CQ fail\n");
+			return -EINVAL;
+		}
+	} else {
+		*prev_lane_adjust = link_status[4];
+	}
+	return -EAGAIN;
+}
+
+static int mtk_dp_train_tps_2_3(struct mtk_dp *mtk_dp, u8 target_linkrate,
+				u8 target_lane_count, int *iteration_count,
+				u8 *lane_adjust,  int *status_control,
+				u8 *prev_lane_adjust)
+{
+	u8 val;
+	u8 link_status[DP_LINK_STATUS_SIZE] = {};
+
+	if (*status_control == 1) {
+		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) * 2);
+
+		mtk_dp_train_update_swing_pre(mtk_dp,
+					      target_lane_count, lane_adjust);
+		*status_control = 2;
+		(*iteration_count)++;
+	}
+
+	drm_dp_link_train_channel_eq_delay(&mtk_dp->aux, mtk_dp->rx_cap);
+
+	drm_dp_dpcd_read_link_status(&mtk_dp->aux, 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");
+		return -EINVAL;
+	}
+
+	if (drm_dp_channel_eq_ok(link_status, target_lane_count)) {
+		mtk_dp->train_info.eq_done = true;
+		dev_dbg(mtk_dp->dev, "Link train EQ pass\n");
+		return 0;
+	}
+
+	if (*prev_lane_adjust == link_status[4])
+		(*iteration_count)++;
+	else
+		*prev_lane_adjust = link_status[4];
+
+	return -EAGAIN;
+}
+
+static int mtk_dp_train_flow(struct mtk_dp *mtk_dp, u8 target_link_rate,
+			     u8 target_lane_count)
+{
+	u8 lane_adjust[2] = {};
+	bool pass_tps1 = false;
+	bool pass_tps2_3 = false;
+	int train_retries;
+	int status_control;
+	int iteration_count;
+	int ret;
+	u8 prev_lane_adjust;
+
+	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);
+	ret = mtk_dp_phy_configure(mtk_dp, target_link_rate, target_lane_count);
+	if (ret)
+		return ret;
+
+	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)
+			return -ENODEV;
+
+		if (!pass_tps1) {
+			ret = mtk_dp_train_tps_1(mtk_dp, target_lane_count,
+						 &iteration_count, lane_adjust,
+						 &status_control,
+						 &prev_lane_adjust);
+			if (!ret) {
+				pass_tps1 = true;
+				train_retries = 0;
+			} else if (ret == -EINVAL) {
+				break;
+			}
+		} else {
+			ret = mtk_dp_train_tps_2_3(mtk_dp, target_link_rate,
+						   target_lane_count,
+						   &iteration_count,
+						   lane_adjust, &status_control,
+						   &prev_lane_adjust);
+			if (!ret) {
+				pass_tps2_3 = true;
+				break;
+			} else if (ret == -EINVAL) {
+				break;
+			}
+		}
+
+		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 ret;
+}
+
+static int mtk_dp_parse_capabilities(struct mtk_dp *mtk_dp)
+{
+	u8 val;
+	ssize_t ret;
+	struct mtk_dp_train_info *train_info = &mtk_dp->train_info;
+
+	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, mtk_dp->rx_cap);
+
+	train_info->link_rate = min_t(int, mtk_dp->max_linkrate,
+				      drm_dp_max_link_rate(mtk_dp->rx_cap));
+	train_info->lane_count = min_t(int, mtk_dp->max_lanes,
+				       drm_dp_max_lane_count(mtk_dp->rx_cap));
+
+	train_info->tps3 = drm_dp_tps3_supported(mtk_dp->rx_cap);
+	train_info->tps4 = drm_dp_tps4_supported(mtk_dp->rx_cap);
+
+	train_info->sink_ssc = drm_dp_max_downspread(mtk_dp->rx_cap);
+
+	ret = drm_dp_dpcd_readb(&mtk_dp->aux, DP_MSTM_CAP, &val);
+	if (ret < 1) {
+		drm_err(mtk_dp->drm_dev, "Read mstm cap failed\n");
+		return ret == 0 ? -EIO : ret;
+	}
+
+	if (val & DP_MST_CAP) {
+		/* Clear DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 */
+		ret = drm_dp_dpcd_readb(&mtk_dp->aux,
+					DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0,
+					&val);
+		if (ret < 1) {
+			drm_err(mtk_dp->drm_dev, "Read irq vector failed\n");
+			return ret == 0 ? -EIO : ret;
+		}
+
+		if (val)
+			drm_dp_dpcd_writeb(&mtk_dp->aux,
+					   DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0,
+					   val);
+	}
+
+	return 0;
+}
+
+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);
+}
+
+static int mtk_dp_train_start(struct mtk_dp *mtk_dp)
+{
+	int ret = 0;
+	u8 lane_count;
+	u8 link_rate;
+	u8 train_limit;
+	u8 max_link_rate;
+
+	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_linkrate, 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 DP_LINK_BW_1_62:
+	case DP_LINK_BW_2_7:
+	case DP_LINK_BW_5_4:
+	case DP_LINK_BW_8_1:
+		break;
+	default:
+		mtk_dp->train_info.link_rate = DP_LINK_BW_8_1;
+		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 == -EINVAL || ret == -ENODEV)
+			return ret;
+
+		if (!mtk_dp->train_info.cr_done) {
+			switch (link_rate) {
+			case DP_LINK_BW_1_62:
+				lane_count = lane_count / 2;
+				link_rate = max_link_rate;
+				if (lane_count == 0)
+					return -EIO;
+				break;
+			case DP_LINK_BW_2_7:
+				link_rate = DP_LINK_BW_1_62;
+				break;
+			case DP_LINK_BW_5_4:
+				link_rate = DP_LINK_BW_2_7;
+				break;
+			case DP_LINK_BW_8_1:
+				link_rate = DP_LINK_BW_5_4;
+				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 void mtk_dp_video_enable(struct mtk_dp *mtk_dp, bool enable)
+{
+	/* the mute sequence is different between enable and disable */
+	if (enable) {
+		mtk_dp_msa_bypass_enable(mtk_dp, false);
+		mtk_dp_pg_enable(mtk_dp, false);
+		mtk_dp_set_tx_out(mtk_dp);
+		mtk_dp_video_mute(mtk_dp, false);
+	} else {
+		mtk_dp_video_mute(mtk_dp, true);
+		mtk_dp_msa_bypass_enable(mtk_dp, true);
+		mtk_dp_pg_enable(mtk_dp, true);
+	}
+}
+
+static int mtk_dp_video_config(struct mtk_dp *mtk_dp)
+{
+	int ret;
+
+	mtk_dp_mn_overwrite_disable(mtk_dp);
+
+	mtk_dp_set_msa(mtk_dp);
+
+	ret = mtk_dp_set_color_depth(mtk_dp);
+	if (ret)
+		return ret;
+
+	ret = mtk_dp_set_color_format(mtk_dp, mtk_dp->info.format);
+
+	return ret;
+}
+
+static int mtk_dp_training(struct mtk_dp *mtk_dp)
+{
+	short max_retry = 50;
+	int ret;
+
+	do {
+		ret = mtk_dp_train_start(mtk_dp);
+		if (!ret)
+			break;
+		else if (ret != -EAGAIN)
+			return ret;
+	} while (--max_retry);
+
+	if (!max_retry)
+		return -ETIMEDOUT;
+
+	ret = mtk_dp_video_config(mtk_dp);
+	if (ret)
+		return ret;
+	mtk_dp_video_enable(mtk_dp, true);
+
+	return 0;
+}
+
+static int mtk_dp_init_port(struct mtk_dp *mtk_dp)
+{
+	int ret;
+
+	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);
+	ret = mtk_dp_initialize_digital_settings(mtk_dp);
+	if (ret)
+		return ret;
+
+	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);
+	return 0;
+}
+
+static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
+{
+	struct mtk_dp *mtk_dp = dev;
+
+	if (mtk_dp->train_info.cable_state_change) {
+		mtk_dp->train_info.cable_state_change = false;
+
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
+				   DP_PWR_STATE_BANDGAP_TPLL_LANE,
+				   DP_PWR_STATE_MASK);
+	}
+
+	if (mtk_dp->train_info.irq_sta.hpd_inerrupt) {
+		dev_dbg(mtk_dp->dev, "MTK_DP_HPD_INTERRUPT\n");
+		mtk_dp->train_info.irq_sta.hpd_inerrupt = false;
+		mtk_dp_hpd_sink_event(mtk_dp);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * We need to handle HPD signal in eDP even though eDP is a always connected
+ * device. Besides connected status, there is another feature for HPD signal -
+ * HPD pulse: it presents an IRQ from sink devices to source devices (Refer to
+ * 5.1.4 of DP1.4 spec).
+ */
+static irqreturn_t mtk_dp_hpd_isr_handler(struct mtk_dp *mtk_dp)
+{
+	bool hpd_change = false;
+	u32 irq_status = mtk_dp_swirq_get_clear(mtk_dp) |
+			 mtk_dp_hwirq_get_clear(mtk_dp);
+	struct mtk_dp_train_info *train_info = &mtk_dp->train_info;
+
+	if (!irq_status)
+		return IRQ_HANDLED;
+
+	if (irq_status & MTK_DP_HPD_INTERRUPT)
+		train_info->irq_sta.hpd_inerrupt = true;
+	if (irq_status & MTK_DP_HPD_CONNECT ||
+	    irq_status & MTK_DP_HPD_DISCONNECT)
+		hpd_change = true;
+
+	if (!(hpd_change))
+		return IRQ_WAKE_THREAD;
+
+	if (mtk_dp_plug_state(mtk_dp))
+		train_info->cable_plugged_in = true;
+	else
+		train_info->cable_plugged_in = false;
+
+	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)
+{
+	struct device_node *endpoint;
+	struct device *dev = &pdev->dev;
+	int ret = 0;
+	void __iomem *base;
+	u32 linkrate;
+	int len;
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	mtk_dp->regs = devm_regmap_init_mmio(dev, base, &mtk_dp_regmap_config);
+	if (IS_ERR(mtk_dp->regs))
+		return PTR_ERR(mtk_dp->regs);
+
+	endpoint = of_graph_get_endpoint_by_regs(pdev->dev.of_node, 1, -1);
+	len = of_property_count_elems_of_size(endpoint,
+					      "data-lanes", sizeof(u32));
+	if (len < 0 || len > 4 || len == 3) {
+		dev_err(dev, "invalid data lane size: %d\n", len);
+		return -EINVAL;
+	}
+
+	mtk_dp->max_lanes = len;
+
+	ret = device_property_read_u32(dev, "max-linkrate-mhz", &linkrate);
+	if (ret) {
+		dev_err(dev, "failed to read max linkrate: %d\n", ret);
+		return ret;
+	}
+
+	mtk_dp->max_linkrate = drm_dp_link_rate_to_bw_code(linkrate * 100);
+
+	return 0;
+}
+
+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);
+
+	new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
+
+	if (!enabled)
+		drm_bridge_chain_post_disable(bridge);
+
+	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 ret = 0;
+
+	mtk_dp = container_of(mtk_aux, struct mtk_dp, aux);
+
+	if (!mtk_dp->train_info.cable_plugged_in) {
+		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;
+	}
+
+	do {
+		size_t to_access = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES,
+					 msg->size - accessed_bytes);
+
+		ret = mtk_dp_aux_do_transfer(mtk_dp, is_read, request,
+					     msg->address + accessed_bytes,
+					     msg->buffer + accessed_bytes,
+					     to_access);
+
+		if (ret) {
+			drm_info(mtk_dp->drm_dev,
+				 "Failed to do AUX transfer: %d\n", ret);
+			break;
+		}
+		accessed_bytes += to_access;
+	} while (accessed_bytes < msg->size);
+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)
+{
+	mtk_dp_hwirq_enable(mtk_dp, false);
+	mtk_dp_power_disable(mtk_dp);
+	phy_exit(mtk_dp->phy);
+}
+
+static int mtk_dp_poweron(struct mtk_dp *mtk_dp)
+{
+	int ret = 0;
+
+	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, DP_LINK_BW_1_62, 1);
+	if (ret) {
+		dev_err(mtk_dp->dev, "Failed to configure phy: %d\n", ret);
+		goto err_phy_config;
+	}
+
+	ret = mtk_dp_init_port(mtk_dp);
+	if (ret) {
+		dev_err(mtk_dp->dev, "Failed to init port: %d\n", ret);
+		goto err_phy_config;
+	}
+
+	mtk_dp_power_enable(mtk_dp);
+
+err_phy_config:
+	phy_exit(mtk_dp->phy);
+err_phy_init:
+	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;
+
+	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
+		dev_err(mtk_dp->dev, "Driver does not provide a connector!");
+		return -EINVAL;
+	}
+
+	mtk_dp->aux.drm_dev = bridge->dev;
+	ret = drm_dp_aux_register(&mtk_dp->aux);
+	if (ret) {
+		dev_err(mtk_dp->dev,
+			"failed to register DP AUX channel: %d\n", ret);
+		return ret;
+	}
+
+	ret = mtk_dp_poweron(mtk_dp);
+	if (ret)
+		goto err_aux_register;
+
+	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);
+			goto err_bridge_attach;
+		}
+
+		/* eDP is connected */
+		drm_helper_hpd_irq_event(mtk_dp->bridge.dev);
+	}
+
+	mtk_dp->drm_dev = bridge->dev;
+
+	mtk_dp_hwirq_enable(mtk_dp, true);
+
+	return 0;
+
+err_bridge_attach:
+	mtk_dp_poweroff(mtk_dp);
+err_aux_register:
+	drm_dp_aux_unregister(&mtk_dp->aux);
+	return ret;
+}
+
+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;
+	drm_dp_aux_unregister(&mtk_dp->aux);
+	mtk_dp_poweroff(mtk_dp);
+}
+
+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->enabled = false;
+	/* Ensure the sink is muted */
+	msleep(20);
+}
+
+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);
+}
+
+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);
+	int ret;
+
+	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;
+	}
+
+	mtk_dp_video_mute(mtk_dp, true);
+
+	if (mtk_dp_parse_capabilities(mtk_dp)) {
+		drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n");
+		return;
+	}
+
+	/* Training */
+	ret = mtk_dp_training(mtk_dp);
+	if (ret) {
+		drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret);
+		return;
+	}
+
+	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;
+
+	if ((mode->clock * 1000) / (mode->htotal * mode->vtotal) >
+	    MTK_VDOSYS1_MAX_FRAMERATE)
+		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 = kcalloc(1, 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 = kcalloc(ARRAY_SIZE(mt8195_input_fmts),
+				     sizeof(*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);
+	struct drm_crtc *crtc = conn_state->crtc;
+	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);
+
+	if (input_bus_format == MEDIA_BUS_FMT_YUYV8_1X16)
+		mtk_dp->info.format = DP_PIXELFORMAT_YUV422;
+	else
+		mtk_dp->info.format = DP_PIXELFORMAT_RGB;
+
+	if (!crtc) {
+		drm_err(mtk_dp->drm_dev,
+			"Can't enable bridge as connector state doesn't have a crtc\n");
+		return -EINVAL;
+	}
+
+	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 -EINVAL;
+	}
+
+	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,
+};
+
+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)
+		return -ENOMEM;
+
+	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))
+		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 parse dt\n");
+
+	drm_dp_aux_init(&mtk_dp->aux);
+	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");
+
+	platform_set_drvdata(pdev, mtk_dp);
+
+	mtk_dp->phy_dev = platform_device_register_data(dev, "mediatek-dp-phy",
+							PLATFORM_DEVID_AUTO,
+							&mtk_dp->regs,
+							sizeof(struct regmap *));
+	if (IS_ERR(mtk_dp->phy_dev))
+		return dev_err_probe(dev, PTR_ERR(mtk_dp->phy_dev),
+				     "Failed to create device mediatek-dp-phy\n");
+
+	mtk_dp_get_calibration_data(mtk_dp);
+
+	mtk_dp->phy = devm_phy_get(&mtk_dp->phy_dev->dev, "dp");
+
+	if (IS_ERR(mtk_dp->phy)) {
+		platform_device_unregister(mtk_dp->phy_dev);
+		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.ops =
+		DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD;
+	mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP;
+
+	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);
+
+	platform_device_unregister(mtk_dp->phy_dev);
+	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);
+
+	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);
+	int ret;
+
+	pm_runtime_get_sync(dev);
+
+	ret = mtk_dp_init_port(mtk_dp);
+	if (ret) {
+		dev_err(mtk_dp->dev, "Failed to init port: %d\n", ret);
+		return ret;
+	}
+
+	mtk_dp_hwirq_enable(mtk_dp, true);
+	mtk_dp_power_enable(mtk_dp);
+
+	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_platform_driver(mtk_dp_driver);
+
+MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
+MODULE_AUTHOR("Markus Schneider-Pargmann <msp@baylibre.com>");
+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..c9d587f1bacd
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
@@ -0,0 +1,542 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019-2022 MediaTek Inc.
+ * Copyright (c) 2022 BayLibre
+ */
+#ifndef _MTK_DP_REG_H_
+#define _MTK_DP_REG_H_
+
+#define TOP_OFFSET	0x2000
+#define ENC0_OFFSET	0x3000
+#define ENC1_OFFSET	0x3200
+#define TRANS_OFFSET	0x3400
+#define AUX_OFFSET	0x3600
+#define SEC_OFFSET	0x4000
+
+#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		0x8
+#define RG_CKM_PT0_CKTX_IMPSEL		GENMASK(23, 20)
+
+#define DP_PHY_LANE_TX_0		0x104
+#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		0x204
+#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		0x304
+#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		0x404
+#define RG_XTP_LN3_TX_IMPSEL_PMOS	GENMASK(15, 12)
+#define RG_XTP_LN3_TX_IMPSEL_NMOS	GENMASK(19, 16)
+
+#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			0x34
+#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			0x1040
+#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_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_*/
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v14 06/10] drm/mediatek: Add MT8195 External DisplayPort support
  2022-07-12 11:12 [PATCH v14 00/10] drm/mediatek: Add MT8195 DisplayPort driver Bo-Chen Chen
                   ` (4 preceding siblings ...)
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
@ 2022-07-12 11:12 ` Bo-Chen Chen
  2022-07-25  9:51   ` CK Hu
  2022-07-12 11:12 ` [PATCH v14 07/10] drm/mediatek: add hpd debounce Bo-Chen Chen
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 50+ messages in thread
From: Bo-Chen Chen @ 2022-07-12 11:12 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, daniel, robh+dt, krzysztof.kozlowski+dt,
	mripard, tzimmermann, matthias.bgg, deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	ck.hu, liangxu.xu, dri-devel, linux-mediatek, devicetree,
	linux-kernel, linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group, Bo-Chen Chen

From: Guillaume Ranquet <granquet@baylibre.com>

This patch adds External DisplayPort support to the mt8195 eDP driver.

Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c     | 183 +++++++++++++++++++++-----
 drivers/gpu/drm/mediatek/mtk_dp_reg.h |   1 +
 2 files changed, 148 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index eb61a8810ea2..610651dd6365 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -115,6 +115,11 @@ static struct regmap_config mtk_dp_regmap_config = {
 	.name = "mtk-dp-registers",
 };
 
+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);
@@ -370,6 +375,14 @@ static bool mtk_dp_plug_state(struct mtk_dp *mtk_dp)
 		  HPD_DB_DP_TRANS_P0_MASK);
 }
 
+static bool mtk_dp_plug_state_avoid_pulse(struct mtk_dp *mtk_dp)
+{
+	bool ret;
+
+	return !(readx_poll_timeout(mtk_dp_plug_state, mtk_dp, ret, ret,
+				    4000, 7 * 4000));
+}
+
 static void mtk_dp_aux_irq_clear(struct mtk_dp *mtk_dp)
 {
 	mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3640,
@@ -809,35 +822,67 @@ static void mtk_dp_get_calibration_data(struct mtk_dp *mtk_dp)
 		return;
 	}
 
-	cal_data->glb_bias_trim =
-		check_cal_data_valid(mtk_dp, 1, 0x1e,
-				     (buf[3] >> 27) & 0x1f, 0xf);
-	cal_data->clktx_impse =
-		check_cal_data_valid(mtk_dp, 1, 0xe,
-				     (buf[0] >> 9) & 0xf, 0x8);
-	cal_data->ln_tx_impsel_pmos[0] =
-		check_cal_data_valid(mtk_dp, 1, 0xe,
-				     (buf[2] >> 28) & 0xf, 0x8);
-	cal_data->ln_tx_impsel_nmos[0] =
-		check_cal_data_valid(mtk_dp, 1, 0xe,
-				     (buf[2] >> 24) & 0xf, 0x8);
-	cal_data->ln_tx_impsel_pmos[1] =
-		check_cal_data_valid(mtk_dp, 1, 0xe,
-				     (buf[2] >> 20) & 0xf, 0x8);
-	cal_data->ln_tx_impsel_nmos[1] =
-		check_cal_data_valid(mtk_dp, 1, 0xe,
-				     (buf[2] >> 16) & 0xf, 0x8);
-	cal_data->ln_tx_impsel_pmos[2] =
-		check_cal_data_valid(mtk_dp, 1, 0xe,
-				     (buf[2] >> 12) & 0xf, 0x8);
-	cal_data->ln_tx_impsel_nmos[2] =
-		check_cal_data_valid(mtk_dp, 1, 0xe,
-				     (buf[2] >> 8) & 0xf, 0x8);
-	cal_data->ln_tx_impsel_pmos[3] =
-		check_cal_data_valid(mtk_dp, 1, 0xe,
-				     (buf[2] >> 4) & 0xf, 0x8);
-	cal_data->ln_tx_impsel_nmos[3] =
-		check_cal_data_valid(mtk_dp, 1, 0xe, buf[2] & 0xf, 0x8);
+	if (mtk_dp_is_edp(mtk_dp)) {
+		cal_data->glb_bias_trim =
+			check_cal_data_valid(mtk_dp, 1, 0x1e,
+					     (buf[3] >> 27) & 0x1f, 0xf);
+		cal_data->clktx_impse =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[0] >> 9) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_pmos[0] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[2] >> 28) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_nmos[0] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[2] >> 24) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_pmos[1] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[2] >> 20) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_nmos[1] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[2] >> 16) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_pmos[2] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[2] >> 12) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_nmos[2] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[2] >> 8) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_pmos[3] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[2] >> 4) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_nmos[3] =
+			check_cal_data_valid(mtk_dp, 1, 0xe, buf[2] & 0xf, 0x8);
+	} else {
+		cal_data->glb_bias_trim =
+			check_cal_data_valid(mtk_dp, 1, 0x1e,
+					     (buf[0] >> 27) & 0x1f, 0xf);
+		cal_data->clktx_impse =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[0] >> 13) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_pmos[0] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[1] >> 28) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_nmos[0] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[1] >> 24) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_pmos[1] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[1] >> 20) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_nmos[1] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[1] >> 16) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_pmos[2] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[1] >> 12) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_nmos[2] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[1] >> 8) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_pmos[3] =
+			check_cal_data_valid(mtk_dp, 1, 0xe,
+					     (buf[1] >> 4) & 0xf, 0x8);
+		cal_data->ln_tx_impsel_nmos[3] =
+			check_cal_data_valid(mtk_dp, 1, 0xe, buf[1] & 0xf, 0x8);
+	}
 
 	kfree(buf);
 }
@@ -957,7 +1002,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, MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE, enable);
+	mtk_dp_sip_atf_call(mtk_dp,
+			    mtk_dp_is_edp(mtk_dp) ?
+			    MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE :
+			    MTK_DP_SIP_ATF_VIDEO_UNMUTE, enable);
 }
 
 static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
@@ -1292,6 +1340,9 @@ static int mtk_dp_parse_capabilities(struct mtk_dp *mtk_dp)
 	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))
+		return -ENODEV;
+
 	drm_dp_read_dpcd_caps(&mtk_dp->aux, mtk_dp->rx_cap);
 
 	train_info->link_rate = min_t(int, mtk_dp->max_linkrate,
@@ -1343,6 +1394,9 @@ static int mtk_dp_train_start(struct mtk_dp *mtk_dp)
 	u8 train_limit;
 	u8 max_link_rate;
 
+	if (!mtk_dp_plug_state_avoid_pulse(mtk_dp))
+		return -ENODEV;
+
 	link_rate = mtk_dp->rx_cap[1];
 	lane_count = mtk_dp->rx_cap[2] & 0x1F;
 
@@ -1489,13 +1543,34 @@ static int mtk_dp_init_port(struct mtk_dp *mtk_dp)
 static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
 {
 	struct mtk_dp *mtk_dp = dev;
+	int event;
+
+	event = mtk_dp_plug_state(mtk_dp) ?
+		connector_status_connected : connector_status_disconnected;
+
+	if (event < 0)
+		return IRQ_HANDLED;
+
+	dev_dbg(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_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
-				   DP_PWR_STATE_BANDGAP_TPLL_LANE,
-				   DP_PWR_STATE_MASK);
+		if (!mtk_dp->train_info.cable_plugged_in) {
+			mtk_dp_video_mute(mtk_dp, true);
+
+			mtk_dp_initialize_priv_data(mtk_dp);
+			mtk_dp_set_idle_pattern(mtk_dp, true);
+
+			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);
+		}
 	}
 
 	if (mtk_dp->train_info.irq_sta.hpd_inerrupt) {
@@ -1597,6 +1672,24 @@ static int mtk_dp_dt_parse(struct mtk_dp *mtk_dp,
 	return 0;
 }
 
+static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge)
+{
+	struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
+	enum drm_connector_status ret = connector_status_disconnected;
+	u8 sink_count = 0;
+
+	if (mtk_dp_is_edp(mtk_dp))
+		return connector_status_connected;
+
+	if (mtk_dp_plug_state_avoid_pulse(mtk_dp)) {
+		drm_dp_dpcd_readb(&mtk_dp->aux, DP_SINK_COUNT, &sink_count);
+		if (DP_GET_SINK_COUNT(sink_count))
+			ret = connector_status_connected;
+	}
+
+	return ret;
+}
+
 static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
 				    struct drm_connector *connector)
 {
@@ -1610,7 +1703,8 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
 	drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
 	usleep_range(2000, 5000);
 
-	new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
+	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);
@@ -1961,6 +2055,7 @@ static const struct drm_bridge_funcs mtk_dp_bridge_funcs = {
 	.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)
@@ -1982,9 +2077,15 @@ static int mtk_dp_probe(struct platform_device *pdev)
 				     "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, continue 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)
@@ -2027,7 +2128,10 @@ static int mtk_dp_probe(struct platform_device *pdev)
 
 	mtk_dp->bridge.ops =
 		DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD;
-	mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP;
+	if (mtk_dp_is_edp(mtk_dp))
+		mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP;
+	else
+		mtk_dp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
 
 	drm_bridge_add(&mtk_dp->bridge);
 
@@ -2054,6 +2158,12 @@ 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);
+		/* Ensure the sink is off before shutting down power */
+		usleep_range(2000, 3000);
+	}
+
 	mtk_dp_power_disable(mtk_dp);
 
 	mtk_dp_hwirq_enable(mtk_dp, false);
@@ -2087,6 +2197,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);
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
index c9d587f1bacd..9b6f2e01391d 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
+++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
@@ -14,6 +14,7 @@
 #define SEC_OFFSET	0x4000
 
 #define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE	(BIT(0) | BIT(5))
+#define MTK_DP_SIP_ATF_VIDEO_UNMUTE	BIT(5)
 
 #define DP_PHY_GLB_BIAS_GEN_00		0
 #define RG_XTP_GLB_BIAS_INTR_CTRL	GENMASK(20, 16)
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v14 07/10] drm/mediatek: add hpd debounce
  2022-07-12 11:12 [PATCH v14 00/10] drm/mediatek: Add MT8195 DisplayPort driver Bo-Chen Chen
                   ` (5 preceding siblings ...)
  2022-07-12 11:12 ` [PATCH v14 06/10] drm/mediatek: Add MT8195 External DisplayPort support Bo-Chen Chen
@ 2022-07-12 11:12 ` Bo-Chen Chen
  2022-07-12 11:12 ` [PATCH v14 08/10] drm/mediatek: set monitor to DP_SET_POWER_D3 to avoid garbage Bo-Chen Chen
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 50+ messages in thread
From: Bo-Chen Chen @ 2022-07-12 11:12 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, daniel, robh+dt, krzysztof.kozlowski+dt,
	mripard, tzimmermann, matthias.bgg, deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	ck.hu, liangxu.xu, dri-devel, linux-mediatek, devicetree,
	linux-kernel, linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group, Bo-Chen Chen

From: Jitao Shi <jitao.shi@mediatek.com>

From the DP spec 1.4a chapter 3.3, upstream devices should implement
HPD signal de-bouncing on an external connection.
A period of 100ms should be used to detect an HPD connect event.
To cover these cases, HPD de-bounce should be implemented only after
HPD low has been detected for at least 100ms.

Therefore,
1. If HPD is low (which means plugging out) for longer than 100ms:
   we need to do de-bouncing (which means we need to wait for 100ms).
2. If HPD low is for less than 100ms:
   we don't need to care about the de-bouncing.

In this patch, we start a 100ms timer and use a need_debounce boolean
to implement the feature.

Two cases when HPD is high:
1. If the timer is expired (>100ms):
   - need_debounce is true.
   - When HPD high (plugging event comes), need_debounce will be true
     and then we need to do de-bouncing (wait for 100ms).
2. If the timer is not expired (<100ms):
   - need_debounce is false.
   - When HPD high (plugging event comes), need_debounce will be false
     and no need to do de-bouncing.

HPD_______             __________________
          |            |<-  100ms   ->
          |____________|
          <-  100ms   ->

Without HPD de-bouncing, USB-C to HDMI Adapaters will not be detected.

The change has been successfully tested with the following devices:
- Dell Adapter - USB-C to HDMI
- Acer 1in1 HDMI dongle
- Ugreen 1in1 HDMI dongle
- innowatt HDMI + USB3 hub
- Acer 2in1 HDMI dongle
- Apple 3in1 HDMI dongle (A2119)
- J5Create 3in1 HDMI dongle (JAC379)

Tested-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 610651dd6365..50a4159095a1 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -105,6 +105,8 @@ struct mtk_dp {
 	bool enabled;
 
 	struct drm_connector *conn;
+	bool need_debounce;
+	struct timer_list debounce_timer;
 };
 
 static struct regmap_config mtk_dp_regmap_config = {
@@ -1551,7 +1553,11 @@ static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
 	if (event < 0)
 		return IRQ_HANDLED;
 
+	if (mtk_dp->need_debounce && mtk_dp->train_info.cable_plugged_in)
+		msleep(100);
+
 	dev_dbg(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) {
@@ -1614,6 +1620,12 @@ static irqreturn_t mtk_dp_hpd_isr_handler(struct mtk_dp *mtk_dp)
 
 	train_info->cable_state_change = true;
 
+	if (!train_info->cable_plugged_in) {
+		mod_timer(&mtk_dp->debounce_timer,
+			  jiffies + msecs_to_jiffies(100) - 1);
+		mtk_dp->need_debounce = false;
+	}
+
 	return IRQ_WAKE_THREAD;
 }
 
@@ -2058,6 +2070,13 @@ static const struct drm_bridge_funcs mtk_dp_bridge_funcs = {
 	.detect = mtk_dp_bdg_detect,
 };
 
+static void mtk_dp_debounce_timer(struct timer_list *t)
+{
+	struct mtk_dp *mtk_dp = from_timer(mtk_dp, t, debounce_timer);
+
+	mtk_dp->need_debounce = true;
+}
+
 static int mtk_dp_probe(struct platform_device *pdev)
 {
 	struct mtk_dp *mtk_dp;
@@ -2135,6 +2154,9 @@ static int mtk_dp_probe(struct platform_device *pdev)
 
 	drm_bridge_add(&mtk_dp->bridge);
 
+	mtk_dp->need_debounce = true;
+	timer_setup(&mtk_dp->debounce_timer, mtk_dp_debounce_timer, 0);
+
 	pm_runtime_enable(dev);
 	pm_runtime_get_sync(dev);
 
@@ -2147,6 +2169,7 @@ static int mtk_dp_remove(struct platform_device *pdev)
 
 	platform_device_unregister(mtk_dp->phy_dev);
 	mtk_dp_video_mute(mtk_dp, true);
+	del_timer_sync(&mtk_dp->debounce_timer);
 
 	pm_runtime_disable(&pdev->dev);
 
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v14 08/10] drm/mediatek: set monitor to DP_SET_POWER_D3 to avoid garbage
  2022-07-12 11:12 [PATCH v14 00/10] drm/mediatek: Add MT8195 DisplayPort driver Bo-Chen Chen
                   ` (6 preceding siblings ...)
  2022-07-12 11:12 ` [PATCH v14 07/10] drm/mediatek: add hpd debounce Bo-Chen Chen
@ 2022-07-12 11:12 ` Bo-Chen Chen
  2022-07-12 11:12 ` [PATCH v14 09/10] drm/mediatek: DP audio support for MT8195 Bo-Chen Chen
  2022-07-12 11:12 ` [PATCH v14 10/10] drm/mediatek: Use cached audio config when changing resolution Bo-Chen Chen
  9 siblings, 0 replies; 50+ messages in thread
From: Bo-Chen Chen @ 2022-07-12 11:12 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, daniel, robh+dt, krzysztof.kozlowski+dt,
	mripard, tzimmermann, matthias.bgg, deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	ck.hu, liangxu.xu, dri-devel, linux-mediatek, devicetree,
	linux-kernel, linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group, Bo-Chen Chen

Set the monitor power state to DP_SET_POWER_D3 to avoid garbage.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 50a4159095a1..5ab646bd2bc4 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1887,6 +1887,11 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
 {
 	struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
 
+	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_video_mute(mtk_dp, true);
 
 	mtk_dp->enabled = false;
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v14 09/10] drm/mediatek: DP audio support for MT8195
  2022-07-12 11:12 [PATCH v14 00/10] drm/mediatek: Add MT8195 DisplayPort driver Bo-Chen Chen
                   ` (7 preceding siblings ...)
  2022-07-12 11:12 ` [PATCH v14 08/10] drm/mediatek: set monitor to DP_SET_POWER_D3 to avoid garbage Bo-Chen Chen
@ 2022-07-12 11:12 ` Bo-Chen Chen
  2022-07-14 11:43   ` AngeloGioacchino Del Regno
  2022-07-12 11:12 ` [PATCH v14 10/10] drm/mediatek: Use cached audio config when changing resolution Bo-Chen Chen
  9 siblings, 1 reply; 50+ messages in thread
From: Bo-Chen Chen @ 2022-07-12 11:12 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, daniel, robh+dt, krzysztof.kozlowski+dt,
	mripard, tzimmermann, matthias.bgg, deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	ck.hu, liangxu.xu, dri-devel, linux-mediatek, devicetree,
	linux-kernel, linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group, Bo-Chen Chen

From: Guillaume Ranquet <granquet@baylibre.com>

This patch adds audio support to the DP driver for MT8195 with up to 8
channels.

Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c     | 723 ++++++++++++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_dp_reg.h |   2 +
 2 files changed, 725 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 5ab646bd2bc4..fa7bb102a105 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -44,9 +44,12 @@
 #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_VERSION 0x11
 
 struct mtk_dp_timings {
 	struct videomode vm;
+	u8 frame_rate;
+	u32 pix_rate_khz;
 };
 
 struct mtk_dp_irq_sta {
@@ -67,9 +70,41 @@ struct mtk_dp_train_info {
 	struct mtk_dp_irq_sta irq_sta;
 };
 
+enum mtk_dp_sdp_type {
+	MTK_DP_SDP_NONE = 0x00,
+	MTK_DP_SDP_ACM = 0x01,
+	MTK_DP_SDP_ISRC = 0x02,
+	MTK_DP_SDP_AVI = 0x03,
+	MTK_DP_SDP_AUI = 0x04,
+	MTK_DP_SDP_SPD = 0x05,
+	MTK_DP_SDP_MPEG = 0x06,
+	MTK_DP_SDP_NTSC = 0x07,
+	MTK_DP_SDP_VSP = 0x08,
+	MTK_DP_SDP_VSC = 0x09,
+	MTK_DP_SDP_EXT = 0x0A,
+	MTK_DP_SDP_PPS0 = 0x0B,
+	MTK_DP_SDP_PPS1 = 0x0C,
+	MTK_DP_SDP_PPS2 = 0x0D,
+	MTK_DP_SDP_PPS3 = 0x0E,
+	MTK_DP_SDP_DRM = 0x10,
+	MTK_DP_SDP_MAX_NUM
+};
+
+struct mtk_dp_sdp_packet {
+	enum mtk_dp_sdp_type type;
+	struct dp_sdp sdp;
+};
+
+struct mtk_dp_audio_cfg {
+	int sample_rate;
+	int word_length_bits;
+	int channels;
+};
+
 struct mtk_dp_info {
 	u32 depth;
 	enum dp_pixelformat format;
+	struct mtk_dp_audio_cfg audio_caps;
 	struct mtk_dp_timings timings;
 };
 
@@ -103,6 +138,19 @@ struct mtk_dp {
 	struct regmap *regs;
 
 	bool enabled;
+	bool audio_enable;
+
+	/* protect the plugged_cb as it's used in both bridge ops and audio */
+	struct mutex update_plugged_status_lock;
+	/* protect the eld data as it's used in both bridge ops and audio */
+	struct mutex eld_lock;
+	/* protect edid as it is used in both bridge ops and IRQ handler */
+	struct mutex edid_lock;
+	struct edid *edid;
+
+	hdmi_codec_plugged_cb plugged_cb;
+	struct device *codec_dev;
+	u8 connector_eld[MAX_ELD_BYTES];
 
 	struct drm_connector *conn;
 	bool need_debounce;
@@ -371,6 +419,125 @@ static void mtk_dp_pg_enable(struct mtk_dp *mtk_dp, bool enable)
 			   4 << PGEN_PATTERN_SEL_SHIFT, PGEN_PATTERN_SEL_MASK);
 }
 
+static void mtk_dp_audio_setup_channels(struct mtk_dp *mtk_dp,
+					struct mtk_dp_audio_cfg *cfg)
+{
+	u32 channel_enable_bits;
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3324,
+			   AUDIO_SOURCE_MUX_DP_ENC1_P0_DPRX,
+			   AUDIO_SOURCE_MUX_DP_ENC1_P0_MASK);
+
+	/* audio channel count change reset */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_33F4, BIT(9), BIT(9));
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3304,
+			   AU_PRTY_REGEN_DP_ENC1_P0_MASK,
+			   AU_PRTY_REGEN_DP_ENC1_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3304,
+			   AU_CH_STS_REGEN_DP_ENC1_P0_MASK,
+			   AU_CH_STS_REGEN_DP_ENC1_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3304,
+			   AUDIO_SAMPLE_PRSENT_REGEN_DP_ENC1_P0_MASK,
+			   AUDIO_SAMPLE_PRSENT_REGEN_DP_ENC1_P0_MASK);
+
+	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_dp_update_bits(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);
+
+	/* audio channel count change reset */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_33F4, 0, BIT(9));
+
+	/* enable audio reset */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_33F4, BIT(0), BIT(0));
+}
+
+static void mtk_dp_audio_channel_status_set(struct mtk_dp *mtk_dp,
+					    struct mtk_dp_audio_cfg *cfg)
+{
+	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_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_308C,
+			   0, CH_STATUS_0_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3090,
+			   iec.status[3] << 8, CH_STATUS_1_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3094,
+			   iec.status[4], CH_STATUS_2_DP_ENC0_P0_MASK);
+}
+
+static void mtk_dp_audio_sdp_asp_set_channels(struct mtk_dp *mtk_dp,
+					      int channels)
+{
+	if (channels != 2 && channels != 8)
+		channels = 8;
+
+	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 void mtk_dp_audio_set_divider(struct mtk_dp *mtk_dp)
+{
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_30BC,
+			   AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
+			   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) &
@@ -385,6 +552,169 @@ static bool mtk_dp_plug_state_avoid_pulse(struct mtk_dp *mtk_dp)
 				    4000, 7 * 4000));
 }
 
+static void mtk_dp_sdp_trigger_packet(struct mtk_dp *mtk_dp,
+				      enum mtk_dp_sdp_type type)
+{
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3280,
+			   type, SDP_PACKET_TYPE_DP_ENC1_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);
+}
+
+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;
+		break;
+	}
+
+	mtk_dp_bulk_16bit_write(mtk_dp, db_addr, (u8 *)header, 4);
+}
+
+static const u32 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 void mtk_dp_disable_sdp(struct mtk_dp *mtk_dp, enum mtk_dp_sdp_type type)
+{
+	if (type == MTK_DP_SDP_NONE)
+		return;
+
+	/* Disable periodic send */
+	mtk_dp_update_bits(mtk_dp, sdp_type_to_reg[type] & 0xfffc, 0,
+			   0xFF << ((sdp_type_to_reg[type] & 3) * 8));
+}
+
+static void mtk_dp_setup_sdp(struct mtk_dp *mtk_dp,
+			     struct mtk_dp_sdp_packet *packet)
+{
+	u32 reg, shift;
+
+	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_ISRC:
+		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_DRM:
+		mtk_dp_sdp_trigger_packet(mtk_dp, packet->type);
+		mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_31DC,
+				   5 << HDR0_CFG_DP_ENC0_P0_SHIFT,
+				   HDR0_CFG_DP_ENC0_P0_MASK);
+		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:
+		reg = sdp_type_to_reg[packet->type];
+		shift = (reg & 3) * 8;
+
+		mtk_dp_sdp_trigger_packet(mtk_dp, packet->type);
+		/* Enable periodic sending */
+		mtk_dp_update_bits(mtk_dp, reg & 0xfffc,
+				   0x05 << shift, 0xff << shift);
+		break;
+	case MTK_DP_SDP_NONE:
+	default:
+		break;
+	}
+}
+
+static void mtk_dp_sdp_vsc_ext_disable(struct mtk_dp *mtk_dp)
+{
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_30A0,
+			   0, BIT(7) | BIT(8) | BIT(12));
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_328C, 0, BIT(7));
+}
+
 static void mtk_dp_aux_irq_clear(struct mtk_dp *mtk_dp)
 {
 	mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3640,
@@ -1010,6 +1340,32 @@ static void mtk_dp_video_mute(struct mtk_dp *mtk_dp, bool enable)
 			    MTK_DP_SIP_ATF_VIDEO_UNMUTE, enable);
 }
 
+static void mtk_dp_audio_mute(struct mtk_dp *mtk_dp, bool mute)
+{
+	u32 val[3];
+
+	if (mute) {
+		val[0] = BIT(VBID_AUDIO_MUTE_SW_DP_ENC0_P0_SHIFT) |
+			 BIT(VBID_AUDIO_MUTE_SEL_DP_ENC0_P0_SHIFT);
+		val[1] = 0;
+		val[2] = 0;
+	} else {
+		val[0] = 0;
+		val[1] = BIT(AU_EN_DP_ENC0_P0_SHIFT);
+		/* Send one every two frames */
+		val[2] = 0x0F;
+	}
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3030,
+			   val[0],
+			   VBID_AUDIO_MUTE_FLAG_SW_DP_ENC0_P0_MASK |
+			   VBID_AUDIO_MUTE_FLAG_SEL_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3088,
+			   val[1], AU_EN_DP_ENC0_P0_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_30A4,
+			   val[2], AU_TS_CFG_DP_ENC0_P0_MASK);
+}
+
 static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
 {
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE,
@@ -1052,6 +1408,80 @@ static void mtk_dp_initialize_priv_data(struct mtk_dp *mtk_dp)
 	mtk_dp->info.format = DP_PIXELFORMAT_RGB;
 	mtk_dp->info.depth = DP_MSA_MISC_8_BPC;
 	memset(&mtk_dp->info.timings, 0, sizeof(struct mtk_dp_timings));
+	mtk_dp->info.timings.frame_rate = 60;
+
+	mtk_dp->audio_enable = false;
+}
+
+static void mtk_dp_sdp_set_down_cnt_init(struct mtk_dp *mtk_dp,
+					 u32 sram_read_start)
+{
+	u32 sdp_down_cnt_init = 0;
+	struct drm_display_mode mode;
+	struct mtk_dp_timings *timings = &mtk_dp->info.timings;
+
+	drm_display_mode_from_videomode(&timings->vm, &mode);
+
+	if (mtk_dp->info.timings.pix_rate_khz > 0)
+		sdp_down_cnt_init = sram_read_start *
+				    mtk_dp->train_info.link_rate * 2700 * 8 /
+				    (timings->pix_rate_khz * 4);
+
+	switch (mtk_dp->train_info.lane_count) {
+	case 1:
+		sdp_down_cnt_init = max_t(u32, sdp_down_cnt_init, 0x1A);
+		break;
+	case 2:
+		/* case for LowResolution && High Audio Sample Rate */
+		sdp_down_cnt_init = max_t(u32, sdp_down_cnt_init, 0x10);
+		sdp_down_cnt_init += mode.vtotal <= 525 ? 4 : 0;
+		break;
+	case 4:
+	default:
+		sdp_down_cnt_init = max_t(u32, sdp_down_cnt_init, 6);
+		break;
+	}
+
+	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 void 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;
+	struct drm_display_mode mode;
+	struct mtk_dp_timings *timings = &mtk_dp->info.timings;
+
+	drm_display_mode_from_videomode(&timings->vm, &mode);
+
+	pix_clk_mhz = mtk_dp->info.format == DP_PIXELFORMAT_YUV420 ?
+		      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 = (mode.vtotal <= 525) ? 0x14 : 0x00;
+		spd_down_cnt_init = 0x18 + dc_offset;
+		break;
+	case 4:
+	default:
+		dc_offset = (mode.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;
+	}
+
+	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)
@@ -1063,13 +1493,44 @@ static void mtk_dp_setup_tu(struct mtk_dp *mtk_dp)
 				    MTK_DP_PIX_PER_ADDR);
 	mtk_dp_set_sram_read_start(mtk_dp, sram_read_start);
 	mtk_dp_setup_encoder(mtk_dp);
+	mtk_dp_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)
+{
+	u32 target_pixel_clk;
+	struct drm_display_mode mode;
+	struct mtk_dp_timings *timings = &mtk_dp->info.timings;
+
+	drm_display_mode_from_videomode(&timings->vm, &mode);
+
+	if (mtk_dp->info.timings.frame_rate > 0) {
+		target_pixel_clk = mode.htotal * mode.vtotal *
+				   mtk_dp->info.timings.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 = mode.htotal * mode.vtotal * 60;
+	}
+
+	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_calculate_pixrate(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 void mtk_dp_hpd_sink_event(struct mtk_dp *mtk_dp)
 {
 	ssize_t ret;
@@ -1104,6 +1565,17 @@ static void mtk_dp_hpd_sink_event(struct mtk_dp *mtk_dp)
 				   DP_REMOTE_CONTROL_COMMAND_PENDING);
 }
 
+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])
 {
@@ -1382,6 +1854,55 @@ static int mtk_dp_parse_capabilities(struct mtk_dp *mtk_dp)
 	return 0;
 }
 
+static bool 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;
+	bool ret = false;
+
+	if (mtk_dp_is_edp(mtk_dp))
+		return false;
+
+	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 false;
+	}
+	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 false;
+	}
+
+	for (i = 0; i < sad_count; i++) {
+		int sample_rate, 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 = true;
+		break;
+	}
+	kfree(sads);
+
+	return ret;
+}
+
 static void mtk_dp_train_change_mode(struct mtk_dp *mtk_dp)
 {
 	phy_reset(mtk_dp->phy);
@@ -1479,6 +2000,47 @@ 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_VERSION);
+
+	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 int mtk_dp_video_config(struct mtk_dp *mtk_dp)
 {
 	int ret;
@@ -1517,6 +2079,17 @@ static int mtk_dp_training(struct mtk_dp *mtk_dp)
 		return ret;
 	mtk_dp_video_enable(mtk_dp, true);
 
+	mtk_dp->audio_enable =
+		mtk_dp_edid_parse_audio_capabilities(mtk_dp,
+						     &mtk_dp->info.audio_caps);
+	if (mtk_dp->audio_enable) {
+		mtk_dp_audio_setup(mtk_dp, &mtk_dp->info.audio_caps);
+		mtk_dp_audio_mute(mtk_dp, false);
+	} else {
+		memset(&mtk_dp->info.audio_caps, 0,
+		       sizeof(mtk_dp->info.audio_caps));
+	}
+
 	return 0;
 }
 
@@ -1565,10 +2138,13 @@ static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
 
 		if (!mtk_dp->train_info.cable_plugged_in) {
 			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);
+			mtk_dp_sdp_stop_sending(mtk_dp);
 
+			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);
@@ -1684,6 +2260,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_avoid_pulse(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)
 {
 	struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
@@ -1699,6 +2287,7 @@ static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge)
 			ret = connector_status_connected;
 	}
 
+	mtk_dp_update_plugged_status(mtk_dp);
 	return ret;
 }
 
@@ -1721,6 +2310,18 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
 	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;
 }
 
@@ -1893,6 +2494,7 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
 	}
 
 	mtk_dp_video_mute(mtk_dp, true);
+	mtk_dp_audio_mute(mtk_dp, true);
 
 	mtk_dp->enabled = false;
 	/* Ensure the sink is muted */
@@ -1905,6 +2507,7 @@ static void mtk_dp_parse_drm_mode_timings(struct mtk_dp *mtk_dp,
 	struct mtk_dp_timings *timings = &mtk_dp->info.timings;
 
 	drm_display_mode_to_videomode(mode, &timings->vm);
+	timings->frame_rate = drm_mode_vrefresh(mode);
 }
 
 static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
@@ -1922,6 +2525,8 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
 	}
 
 	mtk_dp_video_mute(mtk_dp, true);
+	mtk_dp_audio_mute(mtk_dp, true);
+	mtk_dp_sdp_stop_sending(mtk_dp);
 
 	if (mtk_dp_parse_capabilities(mtk_dp)) {
 		drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n");
@@ -1935,7 +2540,13 @@ 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);
+
 	mtk_dp->enabled = true;
+
+	mtk_dp_update_plugged_status(mtk_dp);
 }
 
 static enum drm_mode_status
@@ -2082,6 +2693,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;
@@ -2127,8 +2836,21 @@ static int mtk_dp_probe(struct platform_device *pdev)
 		return dev_err_probe(dev, -EPROBE_DEFER,
 				     "failed to request mediatek dptx irq\n");
 
+	mutex_init(&mtk_dp->edid_lock);
+	mutex_init(&mtk_dp->eld_lock);
+	mutex_init(&mtk_dp->update_plugged_status_lock);
+
 	platform_set_drvdata(pdev, mtk_dp);
 
+	if (!mtk_dp_is_edp(mtk_dp)) {
+		ret = mtk_dp_register_audio_driver(dev);
+		if (ret) {
+			dev_err(dev, "Failed to register audio driver: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
 	mtk_dp->phy_dev = platform_device_register_data(dev, "mediatek-dp-phy",
 							PLATFORM_DEVID_AUTO,
 							&mtk_dp->regs,
@@ -2174,6 +2896,7 @@ static int mtk_dp_remove(struct platform_device *pdev)
 
 	platform_device_unregister(mtk_dp->phy_dev);
 	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);
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
index 9b6f2e01391d..fce2ef329820 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
+++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
@@ -240,6 +240,8 @@
 #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)
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v14 10/10] drm/mediatek: Use cached audio config when changing resolution
  2022-07-12 11:12 [PATCH v14 00/10] drm/mediatek: Add MT8195 DisplayPort driver Bo-Chen Chen
                   ` (8 preceding siblings ...)
  2022-07-12 11:12 ` [PATCH v14 09/10] drm/mediatek: DP audio support for MT8195 Bo-Chen Chen
@ 2022-07-12 11:12 ` Bo-Chen Chen
  9 siblings, 0 replies; 50+ messages in thread
From: Bo-Chen Chen @ 2022-07-12 11:12 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, daniel, robh+dt, krzysztof.kozlowski+dt,
	mripard, tzimmermann, matthias.bgg, deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	ck.hu, liangxu.xu, dri-devel, linux-mediatek, devicetree,
	linux-kernel, linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group, Bo-Chen Chen

When the audio is playing, we need to use the original configuration to
set the audio instead of using new configuration. Therefore, use the
cached audio configuration during a resolution switch to avoid loss of
sound.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 54 ++++++++++---------------------
 1 file changed, 17 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index fa7bb102a105..32fb7be374ed 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -104,7 +104,7 @@ struct mtk_dp_audio_cfg {
 struct mtk_dp_info {
 	u32 depth;
 	enum dp_pixelformat format;
-	struct mtk_dp_audio_cfg audio_caps;
+	struct mtk_dp_audio_cfg audio_cur_cfg;
 	struct mtk_dp_timings timings;
 };
 
@@ -1858,9 +1858,7 @@ static bool 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;
-	bool ret = false;
+	int ret;
 
 	if (mtk_dp_is_edp(mtk_dp))
 		return false;
@@ -1871,36 +1869,16 @@ static bool mtk_dp_edid_parse_audio_capabilities(struct mtk_dp *mtk_dp,
 		dev_err(mtk_dp->dev, "EDID not found!\n");
 		return false;
 	}
-	sad_count = drm_edid_to_sad(mtk_dp->edid, &sads);
-	mutex_unlock(&mtk_dp->edid_lock);
 
-	if (sad_count <= 0) {
+	ret = drm_edid_to_sad(mtk_dp->edid, &sads);
+	mutex_unlock(&mtk_dp->edid_lock);
+	if (ret <= 0) {
 		drm_info(mtk_dp->drm_dev, "The SADs is NULL\n");
 		return false;
 	}
-
-	for (i = 0; i < sad_count; i++) {
-		int sample_rate, 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 = true;
-		break;
-	}
 	kfree(sads);
 
-	return ret;
+	return true;
 }
 
 static void mtk_dp_train_change_mode(struct mtk_dp *mtk_dp)
@@ -2081,13 +2059,13 @@ static int mtk_dp_training(struct mtk_dp *mtk_dp)
 
 	mtk_dp->audio_enable =
 		mtk_dp_edid_parse_audio_capabilities(mtk_dp,
-						     &mtk_dp->info.audio_caps);
+						     &mtk_dp->info.audio_cur_cfg);
 	if (mtk_dp->audio_enable) {
-		mtk_dp_audio_setup(mtk_dp, &mtk_dp->info.audio_caps);
+		mtk_dp_audio_setup(mtk_dp, &mtk_dp->info.audio_cur_cfg);
 		mtk_dp_audio_mute(mtk_dp, false);
 	} else {
-		memset(&mtk_dp->info.audio_caps, 0,
-		       sizeof(mtk_dp->info.audio_caps));
+		memset(&mtk_dp->info.audio_cur_cfg, 0,
+		       sizeof(mtk_dp->info.audio_cur_cfg));
 	}
 
 	return 0;
@@ -2491,6 +2469,9 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
 	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);
+	} else {
+		memset(&mtk_dp->info.audio_cur_cfg, 0,
+		       sizeof(mtk_dp->info.audio_cur_cfg));
 	}
 
 	mtk_dp_video_mute(mtk_dp, true);
@@ -2701,18 +2682,17 @@ static int mtk_dp_audio_hw_params(struct device *dev, void *data,
 				  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->info.audio_cur_cfg.channels = params->cea.channels;
+	mtk_dp->info.audio_cur_cfg.sample_rate = params->sample_rate;
+	mtk_dp->info.audio_cur_cfg.word_length_bits = 24;
 
-	mtk_dp_audio_setup(mtk_dp, &cfg);
+	mtk_dp_audio_setup(mtk_dp, &mtk_dp->info.audio_cur_cfg);
 
 	return 0;
 }
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 01/10] dt-bindings: mediatek,dp: Add Display Port binding
  2022-07-12 11:12 ` [PATCH v14 01/10] dt-bindings: mediatek,dp: Add Display Port binding Bo-Chen Chen
@ 2022-07-13  7:56   ` CK Hu
  2022-07-26  6:18     ` Rex-BC Chen
  2022-07-18 20:21   ` Rob Herring
  1 sibling, 1 reply; 50+ messages in thread
From: CK Hu @ 2022-07-13  7:56 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This controller is present on several mediatek hardware. Currently
> mt8195 and mt8395 have this controller without a functional
> difference,
> so only one compatible field is added.
> 
> The controller can have two forms, as a normal display port and as an
> embedded display port.
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---
>  .../display/mediatek/mediatek,dp.yaml         | 115
> ++++++++++++++++++
>  1 file changed, 115 insertions(+)
>  create mode 100644
> Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
> 
> diff --git
> a/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
> b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
> new file mode 100644
> index 000000000000..e2d6cb314297
> --- /dev/null
> +++
> b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
> @@ -0,0 +1,115 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: 
> http://devicetree.org/schemas/display/mediatek/mediatek,dp.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek Display Port Controller
> +
> +maintainers:
> +  - Chun-Kuang Hu <chunkuang.hu@kernel.org>
> +  - Jitao shi <jitao.shi@mediatek.com>
> +
> +description: |
> +  Device tree bindings for the MediaTek display port TX (DP) and
> +  embedded display port TX (eDP) controller present on some MediaTek
> SoCs.
> +  MediaTek DP and eDP are different hardwares and they have
> different
> +  base address for registers, so we need two different compatibles
> to
> +  separate them.
> +
> +properties:
> +  compatible:
> +    enum:
> +      - mediatek,mt8195-dp-tx
> +      - mediatek,mt8195-edp-tx
> +
> +  reg:
> +    maxItems: 1
> +
> +  nvmem-cells:
> +    maxItems: 1
> +    description: efuse data for display port calibration
> +
> +  nvmem-cell-names:
> +    const: dp_calibration_data
> +
> +  power-domains:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +    properties:
> +      port@0:
> +        $ref: /schemas/graph.yaml#/properties/port
> +        description: Input endpoint of the controller, usually
> dp_intf
> +
> +      port@1:
> +        $ref: /schemas/graph.yaml#/$defs/port-base
> +        unevaluatedProperties: false
> +        description: Output endpoint of the controller
> +        properties:
> +          endpoint:
> +            $ref: /schemas/media/video-interfaces.yaml#
> +            unevaluatedProperties: false
> +            properties:
> +              data-lanes:
> +                description: |
> +                  number of lanes supported by the hardware.
> +                  The possible values:
> +                  0       - For 1 lane enabled in IP.
> +                  0 1     - For 2 lanes enabled in IP.
> +                  0 1 2 3 - For 4 lanes enabled in IP.
> +                minItems: 1
> +                maxItems: 4
> +            required:
> +              - data-lanes
> +
> +    required:
> +      - port@0
> +      - port@1
> +
> +  max-linkrate-mhz:
> +    enum: [ 1620, 2700, 5400, 8100 ]
> +    description: maximum link rate supported by the hardware.
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - ports
> +  - max-linkrate-mhz
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/power/mt8195-power.h>
> +    dp_tx@1c600000 {
> +        compatible = "mediatek,mt8195-dp-tx";
> +        reg = <0x1c600000 0x8000>;
> +        power-domains = <&spm MT8195_POWER_DOMAIN_DP_TX>;
> +        interrupts = <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH 0>;
> +        max-linkrate-mhz = <8100>;

Why dp-tx has no clock property? I think this device should work with a
clock.

Regards,
CK

> +
> +        ports {
> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +
> +            port@0 {
> +                reg = <0>;
> +                dptx_in: endpoint {
> +                    remote-endpoint = <&dp_intf0_out>;
> +                };
> +            };
> +            port@1 {
> +                reg = <1>;
> +                dptx_out: endpoint {
> +                    data-lanes = <0 1 2 3>;
> +                };
> +            };
> +        };
> +    };


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
@ 2022-07-13  8:03   ` CK Hu
  2022-07-13  8:10   ` CK Hu
                     ` (15 subsequent siblings)
  16 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-13  8:03 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
> +{
> +	struct mtk_dp *mtk_dp = dev;
> +
> +	if (mtk_dp->train_info.cable_state_change) {
> +		mtk_dp->train_info.cable_state_change = false;
> +
> +		mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
> +				   DP_PWR_STATE_BANDGAP_TPLL_LANE,
> +				   DP_PWR_STATE_MASK);

You set cable_state_change to true in isr handler just to update a
register in isr thread. I think you could just update this register in
isr handler and drop cable_state_change.

Regards,
CK

> +	}
> +
> +	if (mtk_dp->train_info.irq_sta.hpd_inerrupt) {
> +		dev_dbg(mtk_dp->dev, "MTK_DP_HPD_INTERRUPT\n");
> +		mtk_dp->train_info.irq_sta.hpd_inerrupt = false;
> +		mtk_dp_hpd_sink_event(mtk_dp);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
  2022-07-13  8:03   ` CK Hu
@ 2022-07-13  8:10   ` CK Hu
  2022-07-14  8:24     ` Rex-BC Chen
  2022-07-13  8:22   ` CK Hu
                     ` (14 subsequent siblings)
  16 siblings, 1 reply; 50+ messages in thread
From: CK Hu @ 2022-07-13  8:10 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +struct mtk_dp_timings {
> +	struct videomode vm;
> +};
> +
> +struct mtk_dp_irq_sta {
> +	bool hpd_inerrupt;
> +};
> +
> +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;
> +	struct mtk_dp_irq_sta irq_sta;

There is only one member in struct mtk_dp_irq_sta, so drop struct
mtk_dp_irq_sta and use bool hpd_inerrupt directly here.

> +};
> +
> +struct mtk_dp_info {
> +	u32 depth;
> +	enum dp_pixelformat format;
> +	struct mtk_dp_timings timings;

There is only one member in struct mtk_dp_timings, so drop struct
mtk_dp_timings and use struct videomode vm directly here.

Regards,
CK

> +};
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
  2022-07-13  8:03   ` CK Hu
  2022-07-13  8:10   ` CK Hu
@ 2022-07-13  8:22   ` CK Hu
  2022-07-13  8:30   ` CK Hu
                     ` (13 subsequent siblings)
  16 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-13  8:22 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +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);
> +	struct drm_crtc *crtc = conn_state->crtc;
> +	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);
> +
> +	if (input_bus_format == MEDIA_BUS_FMT_YUYV8_1X16)
> +		mtk_dp->info.format = DP_PIXELFORMAT_YUV422;
> +	else
> +		mtk_dp->info.format = DP_PIXELFORMAT_RGB;
> +
> +	if (!crtc) {
> +		drm_err(mtk_dp->drm_dev,
> +			"Can't enable bridge as connector state doesn't
> have a crtc\n");
> +		return -EINVAL;
> +	}
> +
> +	mtk_dp_parse_drm_mode_timings(mtk_dp, &crtc_state-
> >adjusted_mode);
> +	if (mtk_dp_parse_capabilities(mtk_dp)) {

mtk_dp_bridge_atomic_enable() would call mtk_dp_parse_capabilities(),
so this is redundant.

Regards,
CK

> +		drm_err(mtk_dp->drm_dev,
> +			"Can't enable bridge as nothing is plugged
> in\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (2 preceding siblings ...)
  2022-07-13  8:22   ` CK Hu
@ 2022-07-13  8:30   ` CK Hu
  2022-07-13  9:12   ` CK Hu
                     ` (12 subsequent siblings)
  16 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-13  8:30 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +static int mtk_dp_set_color_depth(struct mtk_dp *mtk_dp)
> +{
> +	/* Only support 8 bits currently */
> +	mtk_dp->info.depth = DP_MSA_MISC_8_BPC;

Only support DP_MSA_MISC_8_BPC, so it's not necessary use a variable to
store this information. Drop depth.

Regards,
CK

> +
> +	/* Update MISC0 */
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
> +			   DP_MSA_MISC_8_BPC, DP_TEST_BIT_DEPTH_MASK);
> +
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
> +			   VIDEO_COLOR_DEPTH_DP_ENC0_P0_8BIT,
> +			   VIDEO_COLOR_DEPTH_DP_ENC0_P0_MASK);
> +	return 0;
> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (3 preceding siblings ...)
  2022-07-13  8:30   ` CK Hu
@ 2022-07-13  9:12   ` CK Hu
  2022-07-13  9:31   ` CK Hu
                     ` (11 subsequent siblings)
  16 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-13  9:12 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +static void mtk_dp_msa_bypass_enable(struct mtk_dp *mtk_dp, bool
> enable)
> +{
> +	u32 mask = 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);

I would like define a symbol like this

#define HTOTAL_SEL_DP_ENC0_P0 BIT(0)
#define VTOTAL_SEL_DP_ENC0_P0 BIT(1)
#define HSTART_SEL_DP_ENC0_P0 BIT(2)

Regards,
CK

> +	u32 val = enable ? 0 : mask;
> +
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3030, val, mask);
> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (4 preceding siblings ...)
  2022-07-13  9:12   ` CK Hu
@ 2022-07-13  9:31   ` CK Hu
  2022-07-14  8:52     ` Rex-BC Chen
  2022-07-13  9:33   ` CK Hu
                     ` (10 subsequent siblings)
  16 siblings, 1 reply; 50+ messages in thread
From: CK Hu @ 2022-07-13  9:31 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +static void mtk_dp_bulk_16bit_write(struct mtk_dp *mtk_dp, u32
> offset, u8 *buf,
> +				    size_t length)

The offset would always be MTK_DP_AUX_P0_3708, so drop offset and use
MTK_DP_AUX_P0_3708 directly.

> +{
> +	int i;
> +	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);
> +
> +		if (mtk_dp_write(mtk_dp, offset + i * 4, val))
> +			return;
> +	}

for (i = 0; i < length; i += 2) {
	val = buf[i] | (i + 1 < length ? buf[i + 1] << 8 : 0);
	if (mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3708 + i * 2, val))
		return;
}

Regards,
CK

> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (5 preceding siblings ...)
  2022-07-13  9:31   ` CK Hu
@ 2022-07-13  9:33   ` CK Hu
  2022-07-14  8:57     ` Rex-BC Chen
  2022-07-13  9:45   ` CK Hu
                     ` (9 subsequent siblings)
  16 siblings, 1 reply; 50+ messages in thread
From: CK Hu @ 2022-07-13  9:33 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +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);

mtk_dp_aux_fill_write_fifo() directly call mtk_dp_bulk_16bit_write(),
so I think we could just keep one of them and drop another one.

Regards,
CK

> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (6 preceding siblings ...)
  2022-07-13  9:33   ` CK Hu
@ 2022-07-13  9:45   ` CK Hu
  2022-07-14  6:51   ` CK Hu
                     ` (8 subsequent siblings)
  16 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-13  9:45 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +static void mtk_dp_set_msa(struct mtk_dp *mtk_dp)
> +{
> +	struct drm_display_mode mode;
> +	struct mtk_dp_timings *timings = &mtk_dp->info.timings;
> +
> +	drm_display_mode_from_videomode(&timings->vm, &mode);
> +
> +	/* horizontal */
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3010,
> +			   mode.htotal, HTOTAL_SW_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3018,
> +			   timings->vm.hsync_len + timings-
> >vm.hback_porch,
> +			   HSTART_SW_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3028,
> +			   timings->vm.hsync_len <<
> HSW_SW_DP_ENC0_P0_SHIFT,

Directly use a number for shift because we know it's a shift, so it's
not necessary to define a symbol for shift.

> +			   HSW_SW_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3028,
> +			   0, HSP_SW_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3020,
> +			   timings->vm.hactive,
> HWIDTH_SW_DP_ENC0_P0_MASK);
> +
> +	/* vertical */
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3014,
> +			   mode.vtotal, VTOTAL_SW_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_301C,
> +			   timings->vm.vsync_len + timings-
> >vm.vback_porch,
> +			   VSTART_SW_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_302C,
> +			   timings->vm.vsync_len <<
> VSW_SW_DP_ENC0_P0_SHIFT,

Ditto.

Regards,
CK

> +			   VSW_SW_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_302C,
> +			   0, VSP_SW_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3024,
> +			   timings->vm.vactive,
> VHEIGHT_SW_DP_ENC0_P0_MASK);
> +
> +	/* horizontal */
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3064,
> +			   timings->vm.hactive,
> HDE_NUM_LAST_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3154,
> +			   mode.htotal, PGEN_HTOTAL_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3158,
> +			   timings->vm.hfront_porch,
> +			   PGEN_HSYNC_RISING_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_315C,
> +			   timings->vm.hsync_len,
> +			   PGEN_HSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3160,
> +			   timings->vm.hback_porch + timings-
> >vm.hsync_len,
> +			   PGEN_HFDE_START_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3164,
> +			   timings->vm.hactive,
> +			   PGEN_HFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK);
> +
> +	/* vertical */
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3168,
> +			   mode.vtotal,
> +			   PGEN_VTOTAL_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_316C,
> +			   timings->vm.vfront_porch,
> +			   PGEN_VSYNC_RISING_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3170,
> +			   timings->vm.vsync_len,
> +			   PGEN_VSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3174,
> +			   timings->vm.vback_porch + timings-
> >vm.vsync_len,
> +			   PGEN_VFDE_START_DP_ENC0_P0_MASK);
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3178,
> +			   timings->vm.vactive,
> +			   PGEN_VFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK);
> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (7 preceding siblings ...)
  2022-07-13  9:45   ` CK Hu
@ 2022-07-14  6:51   ` CK Hu
  2022-07-14  9:09     ` Rex-BC Chen
  2022-07-14  7:06   ` CK Hu
                     ` (7 subsequent siblings)
  16 siblings, 1 reply; 50+ messages in thread
From: CK Hu @ 2022-07-14  6:51 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +static int mtk_dp_train_tps_2_3(struct mtk_dp *mtk_dp, u8
> target_linkrate,
> +				u8 target_lane_count, int
> *iteration_count,
> +				u8 *lane_adjust,  int *status_control,
> +				u8 *prev_lane_adjust)
> +{
> +	u8 val;
> +	u8 link_status[DP_LINK_STATUS_SIZE] = {};
> +
> +	if (*status_control == 1) {
> +		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) * 2);
> +
> +		mtk_dp_train_update_swing_pre(mtk_dp,
> +					      target_lane_count,
> lane_adjust);
> +		*status_control = 2;
> +		(*iteration_count)++;
> +	}
> +
> +	drm_dp_link_train_channel_eq_delay(&mtk_dp->aux, mtk_dp-
> >rx_cap);
> +
> +	drm_dp_dpcd_read_link_status(&mtk_dp->aux, link_status);
> +
> +	if (!drm_dp_clock_recovery_ok(link_status, target_lane_count)) 

I think this checking is redundant. I think we could just keep
drm_dp_channel_eq_ok() and drop drm_dp_clock_recovery_ok() here because
if drm_dp_clock_recovery_ok() fail, it imply that
drm_dp_channel_eq_ok() would fail. So just check drm_dp_channel_eq_ok()
is enough.

Regards,
CK

> {
> +		mtk_dp->train_info.cr_done = false;
> +		mtk_dp->train_info.eq_done = false;
> +		dev_dbg(mtk_dp->dev, "Link train EQ fail\n");
> +		return -EINVAL;
> +	}
> +
> +	if (drm_dp_channel_eq_ok(link_status, target_lane_count)) {
> +		mtk_dp->train_info.eq_done = true;
> +		dev_dbg(mtk_dp->dev, "Link train EQ pass\n");
> +		return 0;
> +	}
> +
> +	if (*prev_lane_adjust == link_status[4])
> +		(*iteration_count)++;
> +	else
> +		*prev_lane_adjust = link_status[4];
> +
> +	return -EAGAIN;
> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (8 preceding siblings ...)
  2022-07-14  6:51   ` CK Hu
@ 2022-07-14  7:06   ` CK Hu
  2022-07-15  8:51   ` CK Hu
                     ` (6 subsequent siblings)
  16 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-14  7:06 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +static int mtk_dp_train_flow(struct mtk_dp *mtk_dp, u8
> target_link_rate,
> +			     u8 target_lane_count)
> +{
> +	u8 lane_adjust[2] = {};
> +	bool pass_tps1 = false;
> +	bool pass_tps2_3 = false;
> +	int train_retries;
> +	int status_control;
> +	int iteration_count;
> +	int ret;
> +	u8 prev_lane_adjust;
> +
> +	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);
> +	ret = mtk_dp_phy_configure(mtk_dp, target_link_rate,
> target_lane_count);
> +	if (ret)
> +		return ret;
> +
> +	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)
> +			return -ENODEV;
> +
> +		if (!pass_tps1) {
> +			ret = mtk_dp_train_tps_1(mtk_dp,
> target_lane_count,
> +						 &iteration_count,
> lane_adjust,
> +						 &status_control,
> +						 &prev_lane_adjust);
> +			if (!ret) {
> +				pass_tps1 = true;
> +				train_retries = 0;
> +			} else if (ret == -EINVAL) {
> +				break;
> +			}
> +		} else {
> +			ret = mtk_dp_train_tps_2_3(mtk_dp,
> target_link_rate,
> +						   target_lane_count,
> +						   &iteration_count,
> +						   lane_adjust,
> &status_control,
> +						   &prev_lane_adjust);
> +			if (!ret) {
> +				pass_tps2_3 = true;
> +				break;
> +			} else if (ret == -EINVAL) {
> +				break;
> +			}
> +		}
> +
> +		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);

train_retries and iteration_count are the same thing, so keep one and
drop another one.

Regards,
CK

> +
> +	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 ret;
> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-13  8:10   ` CK Hu
@ 2022-07-14  8:24     ` Rex-BC Chen
  2022-07-14 10:21       ` CK Hu
  0 siblings, 1 reply; 50+ messages in thread
From: Rex-BC Chen @ 2022-07-14  8:24 UTC (permalink / raw)
  To: CK Hu, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Wed, 2022-07-13 at 16:10 +0800, CK Hu wrote:
> Hi, Bo-Chen:
> 
> On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > 
> > This patch adds a embedded 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 creates a child device for the phy. The child device
> > will
> > never exist without the parent being active. As they are sharing a
> > register range, the parent passes a regmap pointer to the child so
> > that
> > both can work with the same register range. The phy driver sets
> > device
> > data that is read by the parent to get the phy device that can be
> > used
> > to control the phy properties.
> > 
> > This driver is based on an initial version by
> > Jitao shi <jitao.shi@mediatek.com>
> > 
> > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > ---
> 
> [snip]
> 
> > +
> > +struct mtk_dp_timings {
> > +	struct videomode vm;
> > +};
> > +
> > +struct mtk_dp_irq_sta {
> > +	bool hpd_inerrupt;
> > +};
> > +
> > +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;
> > +	struct mtk_dp_irq_sta irq_sta;
> 
> There is only one member in struct mtk_dp_irq_sta, so drop struct
> mtk_dp_irq_sta and use bool hpd_inerrupt directly here.
> 

Hello CK,

ok, I will drop this.

> > +};
> > +
> > +struct mtk_dp_info {
> > +	u32 depth;
> > +	enum dp_pixelformat format;
> > +	struct mtk_dp_timings timings;
> 
> There is only one member in struct mtk_dp_timings, so drop struct
> mtk_dp_timings and use struct videomode vm directly here.
> 

This structure will add more variable in following patch.
whole struct is like,
struct mtk_dp_timings {
	struct videomode vm;
	u8 frame_rate;
	u32 pix_rate_khz;
};

I want to keep this.

BRs,
Bo-Chen


> Regards,
> CK
> 
> > +};
> > +
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-13  9:31   ` CK Hu
@ 2022-07-14  8:52     ` Rex-BC Chen
  0 siblings, 0 replies; 50+ messages in thread
From: Rex-BC Chen @ 2022-07-14  8:52 UTC (permalink / raw)
  To: CK Hu, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Wed, 2022-07-13 at 17:31 +0800, CK Hu wrote:
> Hi, Bo-Chen:
> 
> On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > 
> > This patch adds a embedded 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 creates a child device for the phy. The child device
> > will
> > never exist without the parent being active. As they are sharing a
> > register range, the parent passes a regmap pointer to the child so
> > that
> > both can work with the same register range. The phy driver sets
> > device
> > data that is read by the parent to get the phy device that can be
> > used
> > to control the phy properties.
> > 
> > This driver is based on an initial version by
> > Jitao shi <jitao.shi@mediatek.com>
> > 
> > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > ---
> 
> [snip]
> 
> > +
> > +static void mtk_dp_bulk_16bit_write(struct mtk_dp *mtk_dp, u32
> > offset, u8 *buf,
> > +				    size_t length)
> 
> The offset would always be MTK_DP_AUX_P0_3708, so drop offset and use
> MTK_DP_AUX_P0_3708 directly.
> 

Hello CK,

I don't think it's a good idea. this function is a fucntion of writing
registers. I want to keep the offset variable.

> > +{
> > +	int i;
> > +	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);
> > +
> > +		if (mtk_dp_write(mtk_dp, offset + i * 4, val))
> > +			return;
> > +	}
> 
> for (i = 0; i < length; i += 2) {
> 	val = buf[i] | (i + 1 < length ? buf[i + 1] << 8 : 0);
> 	if (mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_3708 + i * 2, val))
> 		return;
> }
> 

ok.

BRs,
Bo-Chen

> Regards,
> CK
> 
> > +}
> > +
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-13  9:33   ` CK Hu
@ 2022-07-14  8:57     ` Rex-BC Chen
  0 siblings, 0 replies; 50+ messages in thread
From: Rex-BC Chen @ 2022-07-14  8:57 UTC (permalink / raw)
  To: CK Hu, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Wed, 2022-07-13 at 17:33 +0800, CK Hu wrote:
> Hi, Bo-Chen:
> 
> On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > 
> > This patch adds a embedded 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 creates a child device for the phy. The child device
> > will
> > never exist without the parent being active. As they are sharing a
> > register range, the parent passes a regmap pointer to the child so
> > that
> > both can work with the same register range. The phy driver sets
> > device
> > data that is read by the parent to get the phy device that can be
> > used
> > to control the phy properties.
> > 
> > This driver is based on an initial version by
> > Jitao shi <jitao.shi@mediatek.com>
> > 
> > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > ---
> 
> [snip]
> 
> > +
> > +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);
> 
> mtk_dp_aux_fill_write_fifo() directly call mtk_dp_bulk_16bit_write(),
> so I think we could just keep one of them and drop another one.
> 

Hello CK,

mtk_dp_bulk_16bit_write() will also be used in following patches.
I want to keep the driver like this.

BRs,
Bo-Chen
> Regards,
> CK
> 
> > +}
> > +
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-14  6:51   ` CK Hu
@ 2022-07-14  9:09     ` Rex-BC Chen
  2022-07-14 10:34       ` CK Hu
  0 siblings, 1 reply; 50+ messages in thread
From: Rex-BC Chen @ 2022-07-14  9:09 UTC (permalink / raw)
  To: CK Hu, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Thu, 2022-07-14 at 14:51 +0800, CK Hu wrote:
> Hi, Bo-Chen:
> 
> On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > 
> > This patch adds a embedded 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 creates a child device for the phy. The child device
> > will
> > never exist without the parent being active. As they are sharing a
> > register range, the parent passes a regmap pointer to the child so
> > that
> > both can work with the same register range. The phy driver sets
> > device
> > data that is read by the parent to get the phy device that can be
> > used
> > to control the phy properties.
> > 
> > This driver is based on an initial version by
> > Jitao shi <jitao.shi@mediatek.com>
> > 
> > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > ---
> 
> [snip]
> 
> > +static int mtk_dp_train_tps_2_3(struct mtk_dp *mtk_dp, u8
> > target_linkrate,
> > +				u8 target_lane_count, int
> > *iteration_count,
> > +				u8 *lane_adjust,  int *status_control,
> > +				u8 *prev_lane_adjust)
> > +{
> > +	u8 val;
> > +	u8 link_status[DP_LINK_STATUS_SIZE] = {};
> > +
> > +	if (*status_control == 1) {
> > +		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) * 2);
> > +
> > +		mtk_dp_train_update_swing_pre(mtk_dp,
> > +					      target_lane_count,
> > lane_adjust);
> > +		*status_control = 2;
> > +		(*iteration_count)++;
> > +	}
> > +
> > +	drm_dp_link_train_channel_eq_delay(&mtk_dp->aux, mtk_dp-
> > > rx_cap);
> > 
> > +
> > +	drm_dp_dpcd_read_link_status(&mtk_dp->aux, link_status);
> > +
> > +	if (!drm_dp_clock_recovery_ok(link_status, target_lane_count)) 
> 
> I think this checking is redundant. I think we could just keep
> drm_dp_channel_eq_ok() and drop drm_dp_clock_recovery_ok() here
> because
> if drm_dp_clock_recovery_ok() fail, it imply that
> drm_dp_channel_eq_ok() would fail. So just check
> drm_dp_channel_eq_ok()
> is enough.
> 
> Regards,
> CK
> 
> > {
> > +		mtk_dp->train_info.cr_done = false;
> > +		mtk_dp->train_info.eq_done = false;
> > +		dev_dbg(mtk_dp->dev, "Link train EQ fail\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (drm_dp_channel_eq_ok(link_status, target_lane_count)) {
> > +		mtk_dp->train_info.eq_done = true;
> > +		dev_dbg(mtk_dp->dev, "Link train EQ pass\n");
> > +		return 0;
> > +	}
> > +

Hello CK,

do you mean like this?
if (drm_dp_channel_eq_ok(link_status, target_lane_count)) {
  mtk_dp-
>train_info.eq_done = true;
  dev_dbg(mtk_dp->dev, "Link train EQ pass\n");
  return 0;
} else {
  mtk_dp->train_info.cr_done = false;
  mtk_dp->train_info.eq_done = false;
  dev_dbg(mtk_dp->dev, "Link train EQ fail\n");
  return -EINVAL;
}

BRs,
Bo-Chen

> > +	if (*prev_lane_adjust == link_status[4])
> > +		(*iteration_count)++;
> > +	else
> > +		*prev_lane_adjust = link_status[4];
> > +
> > +	return -EAGAIN;
> > +}
> > +
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-14  8:24     ` Rex-BC Chen
@ 2022-07-14 10:21       ` CK Hu
  0 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-14 10:21 UTC (permalink / raw)
  To: Rex-BC Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Thu, 2022-07-14 at 16:24 +0800, Rex-BC Chen wrote:
> On Wed, 2022-07-13 at 16:10 +0800, CK Hu wrote:
> > Hi, Bo-Chen:
> > 
> > On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > > 
> > > This patch adds a embedded 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 creates a child device for the phy. The child device
> > > will
> > > never exist without the parent being active. As they are sharing
> > > a
> > > register range, the parent passes a regmap pointer to the child
> > > so
> > > that
> > > both can work with the same register range. The phy driver sets
> > > device
> > > data that is read by the parent to get the phy device that can be
> > > used
> > > to control the phy properties.
> > > 
> > > This driver is based on an initial version by
> > > Jitao shi <jitao.shi@mediatek.com>
> > > 
> > > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > > ---
> > 
> > [snip]
> > 
> > > +
> > > +struct mtk_dp_timings {
> > > +	struct videomode vm;
> > > +};
> > > +
> > > +struct mtk_dp_irq_sta {
> > > +	bool hpd_inerrupt;
> > > +};
> > > +
> > > +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;
> > > +	struct mtk_dp_irq_sta irq_sta;
> > 
> > There is only one member in struct mtk_dp_irq_sta, so drop struct
> > mtk_dp_irq_sta and use bool hpd_inerrupt directly here.
> > 
> 
> Hello CK,
> 
> ok, I will drop this.
> 
> > > +};
> > > +
> > > +struct mtk_dp_info {
> > > +	u32 depth;
> > > +	enum dp_pixelformat format;
> > > +	struct mtk_dp_timings timings;
> > 
> > There is only one member in struct mtk_dp_timings, so drop struct
> > mtk_dp_timings and use struct videomode vm directly here.
> > 
> 
> This structure will add more variable in following patch.
> whole struct is like,
> struct mtk_dp_timings {
> 	struct videomode vm;
> 	u8 frame_rate;
> 	u32 pix_rate_khz;
> };
> 
> I want to keep this.

I think we could just drop struct mtk_dp_timings and place these member
directly in struct mtk_dp_info.

Regards,
CK

> 
> BRs,
> Bo-Chen
> 
> 
> > Regards,
> > CK
> > 
> > > +};
> > > +
> > 
> > 
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-14  9:09     ` Rex-BC Chen
@ 2022-07-14 10:34       ` CK Hu
  0 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-14 10:34 UTC (permalink / raw)
  To: Rex-BC Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Thu, 2022-07-14 at 17:09 +0800, Rex-BC Chen wrote:
> On Thu, 2022-07-14 at 14:51 +0800, CK Hu wrote:
> > Hi, Bo-Chen:
> > 
> > On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > > 
> > > This patch adds a embedded 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 creates a child device for the phy. The child device
> > > will
> > > never exist without the parent being active. As they are sharing
> > > a
> > > register range, the parent passes a regmap pointer to the child
> > > so
> > > that
> > > both can work with the same register range. The phy driver sets
> > > device
> > > data that is read by the parent to get the phy device that can be
> > > used
> > > to control the phy properties.
> > > 
> > > This driver is based on an initial version by
> > > Jitao shi <jitao.shi@mediatek.com>
> > > 
> > > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > > ---
> > 
> > [snip]
> > 
> > > +static int mtk_dp_train_tps_2_3(struct mtk_dp *mtk_dp, u8
> > > target_linkrate,
> > > +				u8 target_lane_count, int
> > > *iteration_count,
> > > +				u8 *lane_adjust,  int *status_control,
> > > +				u8 *prev_lane_adjust)
> > > +{
> > > +	u8 val;
> > > +	u8 link_status[DP_LINK_STATUS_SIZE] = {};
> > > +
> > > +	if (*status_control == 1) {
> > > +		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) * 2);
> > > +
> > > +		mtk_dp_train_update_swing_pre(mtk_dp,
> > > +					      target_lane_count,
> > > lane_adjust);
> > > +		*status_control = 2;
> > > +		(*iteration_count)++;
> > > +	}
> > > +
> > > +	drm_dp_link_train_channel_eq_delay(&mtk_dp->aux, mtk_dp-
> > > > rx_cap);
> > > 
> > > +
> > > +	drm_dp_dpcd_read_link_status(&mtk_dp->aux, link_status);
> > > +
> > > +	if (!drm_dp_clock_recovery_ok(link_status, target_lane_count)) 
> > 
> > I think this checking is redundant. I think we could just keep
> > drm_dp_channel_eq_ok() and drop drm_dp_clock_recovery_ok() here
> > because
> > if drm_dp_clock_recovery_ok() fail, it imply that
> > drm_dp_channel_eq_ok() would fail. So just check
> > drm_dp_channel_eq_ok()
> > is enough.
> > 
> > Regards,
> > CK
> > 
> > > {
> > > +		mtk_dp->train_info.cr_done = false;
> > > +		mtk_dp->train_info.eq_done = false;
> > > +		dev_dbg(mtk_dp->dev, "Link train EQ fail\n");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	if (drm_dp_channel_eq_ok(link_status, target_lane_count)) {
> > > +		mtk_dp->train_info.eq_done = true;
> > > +		dev_dbg(mtk_dp->dev, "Link train EQ pass\n");
> > > +		return 0;
> > > +	}
> > > +
> 
> Hello CK,
> 
> do you mean like this?
> if (drm_dp_channel_eq_ok(link_status, target_lane_count)) {
>   mtk_dp-
> > train_info.eq_done = true;
> 
>   dev_dbg(mtk_dp->dev, "Link train EQ pass\n");
>   return 0;
> } else {
>   mtk_dp->train_info.cr_done = false;
>   mtk_dp->train_info.eq_done = false;
>   dev_dbg(mtk_dp->dev, "Link train EQ fail\n");
>   return -EINVAL;
> }

No, I mean just remove drm_dp_clock_recovery_ok() checking. When
drm_dp_channel_eq_ok() fail, it should keep retry. If clock recovery
has some problem, drm_dp_channel_eq_ok() would be finally out of retry
count.

Regards,
CK

> 
> BRs,
> Bo-Chen
> 
> > > +	if (*prev_lane_adjust == link_status[4])
> > > +		(*iteration_count)++;
> > > +	else
> > > +		*prev_lane_adjust = link_status[4];
> > > +
> > > +	return -EAGAIN;
> > > +}
> > > +
> > 
> > 
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 03/10] drm/edid: Add cea_sad helpers for freq/length
  2022-07-12 11:12 ` [PATCH v14 03/10] drm/edid: Add cea_sad helpers for freq/length Bo-Chen Chen
@ 2022-07-14 11:12   ` AngeloGioacchino Del Regno
  2022-07-14 11:19     ` Rex-BC Chen
  0 siblings, 1 reply; 50+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-07-14 11:12 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, ck.hu, liangxu.xu, dri-devel,
	linux-mediatek, devicetree, linux-kernel, linux-arm-kernel,
	linux-fbdev, Project_Global_Chrome_Upstream_Group

Il 12/07/22 13:12, Bo-Chen Chen ha scritto:
> From: Guillaume Ranquet <granquet@baylibre.com>
> 
> 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 <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---
>   drivers/gpu/drm/drm_edid.c | 73 ++++++++++++++++++++++++++++++++++++++
>   include/drm/drm_edid.h     | 14 ++++++++
>   2 files changed, 87 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index bc43e1b32092..79316d7f1fd8 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -4916,6 +4916,79 @@ int drm_edid_to_speaker_allocation(const 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_pcm(const struct cea_sad *sad)
> +{
> +	switch (sad->format) {
> +	case HDMI_AUDIO_CODING_TYPE_PCM:
> +		return true;
> +	default:
> +		return false;
> +	}

Are you sure that you need this helper? That's used only in one function...
...if you really need this one, though, I don't think that using a switch
is the best option here.

Unless anyone is against that (please, reason?), I would be for doing it like:

	return sad->format == HDMI_AUDIO_CODING_TYPE_PCM;

Everything else looks good to me (and working, too).

Cheers,
Angelo

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 03/10] drm/edid: Add cea_sad helpers for freq/length
  2022-07-14 11:12   ` AngeloGioacchino Del Regno
@ 2022-07-14 11:19     ` Rex-BC Chen
  0 siblings, 0 replies; 50+ messages in thread
From: Rex-BC Chen @ 2022-07-14 11:19 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno, chunkuang.hu, p.zabel, daniel,
	robh+dt, krzysztof.kozlowski+dt, mripard, tzimmermann,
	matthias.bgg, deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, ck.hu, liangxu.xu, dri-devel,
	linux-mediatek, devicetree, linux-kernel, linux-arm-kernel,
	linux-fbdev, Project_Global_Chrome_Upstream_Group

On Thu, 2022-07-14 at 13:12 +0200, AngeloGioacchino Del Regno wrote:
> Il 12/07/22 13:12, Bo-Chen Chen ha scritto:
> > From: Guillaume Ranquet <granquet@baylibre.com>
> > 
> > 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 <msp@baylibre.com>
> > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > ---
> >   drivers/gpu/drm/drm_edid.c | 73
> > ++++++++++++++++++++++++++++++++++++++
> >   include/drm/drm_edid.h     | 14 ++++++++
> >   2 files changed, 87 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/drm_edid.c
> > b/drivers/gpu/drm/drm_edid.c
> > index bc43e1b32092..79316d7f1fd8 100644
> > --- a/drivers/gpu/drm/drm_edid.c
> > +++ b/drivers/gpu/drm/drm_edid.c
> > @@ -4916,6 +4916,79 @@ int drm_edid_to_speaker_allocation(const
> > 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_pcm(const struct cea_sad *sad)
> > +{
> > +	switch (sad->format) {
> > +	case HDMI_AUDIO_CODING_TYPE_PCM:
> > +		return true;
> > +	default:
> > +		return false;
> > +	}
> 
> Are you sure that you need this helper? That's used only in one
> function...
> ...if you really need this one, though, I don't think that using a
> switch
> is the best option here.
> 
> Unless anyone is against that (please, reason?), I would be for doing
> it like:
> 
> 	return sad->format == HDMI_AUDIO_CODING_TYPE_PCM;
> 
> Everything else looks good to me (and working, too).
> 
> Cheers,
> Angelo

Hello Angelo,

I think you are right,
in this case, we don't need this help function.
I will merge this function into
drm_cea_sad_get_uncompressed_word_length()

BRs,
Bo-Chen



^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 04/10] video/hdmi: Add audio_infoframe packing for DP
  2022-07-12 11:12 ` [PATCH v14 04/10] video/hdmi: Add audio_infoframe packing for DP Bo-Chen Chen
@ 2022-07-14 11:26   ` AngeloGioacchino Del Regno
  0 siblings, 0 replies; 50+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-07-14 11:26 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, ck.hu, liangxu.xu, dri-devel,
	linux-mediatek, devicetree, linux-kernel, linux-arm-kernel,
	linux-fbdev, Project_Global_Chrome_Upstream_Group

Il 12/07/22 13:12, Bo-Chen Chen ha scritto:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> 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.
> 
> Also constify the frame parameter in hdmi_audio_infoframe_check() as
> it is passed to hdmi_audio_infoframe_check_only() which expects a const.
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---
>   drivers/video/hdmi.c         | 82 +++++++++++++++++++++++++++---------
>   include/drm/display/drm_dp.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..86805d77cc86 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -21,6 +21,7 @@
>    * DEALINGS IN THE SOFTWARE.
>    */
>   
> +#include <drm/display/drm_dp.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

"This is filled with the appropriate data"

... well, that's pretty obvious, isn't it?
You're describing that this function is filling sdp in the description, so you
can just remove that part.

Also, "Secondary data packet for DisplayPort", please.


> + * @dp_version: Display Port version to be encoded in the header

We're not meaning "a display port", but really "DisplayPort": please remove
the space between "Display" and "Port" :-)

(here and in the description below)

> + *
> + * 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;

What's this magic number 4 about?

Please use a definition for that.

> +}
> +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/display/drm_dp.h b/include/drm/display/drm_dp.h
> index 9e3aff7e68bb..6c0871164771 100644
> --- a/include/drm/display/drm_dp.h
> +++ b/include/drm/display/drm_dp.h
> @@ -1536,6 +1536,8 @@ enum drm_dp_phy {
>   #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,


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 09/10] drm/mediatek: DP audio support for MT8195
  2022-07-12 11:12 ` [PATCH v14 09/10] drm/mediatek: DP audio support for MT8195 Bo-Chen Chen
@ 2022-07-14 11:43   ` AngeloGioacchino Del Regno
  0 siblings, 0 replies; 50+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-07-14 11:43 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, ck.hu, liangxu.xu, dri-devel,
	linux-mediatek, devicetree, linux-kernel, linux-arm-kernel,
	linux-fbdev, Project_Global_Chrome_Upstream_Group

Il 12/07/22 13:12, Bo-Chen Chen ha scritto:
> From: Guillaume Ranquet <granquet@baylibre.com>
> 
> This patch adds audio support to the DP driver for MT8195 with up to 8
> channels.
> 
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---
>   drivers/gpu/drm/mediatek/mtk_dp.c     | 723 ++++++++++++++++++++++++++
>   drivers/gpu/drm/mediatek/mtk_dp_reg.h |   2 +
>   2 files changed, 725 insertions(+)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index 5ab646bd2bc4..fa7bb102a105 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c

..snip..

> @@ -2082,6 +2693,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__);

drm_err() here please.

> +		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;
> +}
> +

..snip..

> +
> +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);

You're never unregistering this device, which is unacceptable.

Please add a platform device pointer in struct mtk_dp, so that this function
becomes, simply:

	mtk_dp->audio_pdev = platform_device_register_data(dev,
						HDMI_CODEC_DRV_NAME,
						PLATFORM_DEVID_AUTO, &codec_data,
						sizeof(codec_data));
	return PTR_ERR_OR_ZERO(mtk_dp->audio_pdev);

> +
> +	return 0;
> +}
> +
>   static int mtk_dp_probe(struct platform_device *pdev)
>   {
>   	struct mtk_dp *mtk_dp;
> @@ -2127,8 +2836,21 @@ static int mtk_dp_probe(struct platform_device *pdev)
>   		return dev_err_probe(dev, -EPROBE_DEFER,
>   				     "failed to request mediatek dptx irq\n");
>   
> +	mutex_init(&mtk_dp->edid_lock);
> +	mutex_init(&mtk_dp->eld_lock);
> +	mutex_init(&mtk_dp->update_plugged_status_lock);
> +
>   	platform_set_drvdata(pdev, mtk_dp);
>   
> +	if (!mtk_dp_is_edp(mtk_dp)) {
> +		ret = mtk_dp_register_audio_driver(dev);
> +		if (ret) {
> +			dev_err(dev, "Failed to register audio driver: %d\n",
> +				ret);
> +			return ret;
> +		}
> +	}
> +
>   	mtk_dp->phy_dev = platform_device_register_data(dev, "mediatek-dp-phy",
>   							PLATFORM_DEVID_AUTO,
>   							&mtk_dp->regs,
> @@ -2174,6 +2896,7 @@ static int mtk_dp_remove(struct platform_device *pdev)
>   
>   	platform_device_unregister(mtk_dp->phy_dev);

... and unregister it here:

	if (mtk_dp->audio_pdev)
		platform_device_unregister(mtk_dp->audio_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);

Regards,
Angelo

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (9 preceding siblings ...)
  2022-07-14  7:06   ` CK Hu
@ 2022-07-15  8:51   ` CK Hu
  2022-07-21  2:38     ` Rex-BC Chen
  2022-07-15  9:13   ` CK Hu
                     ` (5 subsequent siblings)
  16 siblings, 1 reply; 50+ messages in thread
From: CK Hu @ 2022-07-15  8:51 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +static void mtk_dp_hpd_sink_event(struct mtk_dp *mtk_dp)
> +{
> +	ssize_t ret;
> +	u8 sink_count;
> +	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);

According to your last reply, if drm_dp_dpcd_readb() fail, we could
skip below statement. So this just for error checking? If so, the next
drm_dp_dpcd_read() would also do the error checking, so the checking
here is redundant.

Regards,
CK

> +	if (ret < 1) {
> +		drm_err(mtk_dp->drm_dev, "Read sink count failed\n");
> +		return;
> +	}
> +
> +	drm_dbg(mtk_dp->drm_dev,
> +		"read sink count from dpcd: %d\n", sink_count);
> +
> +	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\n");
> +		return;
> +	}
> +
> +	if (!drm_dp_channel_eq_ok(link_status, mtk_dp-
> >train_info.lane_count)) {
> +		drm_err(mtk_dp->drm_dev, "Channel EQ failed\n");
> +		return;
> +	}
> +
> +	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);
> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (10 preceding siblings ...)
  2022-07-15  8:51   ` CK Hu
@ 2022-07-15  9:13   ` CK Hu
  2022-07-15  9:14   ` CK Hu
                     ` (4 subsequent siblings)
  16 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-15  9:13 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +static int mtk_dp_set_color_depth(struct mtk_dp *mtk_dp)

This function just return 0, so let this function to be void.

Regards,
CK

> +{
> +	/* Only support 8 bits currently */
> +	mtk_dp->info.depth = DP_MSA_MISC_8_BPC;
> +
> +	/* Update MISC0 */
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3034,
> +			   DP_MSA_MISC_8_BPC, DP_TEST_BIT_DEPTH_MASK);
> +
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
> +			   VIDEO_COLOR_DEPTH_DP_ENC0_P0_8BIT,
> +			   VIDEO_COLOR_DEPTH_DP_ENC0_P0_MASK);
> +	return 0;
> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (11 preceding siblings ...)
  2022-07-15  9:13   ` CK Hu
@ 2022-07-15  9:14   ` CK Hu
  2022-07-15  9:37   ` CK Hu
                     ` (3 subsequent siblings)
  16 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-15  9:14 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +static void mtk_dp_mn_overwrite_disable(struct mtk_dp *mtk_dp)
> +{
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004,
> +			   0, VIDEO_M_CODE_SEL_DP_ENC0_P0_MASK);
> +}

Why has mtk_dp_mn_overwrite_disable() but no
mtk_dp_mn_overwrite_enable()?

Regards,
CK

> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (12 preceding siblings ...)
  2022-07-15  9:14   ` CK Hu
@ 2022-07-15  9:37   ` CK Hu
  2022-07-15 18:01   ` kernel test robot
                     ` (2 subsequent siblings)
  16 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-15  9:37 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +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;
> +
> +	if ((mode->clock * 1000) / (mode->htotal * mode->vtotal) >
> +	    MTK_VDOSYS1_MAX_FRAMERATE)

Why limit frame rate to 60fps? If the resolution is small enough, why
not support higher fps?

Regards,
CK

> +		return MODE_CLOCK_HIGH;
> +
> +	return MODE_OK;
> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (13 preceding siblings ...)
  2022-07-15  9:37   ` CK Hu
@ 2022-07-15 18:01   ` kernel test robot
  2022-07-25  9:16   ` CK Hu
  2022-07-25  9:23   ` CK Hu
  16 siblings, 0 replies; 50+ messages in thread
From: kernel test robot @ 2022-07-15 18:01 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: kbuild-all, devicetree, linux-fbdev, granquet, jitao.shi,
	liangxu.xu, linux-kernel, dri-devel, msp,
	Project_Global_Chrome_Upstream_Group, Bo-Chen Chen,
	linux-mediatek, wenst, linux-arm-kernel,
	angelogioacchino.delregno

Hi Bo-Chen,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on drm/drm-next pza/reset/next linus/master v5.19-rc6 next-20220715]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bo-Chen-Chen/drm-mediatek-Add-MT8195-DisplayPort-driver/20220712-191341
base:   git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
config: arm-allyesconfig (https://download.01.org/0day-ci/archive/20220716/202207160102.zyueiI7S-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/a3869f524e16c38015e0f124c6597927fc6d26b0
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Bo-Chen-Chen/drm-mediatek-Add-MT8195-DisplayPort-driver/20220712-191341
        git checkout a3869f524e16c38015e0f124c6597927fc6d26b0
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash drivers/gpu/drm/mediatek/ drivers/pci/controller/dwc/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/mediatek/mtk_dp.c: In function 'mtk_dp_train_tps_1':
>> drivers/gpu/drm/mediatek/mtk_dp.c:1092:12: warning: variable 'val' set but not used [-Wunused-but-set-variable]
    1092 |         u8 val;
         |            ^~~
   drivers/gpu/drm/mediatek/mtk_dp.c: In function 'mtk_dp_bridge_atomic_get_output_bus_fmts':
   drivers/gpu/drm/mediatek/mtk_dp.c:1865:26: error: 'MEDIA_BUS_FMT_FIXED' undeclared (first use in this function)
    1865 |         output_fmts[0] = MEDIA_BUS_FMT_FIXED;
         |                          ^~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/mediatek/mtk_dp.c:1865:26: note: each undeclared identifier is reported only once for each function it appears in
   drivers/gpu/drm/mediatek/mtk_dp.c: At top level:
   drivers/gpu/drm/mediatek/mtk_dp.c:1870:9: error: 'MEDIA_BUS_FMT_RGB888_1X24' undeclared here (not in a function)
    1870 |         MEDIA_BUS_FMT_RGB888_1X24,
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/mediatek/mtk_dp.c:1871:9: error: 'MEDIA_BUS_FMT_YUV8_1X24' undeclared here (not in a function)
    1871 |         MEDIA_BUS_FMT_YUV8_1X24,
         |         ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/mediatek/mtk_dp.c:1872:9: error: 'MEDIA_BUS_FMT_YUYV8_1X16' undeclared here (not in a function)
    1872 |         MEDIA_BUS_FMT_YUYV8_1X16,
         |         ^~~~~~~~~~~~~~~~~~~~~~~~


vim +/val +1092 drivers/gpu/drm/mediatek/mtk_dp.c

  1087	
  1088	static int mtk_dp_train_tps_1(struct mtk_dp *mtk_dp, u8 target_lane_count,
  1089				      int *iteration_count, u8 *lane_adjust,
  1090				      int *status_control, u8 *prev_lane_adjust)
  1091	{
> 1092		u8 val;
  1093		u8 link_status[DP_LINK_STATUS_SIZE] = {};
  1094	
  1095		mtk_dp_training_set_scramble(mtk_dp, false);
  1096	
  1097		if (*status_control == 0) {
  1098			mtk_dp_train_set_pattern(mtk_dp, 1);
  1099			val = DP_LINK_SCRAMBLING_DISABLE |
  1100				DP_TRAINING_PATTERN_1;
  1101			drm_dp_dpcd_writeb(&mtk_dp->aux,
  1102					   DP_TRAINING_PATTERN_SET,
  1103					   DP_LINK_SCRAMBLING_DISABLE |
  1104					   DP_TRAINING_PATTERN_1);
  1105			drm_dp_dpcd_read(&mtk_dp->aux,
  1106					 DP_ADJUST_REQUEST_LANE0_1,
  1107					 lane_adjust,
  1108					 sizeof(*lane_adjust) * 2);
  1109	
  1110			mtk_dp_train_update_swing_pre(mtk_dp,
  1111						      target_lane_count, lane_adjust);
  1112			*status_control = 1;
  1113			(*iteration_count)++;
  1114		}
  1115	
  1116		drm_dp_link_train_clock_recovery_delay(&mtk_dp->aux, mtk_dp->rx_cap);
  1117		drm_dp_dpcd_read_link_status(&mtk_dp->aux, link_status);
  1118	
  1119		if (drm_dp_clock_recovery_ok(link_status,
  1120					     target_lane_count)) {
  1121			mtk_dp->train_info.cr_done = true;
  1122			*iteration_count = 1;
  1123			dev_dbg(mtk_dp->dev, "Link train CR pass\n");
  1124			return 0;
  1125		} else if (*prev_lane_adjust == link_status[4]) {
  1126			(*iteration_count)++;
  1127			if (*prev_lane_adjust & DP_ADJUST_VOLTAGE_SWING_LANE0_MASK) {
  1128				dev_dbg(mtk_dp->dev, "Link train CQ fail\n");
  1129				return -EINVAL;
  1130			}
  1131		} else {
  1132			*prev_lane_adjust = link_status[4];
  1133		}
  1134		return -EAGAIN;
  1135	}
  1136	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 01/10] dt-bindings: mediatek,dp: Add Display Port binding
  2022-07-12 11:12 ` [PATCH v14 01/10] dt-bindings: mediatek,dp: Add Display Port binding Bo-Chen Chen
  2022-07-13  7:56   ` CK Hu
@ 2022-07-18 20:21   ` Rob Herring
  1 sibling, 0 replies; 50+ messages in thread
From: Rob Herring @ 2022-07-18 20:21 UTC (permalink / raw)
  To: Bo-Chen Chen
  Cc: chunkuang.hu, p.zabel, daniel, krzysztof.kozlowski+dt, mripard,
	tzimmermann, matthias.bgg, deller, airlied, msp, granquet,
	jitao.shi, wenst, angelogioacchino.delregno, ck.hu, liangxu.xu,
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Tue, Jul 12, 2022 at 07:12:14PM +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This controller is present on several mediatek hardware. Currently
> mt8195 and mt8395 have this controller without a functional difference,
> so only one compatible field is added.
> 
> The controller can have two forms, as a normal display port and as an
> embedded display port.
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---
>  .../display/mediatek/mediatek,dp.yaml         | 115 ++++++++++++++++++
>  1 file changed, 115 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
> new file mode 100644
> index 000000000000..e2d6cb314297
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
> @@ -0,0 +1,115 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/mediatek/mediatek,dp.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek Display Port Controller
> +
> +maintainers:
> +  - Chun-Kuang Hu <chunkuang.hu@kernel.org>
> +  - Jitao shi <jitao.shi@mediatek.com>
> +
> +description: |
> +  Device tree bindings for the MediaTek display port TX (DP) and
> +  embedded display port TX (eDP) controller present on some MediaTek SoCs.
> +  MediaTek DP and eDP are different hardwares and they have different
> +  base address for registers, so we need two different compatibles to
> +  separate them.

As I said before, 'different base address for registers' is not a reason 
for different compatibles. If it was, then we'd never have a compatible 
string appear more than once in a DT.

Explain WHAT is different within the block. For example[1].

Rob

[1] https://lore.kernel.org/all/20220710084133.30976-10-dmitry.baryshkov@linaro.org/


> +
> +properties:
> +  compatible:
> +    enum:
> +      - mediatek,mt8195-dp-tx
> +      - mediatek,mt8195-edp-tx
> +
> +  reg:
> +    maxItems: 1
> +
> +  nvmem-cells:
> +    maxItems: 1
> +    description: efuse data for display port calibration
> +
> +  nvmem-cell-names:
> +    const: dp_calibration_data
> +
> +  power-domains:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +    properties:
> +      port@0:
> +        $ref: /schemas/graph.yaml#/properties/port
> +        description: Input endpoint of the controller, usually dp_intf
> +
> +      port@1:
> +        $ref: /schemas/graph.yaml#/$defs/port-base
> +        unevaluatedProperties: false
> +        description: Output endpoint of the controller
> +        properties:
> +          endpoint:
> +            $ref: /schemas/media/video-interfaces.yaml#
> +            unevaluatedProperties: false
> +            properties:
> +              data-lanes:
> +                description: |
> +                  number of lanes supported by the hardware.
> +                  The possible values:
> +                  0       - For 1 lane enabled in IP.
> +                  0 1     - For 2 lanes enabled in IP.
> +                  0 1 2 3 - For 4 lanes enabled in IP.
> +                minItems: 1
> +                maxItems: 4
> +            required:
> +              - data-lanes
> +
> +    required:
> +      - port@0
> +      - port@1
> +
> +  max-linkrate-mhz:
> +    enum: [ 1620, 2700, 5400, 8100 ]
> +    description: maximum link rate supported by the hardware.
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - ports
> +  - max-linkrate-mhz
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/power/mt8195-power.h>
> +    dp_tx@1c600000 {
> +        compatible = "mediatek,mt8195-dp-tx";
> +        reg = <0x1c600000 0x8000>;
> +        power-domains = <&spm MT8195_POWER_DOMAIN_DP_TX>;
> +        interrupts = <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH 0>;
> +        max-linkrate-mhz = <8100>;
> +
> +        ports {
> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +
> +            port@0 {
> +                reg = <0>;
> +                dptx_in: endpoint {
> +                    remote-endpoint = <&dp_intf0_out>;
> +                };
> +            };
> +            port@1 {
> +                reg = <1>;
> +                dptx_out: endpoint {
> +                    data-lanes = <0 1 2 3>;
> +                };
> +            };
> +        };
> +    };
> -- 
> 2.18.0
> 
> 

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-15  8:51   ` CK Hu
@ 2022-07-21  2:38     ` Rex-BC Chen
  2022-07-21  6:24       ` CK Hu
  0 siblings, 1 reply; 50+ messages in thread
From: Rex-BC Chen @ 2022-07-21  2:38 UTC (permalink / raw)
  To: CK Hu, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Fri, 2022-07-15 at 16:51 +0800, CK Hu wrote:
> Hi, Bo-Chen:
> 
> On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > 
> > This patch adds a embedded 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 creates a child device for the phy. The child device
> > will
> > never exist without the parent being active. As they are sharing a
> > register range, the parent passes a regmap pointer to the child so
> > that
> > both can work with the same register range. The phy driver sets
> > device
> > data that is read by the parent to get the phy device that can be
> > used
> > to control the phy properties.
> > 
> > This driver is based on an initial version by
> > Jitao shi <jitao.shi@mediatek.com>
> > 
> > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > ---
> 
> [snip]
> 
> > +static void mtk_dp_hpd_sink_event(struct mtk_dp *mtk_dp)
> > +{
> > +	ssize_t ret;
> > +	u8 sink_count;
> > +	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);
> 
> According to your last reply, if drm_dp_dpcd_readb() fail, we could
> skip below statement. So this just for error checking? If so, the
> next
> drm_dp_dpcd_read() would also do the error checking, so the checking
> here is redundant.
> 
> Regards,
> CK
> 

Hello CK,

sorry, I don't get your point.
We use "drm_dp_dpcd_readb(&mtk_dp->aux, sink_count_reg, &sink_count)"
to get sink count and use "drm_dp_dpcd_read(&mtk_dp->aux,
link_status_reg, link_status, sizeof(link_status));" to get link
status.

If we don't get any sink count, we don't need to check the link status.
Therefore, we just return if we are failed to get sink count.

BRs,
Bo-Chen

> > +	if (ret < 1) {
> > +		drm_err(mtk_dp->drm_dev, "Read sink count failed\n");
> > +		return;
> > +	}
> > +
> > +	drm_dbg(mtk_dp->drm_dev,
> > +		"read sink count from dpcd: %d\n", sink_count);
> > +
> > +	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\n");
> > +		return;
> > +	}
> > +
> > +	if (!drm_dp_channel_eq_ok(link_status, mtk_dp-
> > > train_info.lane_count)) {
> > 
> > +		drm_err(mtk_dp->drm_dev, "Channel EQ failed\n");
> > +		return;
> > +	}
> > +
> > +	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);
> > +}
> > +
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-21  2:38     ` Rex-BC Chen
@ 2022-07-21  6:24       ` CK Hu
  0 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-21  6:24 UTC (permalink / raw)
  To: Rex-BC Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Rex:

On Thu, 2022-07-21 at 10:38 +0800, Rex-BC Chen wrote:
> On Fri, 2022-07-15 at 16:51 +0800, CK Hu wrote:
> > Hi, Bo-Chen:
> > 
> > On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > > 
> > > This patch adds a embedded 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 creates a child device for the phy. The child device
> > > will
> > > never exist without the parent being active. As they are sharing
> > > a
> > > register range, the parent passes a regmap pointer to the child
> > > so
> > > that
> > > both can work with the same register range. The phy driver sets
> > > device
> > > data that is read by the parent to get the phy device that can be
> > > used
> > > to control the phy properties.
> > > 
> > > This driver is based on an initial version by
> > > Jitao shi <jitao.shi@mediatek.com>
> > > 
> > > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > > ---
> > 
> > [snip]
> > 
> > > +static void mtk_dp_hpd_sink_event(struct mtk_dp *mtk_dp)
> > > +{
> > > +	ssize_t ret;
> > > +	u8 sink_count;
> > > +	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);
> > 
> > According to your last reply, if drm_dp_dpcd_readb() fail, we could
> > skip below statement. So this just for error checking? If so, the
> > next
> > drm_dp_dpcd_read() would also do the error checking, so the
> > checking
> > here is redundant.
> > 
> > Regards,
> > CK
> > 
> 
> Hello CK,
> 
> sorry, I don't get your point.
> We use "drm_dp_dpcd_readb(&mtk_dp->aux, sink_count_reg, &sink_count)"
> to get sink count and use "drm_dp_dpcd_read(&mtk_dp->aux,
> link_status_reg, link_status, sizeof(link_status));" to get link
> status.
> 
> If we don't get any sink count, we don't need to check the link
> status.
> Therefore, we just return if we are failed to get sink count.

I assume that when error happen, both read sink_count and read
link_status would fail, so you could directly read link_status. Do you
think that when error happen, only read sink_count would fail and read
link_status would success? It it is the later case, we should keep the
checking of sink_count.

Regards,
CK

> 
> BRs,
> Bo-Chen
> 
> > > +	if (ret < 1) {
> > > +		drm_err(mtk_dp->drm_dev, "Read sink count failed\n");
> > > +		return;
> > > +	}
> > > +
> > > +	drm_dbg(mtk_dp->drm_dev,
> > > +		"read sink count from dpcd: %d\n", sink_count);
> > > +
> > > +	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\n");
> > > +		return;
> > > +	}
> > > +
> > > +	if (!drm_dp_channel_eq_ok(link_status, mtk_dp-
> > > > train_info.lane_count)) {
> > > 
> > > +		drm_err(mtk_dp->drm_dev, "Channel EQ failed\n");
> > > +		return;
> > > +	}
> > > +
> > > +	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);
> > > +}
> > > +
> > 
> > 
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (14 preceding siblings ...)
  2022-07-15 18:01   ` kernel test robot
@ 2022-07-25  9:16   ` CK Hu
  2022-07-26  6:42     ` Rex-BC Chen
  2022-07-25  9:23   ` CK Hu
  16 siblings, 1 reply; 50+ messages in thread
From: CK Hu @ 2022-07-25  9:16 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +static int mtk_dp_training(struct mtk_dp *mtk_dp)
> +{
> +	short max_retry = 50;
> +	int ret;
> +
> +	do {
> +		ret = mtk_dp_train_start(mtk_dp);
> +		if (!ret)
> +			break;
> +		else if (ret != -EAGAIN)
> +			return ret;
> +	} while (--max_retry);

mtk_dp_train_start() would never return -EAGAIN, so drop this while
loop.

Regards,
CK

> 
> +	if (!max_retry)
> +		return -ETIMEDOUT;
> +
> +	ret = mtk_dp_video_config(mtk_dp);
> +	if (ret)
> +		return ret;
> +	mtk_dp_video_enable(mtk_dp, true);
> +
> +	return 0;
> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
                     ` (15 preceding siblings ...)
  2022-07-25  9:16   ` CK Hu
@ 2022-07-25  9:23   ` CK Hu
  2022-07-26  3:30     ` Rex-BC Chen
  16 siblings, 1 reply; 50+ messages in thread
From: CK Hu @ 2022-07-25  9:23 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Markus Schneider-Pargmann <msp@baylibre.com>
> 
> This patch adds a embedded 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 creates a child device for the phy. The child device will
> never exist without the parent being active. As they are sharing a
> register range, the parent passes a regmap pointer to the child so
> that
> both can work with the same register range. The phy driver sets
> device
> data that is read by the parent to get the phy device that can be
> used
> to control the phy properties.
> 
> This driver is based on an initial version by
> Jitao shi <jitao.shi@mediatek.com>
> 
> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> +
> +/*
> + * We need to handle HPD signal in eDP even though eDP is a always
> connected
> + * device. Besides connected status, there is another feature for
> HPD signal -
> + * HPD pulse: it presents an IRQ from sink devices to source devices
> (Refer to
> + * 5.1.4 of DP1.4 spec).
> + */
> +static irqreturn_t mtk_dp_hpd_isr_handler(struct mtk_dp *mtk_dp)
> +{
> +	bool hpd_change = false;
> +	u32 irq_status = mtk_dp_swirq_get_clear(mtk_dp) |
> +			 mtk_dp_hwirq_get_clear(mtk_dp);
> +	struct mtk_dp_train_info *train_info = &mtk_dp->train_info;
> +
> +	if (!irq_status)
> +		return IRQ_HANDLED;
> +
> +	if (irq_status & MTK_DP_HPD_INTERRUPT)
> +		train_info->irq_sta.hpd_inerrupt = true;
> +	if (irq_status & MTK_DP_HPD_CONNECT ||
> +	    irq_status & MTK_DP_HPD_DISCONNECT)
> +		hpd_change = true;
> +
> +	if (!(hpd_change))
> +		return IRQ_WAKE_THREAD;
> +
> +	if (mtk_dp_plug_state(mtk_dp))

mtk_dp_plug_state() is called only here, and prevent function call in
isr handler, so squash mtk_dp_plug_state() into this function.

> +		train_info->cable_plugged_in = true;
> +	else
> +		train_info->cable_plugged_in = false;
> +
> +	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);

Prevent function call in isr handler, squash mtk_dp_hpd_isr_handler()
into this function.

Regards,
CK

> +
> +	return IRQ_HANDLED;
> +}
> +


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 06/10] drm/mediatek: Add MT8195 External DisplayPort support
  2022-07-12 11:12 ` [PATCH v14 06/10] drm/mediatek: Add MT8195 External DisplayPort support Bo-Chen Chen
@ 2022-07-25  9:51   ` CK Hu
  0 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-25  9:51 UTC (permalink / raw)
  To: Bo-Chen Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

Hi, Bo-Chen:

On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> From: Guillaume Ranquet <granquet@baylibre.com>
> 
> This patch adds External DisplayPort support to the mt8195 eDP
> driver.
> 
> Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> ---

[snip]

> @@ -1489,13 +1543,34 @@ static int mtk_dp_init_port(struct mtk_dp
> *mtk_dp)
>  static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
>  {
>  	struct mtk_dp *mtk_dp = dev;
> +	int event;
> +
> +	event = mtk_dp_plug_state(mtk_dp) ?
> +		connector_status_connected :
> connector_status_disconnected;
> +
> +	if (event < 0)
> +		return IRQ_HANDLED;

event is useless, so drop it.

Regards,
CK

> +
> +	dev_dbg(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_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
> -				   DP_PWR_STATE_BANDGAP_TPLL_LANE,
> -				   DP_PWR_STATE_MASK);
> +		if (!mtk_dp->train_info.cable_plugged_in) {
> +			mtk_dp_video_mute(mtk_dp, true);
> +
> +			mtk_dp_initialize_priv_data(mtk_dp);
> +			mtk_dp_set_idle_pattern(mtk_dp, true);
> +
> +			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_LA
> NE,
> +					   DP_PWR_STATE_MASK);
> +		}
>  	}
>  
>  	if (mtk_dp->train_info.irq_sta.hpd_inerrupt) {
> @@ -1597,6 +1672,24 @@ static int mtk_dp_dt_parse(struct mtk_dp
> *mtk_dp,
>  	return 0;
>  }
>  


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-25  9:23   ` CK Hu
@ 2022-07-26  3:30     ` Rex-BC Chen
  2022-07-26  8:37       ` CK Hu
  0 siblings, 1 reply; 50+ messages in thread
From: Rex-BC Chen @ 2022-07-26  3:30 UTC (permalink / raw)
  To: CK Hu, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Mon, 2022-07-25 at 17:23 +0800, CK Hu wrote:
> Hi, Bo-Chen:
> 
> On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > 
> > This patch adds a embedded 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 creates a child device for the phy. The child device
> > will
> > never exist without the parent being active. As they are sharing a
> > register range, the parent passes a regmap pointer to the child so
> > that
> > both can work with the same register range. The phy driver sets
> > device
> > data that is read by the parent to get the phy device that can be
> > used
> > to control the phy properties.
> > 
> > This driver is based on an initial version by
> > Jitao shi <jitao.shi@mediatek.com>
> > 
> > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > ---
> 
> [snip]
> 
> > +
> > +/*
> > + * We need to handle HPD signal in eDP even though eDP is a always
> > connected
> > + * device. Besides connected status, there is another feature for
> > HPD signal -
> > + * HPD pulse: it presents an IRQ from sink devices to source
> > devices
> > (Refer to
> > + * 5.1.4 of DP1.4 spec).
> > + */
> > +static irqreturn_t mtk_dp_hpd_isr_handler(struct mtk_dp *mtk_dp)
> > +{
> > +	bool hpd_change = false;
> > +	u32 irq_status = mtk_dp_swirq_get_clear(mtk_dp) |
> > +			 mtk_dp_hwirq_get_clear(mtk_dp);
> > +	struct mtk_dp_train_info *train_info = &mtk_dp->train_info;
> > +
> > +	if (!irq_status)
> > +		return IRQ_HANDLED;
> > +
> > +	if (irq_status & MTK_DP_HPD_INTERRUPT)
> > +		train_info->irq_sta.hpd_inerrupt = true;
> > +	if (irq_status & MTK_DP_HPD_CONNECT ||
> > +	    irq_status & MTK_DP_HPD_DISCONNECT)
> > +		hpd_change = true;
> > +
> > +	if (!(hpd_change))
> > +		return IRQ_WAKE_THREAD;
> > +
> > +	if (mtk_dp_plug_state(mtk_dp))
> 
> mtk_dp_plug_state() is called only here, and prevent function call in
> isr handler, so squash mtk_dp_plug_state() into this function.
> 

Hello CK,

Thanks for review.

I would like to keep this because we will use this function for
mtk_dp_plug_state_avoid_pulse() in dp patch.

> > +		train_info->cable_plugged_in = true;
> > +	else
> > +		train_info->cable_plugged_in = false;
> > +
> > +	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);
> 
> Prevent function call in isr handler, squash mtk_dp_hpd_isr_handler()
> into this function.
> 

Is this really necessary? We also modify this function in following
patches. I think it's not a good idea to expand this.

BRs,
Bo-Chen

> Regards,
> CK
> 
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 01/10] dt-bindings: mediatek,dp: Add Display Port binding
  2022-07-13  7:56   ` CK Hu
@ 2022-07-26  6:18     ` Rex-BC Chen
  2022-07-26  8:46       ` CK Hu
  0 siblings, 1 reply; 50+ messages in thread
From: Rex-BC Chen @ 2022-07-26  6:18 UTC (permalink / raw)
  To: CK Hu, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Wed, 2022-07-13 at 15:56 +0800, CK Hu wrote:
> Hi, Bo-Chen:
> 
> On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > 
> > This controller is present on several mediatek hardware. Currently
> > mt8195 and mt8395 have this controller without a functional
> > difference,
> > so only one compatible field is added.
> > 
> > The controller can have two forms, as a normal display port and as
> > an
> > embedded display port.
> > 
> > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > ---
> >  .../display/mediatek/mediatek,dp.yaml         | 115
> > ++++++++++++++++++
> >  1 file changed, 115 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
> > 
> > diff --git
> > a/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.ya
> > ml
> > b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.ya
> > ml
> > new file mode 100644
> > index 000000000000..e2d6cb314297
> > --- /dev/null
> > +++
> > b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.ya
> > ml
> > @@ -0,0 +1,115 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: 
> > http://devicetree.org/schemas/display/mediatek/mediatek,dp.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: MediaTek Display Port Controller
> > +
> > +maintainers:
> > +  - Chun-Kuang Hu <chunkuang.hu@kernel.org>
> > +  - Jitao shi <jitao.shi@mediatek.com>
> > +
> > +description: |
> > +  Device tree bindings for the MediaTek display port TX (DP) and
> > +  embedded display port TX (eDP) controller present on some
> > MediaTek
> > SoCs.
> > +  MediaTek DP and eDP are different hardwares and they have
> > different
> > +  base address for registers, so we need two different compatibles
> > to
> > +  separate them.
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - mediatek,mt8195-dp-tx
> > +      - mediatek,mt8195-edp-tx
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  nvmem-cells:
> > +    maxItems: 1
> > +    description: efuse data for display port calibration
> > +
> > +  nvmem-cell-names:
> > +    const: dp_calibration_data
> > +
> > +  power-domains:
> > +    maxItems: 1
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +
> > +  ports:
> > +    $ref: /schemas/graph.yaml#/properties/ports
> > +    properties:
> > +      port@0:
> > +        $ref: /schemas/graph.yaml#/properties/port
> > +        description: Input endpoint of the controller, usually
> > dp_intf
> > +
> > +      port@1:
> > +        $ref: /schemas/graph.yaml#/$defs/port-base
> > +        unevaluatedProperties: false
> > +        description: Output endpoint of the controller
> > +        properties:
> > +          endpoint:
> > +            $ref: /schemas/media/video-interfaces.yaml#
> > +            unevaluatedProperties: false
> > +            properties:
> > +              data-lanes:
> > +                description: |
> > +                  number of lanes supported by the hardware.
> > +                  The possible values:
> > +                  0       - For 1 lane enabled in IP.
> > +                  0 1     - For 2 lanes enabled in IP.
> > +                  0 1 2 3 - For 4 lanes enabled in IP.
> > +                minItems: 1
> > +                maxItems: 4
> > +            required:
> > +              - data-lanes
> > +
> > +    required:
> > +      - port@0
> > +      - port@1
> > +
> > +  max-linkrate-mhz:
> > +    enum: [ 1620, 2700, 5400, 8100 ]
> > +    description: maximum link rate supported by the hardware.
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - ports
> > +  - max-linkrate-mhz
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > +    #include <dt-bindings/power/mt8195-power.h>
> > +    dp_tx@1c600000 {
> > +        compatible = "mediatek,mt8195-dp-tx";
> > +        reg = <0x1c600000 0x8000>;
> > +        power-domains = <&spm MT8195_POWER_DOMAIN_DP_TX>;
> > +        interrupts = <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH 0>;
> > +        max-linkrate-mhz = <8100>;
> 
> Why dp-tx has no clock property? I think this device should work with
> a
> clock.
> 
> Regards,
> CK
> 

Hello CK,

We just need to enable the power domain of dp.
The clock of dp is generated by itself and we are not using the global
pll to generate clocks.

BRs,
Bo-Chen

> > +
> > +        ports {
> > +            #address-cells = <1>;
> > +            #size-cells = <0>;
> > +
> > +            port@0 {
> > +                reg = <0>;
> > +                dptx_in: endpoint {
> > +                    remote-endpoint = <&dp_intf0_out>;
> > +                };
> > +            };
> > +            port@1 {
> > +                reg = <1>;
> > +                dptx_out: endpoint {
> > +                    data-lanes = <0 1 2 3>;
> > +                };
> > +            };
> > +        };
> > +    };
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-25  9:16   ` CK Hu
@ 2022-07-26  6:42     ` Rex-BC Chen
  2022-07-26  9:34       ` CK Hu
  0 siblings, 1 reply; 50+ messages in thread
From: Rex-BC Chen @ 2022-07-26  6:42 UTC (permalink / raw)
  To: CK Hu, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Mon, 2022-07-25 at 17:16 +0800, CK Hu wrote:
> Hi, Bo-Chen:
> 
> On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > 
> > This patch adds a embedded 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 creates a child device for the phy. The child device
> > will
> > never exist without the parent being active. As they are sharing a
> > register range, the parent passes a regmap pointer to the child so
> > that
> > both can work with the same register range. The phy driver sets
> > device
> > data that is read by the parent to get the phy device that can be
> > used
> > to control the phy properties.
> > 
> > This driver is based on an initial version by
> > Jitao shi <jitao.shi@mediatek.com>
> > 
> > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > ---
> 
> [snip]
> 
> > +
> > +static int mtk_dp_training(struct mtk_dp *mtk_dp)
> > +{
> > +	short max_retry = 50;
> > +	int ret;
> > +
> > +	do {
> > +		ret = mtk_dp_train_start(mtk_dp);
> > +		if (!ret)
> > +			break;
> > +		else if (ret != -EAGAIN)
> > +			return ret;
> > +	} while (--max_retry);
> 
> mtk_dp_train_start() would never return -EAGAIN, so drop this while
> loop.
> 
> Regards,
> CK
> 

Hello CK,

the function will not return -EAGAIN, but we still want to retry 50
times if mtk_dp_train_start() is failed. If we retry 50 times and it is
still failed. We can confirm there are some issues for the device.

I will remove the else if of -EAGAIN and keep th while loop.

BRs,
Bo-Chen
> > 
> > +	if (!max_retry)
> > +		return -ETIMEDOUT;
> > +
> > +	ret = mtk_dp_video_config(mtk_dp);
> > +	if (ret)
> > +		return ret;
> > +	mtk_dp_video_enable(mtk_dp, true);
> > +
> > +	return 0;
> > +}
> > +
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-26  3:30     ` Rex-BC Chen
@ 2022-07-26  8:37       ` CK Hu
  0 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-26  8:37 UTC (permalink / raw)
  To: Rex-BC Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Tue, 2022-07-26 at 11:30 +0800, Rex-BC Chen wrote:
> On Mon, 2022-07-25 at 17:23 +0800, CK Hu wrote:
> > Hi, Bo-Chen:
> > 
> > On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > > 
> > > This patch adds a embedded 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 creates a child device for the phy. The child device
> > > will
> > > never exist without the parent being active. As they are sharing
> > > a
> > > register range, the parent passes a regmap pointer to the child
> > > so
> > > that
> > > both can work with the same register range. The phy driver sets
> > > device
> > > data that is read by the parent to get the phy device that can be
> > > used
> > > to control the phy properties.
> > > 
> > > This driver is based on an initial version by
> > > Jitao shi <jitao.shi@mediatek.com>
> > > 
> > > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > > ---
> > 
> > [snip]
> > 
> > > +
> > > +/*
> > > + * We need to handle HPD signal in eDP even though eDP is a
> > > always
> > > connected
> > > + * device. Besides connected status, there is another feature
> > > for
> > > HPD signal -
> > > + * HPD pulse: it presents an IRQ from sink devices to source
> > > devices
> > > (Refer to
> > > + * 5.1.4 of DP1.4 spec).
> > > + */
> > > +static irqreturn_t mtk_dp_hpd_isr_handler(struct mtk_dp *mtk_dp)
> > > +{
> > > +	bool hpd_change = false;
> > > +	u32 irq_status = mtk_dp_swirq_get_clear(mtk_dp) |
> > > +			 mtk_dp_hwirq_get_clear(mtk_dp);
> > > +	struct mtk_dp_train_info *train_info = &mtk_dp->train_info;
> > > +
> > > +	if (!irq_status)
> > > +		return IRQ_HANDLED;
> > > +
> > > +	if (irq_status & MTK_DP_HPD_INTERRUPT)
> > > +		train_info->irq_sta.hpd_inerrupt = true;
> > > +	if (irq_status & MTK_DP_HPD_CONNECT ||
> > > +	    irq_status & MTK_DP_HPD_DISCONNECT)
> > > +		hpd_change = true;
> > > +
> > > +	if (!(hpd_change))
> > > +		return IRQ_WAKE_THREAD;
> > > +
> > > +	if (mtk_dp_plug_state(mtk_dp))
> > 
> > mtk_dp_plug_state() is called only here, and prevent function call
> > in
> > isr handler, so squash mtk_dp_plug_state() into this function.
> > 
> 
> Hello CK,
> 
> Thanks for review.
> 
> I would like to keep this because we will use this function for
> mtk_dp_plug_state_avoid_pulse() in dp patch.

Use train_info->cable_plugged_in instead of calling mtk_dp_plug_state()
because I think train_info->cable_plugged_in is synced with
mtk_dp_plug_state().

> 
> > > +		train_info->cable_plugged_in = true;
> > > +	else
> > > +		train_info->cable_plugged_in = false;
> > > +
> > > +	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);
> > 
> > Prevent function call in isr handler, squash
> > mtk_dp_hpd_isr_handler()
> > into this function.
> > 
> 
> Is this really necessary? We also modify this function in following
> patches. I think it's not a good idea to expand this.

mtk_dp_hpd_isr_handler() is only called in this function, is it really
necessary to separate this to a independent function? The function call
would increase jump instruction and stack push/pop instruction. I think
we should not do many things in isr handler. I've reviewed the later
patch and the later patch should be modified according to this.

Regards,
CK

> 
> BRs,
> Bo-Chen
> 
> > Regards,
> > CK
> > 
> > > +
> > > +	return IRQ_HANDLED;
> > > +}
> > > +
> > 
> > 
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 01/10] dt-bindings: mediatek,dp: Add Display Port binding
  2022-07-26  6:18     ` Rex-BC Chen
@ 2022-07-26  8:46       ` CK Hu
  0 siblings, 0 replies; 50+ messages in thread
From: CK Hu @ 2022-07-26  8:46 UTC (permalink / raw)
  To: Rex-BC Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, jitao.shi, wenst, angelogioacchino.delregno,
	liangxu.xu, dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Tue, 2022-07-26 at 14:18 +0800, Rex-BC Chen wrote:
> On Wed, 2022-07-13 at 15:56 +0800, CK Hu wrote:
> > Hi, Bo-Chen:
> > 
> > On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > > 
> > > This controller is present on several mediatek hardware.
> > > Currently
> > > mt8195 and mt8395 have this controller without a functional
> > > difference,
> > > so only one compatible field is added.
> > > 
> > > The controller can have two forms, as a normal display port and
> > > as
> > > an
> > > embedded display port.
> > > 
> > > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > > ---
> > >  .../display/mediatek/mediatek,dp.yaml         | 115
> > > ++++++++++++++++++
> > >  1 file changed, 115 insertions(+)
> > >  create mode 100644
> > > Documentation/devicetree/bindings/display/mediatek/mediatek,dp.ya
> > > ml
> > > 
> > > diff --git
> > > a/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.
> > > ya
> > > ml
> > > b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.
> > > ya
> > > ml
> > > new file mode 100644
> > > index 000000000000..e2d6cb314297
> > > --- /dev/null
> > > +++
> > > b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.
> > > ya
> > > ml
> > > @@ -0,0 +1,115 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: 
> > > http://devicetree.org/schemas/display/mediatek/mediatek,dp.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: MediaTek Display Port Controller
> > > +
> > > +maintainers:
> > > +  - Chun-Kuang Hu <chunkuang.hu@kernel.org>
> > > +  - Jitao shi <jitao.shi@mediatek.com>
> > > +
> > > +description: |
> > > +  Device tree bindings for the MediaTek display port TX (DP) and
> > > +  embedded display port TX (eDP) controller present on some
> > > MediaTek
> > > SoCs.
> > > +  MediaTek DP and eDP are different hardwares and they have
> > > different
> > > +  base address for registers, so we need two different
> > > compatibles
> > > to
> > > +  separate them.
> > > +
> > > +properties:
> > > +  compatible:
> > > +    enum:
> > > +      - mediatek,mt8195-dp-tx
> > > +      - mediatek,mt8195-edp-tx
> > > +
> > > +  reg:
> > > +    maxItems: 1
> > > +
> > > +  nvmem-cells:
> > > +    maxItems: 1
> > > +    description: efuse data for display port calibration
> > > +
> > > +  nvmem-cell-names:
> > > +    const: dp_calibration_data
> > > +
> > > +  power-domains:
> > > +    maxItems: 1
> > > +
> > > +  interrupts:
> > > +    maxItems: 1
> > > +
> > > +  ports:
> > > +    $ref: /schemas/graph.yaml#/properties/ports
> > > +    properties:
> > > +      port@0:
> > > +        $ref: /schemas/graph.yaml#/properties/port
> > > +        description: Input endpoint of the controller, usually
> > > dp_intf
> > > +
> > > +      port@1:
> > > +        $ref: /schemas/graph.yaml#/$defs/port-base
> > > +        unevaluatedProperties: false
> > > +        description: Output endpoint of the controller
> > > +        properties:
> > > +          endpoint:
> > > +            $ref: /schemas/media/video-interfaces.yaml#
> > > +            unevaluatedProperties: false
> > > +            properties:
> > > +              data-lanes:
> > > +                description: |
> > > +                  number of lanes supported by the hardware.
> > > +                  The possible values:
> > > +                  0       - For 1 lane enabled in IP.
> > > +                  0 1     - For 2 lanes enabled in IP.
> > > +                  0 1 2 3 - For 4 lanes enabled in IP.
> > > +                minItems: 1
> > > +                maxItems: 4
> > > +            required:
> > > +              - data-lanes
> > > +
> > > +    required:
> > > +      - port@0
> > > +      - port@1
> > > +
> > > +  max-linkrate-mhz:
> > > +    enum: [ 1620, 2700, 5400, 8100 ]
> > > +    description: maximum link rate supported by the hardware.
> > > +
> > > +required:
> > > +  - compatible
> > > +  - reg
> > > +  - interrupts
> > > +  - ports
> > > +  - max-linkrate-mhz
> > > +
> > > +additionalProperties: false
> > > +
> > > +examples:
> > > +  - |
> > > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > > +    #include <dt-bindings/power/mt8195-power.h>
> > > +    dp_tx@1c600000 {
> > > +        compatible = "mediatek,mt8195-dp-tx";
> > > +        reg = <0x1c600000 0x8000>;
> > > +        power-domains = <&spm MT8195_POWER_DOMAIN_DP_TX>;
> > > +        interrupts = <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH 0>;
> > > +        max-linkrate-mhz = <8100>;
> > 
> > Why dp-tx has no clock property? I think this device should work
> > with
> > a
> > clock.
> > 
> > Regards,
> > CK
> > 
> 
> Hello CK,
> 
> We just need to enable the power domain of dp.
> The clock of dp is generated by itself and we are not using the
> global
> pll to generate clocks.

Add this to description because this is not trivial.

Regards,
CK

> 
> BRs,
> Bo-Chen
> 
> > > +
> > > +        ports {
> > > +            #address-cells = <1>;
> > > +            #size-cells = <0>;
> > > +
> > > +            port@0 {
> > > +                reg = <0>;
> > > +                dptx_in: endpoint {
> > > +                    remote-endpoint = <&dp_intf0_out>;
> > > +                };
> > > +            };
> > > +            port@1 {
> > > +                reg = <1>;
> > > +                dptx_out: endpoint {
> > > +                    data-lanes = <0 1 2 3>;
> > > +                };
> > > +            };
> > > +        };
> > > +    };
> > 
> > 
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-26  6:42     ` Rex-BC Chen
@ 2022-07-26  9:34       ` CK Hu
  2022-07-26 10:06         ` Rex-BC Chen
  0 siblings, 1 reply; 50+ messages in thread
From: CK Hu @ 2022-07-26  9:34 UTC (permalink / raw)
  To: Rex-BC Chen, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Tue, 2022-07-26 at 14:42 +0800, Rex-BC Chen wrote:
> On Mon, 2022-07-25 at 17:16 +0800, CK Hu wrote:
> > Hi, Bo-Chen:
> > 
> > On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > > 
> > > This patch adds a embedded 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 creates a child device for the phy. The child device
> > > will
> > > never exist without the parent being active. As they are sharing
> > > a
> > > register range, the parent passes a regmap pointer to the child
> > > so
> > > that
> > > both can work with the same register range. The phy driver sets
> > > device
> > > data that is read by the parent to get the phy device that can be
> > > used
> > > to control the phy properties.
> > > 
> > > This driver is based on an initial version by
> > > Jitao shi <jitao.shi@mediatek.com>
> > > 
> > > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > > ---
> > 
> > [snip]
> > 
> > > +
> > > +static int mtk_dp_training(struct mtk_dp *mtk_dp)
> > > +{
> > > +	short max_retry = 50;
> > > +	int ret;
> > > +
> > > +	do {
> > > +		ret = mtk_dp_train_start(mtk_dp);
> > > +		if (!ret)
> > > +			break;
> > > +		else if (ret != -EAGAIN)
> > > +			return ret;
> > > +	} while (--max_retry);
> > 
> > mtk_dp_train_start() would never return -EAGAIN, so drop this while
> > loop.
> > 
> > Regards,
> > CK
> > 
> 
> Hello CK,
> 
> the function will not return -EAGAIN, but we still want to retry 50
> times if mtk_dp_train_start() is failed. If we retry 50 times and it
> is
> still failed. We can confirm there are some issues for the device.
> 
> I will remove the else if of -EAGAIN and keep th while loop.

In this version, it never retry. And I believe you've tested this no-
retry version. If this no-retry version works fine, why do you insist
on retry? If you really need retry, merge this retry into
mtk_dp_train_start() because mtk_dp_train_start() have already retry.

Regards,
CK

> 
> BRs,
> Bo-Chen
> > > 
> > > +	if (!max_retry)
> > > +		return -ETIMEDOUT;
> > > +
> > > +	ret = mtk_dp_video_config(mtk_dp);
> > > +	if (ret)
> > > +		return ret;
> > > +	mtk_dp_video_enable(mtk_dp, true);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > 
> > 
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver
  2022-07-26  9:34       ` CK Hu
@ 2022-07-26 10:06         ` Rex-BC Chen
  0 siblings, 0 replies; 50+ messages in thread
From: Rex-BC Chen @ 2022-07-26 10:06 UTC (permalink / raw)
  To: CK Hu, chunkuang.hu, p.zabel, daniel, robh+dt,
	krzysztof.kozlowski+dt, mripard, tzimmermann, matthias.bgg,
	deller, airlied
  Cc: msp, granquet, Jitao Shi (石记涛),
	wenst, angelogioacchino.delregno, LiangXu Xu (徐亮),
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, linux-fbdev,
	Project_Global_Chrome_Upstream_Group

On Tue, 2022-07-26 at 17:34 +0800, CK Hu wrote:
> On Tue, 2022-07-26 at 14:42 +0800, Rex-BC Chen wrote:
> > On Mon, 2022-07-25 at 17:16 +0800, CK Hu wrote:
> > > Hi, Bo-Chen:
> > > 
> > > On Tue, 2022-07-12 at 19:12 +0800, Bo-Chen Chen wrote:
> > > > From: Markus Schneider-Pargmann <msp@baylibre.com>
> > > > 
> > > > This patch adds a embedded 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 creates a child device for the phy. The child device
> > > > will
> > > > never exist without the parent being active. As they are
> > > > sharing
> > > > a
> > > > register range, the parent passes a regmap pointer to the child
> > > > so
> > > > that
> > > > both can work with the same register range. The phy driver sets
> > > > device
> > > > data that is read by the parent to get the phy device that can
> > > > be
> > > > used
> > > > to control the phy properties.
> > > > 
> > > > This driver is based on an initial version by
> > > > Jitao shi <jitao.shi@mediatek.com>
> > > > 
> > > > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
> > > > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com>
> > > > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
> > > > ---
> > > 
> > > [snip]
> > > 
> > > > +
> > > > +static int mtk_dp_training(struct mtk_dp *mtk_dp)
> > > > +{
> > > > +	short max_retry = 50;
> > > > +	int ret;
> > > > +
> > > > +	do {
> > > > +		ret = mtk_dp_train_start(mtk_dp);
> > > > +		if (!ret)
> > > > +			break;
> > > > +		else if (ret != -EAGAIN)
> > > > +			return ret;
> > > > +	} while (--max_retry);
> > > 
> > > mtk_dp_train_start() would never return -EAGAIN, so drop this
> > > while
> > > loop.
> > > 
> > > Regards,
> > > CK
> > > 
> > 
> > Hello CK,
> > 
> > the function will not return -EAGAIN, but we still want to retry 50
> > times if mtk_dp_train_start() is failed. If we retry 50 times and
> > it
> > is
> > still failed. We can confirm there are some issues for the device.
> > 
> > I will remove the else if of -EAGAIN and keep th while loop.
> 
> In this version, it never retry. And I believe you've tested this no-
> retry version. If this no-retry version works fine, why do you insist
> on retry? If you really need retry, merge this retry into
> mtk_dp_train_start() because mtk_dp_train_start() have already retry.
> 
> Regards,
> CK
> 

Hello Ck,

There are many different devices we are not testing for DP devices.
I think we need to keep this.
This retry is for restart with init state.

I think it's better to keep it here and it's more clear.

I will remain the comments above, and I think it's enough.

BRs,
Bo-Chen

> > 
> > BRs,
> > Bo-Chen
> > > > 
> > > > +	if (!max_retry)
> > > > +		return -ETIMEDOUT;
> > > > +
> > > > +	ret = mtk_dp_video_config(mtk_dp);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +	mtk_dp_video_enable(mtk_dp, true);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > 
> > > 
> > 
> > 
> 
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

end of thread, other threads:[~2022-07-26 10:07 UTC | newest]

Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-12 11:12 [PATCH v14 00/10] drm/mediatek: Add MT8195 DisplayPort driver Bo-Chen Chen
2022-07-12 11:12 ` [PATCH v14 01/10] dt-bindings: mediatek,dp: Add Display Port binding Bo-Chen Chen
2022-07-13  7:56   ` CK Hu
2022-07-26  6:18     ` Rex-BC Chen
2022-07-26  8:46       ` CK Hu
2022-07-18 20:21   ` Rob Herring
2022-07-12 11:12 ` [PATCH v14 02/10] drm/edid: Convert cea_sad helper struct to kernelDoc Bo-Chen Chen
2022-07-12 11:12 ` [PATCH v14 03/10] drm/edid: Add cea_sad helpers for freq/length Bo-Chen Chen
2022-07-14 11:12   ` AngeloGioacchino Del Regno
2022-07-14 11:19     ` Rex-BC Chen
2022-07-12 11:12 ` [PATCH v14 04/10] video/hdmi: Add audio_infoframe packing for DP Bo-Chen Chen
2022-07-14 11:26   ` AngeloGioacchino Del Regno
2022-07-12 11:12 ` [PATCH v14 05/10] drm/mediatek: Add MT8195 Embedded DisplayPort driver Bo-Chen Chen
2022-07-13  8:03   ` CK Hu
2022-07-13  8:10   ` CK Hu
2022-07-14  8:24     ` Rex-BC Chen
2022-07-14 10:21       ` CK Hu
2022-07-13  8:22   ` CK Hu
2022-07-13  8:30   ` CK Hu
2022-07-13  9:12   ` CK Hu
2022-07-13  9:31   ` CK Hu
2022-07-14  8:52     ` Rex-BC Chen
2022-07-13  9:33   ` CK Hu
2022-07-14  8:57     ` Rex-BC Chen
2022-07-13  9:45   ` CK Hu
2022-07-14  6:51   ` CK Hu
2022-07-14  9:09     ` Rex-BC Chen
2022-07-14 10:34       ` CK Hu
2022-07-14  7:06   ` CK Hu
2022-07-15  8:51   ` CK Hu
2022-07-21  2:38     ` Rex-BC Chen
2022-07-21  6:24       ` CK Hu
2022-07-15  9:13   ` CK Hu
2022-07-15  9:14   ` CK Hu
2022-07-15  9:37   ` CK Hu
2022-07-15 18:01   ` kernel test robot
2022-07-25  9:16   ` CK Hu
2022-07-26  6:42     ` Rex-BC Chen
2022-07-26  9:34       ` CK Hu
2022-07-26 10:06         ` Rex-BC Chen
2022-07-25  9:23   ` CK Hu
2022-07-26  3:30     ` Rex-BC Chen
2022-07-26  8:37       ` CK Hu
2022-07-12 11:12 ` [PATCH v14 06/10] drm/mediatek: Add MT8195 External DisplayPort support Bo-Chen Chen
2022-07-25  9:51   ` CK Hu
2022-07-12 11:12 ` [PATCH v14 07/10] drm/mediatek: add hpd debounce Bo-Chen Chen
2022-07-12 11:12 ` [PATCH v14 08/10] drm/mediatek: set monitor to DP_SET_POWER_D3 to avoid garbage Bo-Chen Chen
2022-07-12 11:12 ` [PATCH v14 09/10] drm/mediatek: DP audio support for MT8195 Bo-Chen Chen
2022-07-14 11:43   ` AngeloGioacchino Del Regno
2022-07-12 11:12 ` [PATCH v14 10/10] drm/mediatek: Use cached audio config when changing resolution Bo-Chen Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).