2024-02-06 07:30:47

by Shengyang Chen

[permalink] [raw]
Subject: [PATCH v3 0/2] Add StarFive JH7110 SoC DSI support

This series is the series that attempts to support
the CDNS DSI driver used to converts DPI to DSI.
CDNS DSI is embedded in StarFive JH7110 SoC.
The series has been tested on the VisionFive 2 board.


change since v2:
- Rebased on tag v6.8-rc3.

patch 1:
- Modify commit message and patch subject
- Change 'starfve,jh7110-dsi' to 'starfive,jh7110-dsi'
- Add constraints for reset-names and clock names
- Add resets, reset-names attribute
- Correct reset and clock names

patch 2:
- Modify commit message and patch subject
- Drop useless MAINTAINERS modification
- Change callback name from 'update' to 'mode_fixup'
- Optimize the mode_fixup function.
- Change devm_reset_control_get() to devm_reset_control_get_exclusive()
- Correct reset and clock names

v2: https://patchwork.kernel.org/project/dri-devel/cover/[email protected]/



changes since v1:
- Rebased on tag v6.7.

patch 1:
- Changed the 'starfive,cdns-dsi' to 'starfve,jh7110-dsi'.
- Changed the compatible enum alphabetical order.
- Restrict other variants.
- Drop 'dsi_' prefix.

patch 2:
- Optimize the calculation process.
- Drop useless definition.

v1: https://patchwork.kernel.org/project/dri-devel/cover/[email protected]/

Keith Zhao (2):
dt-bindings: display: bridge: cdns: Add display bridge support for dsi
on StarFive JH7110 SoC
drm/bridge: cdns-dsi: Add support for StarFive JH7110 SoC

.../bindings/display/bridge/cdns,dsi.yaml | 56 ++++-
drivers/gpu/drm/bridge/cadence/Kconfig | 7 +
drivers/gpu/drm/bridge/cadence/Makefile | 1 +
.../gpu/drm/bridge/cadence/cdns-dsi-core.c | 29 ++-
.../gpu/drm/bridge/cadence/cdns-dsi-core.h | 21 ++
.../gpu/drm/bridge/cadence/cdns-dsi-jh7110.c | 193 ++++++++++++++++++
.../gpu/drm/bridge/cadence/cdns-dsi-jh7110.h | 16 ++
7 files changed, 320 insertions(+), 3 deletions(-)
create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c
create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h

--
2.17.1



2024-02-06 07:31:18

by Shengyang Chen

[permalink] [raw]
Subject: [PATCH v3 1/2] dt-bindings: display: bridge: cdns: Add display bridge support for dsi on StarFive JH7110 SoC

From: Keith Zhao <[email protected]>

Add compatible to support dsi bridge on StarFive JH7110 SoC

Signed-off-by: Keith Zhao <[email protected]>
Signed-off-by: Shengyang Chen <[email protected]>
---
.../bindings/display/bridge/cdns,dsi.yaml | 56 ++++++++++++++++++-
1 file changed, 54 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/cdns,dsi.yaml b/Documentation/devicetree/bindings/display/bridge/cdns,dsi.yaml
index 23060324d16e..4ad0ecaacaae 100644
--- a/Documentation/devicetree/bindings/display/bridge/cdns,dsi.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/cdns,dsi.yaml
@@ -16,6 +16,7 @@ properties:
compatible:
enum:
- cdns,dsi
+ - starfive,jh7110-dsi
- ti,j721e-dsi

reg:
@@ -27,14 +28,20 @@ properties:
Register block for wrapper settings registers in case of TI J7 SoCs.

clocks:
+ minItems: 2
items:
- description: PSM clock, used by the IP
- description: sys clock, used by the IP
+ - description: dpi clock, used by the IP
+ - description: txesc clock, used by the IP

clock-names:
+ minItems: 2
items:
- const: dsi_p_clk
- const: dsi_sys_clk
+ - const: dpi
+ - const: txesc

phys:
maxItems: 1
@@ -46,10 +53,22 @@ properties:
maxItems: 1

resets:
- maxItems: 1
+ minItems: 1
+ items:
+ - description: apb reset, associated to dsi_p_clk
+ - description: sys reset, associated to sys clock
+ - description: dpi reset, associated to dpi clock
+ - description: txesc reset, associated to txesc clock
+ - description: txbytehs reset, associated to txbytehs clock

reset-names:
- const: dsi_p_rst
+ minItems: 1
+ items:
+ - const: dsi_p_rst
+ - const: sys
+ - const: dpi
+ - const: txesc
+ - const: txbytehs

ports:
$ref: /schemas/graph.yaml#/properties/ports
@@ -90,6 +109,39 @@ allOf:
reg:
maxItems: 1

+ - if:
+ properties:
+ compatible:
+ contains:
+ const: starfive,jh7110-dsi
+ then:
+ properties:
+ clocks:
+ minItems: 4
+ maxItems: 4
+ clock-names:
+ minItems: 4
+ maxItems: 4
+ resets:
+ minItems: 5
+ maxItems: 5
+ reset-names:
+ minItems: 5
+ maxItems: 5
+ required:
+ - resets
+ - reset-names
+ else:
+ properties:
+ clocks:
+ maxItems: 2
+ clock-names:
+ maxItems: 2
+ resets:
+ maxItems: 1
+ reset-names:
+ maxItems: 1
+
required:
- compatible
- reg
--
2.17.1


2024-02-06 07:32:02

by Shengyang Chen

[permalink] [raw]
Subject: [PATCH v3 2/2] drm/bridge: cdns-dsi: Add support for StarFive JH7110 SoC

From: Keith Zhao <[email protected]>

Add display bridge support for dsi on StarFive JH7110 SoC.

The mainly modification is followed:
1.Add extra clock and reset operation for JH7110.
2.Add callback for JH7110.

Signed-off-by: Keith Zhao <[email protected]>
Signed-off-by: Shengyang Chen <[email protected]>
---
drivers/gpu/drm/bridge/cadence/Kconfig | 7 +
drivers/gpu/drm/bridge/cadence/Makefile | 1 +
.../gpu/drm/bridge/cadence/cdns-dsi-core.c | 29 ++-
.../gpu/drm/bridge/cadence/cdns-dsi-core.h | 21 ++
.../gpu/drm/bridge/cadence/cdns-dsi-jh7110.c | 193 ++++++++++++++++++
.../gpu/drm/bridge/cadence/cdns-dsi-jh7110.h | 16 ++
6 files changed, 266 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c
create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h

diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig
index cced81633ddc..ad9f572f4720 100644
--- a/drivers/gpu/drm/bridge/cadence/Kconfig
+++ b/drivers/gpu/drm/bridge/cadence/Kconfig
@@ -19,6 +19,13 @@ config DRM_CDNS_DSI_J721E
help
Support J721E Cadence DSI wrapper. The wrapper manages
the routing of the DSS DPI signal to the Cadence DSI.
+
+config DRM_CDNS_DSI_JH7110
+ bool "JH7110 SOC Cadence DSI support"
+ default n
+ help
+ Cadence DPI to DSI bridge which is embedded in the
+ StarFive JH7110 SoC.
endif

config DRM_CDNS_MHDP8546
diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile
index c95fd5b81d13..87f603a9f4ad 100644
--- a/drivers/gpu/drm/bridge/cadence/Makefile
+++ b/drivers/gpu/drm/bridge/cadence/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
cdns-dsi-y := cdns-dsi-core.o
cdns-dsi-$(CONFIG_DRM_CDNS_DSI_J721E) += cdns-dsi-j721e.o
+cdns-dsi-$(CONFIG_DRM_CDNS_DSI_JH7110) += cdns-dsi-jh7110.o
obj-$(CONFIG_DRM_CDNS_MHDP8546) += cdns-mhdp8546.o
cdns-mhdp8546-y := cdns-mhdp8546-core.o cdns-mhdp8546-hdcp.o
cdns-mhdp8546-$(CONFIG_DRM_CDNS_MHDP8546_J721E) += cdns-mhdp8546-j721e.o
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index 7457d38622b0..c0c81745e765 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -27,6 +27,10 @@
#include "cdns-dsi-j721e.h"
#endif

+#ifdef CONFIG_DRM_CDNS_DSI_JH7110
+#include "cdns-dsi-jh7110.h"
+#endif
+
#define IP_CONF 0x0
#define SP_HS_FIFO_DEPTH(x) (((x) & GENMASK(30, 26)) >> 26)
#define SP_LP_FIFO_DEPTH(x) (((x) & GENMASK(25, 21)) >> 21)
@@ -552,6 +556,10 @@ static int cdns_dsi_adjust_phy_config(struct cdns_dsi *dsi,
/* data rate was in bytes/sec, convert to bits/sec. */
phy_cfg->hs_clk_rate = dlane_bps * 8;

+ if (dsi->platform_ops && dsi->platform_ops->mode_fixup)
+ adj_dsi_htotal = dsi->platform_ops->mode_fixup(dsi, dsi_cfg, phy_cfg,
+ dpi_hz, dpi_htotal, dsi_htotal);
+
dsi_hfp_ext = adj_dsi_htotal - dsi_htotal;
dsi_cfg->hfp += dsi_hfp_ext;
dsi_cfg->htotal = dsi_htotal + dsi_hfp_ext;
@@ -683,7 +691,7 @@ static void cdns_dsi_bridge_post_disable(struct drm_bridge *bridge)
pm_runtime_put(dsi->base.dev);
}

-static void cdns_dsi_hs_init(struct cdns_dsi *dsi)
+void cdns_dsi_hs_init(struct cdns_dsi *dsi)
{
struct cdns_dsi_output *output = &dsi->output;
u32 status;
@@ -1026,6 +1034,14 @@ static ssize_t cdns_dsi_transfer(struct mipi_dsi_host *host,

cdns_dsi_init_link(dsi);

+ /*
+ * on JH7110 SoC , when transfer dsi command ,
+ * cdns_dsi_hs_init is needed.
+ * or the final ret will be error value.
+ */
+ if (dsi->platform_ops && dsi->platform_ops->transfer)
+ dsi->platform_ops->transfer(dsi);
+
ret = mipi_dsi_create_packet(&packet, msg);
if (ret)
goto out;
@@ -1142,6 +1158,9 @@ static int __maybe_unused cdns_dsi_resume(struct device *dev)
clk_prepare_enable(dsi->dsi_p_clk);
clk_prepare_enable(dsi->dsi_sys_clk);

+ if (dsi->platform_ops && dsi->platform_ops->resume)
+ dsi->platform_ops->resume(dsi);
+
return 0;
}

@@ -1152,6 +1171,10 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev)
clk_disable_unprepare(dsi->dsi_sys_clk);
clk_disable_unprepare(dsi->dsi_p_clk);
reset_control_assert(dsi->dsi_p_rst);
+
+ if (dsi->platform_ops && dsi->platform_ops->suspend)
+ dsi->platform_ops->suspend(dsi);
+
dsi->link_initialized = false;
return 0;
}
@@ -1294,6 +1317,10 @@ static const struct of_device_id cdns_dsi_of_match[] = {
#ifdef CONFIG_DRM_CDNS_DSI_J721E
{ .compatible = "ti,j721e-dsi", .data = &dsi_ti_j721e_ops, },
#endif
+#ifdef CONFIG_DRM_CDNS_DSI_JH7110
+ { .compatible = "starfive,jh7110-dsi", .data = &dsi_ti_jh7110_ops, },
+#endif
+
{ },
};
MODULE_DEVICE_TABLE(of, cdns_dsi_of_match);
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
index ca7ea2da635c..0a86495ead7b 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
@@ -53,12 +53,22 @@ struct cdns_dsi;
* @deinit: Called in the CDNS DSI remove
* @enable: Called at the beginning of CDNS DSI bridge enable
* @disable: Called at the end of CDNS DSI bridge disable
+ * @resume: Called at the resume of CDNS DSI
+ * @suspend: Called at the suspend of CDNS DSI
+ * @update: Called at the middle of CDNS DSI bridge enable
*/
struct cdns_dsi_platform_ops {
int (*init)(struct cdns_dsi *dsi);
void (*deinit)(struct cdns_dsi *dsi);
void (*enable)(struct cdns_dsi *dsi);
void (*disable)(struct cdns_dsi *dsi);
+ void (*resume)(struct cdns_dsi *dsi);
+ void (*suspend)(struct cdns_dsi *dsi);
+ int (*mode_fixup)(struct cdns_dsi *dsi, struct cdns_dsi_cfg *dsi_cfg,
+ struct phy_configure_opts_mipi_dphy *phy_cfg,
+ unsigned long dpi_hz, unsigned long dpi_htotal,
+ unsigned long dsi_htotal);
+ void (*transfer)(struct cdns_dsi *dsi);
};

struct cdns_dsi {
@@ -79,6 +89,17 @@ struct cdns_dsi {
bool link_initialized;
bool phy_initialized;
struct phy *dphy;
+
+#ifdef CONFIG_DRM_CDNS_DSI_JH7110
+ struct clk *dpi_clk;
+ struct clk *txesc_clk;
+ struct reset_control *dpi_rst;
+ struct reset_control *sys_rst;
+ struct reset_control *txesc_rst;
+ struct reset_control *txbytehs_rst;
+#endif
};

+void cdns_dsi_hs_init(struct cdns_dsi *dsi);
+
#endif /* !__CDNS_DSI_H__ */
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c
new file mode 100644
index 000000000000..c6b9296a9275
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * JH7110 SoC Cadence DSI wrapper
+ *
+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/reset.h>
+
+#include "cdns-dsi-jh7110.h"
+
+static int cdns_dsi_clock_enable(struct cdns_dsi *dsi, struct device *dev)
+{
+ int ret;
+
+ ret = clk_prepare_enable(dsi->dpi_clk);
+ if (ret) {
+ dev_err(dev, "Failed to prepare/enable dpi_clk\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(dsi->txesc_clk);
+ if (ret) {
+ dev_err(dev, "Failed to prepare/enable txesc_clk\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static void cdns_dsi_clock_disable(struct cdns_dsi *dsi)
+{
+ clk_disable_unprepare(dsi->dpi_clk);
+ clk_disable_unprepare(dsi->txesc_clk);
+}
+
+static int cdns_dsi_resets_deassert(struct cdns_dsi *dsi, struct device *dev)
+{
+ int ret;
+
+ ret = reset_control_deassert(dsi->dpi_rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to deassert dpi_rst\n");
+ return ret;
+ }
+
+ ret = reset_control_deassert(dsi->txesc_rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to deassert txesc_rst\n");
+ return ret;
+ }
+
+ ret = reset_control_deassert(dsi->sys_rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to deassert sys_rst\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int cdns_dsi_resets_assert(struct cdns_dsi *dsi, struct device *dev)
+{
+ int ret;
+
+ ret = reset_control_assert(dsi->dpi_rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to assert dpi_rst\n");
+ return ret;
+ }
+
+ ret = reset_control_assert(dsi->txesc_rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to assert txesc_rst\n");
+ return ret;
+ }
+
+ ret = reset_control_assert(dsi->sys_rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to assert sys_rst\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int cdns_dsi_get_clock(struct device *dev, struct cdns_dsi *dsi)
+{
+ dsi->dpi_clk = devm_clk_get(dev, "dpi");
+ if (IS_ERR(dsi->dpi_clk))
+ return PTR_ERR(dsi->dpi_clk);
+
+ dsi->txesc_clk = devm_clk_get(dev, "txesc");
+ if (IS_ERR(dsi->txesc_clk))
+ return PTR_ERR(dsi->txesc_clk);
+
+ return 0;
+}
+
+static int cdns_dsi_get_reset(struct device *dev, struct cdns_dsi *dsi)
+{
+ dsi->sys_rst = devm_reset_control_get_exclusive(dev, "sys");
+ if (IS_ERR(dsi->sys_rst))
+ return PTR_ERR(dsi->sys_rst);
+
+ dsi->dpi_rst = devm_reset_control_get_exclusive(dev, "dpi");
+ if (IS_ERR(dsi->dpi_rst))
+ return PTR_ERR(dsi->dpi_rst);
+
+ dsi->txesc_rst = devm_reset_control_get_exclusive(dev, "txesc");
+ if (IS_ERR(dsi->txesc_rst))
+ return PTR_ERR(dsi->txesc_rst);
+
+ dsi->txbytehs_rst = devm_reset_control_get_exclusive(dev, "txbytehs");
+ if (IS_ERR(dsi->txbytehs_rst))
+ return PTR_ERR(dsi->txbytehs_rst);
+
+ return 0;
+}
+
+static int cdns_dsi_jh7110_init(struct cdns_dsi *dsi)
+{
+ int ret;
+
+ ret = cdns_dsi_get_clock(dsi->base.dev, dsi);
+ if (ret)
+ return ret;
+
+ return cdns_dsi_get_reset(dsi->base.dev, dsi);
+}
+
+static void cdns_dsi_jh7110_resume(struct cdns_dsi *dsi)
+{
+ int ret;
+
+ ret = cdns_dsi_clock_enable(dsi, dsi->base.dev);
+ if (ret) {
+ dev_err(dsi->base.dev, "failed to enable clock\n");
+ return;
+ }
+ ret = cdns_dsi_resets_deassert(dsi, dsi->base.dev);
+ if (ret < 0) {
+ dev_err(dsi->base.dev, "failed to deassert reset\n");
+ return;
+ }
+}
+
+static void cdns_dsi_jh7110_suspend(struct cdns_dsi *dsi)
+{
+ int ret;
+
+ ret = cdns_dsi_resets_assert(dsi, dsi->base.dev);
+ if (ret < 0) {
+ dev_err(dsi->base.dev, "failed to deassert reset\n");
+ return;
+ }
+
+ cdns_dsi_clock_disable(dsi);
+}
+
+static int cdns_dsi_jh7110_mode_fixup(struct cdns_dsi *dsi, struct cdns_dsi_cfg *dsi_cfg,
+ struct phy_configure_opts_mipi_dphy *phy_cfg,
+ unsigned long dpi_hz, unsigned long dpi_htotal,
+ unsigned long dsi_htotal)
+{
+ unsigned long long dlane_bps;
+ unsigned long adj_dsi_htotal;
+ unsigned int lanes = dsi->output.dev->lanes;
+
+ phy_cfg->hs_clk_rate = phy_cfg->hs_clk_rate - (phy_cfg->hs_clk_rate % 10000000);
+ phy_cfg->hs_clk_rate += 100000000;
+ dlane_bps = phy_cfg->hs_clk_rate * lanes * dpi_htotal / 8;
+ adj_dsi_htotal = dlane_bps / dpi_hz;
+
+ return adj_dsi_htotal;
+}
+
+static void jh7110_cdns_dsi_hs_init(struct cdns_dsi *dsi)
+{
+ cdns_dsi_hs_init(dsi);
+ reset_control_deassert(dsi->txbytehs_rst);
+}
+
+const struct cdns_dsi_platform_ops dsi_ti_jh7110_ops = {
+ .init = cdns_dsi_jh7110_init,
+ .resume = cdns_dsi_jh7110_resume,
+ .suspend = cdns_dsi_jh7110_suspend,
+ .mode_fixup = cdns_dsi_jh7110_mode_fixup,
+ .transfer = jh7110_cdns_dsi_hs_init,
+};
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h b/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h
new file mode 100644
index 000000000000..15d6a766b502
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * JH7110 Cadence DSI
+ *
+ * Copyright (C) 2022-2023 StarFive Technology Co., Ltd.
+ * Author: keith.zhao <[email protected]>
+ */
+
+#ifndef __CDNS_DSI_JH7110_H__
+#define __CDNS_DSI_JH7110_H__
+
+#include "cdns-dsi-core.h"
+
+extern const struct cdns_dsi_platform_ops dsi_ti_jh7110_ops;
+
+#endif /* !__CDNS_DSI_JH7110_H__ */
--
2.17.1


2024-02-06 16:16:16

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v3 1/2] dt-bindings: display: bridge: cdns: Add display bridge support for dsi on StarFive JH7110 SoC

On Tue, Feb 06, 2024 at 02:57:08PM +0800, Shengyang Chen wrote:
> From: Keith Zhao <[email protected]>
>
> Add compatible to support dsi bridge on StarFive JH7110 SoC
>
> Signed-off-by: Keith Zhao <[email protected]>
> Signed-off-by: Shengyang Chen <[email protected]>

Reviewed-by: Conor Dooley <[email protected]>

Cheers,
Conor.


Attachments:
(No filename) (389.00 B)
signature.asc (235.00 B)
Download all attachments

2024-02-07 10:58:04

by Dmitry Baryshkov

[permalink] [raw]
Subject: Re: [PATCH v3 2/2] drm/bridge: cdns-dsi: Add support for StarFive JH7110 SoC

On Tue, 6 Feb 2024 at 08:57, Shengyang Chen
<[email protected]> wrote:
>
> From: Keith Zhao <[email protected]>
>
> Add display bridge support for dsi on StarFive JH7110 SoC.
>
> The mainly modification is followed:
> 1.Add extra clock and reset operation for JH7110.
> 2.Add callback for JH7110.
>
> Signed-off-by: Keith Zhao <[email protected]>
> Signed-off-by: Shengyang Chen <[email protected]>
> ---
> drivers/gpu/drm/bridge/cadence/Kconfig | 7 +
> drivers/gpu/drm/bridge/cadence/Makefile | 1 +
> .../gpu/drm/bridge/cadence/cdns-dsi-core.c | 29 ++-
> .../gpu/drm/bridge/cadence/cdns-dsi-core.h | 21 ++
> .../gpu/drm/bridge/cadence/cdns-dsi-jh7110.c | 193 ++++++++++++++++++
> .../gpu/drm/bridge/cadence/cdns-dsi-jh7110.h | 16 ++
> 6 files changed, 266 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c
> create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h
>
> diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig
> index cced81633ddc..ad9f572f4720 100644
> --- a/drivers/gpu/drm/bridge/cadence/Kconfig
> +++ b/drivers/gpu/drm/bridge/cadence/Kconfig
> @@ -19,6 +19,13 @@ config DRM_CDNS_DSI_J721E
> help
> Support J721E Cadence DSI wrapper. The wrapper manages
> the routing of the DSS DPI signal to the Cadence DSI.
> +
> +config DRM_CDNS_DSI_JH7110
> + bool "JH7110 SOC Cadence DSI support"
> + default n
> + help
> + Cadence DPI to DSI bridge which is embedded in the
> + StarFive JH7110 SoC.
> endif
>
> config DRM_CDNS_MHDP8546
> diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile
> index c95fd5b81d13..87f603a9f4ad 100644
> --- a/drivers/gpu/drm/bridge/cadence/Makefile
> +++ b/drivers/gpu/drm/bridge/cadence/Makefile
> @@ -2,6 +2,7 @@
> obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
> cdns-dsi-y := cdns-dsi-core.o
> cdns-dsi-$(CONFIG_DRM_CDNS_DSI_J721E) += cdns-dsi-j721e.o
> +cdns-dsi-$(CONFIG_DRM_CDNS_DSI_JH7110) += cdns-dsi-jh7110.o
> obj-$(CONFIG_DRM_CDNS_MHDP8546) += cdns-mhdp8546.o
> cdns-mhdp8546-y := cdns-mhdp8546-core.o cdns-mhdp8546-hdcp.o
> cdns-mhdp8546-$(CONFIG_DRM_CDNS_MHDP8546_J721E) += cdns-mhdp8546-j721e.o
> diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
> index 7457d38622b0..c0c81745e765 100644
> --- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
> +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
> @@ -27,6 +27,10 @@
> #include "cdns-dsi-j721e.h"
> #endif
>
> +#ifdef CONFIG_DRM_CDNS_DSI_JH7110
> +#include "cdns-dsi-jh7110.h"
> +#endif
> +
> #define IP_CONF 0x0
> #define SP_HS_FIFO_DEPTH(x) (((x) & GENMASK(30, 26)) >> 26)
> #define SP_LP_FIFO_DEPTH(x) (((x) & GENMASK(25, 21)) >> 21)
> @@ -552,6 +556,10 @@ static int cdns_dsi_adjust_phy_config(struct cdns_dsi *dsi,
> /* data rate was in bytes/sec, convert to bits/sec. */
> phy_cfg->hs_clk_rate = dlane_bps * 8;
>
> + if (dsi->platform_ops && dsi->platform_ops->mode_fixup)
> + adj_dsi_htotal = dsi->platform_ops->mode_fixup(dsi, dsi_cfg, phy_cfg,
> + dpi_hz, dpi_htotal, dsi_htotal);
> +
> dsi_hfp_ext = adj_dsi_htotal - dsi_htotal;
> dsi_cfg->hfp += dsi_hfp_ext;
> dsi_cfg->htotal = dsi_htotal + dsi_hfp_ext;
> @@ -683,7 +691,7 @@ static void cdns_dsi_bridge_post_disable(struct drm_bridge *bridge)
> pm_runtime_put(dsi->base.dev);
> }
>
> -static void cdns_dsi_hs_init(struct cdns_dsi *dsi)
> +void cdns_dsi_hs_init(struct cdns_dsi *dsi)
> {
> struct cdns_dsi_output *output = &dsi->output;
> u32 status;
> @@ -1026,6 +1034,14 @@ static ssize_t cdns_dsi_transfer(struct mipi_dsi_host *host,
>
> cdns_dsi_init_link(dsi);
>
> + /*
> + * on JH7110 SoC , when transfer dsi command ,
> + * cdns_dsi_hs_init is needed.
> + * or the final ret will be error value.
> + */
> + if (dsi->platform_ops && dsi->platform_ops->transfer)
> + dsi->platform_ops->transfer(dsi);
> +
> ret = mipi_dsi_create_packet(&packet, msg);
> if (ret)
> goto out;
> @@ -1142,6 +1158,9 @@ static int __maybe_unused cdns_dsi_resume(struct device *dev)
> clk_prepare_enable(dsi->dsi_p_clk);
> clk_prepare_enable(dsi->dsi_sys_clk);
>
> + if (dsi->platform_ops && dsi->platform_ops->resume)
> + dsi->platform_ops->resume(dsi);
> +
> return 0;
> }
>
> @@ -1152,6 +1171,10 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev)
> clk_disable_unprepare(dsi->dsi_sys_clk);
> clk_disable_unprepare(dsi->dsi_p_clk);
> reset_control_assert(dsi->dsi_p_rst);
> +
> + if (dsi->platform_ops && dsi->platform_ops->suspend)
> + dsi->platform_ops->suspend(dsi);
> +
> dsi->link_initialized = false;
> return 0;
> }
> @@ -1294,6 +1317,10 @@ static const struct of_device_id cdns_dsi_of_match[] = {
> #ifdef CONFIG_DRM_CDNS_DSI_J721E
> { .compatible = "ti,j721e-dsi", .data = &dsi_ti_j721e_ops, },
> #endif
> +#ifdef CONFIG_DRM_CDNS_DSI_JH7110
> + { .compatible = "starfive,jh7110-dsi", .data = &dsi_ti_jh7110_ops, },
> +#endif
> +
> { },
> };
> MODULE_DEVICE_TABLE(of, cdns_dsi_of_match);
> diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
> index ca7ea2da635c..0a86495ead7b 100644
> --- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
> +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
> @@ -53,12 +53,22 @@ struct cdns_dsi;
> * @deinit: Called in the CDNS DSI remove
> * @enable: Called at the beginning of CDNS DSI bridge enable
> * @disable: Called at the end of CDNS DSI bridge disable
> + * @resume: Called at the resume of CDNS DSI
> + * @suspend: Called at the suspend of CDNS DSI
> + * @update: Called at the middle of CDNS DSI bridge enable
> */
> struct cdns_dsi_platform_ops {
> int (*init)(struct cdns_dsi *dsi);
> void (*deinit)(struct cdns_dsi *dsi);
> void (*enable)(struct cdns_dsi *dsi);
> void (*disable)(struct cdns_dsi *dsi);
> + void (*resume)(struct cdns_dsi *dsi);
> + void (*suspend)(struct cdns_dsi *dsi);
> + int (*mode_fixup)(struct cdns_dsi *dsi, struct cdns_dsi_cfg *dsi_cfg,
> + struct phy_configure_opts_mipi_dphy *phy_cfg,
> + unsigned long dpi_hz, unsigned long dpi_htotal,
> + unsigned long dsi_htotal);
> + void (*transfer)(struct cdns_dsi *dsi);
> };
>
> struct cdns_dsi {
> @@ -79,6 +89,17 @@ struct cdns_dsi {
> bool link_initialized;
> bool phy_initialized;
> struct phy *dphy;
> +
> +#ifdef CONFIG_DRM_CDNS_DSI_JH7110
> + struct clk *dpi_clk;
> + struct clk *txesc_clk;
> + struct reset_control *dpi_rst;
> + struct reset_control *sys_rst;
> + struct reset_control *txesc_rst;
> + struct reset_control *txbytehs_rst;
> +#endif
> };
>
> +void cdns_dsi_hs_init(struct cdns_dsi *dsi);
> +
> #endif /* !__CDNS_DSI_H__ */
> diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c
> new file mode 100644
> index 000000000000..c6b9296a9275
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c
> @@ -0,0 +1,193 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * JH7110 SoC Cadence DSI wrapper
> + *
> + * Copyright (C) 2023 StarFive Technology Co., Ltd.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/reset.h>
> +
> +#include "cdns-dsi-jh7110.h"
> +
> +static int cdns_dsi_clock_enable(struct cdns_dsi *dsi, struct device *dev)
> +{
> + int ret;
> +
> + ret = clk_prepare_enable(dsi->dpi_clk);
> + if (ret) {
> + dev_err(dev, "Failed to prepare/enable dpi_clk\n");
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(dsi->txesc_clk);
> + if (ret) {
> + dev_err(dev, "Failed to prepare/enable txesc_clk\n");
> + return ret;
> + }
> +
> + return ret;
> +}
> +
> +static void cdns_dsi_clock_disable(struct cdns_dsi *dsi)
> +{
> + clk_disable_unprepare(dsi->dpi_clk);
> + clk_disable_unprepare(dsi->txesc_clk);

Please use clk_bulk_ API and inline these two functions.

> +}
> +
> +static int cdns_dsi_resets_deassert(struct cdns_dsi *dsi, struct device *dev)
> +{
> + int ret;
> +
> + ret = reset_control_deassert(dsi->dpi_rst);
> + if (ret < 0) {
> + dev_err(dev, "failed to deassert dpi_rst\n");
> + return ret;
> + }
> +
> + ret = reset_control_deassert(dsi->txesc_rst);
> + if (ret < 0) {
> + dev_err(dev, "failed to deassert txesc_rst\n");
> + return ret;
> + }
> +
> + ret = reset_control_deassert(dsi->sys_rst);
> + if (ret < 0) {
> + dev_err(dev, "failed to deassert sys_rst\n");
> + return ret;
> + }

Same, please use reset_control_bulk API.

> +
> + return ret;
> +}
> +
> +static int cdns_dsi_resets_assert(struct cdns_dsi *dsi, struct device *dev)
> +{
> + int ret;
> +
> + ret = reset_control_assert(dsi->dpi_rst);
> + if (ret < 0) {
> + dev_err(dev, "failed to assert dpi_rst\n");
> + return ret;
> + }
> +
> + ret = reset_control_assert(dsi->txesc_rst);
> + if (ret < 0) {
> + dev_err(dev, "failed to assert txesc_rst\n");
> + return ret;
> + }
> +
> + ret = reset_control_assert(dsi->sys_rst);
> + if (ret < 0) {
> + dev_err(dev, "failed to assert sys_rst\n");
> + return ret;
> + }
> +
> + return ret;
> +}
> +
> +static int cdns_dsi_get_clock(struct device *dev, struct cdns_dsi *dsi)
> +{
> + dsi->dpi_clk = devm_clk_get(dev, "dpi");
> + if (IS_ERR(dsi->dpi_clk))
> + return PTR_ERR(dsi->dpi_clk);
> +
> + dsi->txesc_clk = devm_clk_get(dev, "txesc");
> + if (IS_ERR(dsi->txesc_clk))
> + return PTR_ERR(dsi->txesc_clk);
> +
> + return 0;
> +}
> +
> +static int cdns_dsi_get_reset(struct device *dev, struct cdns_dsi *dsi)
> +{
> + dsi->sys_rst = devm_reset_control_get_exclusive(dev, "sys");
> + if (IS_ERR(dsi->sys_rst))
> + return PTR_ERR(dsi->sys_rst);
> +
> + dsi->dpi_rst = devm_reset_control_get_exclusive(dev, "dpi");
> + if (IS_ERR(dsi->dpi_rst))
> + return PTR_ERR(dsi->dpi_rst);
> +
> + dsi->txesc_rst = devm_reset_control_get_exclusive(dev, "txesc");
> + if (IS_ERR(dsi->txesc_rst))
> + return PTR_ERR(dsi->txesc_rst);
> +
> + dsi->txbytehs_rst = devm_reset_control_get_exclusive(dev, "txbytehs");
> + if (IS_ERR(dsi->txbytehs_rst))
> + return PTR_ERR(dsi->txbytehs_rst);
> +
> + return 0;
> +}
> +
> +static int cdns_dsi_jh7110_init(struct cdns_dsi *dsi)
> +{
> + int ret;
> +
> + ret = cdns_dsi_get_clock(dsi->base.dev, dsi);
> + if (ret)
> + return ret;
> +
> + return cdns_dsi_get_reset(dsi->base.dev, dsi);
> +}
> +
> +static void cdns_dsi_jh7110_resume(struct cdns_dsi *dsi)
> +{
> + int ret;
> +
> + ret = cdns_dsi_clock_enable(dsi, dsi->base.dev);
> + if (ret) {
> + dev_err(dsi->base.dev, "failed to enable clock\n");
> + return;
> + }
> + ret = cdns_dsi_resets_deassert(dsi, dsi->base.dev);
> + if (ret < 0) {
> + dev_err(dsi->base.dev, "failed to deassert reset\n");
> + return;
> + }
> +}
> +
> +static void cdns_dsi_jh7110_suspend(struct cdns_dsi *dsi)
> +{
> + int ret;
> +
> + ret = cdns_dsi_resets_assert(dsi, dsi->base.dev);
> + if (ret < 0) {
> + dev_err(dsi->base.dev, "failed to deassert reset\n");
> + return;
> + }
> +
> + cdns_dsi_clock_disable(dsi);
> +}
> +
> +static int cdns_dsi_jh7110_mode_fixup(struct cdns_dsi *dsi, struct cdns_dsi_cfg *dsi_cfg,
> + struct phy_configure_opts_mipi_dphy *phy_cfg,
> + unsigned long dpi_hz, unsigned long dpi_htotal,
> + unsigned long dsi_htotal)
> +{
> + unsigned long long dlane_bps;
> + unsigned long adj_dsi_htotal;
> + unsigned int lanes = dsi->output.dev->lanes;
> +
> + phy_cfg->hs_clk_rate = phy_cfg->hs_clk_rate - (phy_cfg->hs_clk_rate % 10000000);
> + phy_cfg->hs_clk_rate += 100000000;

phy_cfg->hs_clk_rate = roundup(phy_cfg->hs_clk_rate, 100000000);

> + dlane_bps = phy_cfg->hs_clk_rate * lanes * dpi_htotal / 8;
> + adj_dsi_htotal = dlane_bps / dpi_hz;
> +
> + return adj_dsi_htotal;
> +}
> +
> +static void jh7110_cdns_dsi_hs_init(struct cdns_dsi *dsi)
> +{
> + cdns_dsi_hs_init(dsi);
> + reset_control_deassert(dsi->txbytehs_rst);

Is a single deassert enough here? Which funciion asserts the reset?

> +}
> +
> +const struct cdns_dsi_platform_ops dsi_ti_jh7110_ops = {
> + .init = cdns_dsi_jh7110_init,
> + .resume = cdns_dsi_jh7110_resume,
> + .suspend = cdns_dsi_jh7110_suspend,
> + .mode_fixup = cdns_dsi_jh7110_mode_fixup,
> + .transfer = jh7110_cdns_dsi_hs_init,
> +};
> diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h b/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h
> new file mode 100644
> index 000000000000..15d6a766b502
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * JH7110 Cadence DSI
> + *
> + * Copyright (C) 2022-2023 StarFive Technology Co., Ltd.
> + * Author: keith.zhao <[email protected]>
> + */
> +
> +#ifndef __CDNS_DSI_JH7110_H__
> +#define __CDNS_DSI_JH7110_H__
> +
> +#include "cdns-dsi-core.h"
> +
> +extern const struct cdns_dsi_platform_ops dsi_ti_jh7110_ops;
> +
> +#endif /* !__CDNS_DSI_JH7110_H__ */
> --
> 2.17.1
>


--
With best wishes
Dmitry

2024-02-22 09:19:47

by Shengyang Chen

[permalink] [raw]
Subject: RE: [PATCH v3 2/2] drm/bridge: cdns-dsi: Add support for StarFive JH7110 SoC

Hi, Dmitry

Thanks for review and comment.

> -----Original Message-----
> From: Dmitry Baryshkov <[email protected]>
> Sent: 2024年2月7日 18:58
> To: Shengyang Chen <[email protected]>
> Cc: [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected];
> [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected];
> [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> Changhuang Liang <[email protected]>; Keith Zhao
> <[email protected]>; Jack Zhu <[email protected]>;
> [email protected]
> Subject: Re: [PATCH v3 2/2] drm/bridge: cdns-dsi: Add support for StarFive
> JH7110 SoC
>
> On Tue, 6 Feb 2024 at 08:57, Shengyang Chen
> <[email protected]> wrote:
> >
> > From: Keith Zhao <[email protected]>
> >
> > Add display bridge support for dsi on StarFive JH7110 SoC.
> >
> > The mainly modification is followed:
> > 1.Add extra clock and reset operation for JH7110.
> > 2.Add callback for JH7110.
> >
> > Signed-off-by: Keith Zhao <[email protected]>
> > Signed-off-by: Shengyang Chen <[email protected]>
> > ---
> > drivers/gpu/drm/bridge/cadence/Kconfig | 7 +
> > drivers/gpu/drm/bridge/cadence/Makefile | 1 +
> > .../gpu/drm/bridge/cadence/cdns-dsi-core.c | 29 ++-
> > .../gpu/drm/bridge/cadence/cdns-dsi-core.h | 21 ++
> > .../gpu/drm/bridge/cadence/cdns-dsi-jh7110.c | 193
> > ++++++++++++++++++ .../gpu/drm/bridge/cadence/cdns-dsi-jh7110.h |
> > 16 ++
> > 6 files changed, 266 insertions(+), 1 deletion(-) create mode 100644
> > drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c
> > create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h
> >
> > diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig
> > b/drivers/gpu/drm/bridge/cadence/Kconfig
> > index cced81633ddc..ad9f572f4720 100644
> > --- a/drivers/gpu/drm/bridge/cadence/Kconfig
> > +++ b/drivers/gpu/drm/bridge/cadence/Kconfig
> > @@ -19,6 +19,13 @@ config DRM_CDNS_DSI_J721E
> > help
> > Support J721E Cadence DSI wrapper. The wrapper manages
> > the routing of the DSS DPI signal to the Cadence DSI.
> > +
> > +config DRM_CDNS_DSI_JH7110
> > + bool "JH7110 SOC Cadence DSI support"
> > + default n
> > + help
> > + Cadence DPI to DSI bridge which is embedded in the
> > + StarFive JH7110 SoC.
> > endif
> >
> > config DRM_CDNS_MHDP8546
> > diff --git a/drivers/gpu/drm/bridge/cadence/Makefile
> > b/drivers/gpu/drm/bridge/cadence/Makefile
> > index c95fd5b81d13..87f603a9f4ad 100644
> > --- a/drivers/gpu/drm/bridge/cadence/Makefile
> > +++ b/drivers/gpu/drm/bridge/cadence/Makefile
> > @@ -2,6 +2,7 @@
> > obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o cdns-dsi-y :=
> > cdns-dsi-core.o
> > cdns-dsi-$(CONFIG_DRM_CDNS_DSI_J721E) += cdns-dsi-j721e.o
> > +cdns-dsi-$(CONFIG_DRM_CDNS_DSI_JH7110) += cdns-dsi-jh7110.o
> > obj-$(CONFIG_DRM_CDNS_MHDP8546) += cdns-mhdp8546.o
> cdns-mhdp8546-y
> > := cdns-mhdp8546-core.o cdns-mhdp8546-hdcp.o
> > cdns-mhdp8546-$(CONFIG_DRM_CDNS_MHDP8546_J721E) +=
> > cdns-mhdp8546-j721e.o diff --git
> > a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
> > b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
> > index 7457d38622b0..c0c81745e765 100644
> > --- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
> > +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
> > @@ -27,6 +27,10 @@
> > #include "cdns-dsi-j721e.h"
> > #endif
> >
> > +#ifdef CONFIG_DRM_CDNS_DSI_JH7110
> > +#include "cdns-dsi-jh7110.h"
> > +#endif
> > +
> > #define IP_CONF 0x0
> > #define SP_HS_FIFO_DEPTH(x) (((x) & GENMASK(30, 26)) >>
> 26)
> > #define SP_LP_FIFO_DEPTH(x) (((x) & GENMASK(25, 21)) >>
> 21)
> > @@ -552,6 +556,10 @@ static int cdns_dsi_adjust_phy_config(struct cdns_dsi
> *dsi,
> > /* data rate was in bytes/sec, convert to bits/sec. */
> > phy_cfg->hs_clk_rate = dlane_bps * 8;
> >
> > + if (dsi->platform_ops && dsi->platform_ops->mode_fixup)
> > + adj_dsi_htotal = dsi->platform_ops->mode_fixup(dsi,
> dsi_cfg, phy_cfg,
> > +
> dpi_hz,
> > + dpi_htotal, dsi_htotal);
> > +
> > dsi_hfp_ext = adj_dsi_htotal - dsi_htotal;
> > dsi_cfg->hfp += dsi_hfp_ext;
> > dsi_cfg->htotal = dsi_htotal + dsi_hfp_ext; @@ -683,7 +691,7
> > @@ static void cdns_dsi_bridge_post_disable(struct drm_bridge *bridge)
> > pm_runtime_put(dsi->base.dev); }
> >
> > -static void cdns_dsi_hs_init(struct cdns_dsi *dsi)
> > +void cdns_dsi_hs_init(struct cdns_dsi *dsi)
> > {
> > struct cdns_dsi_output *output = &dsi->output;
> > u32 status;
> > @@ -1026,6 +1034,14 @@ static ssize_t cdns_dsi_transfer(struct
> > mipi_dsi_host *host,
> >
> > cdns_dsi_init_link(dsi);
> >
> > + /*
> > + * on JH7110 SoC , when transfer dsi command ,
> > + * cdns_dsi_hs_init is needed.
> > + * or the final ret will be error value.
> > + */
> > + if (dsi->platform_ops && dsi->platform_ops->transfer)
> > + dsi->platform_ops->transfer(dsi);
> > +
> > ret = mipi_dsi_create_packet(&packet, msg);
> > if (ret)
> > goto out;
> > @@ -1142,6 +1158,9 @@ static int __maybe_unused cdns_dsi_resume(struct
> device *dev)
> > clk_prepare_enable(dsi->dsi_p_clk);
> > clk_prepare_enable(dsi->dsi_sys_clk);
> >
> > + if (dsi->platform_ops && dsi->platform_ops->resume)
> > + dsi->platform_ops->resume(dsi);
> > +
> > return 0;
> > }
> >
> > @@ -1152,6 +1171,10 @@ static int __maybe_unused
> cdns_dsi_suspend(struct device *dev)
> > clk_disable_unprepare(dsi->dsi_sys_clk);
> > clk_disable_unprepare(dsi->dsi_p_clk);
> > reset_control_assert(dsi->dsi_p_rst);
> > +
> > + if (dsi->platform_ops && dsi->platform_ops->suspend)
> > + dsi->platform_ops->suspend(dsi);
> > +
> > dsi->link_initialized = false;
> > return 0;
> > }
> > @@ -1294,6 +1317,10 @@ static const struct of_device_id
> > cdns_dsi_of_match[] = { #ifdef CONFIG_DRM_CDNS_DSI_J721E
> > { .compatible = "ti,j721e-dsi", .data = &dsi_ti_j721e_ops, },
> > #endif
> > +#ifdef CONFIG_DRM_CDNS_DSI_JH7110
> > + { .compatible = "starfive,jh7110-dsi", .data =
> > +&dsi_ti_jh7110_ops, }, #endif
> > +
> > { },
> > };
> > MODULE_DEVICE_TABLE(of, cdns_dsi_of_match); diff --git
> > a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
> > b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
> > index ca7ea2da635c..0a86495ead7b 100644
> > --- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
> > +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
> > @@ -53,12 +53,22 @@ struct cdns_dsi;
> > * @deinit: Called in the CDNS DSI remove
> > * @enable: Called at the beginning of CDNS DSI bridge enable
> > * @disable: Called at the end of CDNS DSI bridge disable
> > + * @resume: Called at the resume of CDNS DSI
> > + * @suspend: Called at the suspend of CDNS DSI
> > + * @update: Called at the middle of CDNS DSI bridge enable
> > */
> > struct cdns_dsi_platform_ops {
> > int (*init)(struct cdns_dsi *dsi);
> > void (*deinit)(struct cdns_dsi *dsi);
> > void (*enable)(struct cdns_dsi *dsi);
> > void (*disable)(struct cdns_dsi *dsi);
> > + void (*resume)(struct cdns_dsi *dsi);
> > + void (*suspend)(struct cdns_dsi *dsi);
> > + int (*mode_fixup)(struct cdns_dsi *dsi, struct cdns_dsi_cfg *dsi_cfg,
> > + struct phy_configure_opts_mipi_dphy
> *phy_cfg,
> > + unsigned long dpi_hz, unsigned long
> dpi_htotal,
> > + unsigned long dsi_htotal);
> > + void (*transfer)(struct cdns_dsi *dsi);
> > };
> >
> > struct cdns_dsi {
> > @@ -79,6 +89,17 @@ struct cdns_dsi {
> > bool link_initialized;
> > bool phy_initialized;
> > struct phy *dphy;
> > +
> > +#ifdef CONFIG_DRM_CDNS_DSI_JH7110
> > + struct clk *dpi_clk;
> > + struct clk *txesc_clk;
> > + struct reset_control *dpi_rst;
> > + struct reset_control *sys_rst;
> > + struct reset_control *txesc_rst;
> > + struct reset_control *txbytehs_rst; #endif
> > };
> >
> > +void cdns_dsi_hs_init(struct cdns_dsi *dsi);
> > +
> > #endif /* !__CDNS_DSI_H__ */
> > diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c
> > b/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c
> > new file mode 100644
> > index 000000000000..c6b9296a9275
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.c
> > @@ -0,0 +1,193 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * JH7110 SoC Cadence DSI wrapper
> > + *
> > + * Copyright (C) 2023 StarFive Technology Co., Ltd.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/io.h>
> > +#include <linux/iopoll.h>
> > +#include <linux/reset.h>
> > +
> > +#include "cdns-dsi-jh7110.h"
> > +
> > +static int cdns_dsi_clock_enable(struct cdns_dsi *dsi, struct device
> > +*dev) {
> > + int ret;
> > +
> > + ret = clk_prepare_enable(dsi->dpi_clk);
> > + if (ret) {
> > + dev_err(dev, "Failed to prepare/enable dpi_clk\n");
> > + return ret;
> > + }
> > +
> > + ret = clk_prepare_enable(dsi->txesc_clk);
> > + if (ret) {
> > + dev_err(dev, "Failed to prepare/enable txesc_clk\n");
> > + return ret;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static void cdns_dsi_clock_disable(struct cdns_dsi *dsi) {
> > + clk_disable_unprepare(dsi->dpi_clk);
> > + clk_disable_unprepare(dsi->txesc_clk);
>
> Please use clk_bulk_ API and inline these two functions.
>

ok, will follow up this issue.

> > +}
> > +
> > +static int cdns_dsi_resets_deassert(struct cdns_dsi *dsi, struct
> > +device *dev) {
> > + int ret;
> > +
> > + ret = reset_control_deassert(dsi->dpi_rst);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to deassert dpi_rst\n");
> > + return ret;
> > + }
> > +
> > + ret = reset_control_deassert(dsi->txesc_rst);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to deassert txesc_rst\n");
> > + return ret;
> > + }
> > +
> > + ret = reset_control_deassert(dsi->sys_rst);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to deassert sys_rst\n");
> > + return ret;
> > + }
>
> Same, please use reset_control_bulk API.
>

ok, will follow up this issue.

> > +
> > + return ret;
> > +}
> > +
> > +static int cdns_dsi_resets_assert(struct cdns_dsi *dsi, struct device
> > +*dev) {
> > + int ret;
> > +
> > + ret = reset_control_assert(dsi->dpi_rst);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to assert dpi_rst\n");
> > + return ret;
> > + }
> > +
> > + ret = reset_control_assert(dsi->txesc_rst);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to assert txesc_rst\n");
> > + return ret;
> > + }
> > +
> > + ret = reset_control_assert(dsi->sys_rst);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to assert sys_rst\n");
> > + return ret;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static int cdns_dsi_get_clock(struct device *dev, struct cdns_dsi
> > +*dsi) {
> > + dsi->dpi_clk = devm_clk_get(dev, "dpi");
> > + if (IS_ERR(dsi->dpi_clk))
> > + return PTR_ERR(dsi->dpi_clk);
> > +
> > + dsi->txesc_clk = devm_clk_get(dev, "txesc");
> > + if (IS_ERR(dsi->txesc_clk))
> > + return PTR_ERR(dsi->txesc_clk);
> > +
> > + return 0;
> > +}
> > +
> > +static int cdns_dsi_get_reset(struct device *dev, struct cdns_dsi
> > +*dsi) {
> > + dsi->sys_rst = devm_reset_control_get_exclusive(dev, "sys");
> > + if (IS_ERR(dsi->sys_rst))
> > + return PTR_ERR(dsi->sys_rst);
> > +
> > + dsi->dpi_rst = devm_reset_control_get_exclusive(dev, "dpi");
> > + if (IS_ERR(dsi->dpi_rst))
> > + return PTR_ERR(dsi->dpi_rst);
> > +
> > + dsi->txesc_rst = devm_reset_control_get_exclusive(dev, "txesc");
> > + if (IS_ERR(dsi->txesc_rst))
> > + return PTR_ERR(dsi->txesc_rst);
> > +
> > + dsi->txbytehs_rst = devm_reset_control_get_exclusive(dev,
> "txbytehs");
> > + if (IS_ERR(dsi->txbytehs_rst))
> > + return PTR_ERR(dsi->txbytehs_rst);
> > +
> > + return 0;
> > +}
> > +
> > +static int cdns_dsi_jh7110_init(struct cdns_dsi *dsi) {
> > + int ret;
> > +
> > + ret = cdns_dsi_get_clock(dsi->base.dev, dsi);
> > + if (ret)
> > + return ret;
> > +
> > + return cdns_dsi_get_reset(dsi->base.dev, dsi); }
> > +
> > +static void cdns_dsi_jh7110_resume(struct cdns_dsi *dsi) {
> > + int ret;
> > +
> > + ret = cdns_dsi_clock_enable(dsi, dsi->base.dev);
> > + if (ret) {
> > + dev_err(dsi->base.dev, "failed to enable clock\n");
> > + return;
> > + }
> > + ret = cdns_dsi_resets_deassert(dsi, dsi->base.dev);
> > + if (ret < 0) {
> > + dev_err(dsi->base.dev, "failed to deassert reset\n");
> > + return;
> > + }
> > +}
> > +
> > +static void cdns_dsi_jh7110_suspend(struct cdns_dsi *dsi) {
> > + int ret;
> > +
> > + ret = cdns_dsi_resets_assert(dsi, dsi->base.dev);
> > + if (ret < 0) {
> > + dev_err(dsi->base.dev, "failed to deassert reset\n");
> > + return;
> > + }
> > +
> > + cdns_dsi_clock_disable(dsi);
> > +}
> > +
> > +static int cdns_dsi_jh7110_mode_fixup(struct cdns_dsi *dsi, struct
> cdns_dsi_cfg *dsi_cfg,
> > + struct
> phy_configure_opts_mipi_dphy *phy_cfg,
> > + unsigned long dpi_hz, unsigned
> long dpi_htotal,
> > + unsigned long dsi_htotal) {
> > + unsigned long long dlane_bps;
> > + unsigned long adj_dsi_htotal;
> > + unsigned int lanes = dsi->output.dev->lanes;
> > +
> > + phy_cfg->hs_clk_rate = phy_cfg->hs_clk_rate -
> (phy_cfg->hs_clk_rate % 10000000);
> > + phy_cfg->hs_clk_rate += 100000000;
>
> phy_cfg->hs_clk_rate = roundup(phy_cfg->hs_clk_rate, 100000000);
>

ok, will fix it
thanks for suggestion.

> > + dlane_bps = phy_cfg->hs_clk_rate * lanes * dpi_htotal / 8;
> > + adj_dsi_htotal = dlane_bps / dpi_hz;
> > +
> > + return adj_dsi_htotal;
> > +}
> > +
> > +static void jh7110_cdns_dsi_hs_init(struct cdns_dsi *dsi) {
> > + cdns_dsi_hs_init(dsi);
> > + reset_control_deassert(dsi->txbytehs_rst);
>
> Is a single deassert enough here? Which funciion asserts the reset?
>

will follow up this issue
We verified that we may add assert in our rpm suspend API in next version.
thanks for mention

> > +}
> > +
> > +const struct cdns_dsi_platform_ops dsi_ti_jh7110_ops = {
> > + .init = cdns_dsi_jh7110_init,
> > + .resume = cdns_dsi_jh7110_resume,
> > + .suspend = cdns_dsi_jh7110_suspend,
> > + .mode_fixup = cdns_dsi_jh7110_mode_fixup,
> > + .transfer = jh7110_cdns_dsi_hs_init, };
> > diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h
> > b/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h
> > new file mode 100644
> > index 000000000000..15d6a766b502
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-jh7110.h
> > @@ -0,0 +1,16 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * JH7110 Cadence DSI
> > + *
> > + * Copyright (C) 2022-2023 StarFive Technology Co., Ltd.
> > + * Author: keith.zhao <[email protected]> */
> > +
> > +#ifndef __CDNS_DSI_JH7110_H__
> > +#define __CDNS_DSI_JH7110_H__
> > +
> > +#include "cdns-dsi-core.h"
> > +
> > +extern const struct cdns_dsi_platform_ops dsi_ti_jh7110_ops;
> > +
> > +#endif /* !__CDNS_DSI_JH7110_H__ */
> > --
> > 2.17.1
> >
>
>
> --
> With best wishes
> Dmitry


thanks.

Best Regards,
Shengyang