2014-12-31 08:19:27

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 00/21] Add support for i.MX MIPI DSI DRM driver

Hi,

This version mainly fixes the Kconfig for the Synopsys DesignWare MIPI DSI
host controller bridge driver so that we may pass the allmodconfig for ARM.
Also, this version contains a minor change for the Himax HX8369A panel
driver to remove several unnecessary headers included.

The i.MX MIPI DSI is a Synopsys DesignWare MIPI DSI host controller IP.
This series adds support for a Synopsys DesignWare MIPI DSI host controller
DRM bridge driver and a i.MX MIPI DSI specific DRM driver.
Currently, the MIPI DSI drivers only support the burst with sync pulse mode.

This series also includes a DRM panel driver for the Truly TFT480800-16-E panel
which is driven by the Himax HX8369A driver IC. The driver IC data sheet could
be found at [1]. As mentioned by the data sheet, the driver IC supports several
interface modes. Currently, the DRM panel driver only supports the MIPI DSI video
mode. New interface modes could be added later(perhaps, just like the way the DRM
simple panel driver supports both MIPI DSI interface panels and simple(parallel)
interface panels).

The MIPI DSI feature is tested on i.MX6Q SabreSD board and i.MX6DL SabreSD board.
The MIPI DSI display could be enabled directly on i.MX6Q SabreSD board after
applying this series, because the 26.4MHz pixel clock the panel requires could be
derived from the IPU HSP clock(264MHz) with an integer divider.
On i.MX6DL SabreSD board, we need to manually disable the LVDS and HDMI displays in
the device tree blob, since the i.MX6DL IPU HSP clock is 198MHz at present, which
makes the pixel clock share the PLL5 video clock source with the LVDS and HDMI,
thus, the panel cannot get the pixel clock rate it wants.

Patch 01/21 is needed to get a precise pixel clock rate(26.4MHz) from the PLL5 video
clock. If we don't have this patch, the pixel clock rate is about 20MHz, which
causes a horitonal shift on the display image.

This series can be applied on the drm-next branch.

[1] http://www.allshore.com/pdf/Himax_HX8369-A.pdf

Liu Ying (21):
clk: divider: Correct parent clk round rate if no bestdiv is normally
found
of: Add vendor prefix for Himax Technologies Inc.
of: Add vendor prefix for Truly Semiconductors Limited
ARM: imx6q: Add GPR3 MIPI muxing control register field shift bits
definition
ARM: imx6q: clk: Add the video_27m clock
ARM: imx6q: clk: Change hdmi_isfr clock's parent to be video_27m clock
ARM: imx6q: clk: Change hsi_tx clock to be a shared clock gate
ARM: imx6q: clk: Add support for mipi_core_cfg clock as a shared clock
gate
ARM: dts: imx6qdl: Move existing MIPI DSI ports into a new 'ports'
node
drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM
bridge driver
drm/bridge: Add Synopsys DesignWare MIPI DSI host controller driver
Documentation: dt-bindings: Add bindings for i.MX specific Synopsys DW
MIPI DSI driver
drm: imx: Support Synopsys DesignWare MIPI DSI host controller
Documentation: dt-bindings: Add bindings for Himax HX8369A DRM panel
driver
drm: panel: Add support for Himax HX8369A MIPI DSI panel
ARM: dtsi: imx6qdl: Add support for MIPI DSI host controller
ARM: dts: imx6qdl-sabresd: Add support for TRULY TFT480800-16-E MIPI
DSI panel
ARM: imx_v6_v7_defconfig: Cleanup for imx drm being moved out of
staging
ARM: imx_v6_v7_defconfig: Add support for MIPI DSI host controller
ARM: imx_v6_v7_defconfig: Add support for Himax HX8369A panel

.../devicetree/bindings/drm/bridge/dw_mipi_dsi.txt | 73 ++
.../devicetree/bindings/drm/imx/mipi_dsi.txt | 78 ++
.../devicetree/bindings/panel/himax,hx8369a.txt | 39 +
.../devicetree/bindings/vendor-prefixes.txt | 2 +
arch/arm/boot/dts/imx6q.dtsi | 20 +-
arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 20 +
arch/arm/boot/dts/imx6qdl.dtsi | 29 +-
arch/arm/configs/imx_v6_v7_defconfig | 17 +-
arch/arm/mach-imx/clk-imx6q.c | 7 +-
drivers/clk/clk-divider.c | 3 +-
drivers/gpu/drm/bridge/Kconfig | 10 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/dw_mipi_dsi.c | 996 +++++++++++++++++++++
drivers/gpu/drm/imx/Kconfig | 7 +
drivers/gpu/drm/imx/Makefile | 1 +
drivers/gpu/drm/imx/dw_mipi_dsi-imx.c | 230 +++++
drivers/gpu/drm/panel/Kconfig | 5 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-himax-hx8369a.c | 610 +++++++++++++
include/drm/bridge/dw_mipi_dsi.h | 27 +
include/drm/drm_mipi_dsi.h | 14 +
include/dt-bindings/clock/imx6qdl-clock.h | 4 +-
include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 1 +
23 files changed, 2165 insertions(+), 30 deletions(-)
create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
create mode 100644 Documentation/devicetree/bindings/drm/imx/mipi_dsi.txt
create mode 100644 Documentation/devicetree/bindings/panel/himax,hx8369a.txt
create mode 100644 drivers/gpu/drm/bridge/dw_mipi_dsi.c
create mode 100644 drivers/gpu/drm/imx/dw_mipi_dsi-imx.c
create mode 100644 drivers/gpu/drm/panel/panel-himax-hx8369a.c
create mode 100644 include/drm/bridge/dw_mipi_dsi.h

--
2.1.0


2014-12-31 08:19:33

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 01/21] clk: divider: Correct parent clk round rate if no bestdiv is normally found

If no best divider is normally found, we will try to use the maximum divider.
We should not set the parent clock rate to be 1Hz by force for being rounded.
Instead, we should take the maximum divider as a base and calculate a correct
parent clock rate for being rounded.

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v4->v5:
* None.

v3->v4:
* None.

v2->v3:
* None.

v1->v2:
* None.

drivers/clk/clk-divider.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index c0a842b..f641d4b 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -311,7 +311,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,

if (!bestdiv) {
bestdiv = _get_maxdiv(divider);
- *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
+ *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
+ MULT_ROUND_UP(rate, bestdiv));
}

return bestdiv;
--
2.1.0

2014-12-31 08:19:42

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 02/21] of: Add vendor prefix for Himax Technologies Inc.

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v4->v5:
* None.

v3->v4:
* Fix an ordering issue to address Stefan Wahren's comment.

v2->v3:
* None.

v1->v2:
* None.

Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 78efebb..f46adb2 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -67,6 +67,7 @@ gumstix Gumstix, Inc.
gw Gateworks Corporation
hannstar HannStar Display Corporation
haoyu Haoyu Microelectronic Co. Ltd.
+himax Himax Technologies, Inc.
hisilicon Hisilicon Limited.
hit Hitachi Ltd.
honeywell Honeywell
--
2.1.0

2014-12-31 08:19:51

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 06/21] ARM: imx6q: clk: Change hdmi_isfr clock's parent to be video_27m clock

According to the table 33-1 in the i.MX6Q reference manual, the hdmi_isfr
clock's parent should be the video_27m clock. The i.MX6DL reference manual
has the same statement. This patch changes the hdmi_isfr clock's parent
from the pll3_pfd1_540m clock to the video_27m clock.

Suggested-by: Philipp Zabel <[email protected]>
Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v4->v5:
* None.

v3->v4:
* None.

v2->v3:
* Newly introduced in v3.

arch/arm/mach-imx/clk-imx6q.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index 9470df3..f19472a 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -401,7 +401,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24);
clk[IMX6QDL_CLK_GPU3D_CORE] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26);
clk[IMX6QDL_CLK_HDMI_IAHB] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0);
- clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "pll3_pfd1_540m", base + 0x70, 4);
+ clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "video_27m", base + 0x70, 4);
clk[IMX6QDL_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6);
clk[IMX6QDL_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8);
clk[IMX6QDL_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10);
--
2.1.0

2014-12-31 08:19:55

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 07/21] ARM: imx6q: clk: Change hsi_tx clock to be a shared clock gate

The CG8 field of the CCM CCGR3 register is named as 'mipi_core_cfg'
clock, according to the i.MX6q/sdl reference manuals. This clock is
actually the gate for several clocks, including the hsi_tx_sel clock's
output and the video_27m clock's output. So, this patch changes the
hsi_tx clock to be a shared clock gate.

Suggested-by: Philipp Zabel <[email protected]>
Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v4->v5:
* None.

v3->v4:
* None.

v2->v3:
* Newly introduced in v3.

arch/arm/mach-imx/clk-imx6q.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index f19472a..080d5b7 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -119,6 +119,7 @@ static unsigned int share_count_asrc;
static unsigned int share_count_ssi1;
static unsigned int share_count_ssi2;
static unsigned int share_count_ssi3;
+static unsigned int share_count_mipi_core_cfg;

static void __init imx6q_clocks_init(struct device_node *ccm_node)
{
@@ -416,7 +417,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_podf", base + 0x74, 12);
clk[IMX6QDL_CLK_LDB_DI1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", base + 0x74, 14);
clk[IMX6QDL_CLK_IPU2_DI1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10);
- clk[IMX6QDL_CLK_HSI_TX] = imx_clk_gate2("hsi_tx", "hsi_tx_podf", base + 0x74, 16);
+ clk[IMX6QDL_CLK_HSI_TX] = imx_clk_gate2_shared("hsi_tx", "hsi_tx_podf", base + 0x74, 16, &share_count_mipi_core_cfg);
if (cpu_is_imx6dl())
/*
* The multiplexer and divider of the imx6q clock gpu2d get
--
2.1.0

2014-12-31 08:20:01

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 08/21] ARM: imx6q: clk: Add support for mipi_core_cfg clock as a shared clock gate

The CG8 field of the CCM CCGR3 register is named as 'mipi_core_cfg' clock,
according to the i.MX6q/sdl reference manuals. This clock is actually the
gate for several clocks, including the hsi_tx_sel clock's output and the
video_27m clock's output. The MIPI DSI host controller embedded in the
i.MX6q/sdl SoCs uses the video_27m clock to generate PLL reference clock and
MIPI core configuration clock. In order to gate/ungate the two MIPI DSI
host controller relevant clocks, this patch adds the mipi_core_cfg clock as
a shared clock gate.

Suggested-by: Philipp Zabel <[email protected]>
Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* Add two spaces in the clock driver to eliminate two errors reported by
the checkpatch.pl script.

v4->v5:
* None.

v3->v4:
* None.

v2->v3:
* Newly introduced in v3.

arch/arm/mach-imx/clk-imx6q.c | 1 +
include/dt-bindings/clock/imx6qdl-clock.h | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index 080d5b7..0f4d07c 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -418,6 +418,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_LDB_DI1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", base + 0x74, 14);
clk[IMX6QDL_CLK_IPU2_DI1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10);
clk[IMX6QDL_CLK_HSI_TX] = imx_clk_gate2_shared("hsi_tx", "hsi_tx_podf", base + 0x74, 16, &share_count_mipi_core_cfg);
+ clk[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg);
if (cpu_is_imx6dl())
/*
* The multiplexer and divider of the imx6q clock gpu2d get
diff --git a/include/dt-bindings/clock/imx6qdl-clock.h b/include/dt-bindings/clock/imx6qdl-clock.h
index 25625bf..dbc828c 100644
--- a/include/dt-bindings/clock/imx6qdl-clock.h
+++ b/include/dt-bindings/clock/imx6qdl-clock.h
@@ -249,6 +249,7 @@
#define IMX6QDL_PLL7_BYPASS 236
#define IMX6QDL_CLK_GPT_3M 237
#define IMX6QDL_CLK_VIDEO_27M 238
-#define IMX6QDL_CLK_END 239
+#define IMX6QDL_CLK_MIPI_CORE_CFG 239
+#define IMX6QDL_CLK_END 240

#endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */
--
2.1.0

2014-12-31 08:20:08

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 10/21] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* Address the over 80 characters in one line warning reported by the
checkpatch.pl script.

v4->v5:
* None.

v3->v4:
* None.

v2->v3:
* None.

v1->v2:
* Thierry Reding suggested that the mipi_dsi_pixel_format_to_bpp() function
could be placed at the common DRM MIPI DSI driver.
This patch is newly added.

include/drm/drm_mipi_dsi.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index f1d8d0d..3662021 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -163,6 +163,20 @@ static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev)
return container_of(dev, struct mipi_dsi_device, dev);
}

+static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
+{
+ switch (fmt) {
+ case MIPI_DSI_FMT_RGB888:
+ case MIPI_DSI_FMT_RGB666:
+ return 24;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ return 18;
+ case MIPI_DSI_FMT_RGB565:
+ return 16;
+ }
+ return -EINVAL;
+}
+
struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np);
int mipi_dsi_attach(struct mipi_dsi_device *dsi);
int mipi_dsi_detach(struct mipi_dsi_device *dsi);
--
2.1.0

2014-12-31 08:20:25

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 14/21] drm: imx: Support Synopsys DesignWare MIPI DSI host controller

This patch adds support for Synopsys DesignWare MIPI DSI host controller
which is embedded in the i.MX6q/sdl SoCs.

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* Make the checkpatch.pl script be happier.

v4->v5:
* None.

v3->v4:
* Move the relevant dt-bindings to a separate patch to address Stefan
Wahren's comment.

v2->v3:
* To address Andy Yan's comments, move the common Synopsys DesignWare MIPI DSI
host controller logic into it's drm/bridge driver and leave the i.MX specific
logic only.

v1->v2:
* Address almost all comments from Thierry Reding and Russell.
* Update the DT documentation to remove the display-timings node in the panel node.
* Update the DT documentation to state that the nodes which represent the possible
DRM CRTCs the controller may connect with should be placed in the node "ports".
* Remove the flag 'enabled' from the struct imx_mipi_dsi.
* Move the format_to_bpp() function in v1 to the common DRM MIPI DSI driver.
* Improve the way we wait for check status for DPHY and command packet transfer.
* Improve the DPMS support for the encoder.
* Split the functions of ->host_attach() and ->mode_valid() clearly as suggested by
Thierry Reding.
* Improve the logics in imx_mipi_dsi_dcs_long_write().
* Enable/disable the pllref_clk and pllref_gate_clk at the component binding/unbinding
stages to help remove the flag 'enabled'.
* Update the module license to be "GPL".
* Other minor changes, such as coding style issues and macro naming issues.

drivers/gpu/drm/imx/Kconfig | 7 ++
drivers/gpu/drm/imx/Makefile | 1 +
drivers/gpu/drm/imx/dw_mipi_dsi-imx.c | 230 ++++++++++++++++++++++++++++++++++
3 files changed, 238 insertions(+)
create mode 100644 drivers/gpu/drm/imx/dw_mipi_dsi-imx.c

diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
index 82fb758..c576f6b 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -51,3 +51,10 @@ config DRM_IMX_HDMI
depends on DRM_IMX
help
Choose this if you want to use HDMI on i.MX6.
+
+config DRM_IMX_MIPI_DSI
+ tristate "Freescale i.MX DRM MIPI DSI"
+ select DRM_DW_MIPI_DSI
+ depends on DRM_IMX
+ help
+ Choose this if you want to use MIPI DSI on i.MX6.
diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile
index 582c438..f0dc278 100644
--- a/drivers/gpu/drm/imx/Makefile
+++ b/drivers/gpu/drm/imx/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
+obj-$(CONFIG_DRM_IMX_MIPI_DSI) += dw_mipi_dsi-imx.o
diff --git a/drivers/gpu/drm/imx/dw_mipi_dsi-imx.c b/drivers/gpu/drm/imx/dw_mipi_dsi-imx.c
new file mode 100644
index 0000000..b2c96e2
--- /dev/null
+++ b/drivers/gpu/drm/imx/dw_mipi_dsi-imx.c
@@ -0,0 +1,230 @@
+/*
+ * i.MX drm driver - MIPI DSI Host Controller
+ *
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/component.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/videodev2.h>
+#include <drm/bridge/dw_mipi_dsi.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_mipi_dsi.h>
+
+#include "imx-drm.h"
+
+#define DRIVER_NAME "imx-mipi-dsi"
+
+struct imx_mipi_dsi {
+ struct drm_encoder encoder;
+ struct device *dev;
+ struct regmap *regmap;
+};
+
+static inline struct imx_mipi_dsi *enc_to_dsi(struct drm_encoder *enc)
+{
+ return container_of(enc, struct imx_mipi_dsi, encoder);
+}
+
+static void imx_mipi_dsi_set_ipu_di_mux(struct imx_mipi_dsi *dsi, int ipu_di)
+{
+ regmap_update_bits(dsi->regmap, IOMUXC_GPR3,
+ IMX6Q_GPR3_MIPI_MUX_CTL_MASK,
+ ipu_di << IMX6Q_GPR3_MIPI_MUX_CTL_SHIFT);
+}
+
+static struct drm_encoder_funcs imx_mipi_dsi_encoder_funcs = {
+ .destroy = imx_drm_encoder_destroy,
+};
+
+static bool imx_mipi_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void imx_mipi_dsi_encoder_prepare(struct drm_encoder *encoder)
+{
+ u32 encoder_pix_fmt, interface_pix_fmt;
+
+ encoder_pix_fmt = dw_mipi_dsi_get_encoder_pixel_format(encoder);
+
+ switch (encoder_pix_fmt) {
+ case MIPI_DSI_FMT_RGB888:
+ interface_pix_fmt = V4L2_PIX_FMT_RGB24;
+ break;
+ case MIPI_DSI_FMT_RGB565:
+ interface_pix_fmt = V4L2_PIX_FMT_RGB565;
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ imx_drm_panel_format(encoder, interface_pix_fmt);
+}
+
+static void imx_mipi_dsi_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void imx_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
+{
+ struct imx_mipi_dsi *dsi = enc_to_dsi(encoder);
+ int mux = imx_drm_encoder_get_mux_id(dsi->dev->of_node, encoder);
+
+ imx_mipi_dsi_set_ipu_di_mux(dsi, mux);
+}
+
+static void imx_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static struct drm_encoder_helper_funcs imx_mipi_dsi_encoder_helper_funcs = {
+ .mode_fixup = imx_mipi_dsi_encoder_mode_fixup,
+ .prepare = imx_mipi_dsi_encoder_prepare,
+ .mode_set = imx_mipi_dsi_encoder_mode_set,
+ .commit = imx_mipi_dsi_encoder_commit,
+ .disable = imx_mipi_dsi_encoder_disable,
+};
+
+static int imx_mipi_dsi_register(struct drm_device *drm,
+ struct imx_mipi_dsi *dsi)
+{
+ int ret;
+
+ ret = imx_drm_encoder_parse_of(drm, &dsi->encoder, dsi->dev->of_node);
+ if (ret)
+ return ret;
+
+ drm_encoder_helper_add(&dsi->encoder,
+ &imx_mipi_dsi_encoder_helper_funcs);
+ drm_encoder_init(drm, &dsi->encoder, &imx_mipi_dsi_encoder_funcs,
+ DRM_MODE_ENCODER_DSI);
+ return 0;
+}
+
+static enum drm_mode_status imx_mipi_dsi_mode_valid(
+ struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ /*
+ * The VID_PKT_SIZE field in the DSI_VID_PKT_CFG
+ * register is 11-bit.
+ */
+ if (mode->hdisplay > 0x7ff)
+ return MODE_BAD_HVALUE;
+
+ /*
+ * The V_ACTIVE_LINES field in the DSI_VTIMING_CFG
+ * register is 11-bit.
+ */
+ if (mode->vdisplay > 0x7ff)
+ return MODE_BAD_VVALUE;
+
+ return MODE_OK;
+}
+
+static struct dw_mipi_dsi_plat_data imx6q_mipi_dsi_drv_data = {
+ .max_data_lanes = 2,
+ .mode_valid = imx_mipi_dsi_mode_valid,
+};
+
+static const struct of_device_id imx_mipi_dsi_dt_ids[] = {
+ {
+ .compatible = "fsl,imx6q-mipi-dsi",
+ .data = &imx6q_mipi_dsi_drv_data,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_mipi_dsi_dt_ids);
+
+static int imx_mipi_dsi_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ const struct of_device_id *of_id =
+ of_match_device(imx_mipi_dsi_dt_ids, dev);
+ const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
+ struct drm_device *drm = data;
+ struct device_node *np = dev->of_node;
+ struct imx_mipi_dsi *dsi;
+ struct resource *res;
+ int ret;
+
+ dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+ if (!dsi)
+ return -ENOMEM;
+
+ dsi->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ dsi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+ if (IS_ERR(dsi->regmap))
+ return PTR_ERR(dsi->regmap);
+
+ ret = imx_mipi_dsi_register(drm, dsi);
+ if (ret)
+ return ret;
+
+ dev_set_drvdata(dev, dsi);
+
+ return dw_mipi_dsi_bind(dev, master, data, &dsi->encoder, res, pdata);
+}
+
+static void imx_mipi_dsi_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ return dw_mipi_dsi_unbind(dev, master, data);
+}
+
+static const struct component_ops imx_mipi_dsi_ops = {
+ .bind = imx_mipi_dsi_bind,
+ .unbind = imx_mipi_dsi_unbind,
+};
+
+static int imx_mipi_dsi_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &imx_mipi_dsi_ops);
+}
+
+static int imx_mipi_dsi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_mipi_dsi_ops);
+ return 0;
+}
+
+static struct platform_driver imx_mipi_dsi_driver = {
+ .probe = imx_mipi_dsi_probe,
+ .remove = imx_mipi_dsi_remove,
+ .driver = {
+ .of_match_table = imx_mipi_dsi_dt_ids,
+ .name = DRIVER_NAME,
+ },
+};
+module_platform_driver(imx_mipi_dsi_driver);
+
+MODULE_DESCRIPTION("i.MX MIPI DSI host controller driver");
+MODULE_AUTHOR("Liu Ying <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
--
2.1.0

2014-12-31 08:20:33

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 16/21] drm: panel: Add support for Himax HX8369A MIPI DSI panel

This patch adds support for Himax HX8369A MIPI DSI panel.

Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* Remove several unnecessary headers included in the driver.

v6->v7:
* Address Andrzej Hajda's following comments.
* Simplify the return logic in hx8369a_dcs_write().
* Replace the macro hx8369a_dsi_init_helper() with a function array to improve
the code quality.
* Handle error cases during getting gpios in probe().
* Add 'Reviewed-by: Andrzej Hajda <[email protected]>'.

v5->v6:
* Make the checkpatch.pl script be happier.
* Do not set the dsi channel number to be zero in probe(), because the MIPI DSI
bus driver would set it.

v4->v5:
* Address Andrzej Hajda's comments.
* Get the bs-gpios property instead of the bs[3:0]-gpios properties.
* Implement error propagation for panel register configurations.
* Other minor changes to improve the code quality.

v3->v4:
* Move the relevant dt-bindings to a separate patch to address Stefan
Wahren's comment.

v2->v3:
* Sort the included header files alphabetically.

v1->v2:
* Address almost all comments from Thierry Reding.
* Remove several DT properties as they can be implied by the compatible string.
* Add the HIMAX/himax prefixes to the driver's Kconfig name and driver name.
* Move the driver's Makefile entry place to sort the entries alphabetically.
* Reuse several standard DCS functions instead of inventing wheels.
* Move the panel resetting and power logics to the driver probe/remove stages.
This may simplify panel prepare/unprepare hooks. The power consumption should
not change a lot at DPMS since the panel enters sleep mode at that time.
* Add the module author.
* Other minor changes, such as coding style issues.

drivers/gpu/drm/panel/Kconfig | 5 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-himax-hx8369a.c | 610 ++++++++++++++++++++++++++++
3 files changed, 616 insertions(+)
create mode 100644 drivers/gpu/drm/panel/panel-himax-hx8369a.c

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 024e98e..81b0bf0 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -16,6 +16,11 @@ config DRM_PANEL_SIMPLE
that it can be automatically turned off when the panel goes into a
low power state.

+config DRM_PANEL_HIMAX_HX8369A
+ tristate "Himax HX8369A panel"
+ depends on OF
+ select DRM_MIPI_DSI
+
config DRM_PANEL_LD9040
tristate "LD9040 RGB/SPI panel"
depends on OF && SPI
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 4b2a043..d5dbe06 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
+obj-$(CONFIG_DRM_PANEL_HIMAX_HX8369A) += panel-himax-hx8369a.o
obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o
obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o
obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
diff --git a/drivers/gpu/drm/panel/panel-himax-hx8369a.c b/drivers/gpu/drm/panel/panel-himax-hx8369a.c
new file mode 100644
index 0000000..34b9a40
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-himax-hx8369a.c
@@ -0,0 +1,610 @@
+/*
+ * Himax HX8369A panel driver.
+ *
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver is based on Samsung s6e8aa0 panel driver.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+
+#define WRDISBV 0x51
+#define WRCTRLD 0x53
+#define WRCABC 0x55
+#define SETPOWER 0xb1
+#define SETDISP 0xb2
+#define SETCYC 0xb4
+#define SETVCOM 0xb6
+#define SETEXTC 0xb9
+#define SETMIPI 0xba
+#define SETPANEL 0xcc
+#define SETGIP 0xd5
+#define SETGAMMA 0xe0
+
+#define HX8369A_MIN_BRIGHTNESS 0x00
+#define HX8369A_MAX_BRIGHTNESS 0xff
+
+enum hx8369a_mpu_interface {
+ HX8369A_DBI_TYPE_A_8BIT,
+ HX8369A_DBI_TYPE_A_9BIT,
+ HX8369A_DBI_TYPE_A_16BIT,
+ HX8369A_DBI_TYPE_A_18BIT,
+ HX8369A_DBI_TYPE_B_8BIT,
+ HX8369A_DBI_TYPE_B_9BIT,
+ HX8369A_DBI_TYPE_B_16BIT,
+ HX8369A_DBI_TYPE_B_18BIT,
+ HX8369A_DSI_CMD_MODE,
+ HX8369A_DBI_TYPE_B_24BIT,
+ HX8369A_DSI_VIDEO_MODE,
+ HX8369A_MDDI,
+ HX8369A_DPI_DBI_TYPE_C_OPT1,
+ HX8369A_DPI_DBI_TYPE_C_OPT2,
+ HX8369A_DPI_DBI_TYPE_C_OPT3
+};
+
+enum hx8369a_resolution {
+ HX8369A_RES_480_864,
+ HX8369A_RES_480_854,
+ HX8369A_RES_480_800,
+ HX8369A_RES_480_640,
+ HX8369A_RES_360_640,
+ HX8369A_RES_480_720,
+};
+
+struct hx8369a_panel_desc {
+ const struct drm_display_mode *mode;
+
+ /* ms */
+ unsigned int power_on_delay;
+ unsigned int reset_delay;
+
+ unsigned int dsi_lanes;
+};
+
+struct hx8369a {
+ struct device *dev;
+ struct drm_panel panel;
+
+ const struct hx8369a_panel_desc *pd;
+
+ struct regulator_bulk_data supplies[5];
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *bs_gpio[4];
+ u8 res_sel;
+};
+
+static inline struct hx8369a *panel_to_hx8369a(struct drm_panel *panel)
+{
+ return container_of(panel, struct hx8369a, panel);
+}
+
+static int hx8369a_dcs_write(struct hx8369a *ctx, const char *func,
+ const void *data, size_t len)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ ssize_t ret;
+
+ ret = mipi_dsi_dcs_write_buffer(dsi, data, len);
+ if (ret < 0)
+ dev_err(ctx->dev, "%s failed: %d\n", func, ret);
+ return ret;
+}
+
+#define hx8369a_dcs_write_seq(ctx, seq...) \
+({ \
+ const u8 d[] = { seq }; \
+ BUILD_BUG_ON_MSG(ARRAY_SIZE(d) > 64, \
+ "DCS sequence too big for stack"); \
+ hx8369a_dcs_write(ctx, __func__, d, ARRAY_SIZE(d)); \
+})
+
+#define hx8369a_dcs_write_seq_static(ctx, seq...) \
+({ \
+ static const u8 d[] = { seq }; \
+ hx8369a_dcs_write(ctx, __func__, d, ARRAY_SIZE(d)); \
+})
+
+static int hx8369a_dsi_set_display_related_register(struct hx8369a *ctx)
+{
+ u8 sec_p = (ctx->res_sel << 4) | 0x03;
+
+ return hx8369a_dcs_write_seq(ctx, SETDISP, 0x00, sec_p, 0x03,
+ 0x03, 0x70, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x03, 0x00, 0x01);
+}
+
+static int hx8369a_dsi_set_display_waveform_cycle(struct hx8369a *ctx)
+{
+ return hx8369a_dcs_write_seq_static(ctx, SETCYC, 0x00, 0x1d,
+ 0x5f, 0x0e, 0x06);
+}
+
+static int hx8369a_dsi_set_gip(struct hx8369a *ctx)
+{
+ return hx8369a_dcs_write_seq_static(ctx, SETGIP, 0x00, 0x04,
+ 0x03, 0x00, 0x01, 0x05, 0x1c, 0x70,
+ 0x01, 0x03, 0x00, 0x00, 0x40, 0x06,
+ 0x51, 0x07, 0x00, 0x00, 0x41, 0x06,
+ 0x50, 0x07, 0x07, 0x0f, 0x04);
+}
+
+static int hx8369a_dsi_set_power(struct hx8369a *ctx)
+{
+ return hx8369a_dcs_write_seq_static(ctx, SETPOWER, 0x01, 0x00,
+ 0x34, 0x06, 0x00, 0x0f, 0x0f, 0x2a,
+ 0x32, 0x3f, 0x3f, 0x07, 0x3a, 0x01,
+ 0xe6, 0xe6, 0xe6, 0xe6, 0xe6);
+}
+
+static int hx8369a_dsi_set_vcom_voltage(struct hx8369a *ctx)
+{
+ return hx8369a_dcs_write_seq_static(ctx, SETVCOM, 0x56, 0x56);
+}
+
+static int hx8369a_dsi_set_panel(struct hx8369a *ctx)
+{
+ return hx8369a_dcs_write_seq_static(ctx, SETPANEL, 0x02);
+}
+
+static int hx8369a_dsi_set_gamma_curve(struct hx8369a *ctx)
+{
+ return hx8369a_dcs_write_seq_static(ctx, SETGAMMA, 0x00, 0x1d,
+ 0x22, 0x38, 0x3d, 0x3f, 0x2e, 0x4a,
+ 0x06, 0x0d, 0x0f, 0x13, 0x15, 0x13,
+ 0x16, 0x10, 0x19, 0x00, 0x1d, 0x22,
+ 0x38, 0x3d, 0x3f, 0x2e, 0x4a, 0x06,
+ 0x0d, 0x0f, 0x13, 0x15, 0x13, 0x16,
+ 0x10, 0x19);
+}
+
+static int hx8369a_dsi_set_mipi(struct hx8369a *ctx)
+{
+ u8 eleventh_p = ctx->pd->dsi_lanes == 2 ? 0x11 : 0x10;
+
+ return hx8369a_dcs_write_seq(ctx, SETMIPI, 0x00, 0xa0, 0xc6,
+ 0x00, 0x0a, 0x00, 0x10, 0x30, 0x6f,
+ 0x02, eleventh_p, 0x18, 0x40);
+}
+
+static int hx8369a_dsi_set_interface_pixel_fomat(struct hx8369a *ctx)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ u8 format;
+ int ret;
+
+ switch (dsi->format) {
+ case MIPI_DSI_FMT_RGB888:
+ case MIPI_DSI_FMT_RGB666:
+ format = 0x77;
+ break;
+ case MIPI_DSI_FMT_RGB565:
+ format = 0x55;
+ break;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ format = 0x66;
+ break;
+ default:
+ dev_err(ctx->dev, "unsupported DSI pixel format\n");
+ return -EINVAL;
+ }
+
+ ret = mipi_dsi_dcs_set_pixel_format(dsi, format);
+ if (ret < 0)
+ dev_err(ctx->dev, "%s failed: %d\n", __func__, ret);
+ return ret;
+}
+
+static int hx8369a_dsi_set_column_address(struct hx8369a *ctx)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ const struct drm_display_mode *mode = ctx->pd->mode;
+ int ret;
+
+ ret = mipi_dsi_dcs_set_column_address(dsi, 0, mode->hdisplay - 1);
+ if (ret < 0)
+ dev_err(ctx->dev, "%s failed: %d\n", __func__, ret);
+ return ret;
+}
+
+static int hx8369a_dsi_set_page_address(struct hx8369a *ctx)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ const struct drm_display_mode *mode = ctx->pd->mode;
+ int ret;
+
+ ret = mipi_dsi_dcs_set_page_address(dsi, 0, mode->vdisplay - 1);
+ if (ret < 0)
+ dev_err(ctx->dev, "%s failed: %d\n", __func__, ret);
+ return ret;
+}
+
+static int hx8369a_dsi_write_display_brightness(struct hx8369a *ctx,
+ u8 brightness)
+{
+ return hx8369a_dcs_write_seq(ctx, WRDISBV, brightness);
+}
+
+static int hx8369a_dsi_write_cabc(struct hx8369a *ctx)
+{
+ return hx8369a_dcs_write_seq_static(ctx, WRCABC, 0x01);
+}
+
+static int hx8369a_dsi_write_control_display(struct hx8369a *ctx)
+{
+ return hx8369a_dcs_write_seq_static(ctx, WRCTRLD, 0x24);
+}
+
+static int hx8369a_dsi_panel_init(struct hx8369a *ctx)
+{
+ int (*funcs[])(struct hx8369a *ctx) = {
+ hx8369a_dsi_set_display_related_register,
+ hx8369a_dsi_set_display_waveform_cycle,
+ hx8369a_dsi_set_gip,
+ hx8369a_dsi_set_power,
+ hx8369a_dsi_set_vcom_voltage,
+ hx8369a_dsi_set_panel,
+ hx8369a_dsi_set_gamma_curve,
+ hx8369a_dsi_set_mipi,
+ hx8369a_dsi_set_interface_pixel_fomat,
+ hx8369a_dsi_set_column_address,
+ hx8369a_dsi_set_page_address,
+ hx8369a_dsi_write_cabc,
+ hx8369a_dsi_write_control_display,
+ };
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(funcs); i++) {
+ ret = funcs[i](ctx);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int hx8369a_dsi_set_extension_command(struct hx8369a *ctx)
+{
+ return hx8369a_dcs_write_seq_static(ctx, SETEXTC, 0xff, 0x83, 0x69);
+}
+
+static int hx8369a_dsi_set_maximum_return_packet_size(struct hx8369a *ctx,
+ u16 size)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ int ret;
+
+ ret = mipi_dsi_set_maximum_return_packet_size(dsi, size);
+ if (ret < 0)
+ dev_err(ctx->dev,
+ "error %d setting maximum return packet size to %d\n",
+ ret, size);
+ return ret;
+}
+
+static int hx8369a_dsi_set_sequence(struct hx8369a *ctx)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ int ret;
+
+ ret = hx8369a_dsi_set_extension_command(ctx);
+ if (ret < 0)
+ goto out;
+
+ ret = hx8369a_dsi_set_maximum_return_packet_size(ctx, 4);
+ if (ret < 0)
+ goto out;
+
+ ret = hx8369a_dsi_panel_init(ctx);
+ if (ret < 0)
+ goto out;
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ dev_err(ctx->dev, "failed to exit sleep mode: %d\n", ret);
+ goto out;
+ }
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret < 0) {
+ dev_err(ctx->dev, "failed to set display on: %d\n", ret);
+ goto out;
+ }
+
+ /*
+ * It's necessary to wait 120msec after sending the Sleep Out
+ * command before Sleep In command can be sent, according to
+ * the HX8369A data sheet.
+ */
+ msleep(120);
+out:
+ return ret;
+}
+
+static int hx8369a_dsi_disable(struct drm_panel *panel)
+{
+ struct hx8369a *ctx = panel_to_hx8369a(panel);
+
+ return hx8369a_dsi_write_display_brightness(ctx,
+ HX8369A_MIN_BRIGHTNESS);
+}
+
+static int hx8369a_dsi_unprepare(struct drm_panel *panel)
+{
+ struct hx8369a *ctx = panel_to_hx8369a(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ int ret;
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (ret < 0) {
+ dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
+ goto out;
+ }
+
+ ret = mipi_dsi_dcs_set_display_off(dsi);
+ if (ret < 0) {
+ dev_err(ctx->dev, "failed to set display off: %d\n", ret);
+ goto out;
+ }
+
+ /*
+ * This is to allow time for the supply voltages and clock
+ * circuits to stablize, according to the HX8369A data sheet.
+ */
+ msleep(5);
+out:
+ return ret;
+}
+
+static int hx8369a_dsi_prepare(struct drm_panel *panel)
+{
+ struct hx8369a *ctx = panel_to_hx8369a(panel);
+
+ return hx8369a_dsi_set_sequence(ctx);
+}
+
+static int hx8369a_dsi_enable(struct drm_panel *panel)
+{
+ struct hx8369a *ctx = panel_to_hx8369a(panel);
+
+ return hx8369a_dsi_write_display_brightness(ctx,
+ HX8369A_MAX_BRIGHTNESS);
+}
+
+static int hx8369a_get_modes(struct drm_panel *panel)
+{
+ struct drm_connector *connector = panel->connector;
+ struct drm_device *drm = panel->drm;
+ struct hx8369a *ctx = panel_to_hx8369a(panel);
+ struct drm_display_mode *mode;
+ const struct drm_display_mode *m = ctx->pd->mode;
+
+ mode = drm_mode_duplicate(drm, m);
+ if (!mode) {
+ dev_err(drm->dev, "failed to add mode %ux%u@%u\n",
+ m->hdisplay, m->vdisplay, m->vrefresh);
+ return 0;
+ }
+
+ drm_mode_set_name(mode);
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+
+ connector->display_info.bpc = 8;
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
+
+ drm_mode_probed_add(connector, mode);
+
+ return 1;
+}
+
+static const struct drm_panel_funcs hx8369a_dsi_drm_funcs = {
+ .disable = hx8369a_dsi_disable,
+ .unprepare = hx8369a_dsi_unprepare,
+ .prepare = hx8369a_dsi_prepare,
+ .enable = hx8369a_dsi_enable,
+ .get_modes = hx8369a_get_modes,
+};
+
+static int hx8369a_power_on(struct hx8369a *ctx)
+{
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ if (ret < 0)
+ return ret;
+
+ msleep(ctx->pd->power_on_delay);
+
+ gpiod_set_value(ctx->reset_gpio, 1);
+ usleep_range(50, 60);
+ gpiod_set_value(ctx->reset_gpio, 0);
+
+ msleep(ctx->pd->reset_delay);
+
+ return 0;
+}
+
+static int hx8369a_power_off(struct hx8369a *ctx)
+{
+ return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+}
+
+static void hx8369a_vm_to_res_sel(struct hx8369a *ctx)
+{
+ const struct drm_display_mode *mode = ctx->pd->mode;
+
+ switch (mode->hdisplay) {
+ case 480:
+ switch (mode->vdisplay) {
+ case 864:
+ ctx->res_sel = HX8369A_RES_480_864;
+ break;
+ case 854:
+ ctx->res_sel = HX8369A_RES_480_854;
+ break;
+ case 800:
+ ctx->res_sel = HX8369A_RES_480_800;
+ break;
+ case 640:
+ ctx->res_sel = HX8369A_RES_480_640;
+ break;
+ case 720:
+ ctx->res_sel = HX8369A_RES_480_720;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 360:
+ if (mode->vdisplay == 640)
+ ctx->res_sel = HX8369A_RES_360_640;
+ break;
+ default:
+ break;
+ }
+}
+
+static const struct drm_display_mode truly_tft480800_16_e_mode = {
+ .clock = 26400,
+ .hdisplay = 480,
+ .hsync_start = 480 + 8,
+ .hsync_end = 480 + 8 + 8,
+ .htotal = 480 + 8 + 8 + 8,
+ .vdisplay = 800,
+ .vsync_start = 800 + 6,
+ .vsync_end = 800 + 6 + 6,
+ .vtotal = 800 + 6 + 6 + 6,
+ .vrefresh = 60,
+ .width_mm = 45,
+ .height_mm = 76,
+};
+
+static const struct hx8369a_panel_desc truly_tft480800_16_e_dsi = {
+ .mode = &truly_tft480800_16_e_mode,
+ .power_on_delay = 10,
+ .reset_delay = 10,
+ .dsi_lanes = 2,
+};
+
+static const struct of_device_id hx8369a_dsi_of_match[] = {
+ {
+ .compatible = "truly,tft480800-16-e-dsi",
+ .data = &truly_tft480800_16_e_dsi,
+ }, {
+ /* sentinel */
+ },
+};
+MODULE_DEVICE_TABLE(of, hx8369a_dsi_of_match);
+
+static int hx8369a_dsi_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ const struct of_device_id *of_id =
+ of_match_device(hx8369a_dsi_of_match, dev);
+ struct hx8369a *ctx;
+ int ret, i;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->dev = dev;
+
+ if (of_id) {
+ ctx->pd = of_id->data;
+ } else {
+ dev_err(dev, "cannot find compatible device\n");
+ return -ENODEV;
+ }
+
+ hx8369a_vm_to_res_sel(ctx);
+
+ ctx->supplies[0].supply = "vdd1";
+ ctx->supplies[1].supply = "vdd2";
+ ctx->supplies[2].supply = "vdd3";
+ ctx->supplies[3].supply = "dsi-vcc";
+ ctx->supplies[4].supply = "vpp";
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
+ ctx->supplies);
+ if (ret < 0) {
+ dev_info(dev, "failed to get regulators: %d\n", ret);
+ return ret;
+ }
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset_gpio)) {
+ dev_info(dev, "cannot get reset-gpios %ld\n",
+ PTR_ERR(ctx->reset_gpio));
+ return PTR_ERR(ctx->reset_gpio);
+ }
+
+ for (i = 0; i < 4; i++) {
+ ctx->bs_gpio[i] = devm_gpiod_get_index_optional(dev, "bs", i,
+ GPIOD_OUT_HIGH);
+ if (!IS_ERR_OR_NULL(ctx->bs_gpio[i])) {
+ dev_dbg(dev, "bs%d-gpio is configured\n", i);
+ } else if (IS_ERR(ctx->bs_gpio[i])) {
+ dev_info(dev, "failed to get bs%d-gpio\n", i);
+ return PTR_ERR(ctx->bs_gpio[i]);
+ }
+ }
+
+ ret = hx8369a_power_on(ctx);
+ if (ret < 0) {
+ dev_err(dev, "cannot power on\n");
+ return ret;
+ }
+
+ drm_panel_init(&ctx->panel);
+ ctx->panel.dev = dev;
+ ctx->panel.funcs = &hx8369a_dsi_drm_funcs;
+
+ ret = drm_panel_add(&ctx->panel);
+ if (ret < 0)
+ return ret;
+
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ dsi->lanes = ctx->pd->dsi_lanes;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_BURST |
+ MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0)
+ drm_panel_remove(&ctx->panel);
+
+ return ret;
+}
+
+static int hx8369a_dsi_remove(struct mipi_dsi_device *dsi)
+{
+ struct hx8369a *ctx = mipi_dsi_get_drvdata(dsi);
+
+ mipi_dsi_detach(dsi);
+ drm_panel_remove(&ctx->panel);
+ return hx8369a_power_off(ctx);
+}
+
+static struct mipi_dsi_driver hx8369a_dsi_driver = {
+ .probe = hx8369a_dsi_probe,
+ .remove = hx8369a_dsi_remove,
+ .driver = {
+ .name = "panel-hx8369a-dsi",
+ .of_match_table = hx8369a_dsi_of_match,
+ },
+};
+module_mipi_dsi_driver(hx8369a_dsi_driver);
+
+MODULE_DESCRIPTION("Himax HX8369A panel driver");
+MODULE_AUTHOR("Liu Ying <[email protected]>");
+MODULE_LICENSE("GPL v2");
--
2.1.0

2014-12-31 08:20:42

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 18/21] ARM: dts: imx6qdl-sabresd: Add support for TRULY TFT480800-16-E MIPI DSI panel

The TRULY TFT480800-16-E panel is driven by the Himax HX8369A driver IC.
The driver IC supports several display/control interface modes, including
the MIPI DSI video mode and command mode.

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v4->v5:
* Replace the bs[3:0]-gpios properties with the bs-gpios property.
This addresses Andrzej Hajda's comment.

v3->v4:
* None.

v2->v3:
* None.

v1->v2:
* To address Thierry Reding's comments, remove several unnecessary
properties as they can be implied by the compatible string.
* Fix the compatible string.
* Remove the display-timings node from the panel node as it can be
implied by the compatible string as well.
* Remove the status property as it is unneeded.

arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index baf2f00..4e3a666 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -482,6 +482,13 @@
MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059
>;
};
+
+ pinctrl_mipi_panel: mipipanelgrp {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x1b0b0
+ MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x1b0b0
+ >;
+ };
};

gpio_leds {
@@ -518,6 +525,19 @@
};
};

+&mipi_dsi {
+ status = "okay";
+
+ panel {
+ compatible = "truly,tft480800-16-e-dsi";
+ reg = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mipi_panel>;
+ reset-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
+ bs-gpios = <0>, <0>, <&gpio6 14 GPIO_ACTIVE_HIGH>, <0>;
+ };
+};
+
&pcie {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pcie>;
--
2.1.0

2014-12-31 08:20:47

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 20/21] ARM: imx_v6_v7_defconfig: Add support for MIPI DSI host controller

This patch adds support for MIPI DSI host controller.

The new imx_v6_v7_defconfig is generated in this way:
* make ARCH=arm imx_v6_v7_defconfig
* make ARCH=arm menuconfig and manually choose to build in
the MIPI DSI host controller driver
* make ARCH=arm savedefconfig
* cp defconfig arch/arm/configs/imx_v6_v7_defconfig

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v4->v5:
* None.

v3->v4:
* None.

v2->v3:
* None.

v1->v2:
* None.

arch/arm/configs/imx_v6_v7_defconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 0dbd0c3..3e0e589 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -199,6 +199,7 @@ CONFIG_DRM_IMX_TVE=y
CONFIG_DRM_IMX_LDB=y
CONFIG_DRM_IMX_IPUV3=y
CONFIG_DRM_IMX_HDMI=y
+CONFIG_DRM_IMX_MIPI_DSI=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_LCD_L4F00242T03=y
CONFIG_LCD_PLATFORM=y
--
2.1.0

2014-12-31 08:20:52

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 21/21] ARM: imx_v6_v7_defconfig: Add support for Himax HX8369A panel

This patch adds support for Himax HX8369A panel.

The new imx_v6_v7_defconfig is generated in this way:
* make ARCH=arm imx_v6_v7_defconfig
* make ARCH=arm menuconfig and manually choose to build in
the Himax HX8369A panel driver
* make ARCH=arm savedefconfig
* cp defconfig arch/arm/configs/imx_v6_v7_defconfig

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v4->v5:
* None.

v3->v4:
* None.

v2->v3:
* None.

v1->v2:
* Add the HIMAX prefix in the Kconfig name.

arch/arm/configs/imx_v6_v7_defconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 3e0e589..27db91b 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -192,6 +192,7 @@ CONFIG_SOC_CAMERA_OV2640=y
CONFIG_IMX_IPUV3_CORE=y
CONFIG_DRM=y
CONFIG_DRM_PANEL_SIMPLE=y
+CONFIG_DRM_PANEL_HIMAX_HX8369A=y
CONFIG_DRM_IMX=y
CONFIG_DRM_IMX_FB_HELPER=y
CONFIG_DRM_IMX_PARALLEL_DISPLAY=y
--
2.1.0

2014-12-31 08:21:35

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 19/21] ARM: imx_v6_v7_defconfig: Cleanup for imx drm being moved out of staging

The new imx_v6_v7_defconfig is generated in this way:
* make ARCH=arm imx_v6_v7_defconfig
* make ARCH=arm savedefconfig
* cp defconfig arch/arm/configs/imx_v6_v7_defconfig

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v4->v5:
* None.

v3->v4:
* None.

v2->v3:
* None.

v1->v2:
* None.

arch/arm/configs/imx_v6_v7_defconfig | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 6790f1b..0dbd0c3 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -192,7 +192,13 @@ CONFIG_SOC_CAMERA_OV2640=y
CONFIG_IMX_IPUV3_CORE=y
CONFIG_DRM=y
CONFIG_DRM_PANEL_SIMPLE=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_DRM_IMX=y
+CONFIG_DRM_IMX_FB_HELPER=y
+CONFIG_DRM_IMX_PARALLEL_DISPLAY=y
+CONFIG_DRM_IMX_TVE=y
+CONFIG_DRM_IMX_LDB=y
+CONFIG_DRM_IMX_IPUV3=y
+CONFIG_DRM_IMX_HDMI=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_LCD_L4F00242T03=y
CONFIG_LCD_PLATFORM=y
@@ -249,13 +255,6 @@ CONFIG_IMX_SDMA=y
CONFIG_MXS_DMA=y
CONFIG_FSL_EDMA=y
CONFIG_STAGING=y
-CONFIG_DRM_IMX=y
-CONFIG_DRM_IMX_FB_HELPER=y
-CONFIG_DRM_IMX_PARALLEL_DISPLAY=y
-CONFIG_DRM_IMX_TVE=y
-CONFIG_DRM_IMX_LDB=y
-CONFIG_DRM_IMX_IPUV3=y
-CONFIG_DRM_IMX_HDMI=y
# CONFIG_IOMMU_SUPPORT is not set
CONFIG_PWM=y
CONFIG_PWM_IMX=y
--
2.1.0

2014-12-31 08:21:49

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 17/21] ARM: dtsi: imx6qdl: Add support for MIPI DSI host controller

This patch adds support for MIPI DSI host controller.

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v3->v4:
* None.

v2->v3:
* As suggested by Phillip Zabel, change the clocks and the clock-names
properties to use the pllref and core_cfg clocks only.

v1->v2:
* None.

arch/arm/boot/dts/imx6qdl.dtsi | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 96bf2a0..7b1c313 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1006,7 +1006,13 @@
mipi_dsi: mipi@021e0000 {
#address-cells = <1>;
#size-cells = <0>;
+ compatible = "fsl,imx6q-mipi-dsi";
reg = <0x021e0000 0x4000>;
+ interrupts = <0 102 IRQ_TYPE_LEVEL_HIGH>;
+ gpr = <&gpr>;
+ clocks = <&clks IMX6QDL_CLK_MIPI_CORE_CFG>,
+ <&clks IMX6QDL_CLK_MIPI_CORE_CFG>;
+ clock-names = "pllref", "core_cfg";
status = "disabled";

ports {
--
2.1.0

2014-12-31 08:22:16

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 15/21] Documentation: dt-bindings: Add bindings for Himax HX8369A DRM panel driver

This patch adds device tree bindings for Himax HX8369A DRM panel driver.

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v4->v5:
* Merge the bs[3:0]-gpios properties into one property - bs-gpios.
This addresses Andrzej Hajda's comment.

v3->v4:
* Newly introduced in v4. This is separated from the relevant driver patch
in v3 to address Stefan Wahren's comment.

.../devicetree/bindings/panel/himax,hx8369a.txt | 39 ++++++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 Documentation/devicetree/bindings/panel/himax,hx8369a.txt

diff --git a/Documentation/devicetree/bindings/panel/himax,hx8369a.txt b/Documentation/devicetree/bindings/panel/himax,hx8369a.txt
new file mode 100644
index 0000000..3a44b70
--- /dev/null
+++ b/Documentation/devicetree/bindings/panel/himax,hx8369a.txt
@@ -0,0 +1,39 @@
+Himax HX8369A WVGA 16.7M color TFT single chip driver with internal GRAM
+
+Himax HX8369A is a WVGA resolution driving controller.
+It is designed to provide a single chip solution that combines a source
+driver and power supply circuits to drive a TFT dot matrix LCD with
+480RGBx864 dots at the maximum.
+
+The HX8369A supports several interface modes, including MPU MIPI DBI Type
+A/B mode, MIPI DPI/DBI Type C mode, MIPI DSI video mode, MIPI DSI command
+mode and MDDI mode. The interface mode is selected by the external hardware
+pins BS[3:0].
+
+Currently, only the MIPI DSI video mode is supported.
+
+Required properties:
+ - compatible: should be a panel's compatible string
+ - reg: the virtual channel number of a DSI peripheral, as described in [1]
+ - reset-gpios: a GPIO spec for the reset pin, as described in [2]
+
+Optional properties:
+ - vdd1-supply: I/O and interface power supply
+ - vdd2-supply: analog power supply
+ - vdd3-supply: logic power supply
+ - dsi-vcc-supply: DSI and MDDI power supply
+ - vpp-supply: OTP programming voltage
+ - bs-gpios: a GPIO spec for the pins BS[3:0], as described in [2]
+
+[1] Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt
+[2] Documentation/devicetree/bindings/gpio/gpio.txt
+
+Example:
+ panel {
+ compatible = "truly,tft480800-16-e-dsi";
+ reg = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mipi_panel>;
+ reset-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
+ bs-gpios = <0>, <0>, <&gpio6 14 GPIO_ACTIVE_HIGH>, <0>;
+ };
--
2.1.0

2014-12-31 08:20:14

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 11/21] Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM bridge driver

This patch adds device tree bindings for Synopsys DesignWare MIPI DSI
host controller DRM bridge driver.

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* Add the #address-cells and #size-cells properties in the example 'ports'
node.
* Remove the useless input-port properties from the example port@0 and port@1
nodes.

v4->v5:
* None.

v3->v4:
* Newly introduced in v4. This is separated from the relevant driver patch
in v3 to address Stefan Wahren's comment.

.../devicetree/bindings/drm/bridge/dw_mipi_dsi.txt | 73 ++++++++++++++++++++++
1 file changed, 73 insertions(+)
create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt

diff --git a/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt b/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
new file mode 100644
index 0000000..f88a8d6
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
@@ -0,0 +1,73 @@
+Device-Tree bindings for Synopsys DesignWare MIPI DSI host controller
+
+The controller is a digital core that implements all protocol functions
+defined in the MIPI DSI specification, providing an interface between
+the system and the MIPI DPHY, and allowing communication with a MIPI DSI
+compliant display.
+
+Required properties:
+ - #address-cells: Should be <1>.
+ - #size-cells: Should be <0>.
+ - compatible: The compatible string should be "fsl,imx6q-mipi-dsi" for
+ i.MX6q/sdl SoCs. For other SoCs, please refer to their specific
+ device tree binding documentations.
+ - reg: Represent the physical address range of the controller.
+ - interrupts: Represent the controller's interrupt to the CPU(s).
+ - clocks, clock-names: Phandles to the controller pll reference and
+ core configuration clocks, as described in [1].
+
+For more required properties, please refer to relevant device tree binding
+documentations which describe the controller embedded in specific SoCs.
+
+Required sub-nodes:
+ - A node to represent a DSI peripheral as described in [2].
+
+For more required sub-nodes, please refer to relevant device tree binding
+documentations which describe the controller embedded in specific SoCs.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt
+
+example:
+ gpr: iomuxc-gpr@020e0000 {
+ /* ... */
+ };
+
+ mipi_dsi: mipi@021e0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx6q-mipi-dsi";
+ reg = <0x021e0000 0x4000>;
+ interrupts = <0 102 IRQ_TYPE_LEVEL_HIGH>;
+ gpr = <&gpr>;
+ clocks = <&clks IMX6QDL_CLK_MIPI_CORE_CFG>,
+ <&clks IMX6QDL_CLK_MIPI_CORE_CFG>;
+ clock-names = "pllref", "core_cfg";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ mipi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_mipi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ mipi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_mipi>;
+ };
+ };
+ };
+
+ panel {
+ compatible = "truly,tft480800-16-e-dsi";
+ reg = <0>;
+ /* ... */
+ };
+ };
--
2.1.0

2014-12-31 08:23:09

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 13/21] Documentation: dt-bindings: Add bindings for i.MX specific Synopsys DW MIPI DSI driver

This patch adds device tree bindings for i.MX specific Synopsys DW MIPI DSI driver.

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* Add the #address-cells and #size-cells properties in the example 'ports'
node.
* Remove the useless pllref_gate clock from the required clocks, clock-names
property.

v4->v5:
* None.

v3->v4:
* Newly introduced in v4. This is separated from the relevant driver patch
in v3 to address Stefan Wahren's comment.

.../devicetree/bindings/drm/imx/mipi_dsi.txt | 78 ++++++++++++++++++++++
1 file changed, 78 insertions(+)
create mode 100644 Documentation/devicetree/bindings/drm/imx/mipi_dsi.txt

diff --git a/Documentation/devicetree/bindings/drm/imx/mipi_dsi.txt b/Documentation/devicetree/bindings/drm/imx/mipi_dsi.txt
new file mode 100644
index 0000000..75a7766
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/imx/mipi_dsi.txt
@@ -0,0 +1,78 @@
+i.MX specific Device-Tree bindings for Synopsys DesignWare MIPI DSI host controller
+
+MIPI DSI host controller
+========================
+
+The MIPI DSI host controller is a Synopsys DesignWare IP.
+The common device tree documentation for this controller can be found
+at [1].
+
+Required properties:
+ - #address-cells: Should be <1>.
+ - #size-cells: Should be <0>.
+ - compatible: The compatible string should be "fsl,imx6q-mipi-dsi"
+ for i.MX6q/sdl SoCs.
+ - reg: Physical base address of the controller and length of memory
+ mapped region.
+ - interrupts: The controller's interrupt number to the CPU(s).
+ - gpr: Should be <&gpr>.
+ The phandle points to the iomuxc-gpr region containing the
+ multiplexer control register for the controller.
+ - clocks, clock-names: Phandles to the controller pllref and core_cfg clocks,
+ as described in [2] and [3].
+
+Required sub-nodes:
+ - ports: This node may contain up to four port nodes with endpoint
+ definitions as defined in [4], corresponding to the four inputs to
+ the controller multiplexer.
+ - A node to represent a DSI peripheral as described in [5].
+
+[1] Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt.
+[2] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[3] Documentation/devicetree/bindings/clock/imx6q-clock.txt
+[4] Documentation/devicetree/bindings/media/video-interfaces.txt
+[5] Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt
+
+example:
+ gpr: iomuxc-gpr@020e0000 {
+ /* ... */
+ };
+
+ mipi_dsi: mipi@021e0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx6q-mipi-dsi";
+ reg = <0x021e0000 0x4000>;
+ interrupts = <0 102 IRQ_TYPE_LEVEL_HIGH>;
+ gpr = <&gpr>;
+ clocks = <&clks IMX6QDL_CLK_MIPI_CORE_CFG>,
+ <&clks IMX6QDL_CLK_MIPI_CORE_CFG>;
+ clock-names = "pllref", "core_cfg";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ mipi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_mipi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ mipi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_mipi>;
+ };
+ };
+ };
+
+ panel {
+ compatible = "truly,tft480800-16-e-dsi";
+ reg = <0>;
+ /* ... */
+ };
+ };
--
2.1.0

2014-12-31 08:23:38

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 12/21] drm/bridge: Add Synopsys DesignWare MIPI DSI host controller driver

This patch adds Synopsys DesignWare MIPI DSI host controller driver support.
Currently, the driver supports the burst with sync pulses mode only.

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* Fix the driver's Kconfig so that we may pass the allmodconfig for ARM.

v6->v7:
* None.

v5->v6:
* Make the checkpatch.pl script be happier.

v4->v5:
* Remove 'dsi->panel = NULL;' in dw_mipi_dsi_host_detach() to address
Andrzej Hajda's comment.

v3->v4:
* Move the relevant dt-bindings to a separate patch to address Stefan
Wahren's comment.

v2->v3:
* Newly introduced in v3 to address Andy Yan's comment. This is based on
the i.MX MIPI DSI driver in v2. To make the Synopsys DesignWare MIPI DSI
host controller driver less platform-dependant, this patch places it at
the drm/bridge directory as a DRM bridge driver.

drivers/gpu/drm/bridge/Kconfig | 10 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/dw_mipi_dsi.c | 996 +++++++++++++++++++++++++++++++++++
include/drm/bridge/dw_mipi_dsi.h | 27 +
4 files changed, 1034 insertions(+)
create mode 100644 drivers/gpu/drm/bridge/dw_mipi_dsi.c
create mode 100644 include/drm/bridge/dw_mipi_dsi.h

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 884923f..318b325 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -1,3 +1,13 @@
+config DRM_DW_MIPI_DSI
+ tristate "Synopsys DesignWare MIPI DSI host controller bridge"
+ depends on DRM
+ select DRM_KMS_HELPER
+ select DRM_MIPI_DSI
+ select DRM_PANEL
+ help
+ Choose this if you want to use the Synopsys DesignWare MIPI DSI host
+ controller bridge.
+
config DRM_PTN3460
tristate "PTN3460 DP/LVDS bridge"
depends on DRM
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index b4733e1..b326ad5 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,3 +1,4 @@
ccflags-y := -Iinclude/drm

+obj-$(CONFIG_DRM_DW_MIPI_DSI) += dw_mipi_dsi.o
obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
diff --git a/drivers/gpu/drm/bridge/dw_mipi_dsi.c b/drivers/gpu/drm/bridge/dw_mipi_dsi.c
new file mode 100644
index 0000000..2b54d44
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw_mipi_dsi.c
@@ -0,0 +1,996 @@
+/*
+ * Synopsys DesignWare(DW) MIPI DSI Host Controller
+ *
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <drm/bridge/dw_mipi_dsi.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <video/mipi_display.h>
+
+#define DSI_VERSION 0x00
+
+#define DSI_PWR_UP 0x04
+#define RESET 0
+#define POWERUP BIT(0)
+
+#define DSI_CLKMGR_CFG 0x08
+#define TO_CLK_DIVIDSION(div) (((div) & 0xff) << 8)
+#define TX_ESC_CLK_DIVIDSION(div) (((div) & 0xff) << 0)
+
+#define DSI_DPI_CFG 0x0c
+#define EN18_LOOSELY BIT(10)
+#define COLORM_ACTIVE_LOW BIT(9)
+#define SHUTD_ACTIVE_LOW BIT(8)
+#define HSYNC_ACTIVE_LOW BIT(7)
+#define VSYNC_ACTIVE_LOW BIT(6)
+#define DATAEN_ACTIVE_LOW BIT(5)
+#define DPI_COLOR_CODING_16BIT_1 (0x0 << 2)
+#define DPI_COLOR_CODING_16BIT_2 (0x1 << 2)
+#define DPI_COLOR_CODING_16BIT_3 (0x2 << 2)
+#define DPI_COLOR_CODING_18BIT_1 (0x3 << 2)
+#define DPI_COLOR_CODING_18BIT_2 (0x4 << 2)
+#define DPI_COLOR_CODING_24BIT (0x5 << 2)
+#define DPI_VID(vid) (((vid) & 0x3) << 0)
+
+#define DSI_DBI_CFG 0x10
+#define DSI_DBIS_CMDSIZE 0x14
+
+#define DSI_PCKHDL_CFG 0x18
+#define GEN_VID_RX(vid) (((vid) & 0x3) << 5)
+#define EN_CRC_RX BIT(4)
+#define EN_ECC_RX BIT(3)
+#define EN_BTA BIT(2)
+#define EN_EOTN_RX BIT(1)
+#define EN_EOTP_TX BIT(0)
+
+#define DSI_VID_MODE_CFG 0x1c
+#define FRAME_BTA_ACK BIT(11)
+#define EN_NULL_PKT BIT(10)
+#define EN_NULL_PKT_MASK BIT(10)
+#define EN_MULTI_PKT BIT(9)
+#define ENABLE_LOW_POWER (0x3f << 3)
+#define ENABLE_LOW_POWER_MASK (0x3f << 3)
+#define VID_MODE_TYPE_NONBURST_SYNC_PULSES (0x0 << 1)
+#define VID_MODE_TYPE_NONBURST_SYNC_EVENTS (0x1 << 1)
+#define VID_MODE_TYPE_BURST_SYNC_PULSES (0x3 << 1)
+#define VID_MODE_TYPE_MASK (0x3 << 1)
+#define ENABLE_VIDEO_MODE BIT(0)
+#define DISABLE_VIDEO_MODE 0
+#define ENABLE_VIDEO_MODE_MASK BIT(0)
+
+#define DSI_VID_PKT_CFG 0x20
+#define NULL_PKT_SIZE(b) (((b) & 0x3f) << 21)
+#define NUM_CHUNKS(n) (((n) & 0x3f) << 11)
+#define VID_PKT_SIZE(p) (((p) & 0x7ff) << 0)
+#define VID_PKT_MAX_SIZE 0x7ff
+
+#define DSI_CMD_MODE_CFG 0x24
+#define EN_TEAR_FX BIT(14)
+#define EN_ACK_RQST BIT(13)
+#define DCS_LW_TX_LP BIT(12)
+#define GEN_LW_TX_LP BIT(11)
+#define MAX_RD_PKT_SIZE_LP BIT(10)
+#define DCS_SW_2P_TX_LP BIT(9)
+#define DCS_SW_1P_TX_LP BIT(8)
+#define DCS_SW_0P_TX_LP BIT(7)
+#define GEN_SR_2P_TX_LP BIT(6)
+#define GEN_SR_1P_TX_LP BIT(5)
+#define GEN_SR_0P_TX_LP BIT(4)
+#define GEN_SW_2P_TX_LP BIT(3)
+#define GEN_SW_1P_TX_LP BIT(2)
+#define GEN_SW_0P_TX_LP BIT(1)
+#define ENABLE_CMD_MODE BIT(0)
+#define DISABLE_CMD_MODE 0
+#define ENABLE_CMD_MODE_MASK BIT(0)
+#define CMD_MODE_ALL_LP (DCS_LW_TX_LP | \
+ GEN_LW_TX_LP | \
+ MAX_RD_PKT_SIZE_LP | \
+ DCS_SW_2P_TX_LP | \
+ DCS_SW_1P_TX_LP | \
+ DCS_SW_0P_TX_LP | \
+ GEN_SR_2P_TX_LP | \
+ GEN_SR_1P_TX_LP | \
+ GEN_SR_0P_TX_LP | \
+ GEN_SW_2P_TX_LP | \
+ GEN_SW_1P_TX_LP | \
+ GEN_SW_0P_TX_LP)
+
+#define DSI_TMR_LINE_CFG 0x28
+#define HLINE_TIME(lbcc) (((lbcc) & 0x3fff) << 18)
+#define HBP_TIME(lbcc) (((lbcc) & 0x1ff) << 9)
+#define HSA_TIME(lbcc) (((lbcc) & 0x1ff) << 0)
+
+#define DSI_VTIMING_CFG 0x2c
+#define V_ACTIVE_LINES(line) (((line) & 0x7ff) << 16)
+#define VFP_LINES(line) (((line) & 0x3f) << 10)
+#define VBP_LINES(line) (((line) & 0x3f) << 4)
+#define VSA_LINES(line) (((line) & 0xf) << 0)
+
+#define DSI_PHY_TMR_CFG 0x30
+#define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 20)
+#define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 12)
+#define BTA_TIME(lbcc) (((lbcc) & 0xfff) << 0)
+
+#define DSI_GEN_HDR 0x34
+#define GEN_HDATA(data) (((data) & 0xffff) << 8)
+#define GEN_HDATA_MASK (0xffff << 8)
+#define GEN_HTYPE(type) (((type) & 0xff) << 0)
+#define GEN_HTYPE_MASK 0xff
+
+#define DSI_GEN_PLD_DATA 0x38
+
+#define DSI_CMD_PKT_STATUS 0x3c
+#define GEN_CMD_EMPTY BIT(0)
+#define GEN_CMD_FULL BIT(1)
+#define GEN_PLD_W_EMPTY BIT(2)
+#define GEN_PLD_W_FULL BIT(3)
+#define GEN_PLD_R_EMPTY BIT(4)
+#define GEN_RD_CMD_BUSY BIT(6)
+
+#define DSI_TO_CNT_CFG 0x40
+#define DSI_ERROR_ST0 0x44
+#define DSI_ERROR_ST1 0x48
+#define DSI_ERROR_MSK0 0x4c
+#define DSI_ERROR_MSK1 0x50
+
+#define DSI_PHY_RSTZ 0x54
+#define PHY_DISABLECLK 0
+#define PHY_ENABLECLK BIT(2)
+#define PHY_RSTZ 0
+#define PHY_UNRSTZ BIT(1)
+#define PHY_SHUTDOWNZ 0
+#define PHY_UNSHUTDOWNZ BIT(0)
+
+#define DSI_PHY_IF_CFG 0x58
+#define N_LANES(n) ((((n) - 1) & 0x3) << 0)
+#define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0x3ff) << 2)
+
+#define DSI_PHY_IF_CTRL 0x5c
+#define PHY_IF_CTRL_RESET 0x0
+#define TX_REQ_CLK_HS BIT(0)
+
+#define DSI_PHY_STATUS 0x60
+#define LOCK BIT(0)
+#define STOP_STATE_CLK_LANE BIT(2)
+
+#define DSI_PHY_TST_CTRL0 0x64
+#define PHY_TESTCLK BIT(1)
+#define PHY_UNTESTCLK 0
+#define PHY_TESTCLR BIT(0)
+#define PHY_UNTESTCLR 0
+
+#define DSI_PHY_TST_CTRL1 0x68
+#define PHY_TESTEN BIT(16)
+#define PHY_UNTESTEN 0
+#define PHY_TESTDOUT(n) (((n) & 0xff) << 8)
+#define PHY_TESTDIN(n) (((n) & 0xff) << 0)
+
+#define PHY_STATUS_TIMEOUT 10
+#define CMD_PKT_STATUS_TIMEOUT 20
+
+struct dw_mipi_dsi {
+ struct mipi_dsi_host dsi_host;
+ struct drm_connector connector;
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
+ struct drm_panel *panel;
+ struct device *dev;
+
+ void __iomem *base;
+
+ struct clk *pllref_clk;
+ struct clk *cfg_clk;
+
+ unsigned int lane_mbps; /* per lane */
+ u32 channel;
+ u32 lanes;
+ u32 format;
+ struct drm_display_mode *mode;
+
+ const struct dw_mipi_dsi_plat_data *pdata;
+
+ bool enabled;
+};
+
+enum {
+ STATUS_TO_CLEAR,
+ STATUS_TO_SET,
+};
+
+enum dw_mipi_dsi_mode {
+ DW_MIPI_DSI_CMD_MODE,
+ DW_MIPI_DSI_VID_MODE,
+};
+
+struct dphy_pll_testdin_map {
+ unsigned int max_mbps;
+ u8 testdin;
+};
+
+/* The table is based on 27MHz DPHY pll reference clock. */
+static const struct dphy_pll_testdin_map dptdin_map[] = {
+ {160, 0x04}, {180, 0x24}, {200, 0x44}, {210, 0x06},
+ {240, 0x26}, {250, 0x46}, {270, 0x08}, {300, 0x28},
+ {330, 0x48}, {360, 0x2a}, {400, 0x4a}, {450, 0x0c},
+ {500, 0x2c}, {550, 0x0e}, {600, 0x2e}, {650, 0x10},
+ {700, 0x30}, {750, 0x12}, {800, 0x32}, {850, 0x14},
+ {900, 0x34}, {950, 0x54}, {1000, 0x74}
+};
+
+static inline struct dw_mipi_dsi *host_to_dsi(struct mipi_dsi_host *host)
+{
+ return container_of(host, struct dw_mipi_dsi, dsi_host);
+}
+
+static inline struct dw_mipi_dsi *con_to_dsi(struct drm_connector *con)
+{
+ return container_of(con, struct dw_mipi_dsi, connector);
+}
+
+int dw_mipi_dsi_get_encoder_pixel_format(struct drm_encoder *encoder)
+{
+ struct dw_mipi_dsi *dsi = encoder->bridge->driver_private;
+
+ return dsi->format;
+}
+EXPORT_SYMBOL_GPL(dw_mipi_dsi_get_encoder_pixel_format);
+
+static int max_mbps_to_testdin(unsigned int max_mbps)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dptdin_map); i++)
+ if (dptdin_map[i].max_mbps == max_mbps)
+ return dptdin_map[i].testdin;
+
+ return -EINVAL;
+}
+
+static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val)
+{
+ writel(val, dsi->base + reg);
+}
+
+static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg)
+{
+ return readl(dsi->base + reg);
+}
+
+static inline void dsi_modify(struct dw_mipi_dsi *dsi, u32 reg,
+ u32 mask, u32 val)
+{
+ u32 v;
+
+ v = readl(dsi->base + reg);
+ v &= ~mask;
+ v |= val;
+ writel(v, dsi->base + reg);
+}
+
+static int check_status(struct dw_mipi_dsi *dsi, u32 reg, u32 status,
+ unsigned int timeout, bool to_set)
+{
+ unsigned long expire;
+ bool out;
+ u32 val;
+
+ expire = jiffies + msecs_to_jiffies(timeout);
+ for (;;) {
+ val = dsi_read(dsi, reg);
+ out = to_set ? ((val & status) == status) : !(val & status);
+ if (out)
+ break;
+
+ if (time_after(jiffies, expire))
+ return -ETIMEDOUT;
+
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+/*
+ * The controller should generate 2 frames before
+ * preparing the peripheral.
+ */
+static void dw_mipi_dsi_wait_for_two_frames(struct dw_mipi_dsi *dsi)
+{
+ unsigned long expire;
+ int refresh, two_frames;
+
+ refresh = drm_mode_vrefresh(dsi->mode);
+ two_frames = DIV_ROUND_UP(MSEC_PER_SEC, refresh) * 2;
+
+ expire = jiffies + msecs_to_jiffies(two_frames);
+ while (time_before(jiffies, expire))
+ cpu_relax();
+}
+
+static int dw_mipi_dsi_config_testdin(struct dw_mipi_dsi *dsi)
+{
+ int ret, testdin;
+
+ testdin = max_mbps_to_testdin(dsi->lane_mbps);
+ if (testdin < 0) {
+ dev_err(dsi->dev,
+ "failed to get testdin for %dmbps lane clock\n",
+ dsi->lane_mbps);
+ return testdin;
+ }
+
+ dsi_write(dsi, DSI_PHY_IF_CTRL, PHY_IF_CTRL_RESET);
+ dsi_write(dsi, DSI_PWR_UP, POWERUP);
+
+ dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR);
+ dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN | PHY_TESTDOUT(0) |
+ PHY_TESTDIN(0x44));
+ dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
+ dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR);
+ dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_UNTESTEN | PHY_TESTDOUT(0) |
+ PHY_TESTDIN(testdin));
+ dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
+ dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR);
+ dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENABLECLK | PHY_UNRSTZ |
+ PHY_UNSHUTDOWNZ);
+ ret = check_status(dsi, DSI_PHY_STATUS, LOCK,
+ PHY_STATUS_TIMEOUT, STATUS_TO_SET);
+ if (ret < 0) {
+ dev_err(dsi->dev, "failed to wait for phy lock state\n");
+ return ret;
+ }
+ ret = check_status(dsi, DSI_PHY_STATUS, STOP_STATE_CLK_LANE,
+ PHY_STATUS_TIMEOUT, STATUS_TO_SET);
+ if (ret < 0) {
+ dev_err(dsi->dev,
+ "failed to wait for phy clk lane stop state\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
+ unsigned int *final_mbps)
+{
+ int bpp, i;
+ unsigned int target_mbps, mpclk;
+ unsigned long pllref;
+
+ bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+ if (bpp < 0) {
+ dev_err(dsi->dev, "failed to get bpp for pixel format %d\n",
+ dsi->format);
+ return bpp;
+ }
+
+ pllref = clk_get_rate(dsi->pllref_clk);
+ if (pllref != 27000000)
+ dev_warn(dsi->dev, "expect 27MHz DPHY pll reference clock\n");
+
+ mpclk = DIV_ROUND_UP(dsi->mode->clock, MSEC_PER_SEC);
+ if (mpclk) {
+ /* take 1/0.7 blanking overhead into consideration */
+ target_mbps = (mpclk * (bpp / dsi->lanes) * 10) / 7;
+ } else {
+ dev_dbg(dsi->dev, "use default 1Gbps DPHY pll clock\n");
+ target_mbps = 1000;
+ }
+
+ dev_dbg(dsi->dev, "target DPHY pll clock frequency is %uMbps\n",
+ target_mbps);
+
+ for (i = 0; i < ARRAY_SIZE(dptdin_map); i++) {
+ if (target_mbps < dptdin_map[i].max_mbps) {
+ *final_mbps = dptdin_map[i].max_mbps;
+ dev_dbg(dsi->dev,
+ "real DPHY pll clock frequency is %uMbps\n",
+ *final_mbps);
+ return 0;
+ }
+ }
+
+ dev_err(dsi->dev, "DPHY clock frequency %uMbps is out of range\n",
+ target_mbps);
+
+ return -EINVAL;
+}
+
+static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+{
+ struct dw_mipi_dsi *dsi = host_to_dsi(host);
+
+ if (device->lanes > dsi->pdata->max_data_lanes) {
+ dev_err(dsi->dev, "the number of data lanes(%d) is too many\n",
+ device->lanes);
+ return -EINVAL;
+ }
+
+ if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) ||
+ !(device->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) {
+ dev_err(dsi->dev, "device mode is unsupported\n");
+ return -EINVAL;
+ }
+
+ if (device->format != MIPI_DSI_FMT_RGB888 &&
+ device->format != MIPI_DSI_FMT_RGB565) {
+ dev_err(dsi->dev, "device pixel format is unsupported\n");
+ return -EINVAL;
+ }
+
+ dsi->lanes = device->lanes;
+ dsi->channel = device->channel;
+ dsi->format = device->format;
+ dsi->panel = of_drm_find_panel(device->dev.of_node);
+ drm_panel_attach(dsi->panel, &dsi->connector);
+
+ return 0;
+}
+
+static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+{
+ struct dw_mipi_dsi *dsi = host_to_dsi(host);
+
+ drm_panel_detach(dsi->panel);
+
+ return 0;
+}
+
+static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 val)
+{
+ int ret;
+
+ ret = check_status(dsi, DSI_CMD_PKT_STATUS, GEN_CMD_FULL,
+ CMD_PKT_STATUS_TIMEOUT, STATUS_TO_CLEAR);
+ if (ret < 0) {
+ dev_err(dsi->dev, "failed to get available command FIFO\n");
+ return ret;
+ }
+
+ dsi_write(dsi, DSI_GEN_HDR, val);
+
+ ret = check_status(dsi, DSI_CMD_PKT_STATUS,
+ GEN_CMD_EMPTY | GEN_PLD_W_EMPTY,
+ CMD_PKT_STATUS_TIMEOUT, STATUS_TO_SET);
+ if (ret < 0) {
+ dev_err(dsi->dev, "failed to write command FIFO\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi,
+ const struct mipi_dsi_msg *msg)
+{
+ const u16 *tx_buf = msg->tx_buf;
+ u32 val = GEN_HDATA(*tx_buf) | GEN_HTYPE(msg->type);
+
+ if (msg->tx_len > 2) {
+ dev_err(dsi->dev, "too long tx buf length %d for short write\n",
+ msg->tx_len);
+ return -EINVAL;
+ }
+
+ return dw_mipi_dsi_gen_pkt_hdr_write(dsi, val);
+}
+
+static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi,
+ const struct mipi_dsi_msg *msg)
+{
+ const u32 *tx_buf = msg->tx_buf;
+ int len = msg->tx_len, pld_data_bytes = sizeof(*tx_buf), ret;
+ u32 val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type);
+ u32 remainder = 0;
+
+ if (msg->tx_len < 3) {
+ dev_err(dsi->dev, "wrong tx buf length %d for long write\n",
+ msg->tx_len);
+ return -EINVAL;
+ }
+
+ while (DIV_ROUND_UP(len, pld_data_bytes)) {
+ if (len < pld_data_bytes) {
+ memcpy(&remainder, tx_buf, len);
+ dsi_write(dsi, DSI_GEN_PLD_DATA, remainder);
+ len = 0;
+ } else {
+ dsi_write(dsi, DSI_GEN_PLD_DATA, *tx_buf);
+ tx_buf++;
+ len -= pld_data_bytes;
+ }
+ ret = check_status(dsi, DSI_CMD_PKT_STATUS, GEN_PLD_W_FULL,
+ CMD_PKT_STATUS_TIMEOUT, STATUS_TO_CLEAR);
+ if (ret < 0) {
+ dev_err(dsi->dev,
+ "failed to get available write payload FIFO\n");
+ return ret;
+ }
+ }
+
+ return dw_mipi_dsi_gen_pkt_hdr_write(dsi, val);
+}
+
+static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
+ const struct mipi_dsi_msg *msg)
+{
+ struct dw_mipi_dsi *dsi = host_to_dsi(host);
+ int ret;
+
+ switch (msg->type) {
+ case MIPI_DSI_DCS_SHORT_WRITE:
+ case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+ case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+ ret = dw_mipi_dsi_dcs_short_write(dsi, msg);
+ break;
+ case MIPI_DSI_DCS_LONG_WRITE:
+ ret = dw_mipi_dsi_dcs_long_write(dsi, msg);
+ break;
+ default:
+ dev_err(dsi->dev, "unsupported message type\n");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = {
+ .attach = dw_mipi_dsi_host_attach,
+ .detach = dw_mipi_dsi_host_detach,
+ .transfer = dw_mipi_dsi_host_transfer,
+};
+
+static enum drm_connector_status
+dw_mipi_dsi_detect(struct drm_connector *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs dw_mipi_dsi_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = dw_mipi_dsi_detect,
+ .destroy = dw_mipi_dsi_drm_connector_destroy,
+};
+
+static int dw_mipi_dsi_connector_get_modes(struct drm_connector *connector)
+{
+ struct dw_mipi_dsi *dsi = con_to_dsi(connector);
+
+ return drm_panel_get_modes(dsi->panel);
+}
+
+static enum drm_mode_status dw_mipi_dsi_mode_valid(
+ struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct dw_mipi_dsi *dsi = con_to_dsi(connector);
+
+ enum drm_mode_status mode_status = MODE_OK;
+
+ if (dsi->pdata->mode_valid)
+ mode_status = dsi->pdata->mode_valid(connector, mode);
+
+ return mode_status;
+}
+
+static struct drm_encoder *dw_mipi_dsi_connector_best_encoder(
+ struct drm_connector *connector)
+{
+ struct dw_mipi_dsi *dsi = con_to_dsi(connector);
+
+ return dsi->encoder;
+}
+
+static struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = {
+ .get_modes = dw_mipi_dsi_connector_get_modes,
+ .mode_valid = dw_mipi_dsi_mode_valid,
+ .best_encoder = dw_mipi_dsi_connector_best_encoder,
+};
+
+static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
+{
+ u32 val;
+
+ val = VID_MODE_TYPE_BURST_SYNC_PULSES | ENABLE_LOW_POWER;
+
+ dsi_write(dsi, DSI_VID_MODE_CFG, val);
+}
+
+static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi,
+ enum dw_mipi_dsi_mode mode)
+{
+ if (mode == DW_MIPI_DSI_CMD_MODE) {
+ dsi_write(dsi, DSI_PWR_UP, RESET);
+ dsi_modify(dsi, DSI_CMD_MODE_CFG,
+ ENABLE_CMD_MODE_MASK, ENABLE_CMD_MODE);
+ dsi_modify(dsi, DSI_VID_MODE_CFG,
+ ENABLE_VIDEO_MODE_MASK, DISABLE_VIDEO_MODE);
+ dsi_write(dsi, DSI_PWR_UP, POWERUP);
+ } else {
+ dsi_write(dsi, DSI_PWR_UP, RESET);
+ dsi_modify(dsi, DSI_CMD_MODE_CFG,
+ ENABLE_CMD_MODE_MASK, DISABLE_CMD_MODE);
+
+ dw_mipi_dsi_video_mode_config(dsi);
+
+ dsi_modify(dsi, DSI_VID_MODE_CFG,
+ ENABLE_VIDEO_MODE_MASK, ENABLE_VIDEO_MODE);
+ dsi_write(dsi, DSI_PWR_UP, POWERUP);
+ dsi_write(dsi, DSI_PHY_IF_CTRL, TX_REQ_CLK_HS);
+ }
+}
+
+static void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi)
+{
+ dsi_write(dsi, DSI_PHY_IF_CTRL, PHY_IF_CTRL_RESET);
+ dsi_write(dsi, DSI_PWR_UP, RESET);
+ dsi_write(dsi, DSI_PHY_RSTZ, PHY_RSTZ);
+}
+
+static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct dw_mipi_dsi *dsi = bridge->driver_private;
+
+ if (dsi->enabled)
+ return;
+
+ clk_prepare_enable(dsi->cfg_clk);
+ dw_mipi_dsi_config_testdin(dsi);
+ dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
+ dw_mipi_dsi_wait_for_two_frames(dsi);
+ dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
+ drm_panel_prepare(dsi->panel);
+ dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
+ clk_disable_unprepare(dsi->cfg_clk);
+
+ drm_panel_enable(dsi->panel);
+
+ dsi->enabled = true;
+}
+
+static void dw_mipi_dsi_bridge_disable(struct drm_bridge *bridge)
+{
+ struct dw_mipi_dsi *dsi = bridge->driver_private;
+ unsigned long expire;
+
+ if (!dsi->enabled)
+ return;
+
+ drm_panel_disable(dsi->panel);
+
+ clk_prepare_enable(dsi->cfg_clk);
+ dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
+ drm_panel_unprepare(dsi->panel);
+ dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
+
+ /*
+ * This is necessary to make sure the peripheral
+ * will be driven normally when the display is
+ * enabled again later.
+ */
+ expire = jiffies + msecs_to_jiffies(120);
+ while (time_before(jiffies, expire))
+ cpu_relax();
+
+ dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
+ dw_mipi_dsi_disable(dsi);
+ clk_disable_unprepare(dsi->cfg_clk);
+
+ dsi->enabled = false;
+}
+
+static void dw_mipi_dsi_bridge_nope(struct drm_bridge *bridge)
+{
+ /* do nothing */
+}
+
+static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
+{
+ dsi_write(dsi, DSI_PWR_UP, RESET);
+ dsi_write(dsi, DSI_PHY_RSTZ, PHY_DISABLECLK | PHY_RSTZ | PHY_SHUTDOWNZ);
+ dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVIDSION(1) |
+ TX_ESC_CLK_DIVIDSION(7));
+}
+
+static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
+ struct drm_display_mode *mode)
+{
+ u32 val = 0;
+
+ if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
+ val |= VSYNC_ACTIVE_LOW;
+ if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
+ val |= HSYNC_ACTIVE_LOW;
+
+ switch (dsi->format) {
+ case MIPI_DSI_FMT_RGB888:
+ val |= DPI_COLOR_CODING_24BIT;
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ val |= DPI_COLOR_CODING_18BIT_2;
+ val |= EN18_LOOSELY;
+ break;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ val |= DPI_COLOR_CODING_18BIT_1;
+ break;
+ case MIPI_DSI_FMT_RGB565:
+ val |= DPI_COLOR_CODING_16BIT_1;
+ break;
+ }
+
+ val |= DPI_VID(dsi->channel);
+
+ dsi_write(dsi, DSI_DPI_CFG, val);
+}
+
+static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
+{
+ dsi_write(dsi, DSI_PCKHDL_CFG, EN_CRC_RX | EN_ECC_RX | EN_BTA);
+}
+
+static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
+ struct drm_display_mode *mode)
+{
+ dsi_write(dsi, DSI_VID_PKT_CFG, VID_PKT_SIZE(mode->hdisplay));
+}
+
+static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
+{
+ dsi_write(dsi, DSI_CMD_MODE_CFG, CMD_MODE_ALL_LP | ENABLE_CMD_MODE);
+}
+
+/* Get lane byte clock cycles. */
+static u64 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi,
+ u64 hcomponent)
+{
+ u64 frac, lbcc;
+
+ lbcc = hcomponent * dsi->lane_mbps * USEC_PER_SEC / 8;
+ frac = do_div(lbcc, dsi->mode->clock * MSEC_PER_SEC);
+ if (frac)
+ lbcc++;
+
+ return lbcc;
+}
+
+static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi)
+{
+ u32 val = 0, htotal, hsa, hbp, lbcc;
+ struct drm_display_mode *mode = dsi->mode;
+
+ htotal = mode->htotal;
+ hsa = mode->hsync_end - mode->hsync_start;
+ hbp = mode->htotal - mode->hsync_end;
+
+ lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, htotal);
+ val |= HLINE_TIME(lbcc);
+
+ lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, hsa);
+ val |= HSA_TIME(lbcc);
+
+ lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, hbp);
+ val |= HBP_TIME(lbcc);
+
+ dsi_write(dsi, DSI_TMR_LINE_CFG, val);
+}
+
+static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi)
+{
+ u32 val, vactive, vsa, vfp, vbp;
+ struct drm_display_mode *mode = dsi->mode;
+
+ vactive = mode->vdisplay;
+ vsa = mode->vsync_end - mode->vsync_start;
+ vfp = mode->vsync_start - mode->vdisplay;
+ vbp = mode->vtotal - mode->vsync_end;
+
+ val = V_ACTIVE_LINES(vactive) | VSA_LINES(vsa) |
+ VFP_LINES(vfp) | VBP_LINES(vbp);
+
+ dsi_write(dsi, DSI_VTIMING_CFG, val);
+}
+
+static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
+{
+ u32 val;
+
+ val = PHY_HS2LP_TIME(0x40) | PHY_LP2HS_TIME(0x40) |
+ BTA_TIME(0xd00);
+
+ dsi_write(dsi, DSI_PHY_TMR_CFG, val);
+}
+
+static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi)
+{
+ dsi_write(dsi, DSI_PHY_IF_CFG, PHY_STOP_WAIT_TIME(0x20) |
+ N_LANES(dsi->lanes));
+}
+
+static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
+{
+ dsi_read(dsi, DSI_ERROR_ST0);
+ dsi_read(dsi, DSI_ERROR_ST1);
+ dsi_write(dsi, DSI_ERROR_MSK0, 0);
+ dsi_write(dsi, DSI_ERROR_MSK1, 0);
+}
+
+static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct dw_mipi_dsi *dsi = bridge->driver_private;
+ int ret;
+
+ dsi->mode = mode;
+
+ ret = dw_mipi_dsi_get_lane_bps(dsi, &dsi->lane_mbps);
+ if (ret < 0)
+ return;
+
+ clk_prepare_enable(dsi->cfg_clk);
+ dw_mipi_dsi_init(dsi);
+ dw_mipi_dsi_dpi_config(dsi, mode);
+ dw_mipi_dsi_packet_handler_config(dsi);
+ dw_mipi_dsi_video_mode_config(dsi);
+ dw_mipi_dsi_video_packet_config(dsi, mode);
+ dw_mipi_dsi_command_mode_config(dsi);
+ dw_mipi_dsi_line_timer_config(dsi);
+ dw_mipi_dsi_vertical_timing_config(dsi);
+ dw_mipi_dsi_dphy_timing_config(dsi);
+ dw_mipi_dsi_dphy_interface_config(dsi);
+ dw_mipi_dsi_clear_err(dsi);
+ dw_mipi_dsi_config_testdin(dsi);
+ dw_mipi_dsi_wait_for_two_frames(dsi);
+ drm_panel_prepare(dsi->panel);
+ clk_disable_unprepare(dsi->cfg_clk);
+}
+
+static bool dw_mipi_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_mipi_dsi_bridge_destroy(struct drm_bridge *bridge)
+{
+ drm_bridge_cleanup(bridge);
+ kfree(bridge);
+}
+
+static struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
+ .enable = dw_mipi_dsi_bridge_enable,
+ .disable = dw_mipi_dsi_bridge_disable,
+ .pre_enable = dw_mipi_dsi_bridge_nope,
+ .post_disable = dw_mipi_dsi_bridge_nope,
+ .mode_set = dw_mipi_dsi_bridge_mode_set,
+ .mode_fixup = dw_mipi_dsi_bridge_mode_fixup,
+ .destroy = dw_mipi_dsi_bridge_destroy,
+};
+
+static int dw_mipi_dsi_register(struct drm_device *drm, struct dw_mipi_dsi *dsi)
+{
+ struct drm_encoder *encoder = dsi->encoder;
+ struct drm_bridge *bridge;
+ int ret;
+
+ bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
+ if (!bridge)
+ return -ENOMEM;
+
+ dsi->bridge = bridge;
+ bridge->driver_private = dsi;
+
+ ret = drm_bridge_init(drm, bridge, &dw_mipi_dsi_bridge_funcs);
+ if (ret) {
+ dev_err(drm->dev, "failed to initialize bridge with drm\n");
+ return ret;
+ }
+
+ encoder->bridge = bridge;
+
+ drm_connector_helper_add(&dsi->connector,
+ &dw_mipi_dsi_connector_helper_funcs);
+ drm_connector_init(drm, &dsi->connector, &dw_mipi_dsi_connector_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+
+ drm_mode_connector_attach_encoder(&dsi->connector, dsi->encoder);
+
+ return 0;
+}
+
+int dw_mipi_dsi_bind(struct device *dev, struct device *master, void *data,
+ struct drm_encoder *encoder, struct resource *res,
+ const struct dw_mipi_dsi_plat_data *pdata)
+{
+ struct drm_device *drm = data;
+ struct dw_mipi_dsi *dsi;
+ u32 val;
+ int ret;
+
+ dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+ if (!dsi)
+ return -ENOMEM;
+
+ dsi->pdata = pdata;
+ dsi->dev = dev;
+ dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
+ dsi->dsi_host.dev = dev;
+ dsi->encoder = encoder;
+
+ dsi->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(dsi->base))
+ return PTR_ERR(dsi->base);
+
+ dsi->pllref_clk = devm_clk_get(dev, "pllref");
+ if (IS_ERR(dsi->pllref_clk)) {
+ ret = PTR_ERR(dsi->pllref_clk);
+ dev_err(dev, "Unable to get pll reference clock: %d\n", ret);
+ return ret;
+ }
+ clk_prepare_enable(dsi->pllref_clk);
+
+ dsi->cfg_clk = devm_clk_get(dev, "core_cfg");
+ if (IS_ERR(dsi->cfg_clk)) {
+ ret = PTR_ERR(dsi->cfg_clk);
+ dev_err(dev, "Unable to get configuration clock: %d\n", ret);
+ goto err_pllref;
+ }
+
+ clk_prepare_enable(dsi->cfg_clk);
+ val = dsi_read(dsi, DSI_VERSION);
+ clk_disable_unprepare(dsi->cfg_clk);
+
+ dev_info(dev, "version number is 0x%08x\n", val);
+
+ ret = dw_mipi_dsi_register(drm, dsi);
+ if (ret)
+ goto err_pllref;
+
+ dev_set_drvdata(dev, dsi);
+
+ return mipi_dsi_host_register(&dsi->dsi_host);
+
+err_pllref:
+ clk_disable_unprepare(dsi->pllref_clk);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind);
+
+void dw_mipi_dsi_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
+
+ mipi_dsi_host_unregister(&dsi->dsi_host);
+ clk_disable_unprepare(dsi->pllref_clk);
+}
+EXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind);
+
+MODULE_DESCRIPTION("Synopsys DesignWare MIPI DSI host controller driver");
+MODULE_AUTHOR("Liu Ying <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h
new file mode 100644
index 0000000..e84e355
--- /dev/null
+++ b/include/drm/bridge/dw_mipi_dsi.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#ifndef __DW_MIPI_DSI__
+#define __DW_MIPI_DSI__
+
+#include <drm/drmP.h>
+
+struct dw_mipi_dsi_plat_data {
+ unsigned int max_data_lanes;
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+};
+
+int dw_mipi_dsi_get_encoder_pixel_format(struct drm_encoder *encoder);
+
+int dw_mipi_dsi_bind(struct device *dev, struct device *master, void *data,
+ struct drm_encoder *encoder, struct resource *res,
+ const struct dw_mipi_dsi_plat_data *pdata);
+void dw_mipi_dsi_unbind(struct device *dev, struct device *master, void *data);
+#endif /* __DW_MIPI_DSI__ */
--
2.1.0

2014-12-31 08:24:09

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 09/21] ARM: dts: imx6qdl: Move existing MIPI DSI ports into a new 'ports' node

The MIPI DSI node contains some ports which represent possible DRM CRTCs
it can connect with. Each port has a 'reg' property embedded. This
property will be wrongly interpretted by the MIPI DSI bus driver, because
the driver will take each subnode which contains a 'reg' property as a
DSI peripheral device. This patch moves the existing MIPI DSI ports into
a new 'ports' node so that the MIPI DSI bus driver may distinguish its
DSI peripheral device(s) from the existing ports.

Acked-by: Philipp Zabel <[email protected]>
Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v5->v6:
* None.

v4->v5:
* None.

v3->v4:
* None.

v2->v3:
* Add Philipp's Ack.

v1->v2:
* Newly added, as suggested by Thierry Reding.

arch/arm/boot/dts/imx6q.dtsi | 20 +++++++++++---------
arch/arm/boot/dts/imx6qdl.dtsi | 23 ++++++++++++++---------
2 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index e9f3646..9c0990b 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -292,19 +292,21 @@
};

&mipi_dsi {
- port@2 {
- reg = <2>;
+ ports {
+ port@2 {
+ reg = <2>;

- mipi_mux_2: endpoint {
- remote-endpoint = <&ipu2_di0_mipi>;
+ mipi_mux_2: endpoint {
+ remote-endpoint = <&ipu2_di0_mipi>;
+ };
};
- };

- port@3 {
- reg = <3>;
+ port@3 {
+ reg = <3>;

- mipi_mux_3: endpoint {
- remote-endpoint = <&ipu2_di1_mipi>;
+ mipi_mux_3: endpoint {
+ remote-endpoint = <&ipu2_di1_mipi>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 9596ed5..96bf2a0 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1009,19 +1009,24 @@
reg = <0x021e0000 0x4000>;
status = "disabled";

- port@0 {
- reg = <0>;
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;

- mipi_mux_0: endpoint {
- remote-endpoint = <&ipu1_di0_mipi>;
+ mipi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_mipi>;
+ };
};
- };

- port@1 {
- reg = <1>;
+ port@1 {
+ reg = <1>;

- mipi_mux_1: endpoint {
- remote-endpoint = <&ipu1_di1_mipi>;
+ mipi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_mipi>;
+ };
};
};
};
--
2.1.0

2014-12-31 08:19:48

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 05/21] ARM: imx6q: clk: Add the video_27m clock

This patch supports the video_27m clock which is a fixed factor
clock of the pll3_pfd1_540m clock.

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v4->v5:
* None.

v3->v4:
* None.

v2->v3:
* None.

v1->v2:
* None.

arch/arm/mach-imx/clk-imx6q.c | 1 +
include/dt-bindings/clock/imx6qdl-clock.h | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index 4e79da7..9470df3 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -246,6 +246,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
clk[IMX6QDL_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2);
clk[IMX6QDL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
+ clk[IMX6QDL_CLK_VIDEO_27M] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20);
if (cpu_is_imx6dl()) {
clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1);
clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
diff --git a/include/dt-bindings/clock/imx6qdl-clock.h b/include/dt-bindings/clock/imx6qdl-clock.h
index b690cdb..25625bf 100644
--- a/include/dt-bindings/clock/imx6qdl-clock.h
+++ b/include/dt-bindings/clock/imx6qdl-clock.h
@@ -248,6 +248,7 @@
#define IMX6QDL_PLL6_BYPASS 235
#define IMX6QDL_PLL7_BYPASS 236
#define IMX6QDL_CLK_GPT_3M 237
-#define IMX6QDL_CLK_END 238
+#define IMX6QDL_CLK_VIDEO_27M 238
+#define IMX6QDL_CLK_END 239

#endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */
--
2.1.0

2014-12-31 08:25:14

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 04/21] ARM: imx6q: Add GPR3 MIPI muxing control register field shift bits definition

This patch adds a macro to define the GPR3 MIPI muxing control register field
shift bits.

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v4->v5:
* None.

v3->v4:
* None.

v2->v3:
* None.

v1->v2:
* None.

include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 1 +
1 file changed, 1 insertion(+)

diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
index ff44374..3b0bed4 100644
--- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
+++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
@@ -207,6 +207,7 @@
#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI1 (0x1 << 6)
#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI0 (0x2 << 6)
#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI1 (0x3 << 6)
+#define IMX6Q_GPR3_MIPI_MUX_CTL_SHIFT 4
#define IMX6Q_GPR3_MIPI_MUX_CTL_MASK (0x3 << 4)
#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI0 (0x0 << 4)
#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI1 (0x1 << 4)
--
2.1.0

2014-12-31 08:19:40

by Liu Ying

[permalink] [raw]
Subject: [PATCH RFC v8 03/21] of: Add vendor prefix for Truly Semiconductors Limited

Signed-off-by: Liu Ying <[email protected]>
---
v7->v8:
* None.

v6->v7:
* None.

v5->v6:
* None.

v4->v5:
* None.

v3->v4:
* None.

v2->v3:
* None.

v1->v2:
* None.

Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index f46adb2..0e67bad 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -158,6 +158,7 @@ tlm Trusted Logic Mobility
toradex Toradex AG
toshiba Toshiba Corporation
toumaz Toumaz
+truly Truly Semiconductors Limited
usi Universal Scientific Industrial Co., Ltd.
v3 V3 Semiconductor
variscite Variscite Ltd.
--
2.1.0

2015-02-02 02:13:12

by Liu Ying

[permalink] [raw]
Subject: Re: [PATCH RFC v8 00/21] Add support for i.MX MIPI DSI DRM driver

Hi,

This version has been submitted for a while.
And, it looks there is no comments on this version.
Can the maintainers consider to take this?

Mike, any comments on patch 01/21? It's a clock driver change.

Regards,
Liu Ying

On Wed, Dec 31, 2014 at 04:23:18PM +0800, Liu Ying wrote:
> Hi,
>
> This version mainly fixes the Kconfig for the Synopsys DesignWare MIPI DSI
> host controller bridge driver so that we may pass the allmodconfig for ARM.
> Also, this version contains a minor change for the Himax HX8369A panel
> driver to remove several unnecessary headers included.
>
> The i.MX MIPI DSI is a Synopsys DesignWare MIPI DSI host controller IP.
> This series adds support for a Synopsys DesignWare MIPI DSI host controller
> DRM bridge driver and a i.MX MIPI DSI specific DRM driver.
> Currently, the MIPI DSI drivers only support the burst with sync pulse mode.
>
> This series also includes a DRM panel driver for the Truly TFT480800-16-E panel
> which is driven by the Himax HX8369A driver IC. The driver IC data sheet could
> be found at [1]. As mentioned by the data sheet, the driver IC supports several
> interface modes. Currently, the DRM panel driver only supports the MIPI DSI video
> mode. New interface modes could be added later(perhaps, just like the way the DRM
> simple panel driver supports both MIPI DSI interface panels and simple(parallel)
> interface panels).
>
> The MIPI DSI feature is tested on i.MX6Q SabreSD board and i.MX6DL SabreSD board.
> The MIPI DSI display could be enabled directly on i.MX6Q SabreSD board after
> applying this series, because the 26.4MHz pixel clock the panel requires could be
> derived from the IPU HSP clock(264MHz) with an integer divider.
> On i.MX6DL SabreSD board, we need to manually disable the LVDS and HDMI displays in
> the device tree blob, since the i.MX6DL IPU HSP clock is 198MHz at present, which
> makes the pixel clock share the PLL5 video clock source with the LVDS and HDMI,
> thus, the panel cannot get the pixel clock rate it wants.
>
> Patch 01/21 is needed to get a precise pixel clock rate(26.4MHz) from the PLL5 video
> clock. If we don't have this patch, the pixel clock rate is about 20MHz, which
> causes a horitonal shift on the display image.
>
> This series can be applied on the drm-next branch.
>
> [1] http://www.allshore.com/pdf/Himax_HX8369-A.pdf
>
> Liu Ying (21):
> clk: divider: Correct parent clk round rate if no bestdiv is normally
> found
> of: Add vendor prefix for Himax Technologies Inc.
> of: Add vendor prefix for Truly Semiconductors Limited
> ARM: imx6q: Add GPR3 MIPI muxing control register field shift bits
> definition
> ARM: imx6q: clk: Add the video_27m clock
> ARM: imx6q: clk: Change hdmi_isfr clock's parent to be video_27m clock
> ARM: imx6q: clk: Change hsi_tx clock to be a shared clock gate
> ARM: imx6q: clk: Add support for mipi_core_cfg clock as a shared clock
> gate
> ARM: dts: imx6qdl: Move existing MIPI DSI ports into a new 'ports'
> node
> drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
> Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM
> bridge driver
> drm/bridge: Add Synopsys DesignWare MIPI DSI host controller driver
> Documentation: dt-bindings: Add bindings for i.MX specific Synopsys DW
> MIPI DSI driver
> drm: imx: Support Synopsys DesignWare MIPI DSI host controller
> Documentation: dt-bindings: Add bindings for Himax HX8369A DRM panel
> driver
> drm: panel: Add support for Himax HX8369A MIPI DSI panel
> ARM: dtsi: imx6qdl: Add support for MIPI DSI host controller
> ARM: dts: imx6qdl-sabresd: Add support for TRULY TFT480800-16-E MIPI
> DSI panel
> ARM: imx_v6_v7_defconfig: Cleanup for imx drm being moved out of
> staging
> ARM: imx_v6_v7_defconfig: Add support for MIPI DSI host controller
> ARM: imx_v6_v7_defconfig: Add support for Himax HX8369A panel
>
> .../devicetree/bindings/drm/bridge/dw_mipi_dsi.txt | 73 ++
> .../devicetree/bindings/drm/imx/mipi_dsi.txt | 78 ++
> .../devicetree/bindings/panel/himax,hx8369a.txt | 39 +
> .../devicetree/bindings/vendor-prefixes.txt | 2 +
> arch/arm/boot/dts/imx6q.dtsi | 20 +-
> arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 20 +
> arch/arm/boot/dts/imx6qdl.dtsi | 29 +-
> arch/arm/configs/imx_v6_v7_defconfig | 17 +-
> arch/arm/mach-imx/clk-imx6q.c | 7 +-
> drivers/clk/clk-divider.c | 3 +-
> drivers/gpu/drm/bridge/Kconfig | 10 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> drivers/gpu/drm/bridge/dw_mipi_dsi.c | 996 +++++++++++++++++++++
> drivers/gpu/drm/imx/Kconfig | 7 +
> drivers/gpu/drm/imx/Makefile | 1 +
> drivers/gpu/drm/imx/dw_mipi_dsi-imx.c | 230 +++++
> drivers/gpu/drm/panel/Kconfig | 5 +
> drivers/gpu/drm/panel/Makefile | 1 +
> drivers/gpu/drm/panel/panel-himax-hx8369a.c | 610 +++++++++++++
> include/drm/bridge/dw_mipi_dsi.h | 27 +
> include/drm/drm_mipi_dsi.h | 14 +
> include/dt-bindings/clock/imx6qdl-clock.h | 4 +-
> include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 1 +
> 23 files changed, 2165 insertions(+), 30 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
> create mode 100644 Documentation/devicetree/bindings/drm/imx/mipi_dsi.txt
> create mode 100644 Documentation/devicetree/bindings/panel/himax,hx8369a.txt
> create mode 100644 drivers/gpu/drm/bridge/dw_mipi_dsi.c
> create mode 100644 drivers/gpu/drm/imx/dw_mipi_dsi-imx.c
> create mode 100644 drivers/gpu/drm/panel/panel-himax-hx8369a.c
> create mode 100644 include/drm/bridge/dw_mipi_dsi.h
>
> --
> 2.1.0
>
> _______________________________________________
> dri-devel mailing list
> [email protected]
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

2015-02-02 05:30:05

by Liu Ying

[permalink] [raw]
Subject: Re: [PATCH RFC v8 00/21] Add support for i.MX MIPI DSI DRM driver

Correct Philipp's email address in the Cc list.

Liu Ying

On Mon, Feb 02, 2015 at 10:17:45AM +0800, Liu Ying wrote:
> Hi,
>
> This version has been submitted for a while.
> And, it looks there is no comments on this version.
> Can the maintainers consider to take this?
>
> Mike, any comments on patch 01/21? It's a clock driver change.
>
> Regards,
> Liu Ying
>
> On Wed, Dec 31, 2014 at 04:23:18PM +0800, Liu Ying wrote:
> > Hi,
> >
> > This version mainly fixes the Kconfig for the Synopsys DesignWare MIPI DSI
> > host controller bridge driver so that we may pass the allmodconfig for ARM.
> > Also, this version contains a minor change for the Himax HX8369A panel
> > driver to remove several unnecessary headers included.
> >
> > The i.MX MIPI DSI is a Synopsys DesignWare MIPI DSI host controller IP.
> > This series adds support for a Synopsys DesignWare MIPI DSI host controller
> > DRM bridge driver and a i.MX MIPI DSI specific DRM driver.
> > Currently, the MIPI DSI drivers only support the burst with sync pulse mode.
> >
> > This series also includes a DRM panel driver for the Truly TFT480800-16-E panel
> > which is driven by the Himax HX8369A driver IC. The driver IC data sheet could
> > be found at [1]. As mentioned by the data sheet, the driver IC supports several
> > interface modes. Currently, the DRM panel driver only supports the MIPI DSI video
> > mode. New interface modes could be added later(perhaps, just like the way the DRM
> > simple panel driver supports both MIPI DSI interface panels and simple(parallel)
> > interface panels).
> >
> > The MIPI DSI feature is tested on i.MX6Q SabreSD board and i.MX6DL SabreSD board.
> > The MIPI DSI display could be enabled directly on i.MX6Q SabreSD board after
> > applying this series, because the 26.4MHz pixel clock the panel requires could be
> > derived from the IPU HSP clock(264MHz) with an integer divider.
> > On i.MX6DL SabreSD board, we need to manually disable the LVDS and HDMI displays in
> > the device tree blob, since the i.MX6DL IPU HSP clock is 198MHz at present, which
> > makes the pixel clock share the PLL5 video clock source with the LVDS and HDMI,
> > thus, the panel cannot get the pixel clock rate it wants.
> >
> > Patch 01/21 is needed to get a precise pixel clock rate(26.4MHz) from the PLL5 video
> > clock. If we don't have this patch, the pixel clock rate is about 20MHz, which
> > causes a horitonal shift on the display image.
> >
> > This series can be applied on the drm-next branch.
> >
> > [1] http://www.allshore.com/pdf/Himax_HX8369-A.pdf
> >
> > Liu Ying (21):
> > clk: divider: Correct parent clk round rate if no bestdiv is normally
> > found
> > of: Add vendor prefix for Himax Technologies Inc.
> > of: Add vendor prefix for Truly Semiconductors Limited
> > ARM: imx6q: Add GPR3 MIPI muxing control register field shift bits
> > definition
> > ARM: imx6q: clk: Add the video_27m clock
> > ARM: imx6q: clk: Change hdmi_isfr clock's parent to be video_27m clock
> > ARM: imx6q: clk: Change hsi_tx clock to be a shared clock gate
> > ARM: imx6q: clk: Add support for mipi_core_cfg clock as a shared clock
> > gate
> > ARM: dts: imx6qdl: Move existing MIPI DSI ports into a new 'ports'
> > node
> > drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
> > Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM
> > bridge driver
> > drm/bridge: Add Synopsys DesignWare MIPI DSI host controller driver
> > Documentation: dt-bindings: Add bindings for i.MX specific Synopsys DW
> > MIPI DSI driver
> > drm: imx: Support Synopsys DesignWare MIPI DSI host controller
> > Documentation: dt-bindings: Add bindings for Himax HX8369A DRM panel
> > driver
> > drm: panel: Add support for Himax HX8369A MIPI DSI panel
> > ARM: dtsi: imx6qdl: Add support for MIPI DSI host controller
> > ARM: dts: imx6qdl-sabresd: Add support for TRULY TFT480800-16-E MIPI
> > DSI panel
> > ARM: imx_v6_v7_defconfig: Cleanup for imx drm being moved out of
> > staging
> > ARM: imx_v6_v7_defconfig: Add support for MIPI DSI host controller
> > ARM: imx_v6_v7_defconfig: Add support for Himax HX8369A panel
> >
> > .../devicetree/bindings/drm/bridge/dw_mipi_dsi.txt | 73 ++
> > .../devicetree/bindings/drm/imx/mipi_dsi.txt | 78 ++
> > .../devicetree/bindings/panel/himax,hx8369a.txt | 39 +
> > .../devicetree/bindings/vendor-prefixes.txt | 2 +
> > arch/arm/boot/dts/imx6q.dtsi | 20 +-
> > arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 20 +
> > arch/arm/boot/dts/imx6qdl.dtsi | 29 +-
> > arch/arm/configs/imx_v6_v7_defconfig | 17 +-
> > arch/arm/mach-imx/clk-imx6q.c | 7 +-
> > drivers/clk/clk-divider.c | 3 +-
> > drivers/gpu/drm/bridge/Kconfig | 10 +
> > drivers/gpu/drm/bridge/Makefile | 1 +
> > drivers/gpu/drm/bridge/dw_mipi_dsi.c | 996 +++++++++++++++++++++
> > drivers/gpu/drm/imx/Kconfig | 7 +
> > drivers/gpu/drm/imx/Makefile | 1 +
> > drivers/gpu/drm/imx/dw_mipi_dsi-imx.c | 230 +++++
> > drivers/gpu/drm/panel/Kconfig | 5 +
> > drivers/gpu/drm/panel/Makefile | 1 +
> > drivers/gpu/drm/panel/panel-himax-hx8369a.c | 610 +++++++++++++
> > include/drm/bridge/dw_mipi_dsi.h | 27 +
> > include/drm/drm_mipi_dsi.h | 14 +
> > include/dt-bindings/clock/imx6qdl-clock.h | 4 +-
> > include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 1 +
> > 23 files changed, 2165 insertions(+), 30 deletions(-)
> > create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
> > create mode 100644 Documentation/devicetree/bindings/drm/imx/mipi_dsi.txt
> > create mode 100644 Documentation/devicetree/bindings/panel/himax,hx8369a.txt
> > create mode 100644 drivers/gpu/drm/bridge/dw_mipi_dsi.c
> > create mode 100644 drivers/gpu/drm/imx/dw_mipi_dsi-imx.c
> > create mode 100644 drivers/gpu/drm/panel/panel-himax-hx8369a.c
> > create mode 100644 include/drm/bridge/dw_mipi_dsi.h
> >
> > --
> > 2.1.0
> >
> > _______________________________________________
> > dri-devel mailing list
> > [email protected]
> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> _______________________________________________
> dri-devel mailing list
> [email protected]
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

2015-02-04 16:03:17

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH RFC v8 02/21] of: Add vendor prefix for Himax Technologies Inc.

On Wed, Dec 31, 2014 at 2:23 AM, Liu Ying <[email protected]> wrote:
> Signed-off-by: Liu Ying <[email protected]>

I don't know what the status is for the rest of the series, but I'm
applying this and patch 3 so you don't have to keep sending them.

Rob

> ---
> v7->v8:
> * None.
>
> v6->v7:
> * None.
>
> v5->v6:
> * None.
>
> v4->v5:
> * None.
>
> v3->v4:
> * Fix an ordering issue to address Stefan Wahren's comment.
>
> v2->v3:
> * None.
>
> v1->v2:
> * None.
>
> Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index 78efebb..f46adb2 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -67,6 +67,7 @@ gumstix Gumstix, Inc.
> gw Gateworks Corporation
> hannstar HannStar Display Corporation
> haoyu Haoyu Microelectronic Co. Ltd.
> +himax Himax Technologies, Inc.
> hisilicon Hisilicon Limited.
> hit Hitachi Ltd.
> honeywell Honeywell
> --
> 2.1.0
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

2015-02-05 02:16:23

by Liu Ying

[permalink] [raw]
Subject: Re: [PATCH RFC v8 02/21] of: Add vendor prefix for Himax Technologies Inc.

On Wed, Feb 04, 2015 at 10:02:53AM -0600, Rob Herring wrote:
> On Wed, Dec 31, 2014 at 2:23 AM, Liu Ying <[email protected]> wrote:
> > Signed-off-by: Liu Ying <[email protected]>
>
> I don't know what the status is for the rest of the series, but I'm
> applying this and patch 3 so you don't have to keep sending them.

Thank you, Rob.

Regards,
Liu Ying

>
> Rob
>
> > ---
> > v7->v8:
> > * None.
> >
> > v6->v7:
> > * None.
> >
> > v5->v6:
> > * None.
> >
> > v4->v5:
> > * None.
> >
> > v3->v4:
> > * Fix an ordering issue to address Stefan Wahren's comment.
> >
> > v2->v3:
> > * None.
> >
> > v1->v2:
> > * None.
> >
> > Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> > index 78efebb..f46adb2 100644
> > --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> > +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> > @@ -67,6 +67,7 @@ gumstix Gumstix, Inc.
> > gw Gateworks Corporation
> > hannstar HannStar Display Corporation
> > haoyu Haoyu Microelectronic Co. Ltd.
> > +himax Himax Technologies, Inc.
> > hisilicon Hisilicon Limited.
> > hit Hitachi Ltd.
> > honeywell Honeywell
> > --
> > 2.1.0
> >
> >
> > _______________________________________________
> > linux-arm-kernel mailing list
> > [email protected]
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

2015-02-05 10:10:30

by Philipp Zabel

[permalink] [raw]
Subject: Re: [PATCH RFC v8 11/21] Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM bridge driver

Am Mittwoch, den 31.12.2014, 16:23 +0800 schrieb Liu Ying:
> This patch adds device tree bindings for Synopsys DesignWare MIPI DSI
> host controller DRM bridge driver.
>
> Signed-off-by: Liu Ying <[email protected]>
> ---
> v7->v8:
> * None.
>
> v6->v7:
> * None.
>
> v5->v6:
> * Add the #address-cells and #size-cells properties in the example 'ports'
> node.
> * Remove the useless input-port properties from the example port@0 and port@1
> nodes.
>
> v4->v5:
> * None.
>
> v3->v4:
> * Newly introduced in v4. This is separated from the relevant driver patch
> in v3 to address Stefan Wahren's comment.
>
> .../devicetree/bindings/drm/bridge/dw_mipi_dsi.txt | 73 ++++++++++++++++++++++
> 1 file changed, 73 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
>
> diff --git a/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt b/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
> new file mode 100644
> index 0000000..f88a8d6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
> @@ -0,0 +1,73 @@
> +Device-Tree bindings for Synopsys DesignWare MIPI DSI host controller
> +
> +The controller is a digital core that implements all protocol functions
> +defined in the MIPI DSI specification, providing an interface between
> +the system and the MIPI DPHY, and allowing communication with a MIPI DSI
> +compliant display.
> +
> +Required properties:
> + - #address-cells: Should be <1>.
> + - #size-cells: Should be <0>.
> + - compatible: The compatible string should be "fsl,imx6q-mipi-dsi" for
> + i.MX6q/sdl SoCs. For other SoCs, please refer to their specific
> + device tree binding documentations.

I think the compatible property should additionally contain
"snps,dw-mipi-dsi". Also I think other SoCs using the same IP core
should eventually list their compatibles here, but that's for later.

How about:
+ - compatible: The compatible string contain "fsl,imx6q-mipi-dsi" for
+ i.MX6q/sdl SoCs. For other SoCs, please refer to their specific
+ device tree binding documentations. A common compatible string
+ "snps,dw-mipi-dsi" should be appended for all SoCs.

> + - reg: Represent the physical address range of the controller.
> + - interrupts: Represent the controller's interrupt to the CPU(s).
> + - clocks, clock-names: Phandles to the controller pll reference and
> + core configuration clocks, as described in [1].

>From the MIPI CSI-2 datasheets it looks like the D-PHY has a refclk and
a cfg_clk input. So I suspect from the name of the "core_cfg" clock,
that it actually represents two clock inputs, the "cfg_clk" wired to the
D-PHY and a core clock wired to the MIPI DSI host controller. I am not
sure if there are designs that control those clocks separately, but I
think it'd be safer to split this into two clocks in the device tree.

Also I am not sure which input to the MIPI DSI host controller the core
clock represents. The i.MX6DQ Reference Manual v2 calls the remaining
clock inputs gated by mipi_core_cfg_clk_enable "ac_clk_125m" and
"ips_clk" (I think the latter is the ABP clock driving the register
bank, just called "pclk" in the MIPI CSI-2 documentation).

regards
Philipp

2015-02-06 08:08:36

by Liu Ying

[permalink] [raw]
Subject: Re: [PATCH RFC v8 11/21] Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM bridge driver

On Thu, Feb 05, 2015 at 11:10:04AM +0100, Philipp Zabel wrote:
> Am Mittwoch, den 31.12.2014, 16:23 +0800 schrieb Liu Ying:
> > This patch adds device tree bindings for Synopsys DesignWare MIPI DSI
> > host controller DRM bridge driver.
> >
> > Signed-off-by: Liu Ying <[email protected]>
> > ---
> > v7->v8:
> > * None.
> >
> > v6->v7:
> > * None.
> >
> > v5->v6:
> > * Add the #address-cells and #size-cells properties in the example 'ports'
> > node.
> > * Remove the useless input-port properties from the example port@0 and port@1
> > nodes.
> >
> > v4->v5:
> > * None.
> >
> > v3->v4:
> > * Newly introduced in v4. This is separated from the relevant driver patch
> > in v3 to address Stefan Wahren's comment.
> >
> > .../devicetree/bindings/drm/bridge/dw_mipi_dsi.txt | 73 ++++++++++++++++++++++
> > 1 file changed, 73 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
> >
> > diff --git a/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt b/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
> > new file mode 100644
> > index 0000000..f88a8d6
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
> > @@ -0,0 +1,73 @@
> > +Device-Tree bindings for Synopsys DesignWare MIPI DSI host controller
> > +
> > +The controller is a digital core that implements all protocol functions
> > +defined in the MIPI DSI specification, providing an interface between
> > +the system and the MIPI DPHY, and allowing communication with a MIPI DSI
> > +compliant display.
> > +
> > +Required properties:
> > + - #address-cells: Should be <1>.
> > + - #size-cells: Should be <0>.
> > + - compatible: The compatible string should be "fsl,imx6q-mipi-dsi" for
> > + i.MX6q/sdl SoCs. For other SoCs, please refer to their specific
> > + device tree binding documentations.
>
> I think the compatible property should additionally contain
> "snps,dw-mipi-dsi". Also I think other SoCs using the same IP core
> should eventually list their compatibles here, but that's for later.
>
> How about:
> + - compatible: The compatible string contain "fsl,imx6q-mipi-dsi" for
> + i.MX6q/sdl SoCs. For other SoCs, please refer to their specific
> + device tree binding documentations. A common compatible string
> + "snps,dw-mipi-dsi" should be appended for all SoCs.

I'm not sure if "snps,dw-mipi-dsi" should be appended.

Is it a compatible string that SoC specific drivers should actually use to
bind a device?

As Andy mentioned in [1], DW MIPI DSI embedded in RK618 is configured via I2C
bus, while i.MX6Q/DL is configured via ARM bus...

Another concern is that if users only specify "snps,dw-mipi-dsi" in their
device tree sources and use a kernel which supports multiple platforms,
say ARM multi v7 platforms, could several enabled SoC specific drivers be
probed for a single DW MIPI DSI device?

[1] http://lists.freedesktop.org/archives/dri-devel/2014-December/074344.html

>
> > + - reg: Represent the physical address range of the controller.
> > + - interrupts: Represent the controller's interrupt to the CPU(s).
> > + - clocks, clock-names: Phandles to the controller pll reference and
> > + core configuration clocks, as described in [1].
>
> From the MIPI CSI-2 datasheets it looks like the D-PHY has a refclk and
> a cfg_clk input. So I suspect from the name of the "core_cfg" clock,
> that it actually represents two clock inputs, the "cfg_clk" wired to the
> D-PHY and a core clock wired to the MIPI DSI host controller. I am not
> sure if there are designs that control those clocks separately, but I
> think it'd be safer to split this into two clocks in the device tree.

What MIPI CSI-2 datasheets do you refer to?
I don't find the refclk and cfg_clk in the MIPI CSI chapter of the i.MX6DQ
Reference Manual v2[2].

I think we need to know the design philosophy of DW MIPI DSI clock sources
to settle down the documentation here. I've asked our internal MIPI DSI
SoC owner for ideas. But, someone from Synopsys might be the right
person, perhaps.

[2] http://cache.freescale.com/files/32bit/doc/ref_manual/IMX6DQRM.pdf?fasp=1&WT_TYPE=Reference%20Manuals&WT_VENDOR=FREESCALE&WT_FILE_FORMAT=pdf&WT_ASSET=Documentation&fileExt=.pdf

>
> Also I am not sure which input to the MIPI DSI host controller the core
> clock represents. The i.MX6DQ Reference Manual v2 calls the remaining
> clock inputs gated by mipi_core_cfg_clk_enable "ac_clk_125m" and
> "ips_clk" (I think the latter is the ABP clock driving the register
> bank, just called "pclk" in the MIPI CSI-2 documentation).

The same MIPI CSI-2 documentation you mentioned above?

I'm also puzzled about the clocks.

Regards,
Liu Ying

>
> regards
> Philipp
>

2015-02-11 07:16:58

by Liu Ying

[permalink] [raw]
Subject: Re: [PATCH RFC v8 11/21] Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM bridge driver

Hi Philipp,

On Fri, Feb 06, 2015 at 04:13:20PM +0800, Liu Ying wrote:
> On Thu, Feb 05, 2015 at 11:10:04AM +0100, Philipp Zabel wrote:
> > Am Mittwoch, den 31.12.2014, 16:23 +0800 schrieb Liu Ying:
> > > This patch adds device tree bindings for Synopsys DesignWare MIPI DSI
> > > host controller DRM bridge driver.
> > >
> > > Signed-off-by: Liu Ying <[email protected]>
> > > ---
> > > v7->v8:
> > > * None.
> > >
> > > v6->v7:
> > > * None.
> > >
> > > v5->v6:
> > > * Add the #address-cells and #size-cells properties in the example 'ports'
> > > node.
> > > * Remove the useless input-port properties from the example port@0 and port@1
> > > nodes.
> > >
> > > v4->v5:
> > > * None.
> > >
> > > v3->v4:
> > > * Newly introduced in v4. This is separated from the relevant driver patch
> > > in v3 to address Stefan Wahren's comment.
> > >
> > > .../devicetree/bindings/drm/bridge/dw_mipi_dsi.txt | 73 ++++++++++++++++++++++
> > > 1 file changed, 73 insertions(+)
> > > create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
> > >
> > > diff --git a/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt b/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
> > > new file mode 100644
> > > index 0000000..f88a8d6
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
> > > @@ -0,0 +1,73 @@
> > > +Device-Tree bindings for Synopsys DesignWare MIPI DSI host controller
> > > +
> > > +The controller is a digital core that implements all protocol functions
> > > +defined in the MIPI DSI specification, providing an interface between
> > > +the system and the MIPI DPHY, and allowing communication with a MIPI DSI
> > > +compliant display.
> > > +
> > > +Required properties:
> > > + - #address-cells: Should be <1>.
> > > + - #size-cells: Should be <0>.
> > > + - compatible: The compatible string should be "fsl,imx6q-mipi-dsi" for
> > > + i.MX6q/sdl SoCs. For other SoCs, please refer to their specific
> > > + device tree binding documentations.
> >
> > I think the compatible property should additionally contain
> > "snps,dw-mipi-dsi". Also I think other SoCs using the same IP core
> > should eventually list their compatibles here, but that's for later.
> >
> > How about:
> > + - compatible: The compatible string contain "fsl,imx6q-mipi-dsi" for
> > + i.MX6q/sdl SoCs. For other SoCs, please refer to their specific
> > + device tree binding documentations. A common compatible string
> > + "snps,dw-mipi-dsi" should be appended for all SoCs.
>
> I'm not sure if "snps,dw-mipi-dsi" should be appended.
>
> Is it a compatible string that SoC specific drivers should actually use to
> bind a device?
>
> As Andy mentioned in [1], DW MIPI DSI embedded in RK618 is configured via I2C
> bus, while i.MX6Q/DL is configured via ARM bus...
>
> Another concern is that if users only specify "snps,dw-mipi-dsi" in their
> device tree sources and use a kernel which supports multiple platforms,
> say ARM multi v7 platforms, could several enabled SoC specific drivers be
> probed for a single DW MIPI DSI device?
>
> [1] http://lists.freedesktop.org/archives/dri-devel/2014-December/074344.html
>
> >
> > > + - reg: Represent the physical address range of the controller.
> > > + - interrupts: Represent the controller's interrupt to the CPU(s).
> > > + - clocks, clock-names: Phandles to the controller pll reference and
> > > + core configuration clocks, as described in [1].
> >
> > From the MIPI CSI-2 datasheets it looks like the D-PHY has a refclk and
> > a cfg_clk input. So I suspect from the name of the "core_cfg" clock,
> > that it actually represents two clock inputs, the "cfg_clk" wired to the
> > D-PHY and a core clock wired to the MIPI DSI host controller. I am not
> > sure if there are designs that control those clocks separately, but I
> > think it'd be safer to split this into two clocks in the device tree.
>

Our internal MIPI DSI SoC owner gave me some feedbacks on the clock sources.
According to him, the Synopsys DesignWare MIPI DSI host controller needs four
clock sources from an application platform - pclk, refclk, cfg_clk and dpipclk.
These clocks are mentioned in the "DesignWare Cores MIPI DSI Host Controller
Databook, 1.01a1.30a.pdf" documentation.

Quote some words from the documentation:
pclk - APB clock signal.
refclk - D-PHY reference clock used for Master-side serial clock generation in
clock multiplying unit(PLL).
cfg_clk - D-PHY Configuration clock used for the initialization of the PHY. It
is also used for exiting ULPS state.
dpipclk - Input Pixel clock signal.

The below table reflects how does i.MX6Q/DL provide the pclk, refclk and cfg_clk
for the DesignWare MIPI DSI host controller, according to the SoC owner.
----------------------------------------------------------------------------
| Synopsys | i.MX6Q/DL MIPI DSI |
| DesignWare |------------------------------------------------------------|
| documentation | clock | clock root | CCM_CCGR bits |
|---------------|------------|--------------------|--------------------------|
| pclk | ips_clk | ipg_clk_root | mipi_core_cfg_clk_enable |
|---------------|------------|--------------------|--------------------------|
| refclk | pll_refclk | video_27m_clk_root | mipi_core_cfg_clk_enable |
|---------------|------------|--------------------|--------------------------|
| cfg_clk | cfg_clk | video_27m_clk_root | mipi_core_cfg_clk_enable |
----------------------------------------------------------------------------

I think we should add a new clock "IMX6QDL_CLK_MIPI_IPG" as a shared clock gate
clock. And, the clock-names property should exactly contain "pclk", "refclk"
and "cfg_clk", right?

Let me know your thoughts. Thanks.

> What MIPI CSI-2 datasheets do you refer to?
> I don't find the refclk and cfg_clk in the MIPI CSI chapter of the i.MX6DQ
> Reference Manual v2[2].
>
> I think we need to know the design philosophy of DW MIPI DSI clock sources
> to settle down the documentation here. I've asked our internal MIPI DSI
> SoC owner for ideas. But, someone from Synopsys might be the right
> person, perhaps.
>
> [2] http://cache.freescale.com/files/32bit/doc/ref_manual/IMX6DQRM.pdf?fasp=1&WT_TYPE=Reference%20Manuals&WT_VENDOR=FREESCALE&WT_FILE_FORMAT=pdf&WT_ASSET=Documentation&fileExt=.pdf
>
> >
> > Also I am not sure which input to the MIPI DSI host controller the core
> > clock represents. The i.MX6DQ Reference Manual v2 calls the remaining
> > clock inputs gated by mipi_core_cfg_clk_enable "ac_clk_125m" and
> > "ips_clk" (I think the latter is the ABP clock driving the register
> > bank, just called "pclk" in the MIPI CSI-2 documentation).

Yes, the "ips_clk" clock is the "pclk" clock. The "ac_clk_125m" clock is
designed for test and should not be used by software development, according to
the SoC owner.

Regards,
Liu Ying

>
> The same MIPI CSI-2 documentation you mentioned above?
>
> I'm also puzzled about the clocks.
>
> Regards,
> Liu Ying
>
> >
> > regards
> > Philipp
> >
> _______________________________________________
> dri-devel mailing list
> [email protected]
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

2015-02-11 13:01:00

by Philipp Zabel

[permalink] [raw]
Subject: Re: [PATCH RFC v8 11/21] Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM bridge driver

Hi Liu,

Am Mittwoch, den 11.02.2015, 15:21 +0800 schrieb Liu Ying:
[...]
> Our internal MIPI DSI SoC owner gave me some feedbacks on the clock sources.
> According to him, the Synopsys DesignWare MIPI DSI host controller needs four
> clock sources from an application platform - pclk, refclk, cfg_clk and dpipclk.
> These clocks are mentioned in the "DesignWare Cores MIPI DSI Host Controller
> Databook, 1.01a1.30a.pdf" documentation.
>
> Quote some words from the documentation:
> pclk - APB clock signal.
> refclk - D-PHY reference clock used for Master-side serial clock generation in
> clock multiplying unit(PLL).
> cfg_clk - D-PHY Configuration clock used for the initialization of the PHY. It
> is also used for exiting ULPS state.
> dpipclk - Input Pixel clock signal.
>
> The below table reflects how does i.MX6Q/DL provide the pclk, refclk and cfg_clk
> for the DesignWare MIPI DSI host controller, according to the SoC owner.
> ----------------------------------------------------------------------------
> | Synopsys | i.MX6Q/DL MIPI DSI |
> | DesignWare |------------------------------------------------------------|
> | documentation | clock | clock root | CCM_CCGR bits |
> |---------------|------------|--------------------|--------------------------|
> | pclk | ips_clk | ipg_clk_root | mipi_core_cfg_clk_enable |
> |---------------|------------|--------------------|--------------------------|
> | refclk | pll_refclk | video_27m_clk_root | mipi_core_cfg_clk_enable |
> |---------------|------------|--------------------|--------------------------|
> | cfg_clk | cfg_clk | video_27m_clk_root | mipi_core_cfg_clk_enable |
> ----------------------------------------------------------------------------
>
> I think we should add a new clock "IMX6QDL_CLK_MIPI_IPG" as a shared clock gate
> clock.

That would be necessary if the pclk clock rate mattered or would be set
anywhere.

> And, the clock-names property should exactly contain "pclk", "refclk"
> and "cfg_clk", right?

My personal preference would be to drop the superfluous "clk" prefix if
the resulting clock name is still clearly relatable to the official
name. Existing clock naming for the pclk is a bit mixed -
The "snps,dw-apb-timer" binding uses "pclk", which seems to be quite
common in other places, too. The "snps,dw-apb-uart" bindings use
"apb_pclk". "snps,dw-hdmi-tx" uses "iahb" and "isfr" without the clk
suffix.
How about "pclk", "ref" and "cfg"?

regards
Philipp

2015-02-11 14:04:44

by Liu Ying

[permalink] [raw]
Subject: Re: [PATCH RFC v8 11/21] Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM bridge driver

Hi Philipp,

On Wed, Feb 11, 2015 at 02:00:48PM +0100, Philipp Zabel wrote:
> Hi Liu,
>
> Am Mittwoch, den 11.02.2015, 15:21 +0800 schrieb Liu Ying:
> [...]
> > Our internal MIPI DSI SoC owner gave me some feedbacks on the clock sources.
> > According to him, the Synopsys DesignWare MIPI DSI host controller needs four
> > clock sources from an application platform - pclk, refclk, cfg_clk and dpipclk.
> > These clocks are mentioned in the "DesignWare Cores MIPI DSI Host Controller
> > Databook, 1.01a1.30a.pdf" documentation.
> >
> > Quote some words from the documentation:
> > pclk - APB clock signal.
> > refclk - D-PHY reference clock used for Master-side serial clock generation in
> > clock multiplying unit(PLL).
> > cfg_clk - D-PHY Configuration clock used for the initialization of the PHY. It
> > is also used for exiting ULPS state.
> > dpipclk - Input Pixel clock signal.
> >
> > The below table reflects how does i.MX6Q/DL provide the pclk, refclk and cfg_clk
> > for the DesignWare MIPI DSI host controller, according to the SoC owner.
> > ----------------------------------------------------------------------------
> > | Synopsys | i.MX6Q/DL MIPI DSI |
> > | DesignWare |------------------------------------------------------------|
> > | documentation | clock | clock root | CCM_CCGR bits |
> > |---------------|------------|--------------------|--------------------------|
> > | pclk | ips_clk | ipg_clk_root | mipi_core_cfg_clk_enable |
> > |---------------|------------|--------------------|--------------------------|
> > | refclk | pll_refclk | video_27m_clk_root | mipi_core_cfg_clk_enable |
> > |---------------|------------|--------------------|--------------------------|
> > | cfg_clk | cfg_clk | video_27m_clk_root | mipi_core_cfg_clk_enable |
> > ----------------------------------------------------------------------------
> >
> > I think we should add a new clock "IMX6QDL_CLK_MIPI_IPG" as a shared clock gate
> > clock.
>
> That would be necessary if the pclk clock rate mattered or would be set
> anywhere.

I don't think the pclk clock rate matters a lot. It should be sufficient
for the driver only to enable/disable the pclk for registers access, just
like the way the pwm-imx driver uses the ipg clock.

>
> > And, the clock-names property should exactly contain "pclk", "refclk"
> > and "cfg_clk", right?
>
> My personal preference would be to drop the superfluous "clk" prefix if
> the resulting clock name is still clearly relatable to the official
> name. Existing clock naming for the pclk is a bit mixed -
> The "snps,dw-apb-timer" binding uses "pclk", which seems to be quite
> common in other places, too. The "snps,dw-apb-uart" bindings use
> "apb_pclk". "snps,dw-hdmi-tx" uses "iahb" and "isfr" without the clk
> suffix.
> How about "pclk", "ref" and "cfg"?

Looks good and clear enough. I'd like to use them. Thanks.

BTW, regarding the compatible string topic, shall I keep my implementation
unchanged and don't append the additional "snps,dw-mipi-dsi" as I shared
my concerns about it before?

Regards,
Liu Ying

>
> regards
> Philipp
>

2015-02-11 15:23:12

by Philipp Zabel

[permalink] [raw]
Subject: Re: [PATCH RFC v8 11/21] Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM bridge driver

Am Mittwoch, den 11.02.2015, 22:09 +0800 schrieb Liu Ying:
> BTW, regarding the compatible string topic, shall I keep my implementation
> unchanged and don't append the additional "snps,dw-mipi-dsi" as I shared
> my concerns about it before?

Leave the implementation unchanged. Still, I'd like to see
"snps,dw-mipi-dsi" appended to the mipi_dsi compatible property in
Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
and in arch/arm/boot/dts/imx6qdl.dtsi. After all, Freescale's i.MX6
specific implementation is register compatible to Synopsys' design,
isn't it?

regards
Philipp

2015-02-12 02:10:16

by Liu Ying

[permalink] [raw]
Subject: Re: [PATCH RFC v8 11/21] Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM bridge driver

On Wed, Feb 11, 2015 at 04:23:01PM +0100, Philipp Zabel wrote:
> Am Mittwoch, den 11.02.2015, 22:09 +0800 schrieb Liu Ying:
> > BTW, regarding the compatible string topic, shall I keep my implementation
> > unchanged and don't append the additional "snps,dw-mipi-dsi" as I shared
> > my concerns about it before?
>
> Leave the implementation unchanged. Still, I'd like to see
> "snps,dw-mipi-dsi" appended to the mipi_dsi compatible property in
> Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
> and in arch/arm/boot/dts/imx6qdl.dtsi. After all, Freescale's i.MX6
> specific implementation is register compatible to Synopsys' design,
> isn't it?

All right. Will do this in the next version.

Regards,
Liu Ying

>
> regards
> Philipp
>