[PATCH 3/3] drm/bridge: add TH1520 DesignWare MIPI DSI host controller

Icenowy Zheng zhengxingda at iscas.ac.cn
Fri Oct 30 00:47:51 PDT 2026


The T-Head TH1520 SoC contains a Synopsys DesignWare MIPI DSI host
controller with an internal DesignWare MIPI D-PHY.

Add a glue driver configuring clocks and PHY parameters for it.

Signed-off-by: Icenowy Zheng <zhengxingda at iscas.ac.cn>
---
 drivers/gpu/drm/bridge/Kconfig              |  10 +
 drivers/gpu/drm/bridge/Makefile             |   1 +
 drivers/gpu/drm/bridge/th1520-dw-mipi-dsi.c | 530 ++++++++++++++++++++++++++++
 3 files changed, 541 insertions(+)

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 4a57d49b4c6d3..b005623ba26bf 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -375,6 +375,16 @@ config DRM_THEAD_TH1520_DW_HDMI
 	  Choose this to enable support for the internal HDMI bridge found
 	  on the T-Head TH1520 SoC.
 
+config DRM_THEAD_TH1520_DW_MIPI_DSI
+	tristate "T-Head TH1520 DesignWare MIPI DSI bridge"
+	depends on OF
+	depends on COMMON_CLK
+	depends on ARCH_THEAD || COMPILE_TEST
+	select DRM_DW_MIPI_DSI
+	help
+	  Choose this to enable support for the internal MIPI DSI bridge
+	  found on the T-Head TH1520 SoC.
+
 config DRM_TOSHIBA_TC358762
 	tristate "TC358762 DSI/DPI bridge"
 	depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 15cc821d85b7e..5af871ba5ce77 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_DRM_SII9234) += sii9234.o
 obj-$(CONFIG_DRM_SIMPLE_BRIDGE) += simple-bridge.o
 obj-$(CONFIG_DRM_SOLOMON_SSD2825) += ssd2825.o
 obj-$(CONFIG_DRM_THEAD_TH1520_DW_HDMI) += th1520-dw-hdmi.o
+obj-$(CONFIG_DRM_THEAD_TH1520_DW_MIPI_DSI) += th1520-dw-mipi-dsi.o
 obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o
 obj-$(CONFIG_DRM_TOSHIBA_TC358762) += tc358762.o
 obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o
diff --git a/drivers/gpu/drm/bridge/th1520-dw-mipi-dsi.c b/drivers/gpu/drm/bridge/th1520-dw-mipi-dsi.c
new file mode 100644
index 0000000000000..e5c7c5d6dcc71
--- /dev/null
+++ b/drivers/gpu/drm/bridge/th1520-dw-mipi-dsi.c
@@ -0,0 +1,530 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 Institute of Software, Chinese Academy of Sciences (ISCAS)
+ *
+ * Author:
+ *   Icenowy Zheng <zhengxingda at iscas.ac.cn>
+ *
+ * Based on dw_mipi_dsi-stm.c, which is:
+ *   Copyright (C) STMicroelectronics SA 2017
+ *
+ * Based on dw-mipi-dsi-rockchip.c, which is:
+ *   Copyright (C) Rockchip Electronics Co., Ltd.
+ *
+ * Based on vendor kernel phy-dw-mipi-dphy.c, which is:
+ *   Copyright (C) Alibaba Group Holding Limited.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/bridge/dw_mipi_dsi.h>
+#include <drm/drm_mipi_dsi.h>
+
+/* DPHY registers */
+
+#define PLL_DELAY_LP_TX_START_LP11	0x02
+#define TXDINDLYTIME_9_2		GENMASK(7,  0)
+
+#define PLL_FSM_CNTRL			0x03
+
+#define PLL_PROP_CHARGE_PUMP_CTRL	0x0e
+#define PLL_PROP_CNTRL			GENMASK(5,  0)
+
+#define PLL_INT_CHARGE_PUMP_CTRL	0x0f
+#define PLL_INT_CNTRL			GENMASK(5,  0)
+
+#define PLL_VCO_CTRL			0x12
+#define PLL_VCO_CNTRL_OVR_EN		BIT(6)
+#define PLL_VCO_CNTRL_OVR		GENMASK(5,  0)
+
+#define PLL_GMP_CTRL_DIGITAL_TEST	0x13
+#define PLL_TESTLOCK			BIT(7)
+#define PLL_GMP_CNTRL			GENMASK(5,  4)
+#define TSTPLLDIG			GENMASK(3,  1)
+#define TSTPLLDIG_LOCK			(0x0 << 1)
+#define TSTPLLDIG_REFCLK		(0x1 << 1)
+#define TSTPLLDIG_FBCLK			(0x2 << 1)
+#define TSTPLLDIG_INT_CLKIN		(0x3 << 1)
+#define TSTPLLDIG_LOCK_FROM_DETECTOR	(0x4 << 1)
+#define TSTPLLDIG_OUTPUT		(0x5 << 1)
+#define TSTPLLDIG_BUF_VCOCLK		(0x6 << 1)
+#define TSTPLLDIG_UPDATEPLL		(0x7 << 1)
+
+#define PLL_N_DIV_FSM_SIG		0x17
+#define PLL_N_OVR			GENMASK(3,  0)
+
+#define PLL_M_DIV			0x18
+#define PLL_M_OVR_4_0			GENMASK(4,  0)
+#define PLL_M_OVR_9_5			GENMASK(4,  0)
+
+#define PLL_N_AND_M_DIV_CTRL		0x19
+#define PLL_M_OVR_EN			BIT(5)
+#define PLL_N_OVR_EN			BIT(4)
+
+#define PLL_CHARGE_PUMP_BIAS_CTRL	0x1c
+#define PLL_CPBIAS_CNTRL		GENMASK(6,  0)
+
+#define PLL_ANALOG_PROGRAM_CONTROL	0x1f
+#define PLL_MPLL_PROG_5_0		GENMASK(5,  0)
+#define PLL_MPLL_PROG_11_6		GENMASK(5,  0)
+#define PLL_MPLL_PROG_16_12		GENMASK(4,  0)
+
+#define HS_FREQ_RANGE_OF_OPERATION	0x44
+#define HSFREQRANGE_OVR_EN		BIT(7)
+#define HSFREQRANGE_OVR			GENMASK(6,  0)
+#define HSFREQRANGE			HSFREQRANGE_OVR
+
+#define PG_LP_BIAS_LANE0		0x4a
+#define PRG_ON_LANE0			BIT(6)
+
+#define SR_FSM_OVR_CNTRL		0xa0
+#define SR_DDL_LOOP_CONF		0xa3
+
+/* syscon registers */
+
+#define MIPIDSI0_SYSREG			0x8
+#define MIPIDSI1_SYSREG			0xc
+#define MIPIDSI_HSFREQRANGE		GENMASK(9,  3)
+#define MIPIDSI_CFGCLKFREQRANGE		GENMASK(15, 10)
+#define MIPIDSI_CFGCLKFREQRANGE_DEF	(0x1c << 10)
+
+struct pll_hsfreqrange {
+	unsigned int max_mbps;
+	u8 hsfreqrange;
+};
+
+static const struct pll_hsfreqrange hsfreqrange_table[] = {
+	{ 80,  0x00 },
+	{ 90,  0x10 },
+	{ 100, 0x20 },
+	{ 110, 0x30 },
+	{ 120, 0x01 },
+	{ 130, 0x11 },
+	{ 140, 0x21 },
+	{ 150, 0x31 },
+	{ 160, 0x02 },
+	{ 170, 0x12 },
+	{ 180, 0x22 },
+	{ 190, 0x32 },
+	{ 205, 0x03 },
+	{ 220, 0x13 },
+	{ 235, 0x23 },
+	{ 250, 0x33 },
+	{ 275, 0x04 },
+	{ 300, 0x14 },
+	{ 325, 0x25 },
+	{ 350, 0x35 },
+	{ 400, 0x05 },
+	{ 450, 0x16 },
+	{ 500, 0x26 },
+	{ 550, 0x37 },
+	{ 600, 0x07 },
+	{ 650, 0x18 },
+	{ 700, 0x28 },
+	{ 750, 0x39 },
+	{ 800, 0x09 },
+	{ 850, 0x19 },
+	{ 900, 0x29 },
+	{ 950, 0x3A },
+	{ 1000, 0x0A },
+	{ 1050, 0x1A },
+	{ 1100, 0x2A },
+	{ 1150, 0x3B },
+	{ 1200, 0x0B },
+	{ 1250, 0x1B },
+	{ 1300, 0x2B },
+	{ 1350, 0x3C },
+	{ 1400, 0x0C },
+	{ 1450, 0x1C },
+	{ 1500, 0x2C },
+	{ 1550, 0x3D },
+	{ 1600, 0x0D },
+	{ 1650, 0x1D },
+	{ 1700, 0x2E },
+	{ 1750, 0x3E },
+	{ 1800, 0x0E },
+	{ 1850, 0x1E },
+	{ 1900, 0x2F },
+	{ 1950, 0x3F },
+	{ 2000, 0x0F },
+	{ 2050, 0x40 },
+	{ 2100, 0x41 },
+	{ 2150, 0x42 },
+	{ 2200, 0x43 },
+	{ 2250, 0x44 },
+	{ 2300, 0x45 },
+	{ 2350, 0x46 },
+	{ 2400, 0x47 },
+	{ 2450, 0x48 },
+	{ 2500, 0x49 },
+};
+
+struct hstt {
+	unsigned int max_mbps;
+	struct dw_mipi_dsi_dphy_timing timing;
+};
+
+#define HSTT(_max_mbps, _c_lp2hs, _c_hs2lp, _d_lp2hs, _d_hs2lp)	\
+{					\
+	.max_mbps = _max_mbps,		\
+	.timing = {			\
+		.clk_lp2hs = _c_lp2hs,	\
+		.clk_hs2lp = _c_hs2lp,	\
+		.data_lp2hs = _d_lp2hs,	\
+		.data_hs2lp = _d_hs2lp,	\
+	}				\
+}
+
+static struct hstt hstt_table[] = {
+	HSTT(80, 21, 17, 15, 10),
+	HSTT(90, 23, 17, 16, 10),
+	HSTT(100, 22, 17, 16, 10),
+	HSTT(110, 25, 18, 17, 11),
+	HSTT(120, 26, 20, 18, 11),
+	HSTT(130, 27, 19, 19, 11),
+	HSTT(140, 27, 19, 19, 11),
+	HSTT(150, 28, 20, 20, 12),
+	HSTT(160, 30, 21, 22, 13),
+	HSTT(170, 30, 21, 23, 13),
+	HSTT(180, 31, 21, 23, 13),
+	HSTT(190, 32, 22, 24, 13),
+	HSTT(205, 35, 22, 25, 13),
+	HSTT(220, 37, 26, 27, 15),
+	HSTT(235, 38, 28, 27, 16),
+	HSTT(250, 41, 29, 30, 17),
+	HSTT(275, 43, 29, 32, 18),
+	HSTT(300, 45, 32, 35, 19),
+	HSTT(325, 48, 33, 36, 18),
+	HSTT(350, 51, 35, 40, 20),
+	HSTT(400, 59, 37, 44, 21),
+	HSTT(450, 65, 40, 49, 23),
+	HSTT(500, 71, 41, 54, 24),
+	HSTT(550, 77, 44, 57, 26),
+	HSTT(600, 82, 46, 64, 27),
+	HSTT(650, 87, 48, 67, 28),
+	HSTT(700, 94, 52, 71, 29),
+	HSTT(750, 99, 52, 75, 31),
+	HSTT(800, 105, 55, 82, 32),
+	HSTT(850, 110, 58, 85, 32),
+	HSTT(900, 115, 58, 88, 35),
+	HSTT(950, 120, 62, 93, 36),
+	HSTT(1000, 128, 63, 99, 38),
+	HSTT(1050, 132, 65, 102, 38),
+	HSTT(1100, 138, 67, 106, 39),
+	HSTT(1150, 146, 69, 112, 42),
+	HSTT(1200, 151, 71, 117, 43),
+	HSTT(1250, 153, 74, 120, 45),
+	HSTT(1300, 160, 73, 124, 46),
+	HSTT(1350, 165, 76, 130, 47),
+	HSTT(1400, 172, 78, 134, 49),
+	HSTT(1450, 177, 80, 138, 49),
+	HSTT(1500, 183, 81, 143, 52),
+	HSTT(1550, 191, 84, 147, 52),
+	HSTT(1600, 194, 85, 152, 52),
+	HSTT(1650, 201, 86, 155, 53),
+	HSTT(1700, 208, 88, 161, 53),
+	HSTT(1750, 212, 89, 165, 53),
+	HSTT(1800, 220, 90, 171, 54),
+	HSTT(1850, 223, 92, 175, 54),
+	HSTT(1900, 231, 91, 180, 55),
+	HSTT(1950, 236, 95, 185, 56),
+	HSTT(2000, 243, 97, 190, 56),
+	HSTT(2050, 248, 99, 194, 58),
+	HSTT(2100, 252, 100, 199, 59),
+	HSTT(2150, 259, 102, 204, 61),
+	HSTT(2200, 266, 105, 210, 62),
+	HSTT(2250, 269, 109, 213, 63),
+	HSTT(2300, 272, 109, 217, 65),
+	HSTT(2350, 281, 112, 225, 66),
+	HSTT(2400, 283, 115, 226, 66),
+	HSTT(2450, 282, 115, 226, 67),
+	HSTT(2500, 281, 118, 227, 67),
+};
+
+struct dsi_chip_data {
+	u64 reg;
+
+	u32 sysreg;
+};
+
+struct th1520_dw_mipi_dsi {
+	struct device *dev;
+
+	struct dw_mipi_dsi *dmd;
+	struct dw_mipi_dsi_plat_data pdata;
+	const struct dsi_chip_data *cdata;
+
+	struct regmap *syscon;
+	struct clk *clk_pix;
+	struct clk *clk_ref;
+	struct clk *clk_cfg;
+
+	unsigned int lane_mbps;
+	u8 hsfreqrange;
+};
+
+static int dsi_phy_init(void *priv_data)
+{
+	struct th1520_dw_mipi_dsi *dsi = priv_data;
+	u32 val;
+
+	val = FIELD_PREP(MIPIDSI_HSFREQRANGE, dsi->hsfreqrange) |
+	      MIPIDSI_CFGCLKFREQRANGE_DEF;
+
+	regmap_update_bits(dsi->syscon, dsi->cdata->sysreg,
+			   MIPIDSI_HSFREQRANGE | MIPIDSI_CFGCLKFREQRANGE, val);
+
+	/* disable slew rate calibration */
+	dw_mipi_dsi_phy_write(dsi->dmd, SR_DDL_LOOP_CONF, 0);
+	dw_mipi_dsi_phy_write(dsi->dmd, SR_FSM_OVR_CNTRL, 1);
+
+	/* configure prg_on_lane0 */
+	dw_mipi_dsi_phy_write(dsi->dmd, PG_LP_BIAS_LANE0, PRG_ON_LANE0);
+
+	/* configure PLL charge pump */
+	if (dsi->lane_mbps >= 1150)
+		dw_mipi_dsi_phy_write(dsi->dmd, PLL_PROP_CHARGE_PUMP_CTRL, 0xE);
+	else
+		dw_mipi_dsi_phy_write(dsi->dmd, PLL_PROP_CHARGE_PUMP_CTRL, 0x8);
+	dw_mipi_dsi_phy_write(dsi->dmd, PLL_CHARGE_PUMP_BIAS_CTRL, 0x10);
+
+	return 0;
+}
+
+static void dsi_phy_power_on(void *priv_data)
+{
+	struct th1520_dw_mipi_dsi *dsi = priv_data;
+
+	clk_prepare_enable(dsi->clk_pix);
+}
+
+static void dsi_phy_power_off(void *priv_data)
+{
+	struct th1520_dw_mipi_dsi *dsi = priv_data;
+
+	clk_disable_unprepare(dsi->clk_pix);
+}
+
+static unsigned int
+calculate_lane_mbps(const struct drm_display_mode *mode,
+		    unsigned long mode_flags,
+		    u32 lanes, u32 format)
+{
+	int bpp = mipi_dsi_pixel_format_to_bpp(format);
+	union phy_configure_opts phy_opts;
+
+	/*
+	 * FIXME: the extra bandwidth headroom logic mimics what the Rockchip
+	 * driver does, and test shows that it's necessary for the hardware
+	 * to work with the mainline dw-mipi-dsi common code.
+	 */
+	phy_mipi_dphy_get_default_config(mode->clock * 1000 * 10 / 8,
+					 bpp, lanes,
+					 &phy_opts.mipi_dphy);
+
+	return DIV_ROUND_UP(phy_opts.mipi_dphy.hs_clk_rate, USEC_PER_SEC);
+}
+
+static int
+dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
+		  unsigned long mode_flags, u32 lanes, u32 format,
+		  unsigned int *lane_mbps)
+{
+	struct th1520_dw_mipi_dsi *dsi = priv_data;
+	int i;
+
+	*lane_mbps = calculate_lane_mbps(mode, mode_flags, lanes, format);
+
+	for (i = 0; i < ARRAY_SIZE(hsfreqrange_table); i++)
+		if (*lane_mbps <= hsfreqrange_table[i].max_mbps)
+			break;
+
+	if (i == ARRAY_SIZE(hsfreqrange_table))
+		return -EINVAL;
+
+	*lane_mbps = hsfreqrange_table[i].max_mbps;
+	dsi->lane_mbps = *lane_mbps;
+	dsi->hsfreqrange = hsfreqrange_table[i].hsfreqrange;
+
+	return 0;
+}
+
+static int
+dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
+		   struct dw_mipi_dsi_dphy_timing *timing)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hstt_table); i++)
+		if (lane_mbps <= hstt_table[i].max_mbps)
+			break;
+
+	if (i == ARRAY_SIZE(hstt_table))
+		return -EINVAL;
+
+	*timing = hstt_table[i].timing;
+
+	return 0;
+}
+
+static const struct dw_mipi_dsi_phy_ops th1520_dw_mipi_dsi_phy_ops = {
+	.init = dsi_phy_init,
+	.power_on = dsi_phy_power_on,
+	.power_off = dsi_phy_power_off,
+	.get_lane_mbps = dsi_get_lane_mbps,
+	.get_timing = dsi_phy_get_timing,
+};
+
+static enum drm_mode_status
+dsi_mode_valid(void *priv_data, const struct drm_display_mode *mode,
+	       unsigned long mode_flags, u32 lanes, u32 format)
+{
+	unsigned int lane_mbps, max_mbps;
+
+	lane_mbps = calculate_lane_mbps(mode, mode_flags, lanes, format);
+	max_mbps = hsfreqrange_table[ARRAY_SIZE(hsfreqrange_table) - 1].max_mbps;
+
+	if (lane_mbps > max_mbps)
+		return MODE_NOCLOCK;
+
+	return MODE_OK;
+}
+
+static struct dsi_chip_data th1520_chip_data[] = {
+	{
+		.reg = 0xffef500000,
+		.sysreg = MIPIDSI0_SYSREG,
+
+		/*
+		 * TODO: The user manual shows a mux register for DSI0 but the
+		 * vendor driver doesn't touch it either.
+		 */
+	},
+	{
+		.reg = 0xffef510000,
+		.sysreg = MIPIDSI1_SYSREG,
+	},
+	{ /* sentinel */ },
+};
+
+static int th1520_dw_mipi_dsi_probe(struct platform_device *pdev)
+{
+	const struct dsi_chip_data *cdata;
+	struct device *dev = &pdev->dev;
+	struct th1520_dw_mipi_dsi *dsi;
+	struct resource *res;
+	void __iomem *base;
+	int i, ret;
+
+	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+	if (!dsi)
+		return -ENOMEM;
+
+	dsi->dev = dev;
+
+	dsi->syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
+	if (IS_ERR(dsi->syscon)) {
+		ret = PTR_ERR(dsi->syscon);
+		dev_err_probe(dev, ret, "Unable to get system controller regmap\n");
+		return ret;
+	}
+
+	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+	if (IS_ERR(base)) {
+		dev_err_probe(dev, ret, "Unable to get DSI registers\n");
+		return PTR_ERR(base);
+	}
+
+	cdata = of_device_get_match_data(dev);
+	i = 0;
+	while (cdata[i].reg) {
+		if (cdata[i].reg == res->start) {
+			dsi->cdata = &cdata[i];
+			break;
+		}
+
+		i++;
+	}
+
+	if (!dsi->cdata) {
+		dev_err(dev, "Failed to find chip data for this controller\n");
+		return -EINVAL;
+	}
+
+	dsi->clk_ref = devm_clk_get_enabled(dev, "ref");
+	if (IS_ERR(dsi->clk_ref)) {
+		ret = PTR_ERR(dsi->clk_ref);
+		dev_err_probe(dev, ret, "Unable to get PHY reference clock\n");
+		return ret;
+	}
+
+	dsi->clk_cfg = devm_clk_get_enabled(dev, "phy_cfg");
+	if (IS_ERR(dsi->clk_cfg)) {
+		ret = PTR_ERR(dsi->clk_cfg);
+		dev_err_probe(dev, ret, "Unable to get PHY configuration clock\n");
+		return ret;
+	}
+
+	dsi->clk_pix = devm_clk_get(dev, "pixel");
+	if (IS_ERR(dsi->clk_pix)) {
+		ret = PTR_ERR(dsi->clk_pix);
+		dev_err_probe(dev, ret, "Unable to get PHY pixel clock\n");
+		return ret;
+	}
+
+	dsi->pdata.base = base;
+	dsi->pdata.priv_data = dsi;
+	dsi->pdata.max_data_lanes = 4;
+	dsi->pdata.phy_ops = &th1520_dw_mipi_dsi_phy_ops;
+	dsi->pdata.mode_valid = dsi_mode_valid;
+
+	platform_set_drvdata(pdev, dsi);
+
+	dsi->dmd = dw_mipi_dsi_probe(pdev, &dsi->pdata);
+	if (IS_ERR(dsi->dmd)) {
+		ret = PTR_ERR(dsi->dmd);
+		dev_err_probe(dev, ret, "Failed to initialize mipi dsi host\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void th1520_dw_mipi_dsi_remove(struct platform_device *pdev)
+{
+	struct th1520_dw_mipi_dsi *dsi = platform_get_drvdata(pdev);
+
+	dw_mipi_dsi_remove(dsi->dmd);
+}
+
+static const struct of_device_id th1520_dw_mipi_dsi_dt_ids[] = {
+	{ .compatible = "thead,th1520-dw-mipi-dsi", .data = &th1520_chip_data },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, th1520_dw_mipi_dsi_dt_ids);
+
+static struct platform_driver th1520_dw_mipi_dsi_driver = {
+	.probe		= th1520_dw_mipi_dsi_probe,
+	.remove		= th1520_dw_mipi_dsi_remove,
+	.driver		= {
+		.of_match_table = th1520_dw_mipi_dsi_dt_ids,
+		.name	= "th1520-dw-mipi-dsi",
+	},
+};
+
+module_platform_driver(th1520_dw_mipi_dsi_driver);
+
+MODULE_AUTHOR("Icenowy Zheng <zhengxingda at iscas.ac.cn>");
+MODULE_DESCRIPTION("T-Head TH1520 MIPI DSI host controller driver");
+MODULE_LICENSE("GPL");

-- 
2.56.0




More information about the linux-arm-kernel mailing list