linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver
@ 2015-02-12  6:01 Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found Liu Ying
                   ` (20 more replies)
  0 siblings, 21 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

Hi,

This version mainly addresses the comments from Philipp Zabel on v8.
The comments include
a. A common compatible string "snps,dw-mipi-dsi" should be appended to all SoCs'
   MIPI DSI device tree documentations and nodes.
b. Clean up the common clocks needed by the Synopsys DesignWare MIPI DSI host
   controller.

This version also drops two documentation patches in v8 for adding Himax and
Truly vendor prefixes since Rob Herring has taken them.

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/20 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 imx-drm/next branch of Philipp Zabel's open
git repository.

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

Liu Ying (20):
  clk: divider: Correct parent clk round rate if no bestdiv is normally
    found
  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: imx6q: clk: Add support for mipi_ipg 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 |   76 ++
 .../devicetree/bindings/drm/imx/mipi_dsi.txt       |   81 ++
 .../devicetree/bindings/panel/himax,hx8369a.txt    |   39 +
 arch/arm/boot/dts/imx6q.dtsi                       |   20 +-
 arch/arm/boot/dts/imx6qdl-sabresd.dtsi             |   20 +
 arch/arm/boot/dts/imx6qdl.dtsi                     |   30 +-
 arch/arm/configs/imx_v6_v7_defconfig               |   23 +-
 arch/arm/mach-imx/clk-imx6q.c                      |    8 +-
 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               | 1006 ++++++++++++++++++++
 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          |    5 +-
 include/linux/mfd/syscon/imx6q-iomuxc-gpr.h        |    1 +
 22 files changed, 2184 insertions(+), 34 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


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

* [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  9:33   ` Sascha Hauer
  2015-02-12  6:01 ` [PATCH RFC v9 02/20] ARM: imx6q: Add GPR3 MIPI muxing control register field shift bits definition Liu Ying
                   ` (19 subsequent siblings)
  20 siblings, 1 reply; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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 <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

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


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

* [PATCH RFC v9 02/20] ARM: imx6q: Add GPR3 MIPI muxing control register field shift bits definition
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 03/20] ARM: imx6q: clk: Add the video_27m clock Liu Ying
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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

Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

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 c877cad..d16f4c8 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


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

* [PATCH RFC v9 03/20] ARM: imx6q: clk: Add the video_27m clock
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 02/20] ARM: imx6q: Add GPR3 MIPI muxing control register field shift bits definition Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 04/20] ARM: imx6q: clk: Change hdmi_isfr clock's parent to be " Liu Ying
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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

Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

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 2daef61..2b7beb8 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


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

* [PATCH RFC v9 04/20] ARM: imx6q: clk: Change hdmi_isfr clock's parent to be video_27m clock
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (2 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 03/20] ARM: imx6q: clk: Add the video_27m clock Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 05/20] ARM: imx6q: clk: Change hsi_tx clock to be a shared clock gate Liu Ying
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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 <p.zabel@pengutronix.de>
Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

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 2b7beb8..0dbc79a 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


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

* [PATCH RFC v9 05/20] ARM: imx6q: clk: Change hsi_tx clock to be a shared clock gate
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (3 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 04/20] ARM: imx6q: clk: Change hdmi_isfr clock's parent to be " Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 06/20] ARM: imx6q: clk: Add support for mipi_core_cfg clock as " Liu Ying
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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 <p.zabel@pengutronix.de>
Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

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 0dbc79a..049e922 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


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

* [PATCH RFC v9 06/20] ARM: imx6q: clk: Add support for mipi_core_cfg clock as a shared clock gate
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (4 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 05/20] ARM: imx6q: clk: Change hsi_tx clock to be a shared clock gate Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 07/20] ARM: imx6q: clk: Add support for mipi_ipg " Liu Ying
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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 <p.zabel@pengutronix.de>
Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

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 049e922..cbdbe2a 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


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

* [PATCH RFC v9 07/20] ARM: imx6q: clk: Add support for mipi_ipg clock as a shared clock gate
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (5 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 06/20] ARM: imx6q: clk: Add support for mipi_core_cfg clock as " Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 08/20] ARM: dts: imx6qdl: Move existing MIPI DSI ports into a new 'ports' node Liu Ying
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

The CG8 field of the CCM CCGR3 register is the 'mipi_core_cfg' gate clock,
according to the i.MX6q/sdl reference manuals.  This clock is actually the
gate for several clocks, including the ipg clock's output.  The MIPI DSI host
controller embedded in the i.MX6q/sdl SoCs takes the ipg clock as the pclk -
the APB clock signal .  In order to gate/ungate the ipg clock, this patch adds
a new shared clock gate named as "mipi_ipg".

Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Newly introduced in v9.

 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 cbdbe2a..909828d 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -419,6 +419,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	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);
+	clk[IMX6QDL_CLK_MIPI_IPG]     = imx_clk_gate2_shared("mipi_ipg", "ipg",             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 dbc828c..8780868 100644
--- a/include/dt-bindings/clock/imx6qdl-clock.h
+++ b/include/dt-bindings/clock/imx6qdl-clock.h
@@ -250,6 +250,7 @@
 #define IMX6QDL_CLK_GPT_3M			237
 #define IMX6QDL_CLK_VIDEO_27M			238
 #define IMX6QDL_CLK_MIPI_CORE_CFG		239
-#define IMX6QDL_CLK_END				240
+#define IMX6QDL_CLK_MIPI_IPG			240
+#define IMX6QDL_CLK_END				241
 
 #endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */
-- 
2.1.0


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

* [PATCH RFC v9 08/20] ARM: dts: imx6qdl: Move existing MIPI DSI ports into a new 'ports' node
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (6 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 07/20] ARM: imx6q: clk: Add support for mipi_ipg " Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 09/20] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format Liu Ying
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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 <p.zabel@pengutronix.de>
Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

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 85f72e6..e152e6e 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 2109d07..55aced8 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1023,19 +1023,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


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

* [PATCH RFC v9 09/20] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (7 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 08/20] ARM: dts: imx6qdl: Move existing MIPI DSI ports into a new 'ports' node Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  9:26   ` Daniel Vetter
                     ` (2 more replies)
  2015-02-12  6:01 ` [PATCH RFC v9 10/20] Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM bridge driver Liu Ying
                   ` (11 subsequent siblings)
  20 siblings, 3 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

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


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

* [PATCH RFC v9 10/20] Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM bridge driver
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (8 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 09/20] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 11/20] drm/bridge: Add Synopsys DesignWare MIPI DSI host controller driver Liu Ying
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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

Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.
 * To address Philipp's comment, mention that a common compatible string
   "snps,dw-mipi-dsi" should be appended for all SoCs.
 * To address Philipp's comment, add a new required clock pclk and clean up
   clock-names.

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 | 76 ++++++++++++++++++++++
 1 file changed, 76 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..bb87466
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/bridge/dw_mipi_dsi.txt
@@ -0,0 +1,76 @@
+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 first 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.  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's pll reference
+   clock(ref), configuration clock(cfg) and APB clock(pclk), 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", "snps,dw-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>,
+			 <&clks IMX6QDL_CLK_MIPI_IPG>;
+		clock-names = "ref", "cfg", "pclk";
+
+		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


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

* [PATCH RFC v9 11/20] drm/bridge: Add Synopsys DesignWare MIPI DSI host controller driver
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (9 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 10/20] Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM bridge driver Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-04-09  8:43   ` Thierry Reding
  2015-02-12  6:01 ` [PATCH RFC v9 12/20] Documentation: dt-bindings: Add bindings for i.MX specific Synopsys DW MIPI DSI driver Liu Ying
                   ` (9 subsequent siblings)
  20 siblings, 1 reply; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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 <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository
   and adapt to bridge API change as the dw-hdmi driver did.
 * To address Philipp's comment, add a new required clock pclk and clean up
   clock-names.
 * Add driver copyright for 2015.

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 | 1006 ++++++++++++++++++++++++++++++++++
 include/drm/bridge/dw_mipi_dsi.h     |   27 +
 4 files changed, 1044 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 f38bbcd..de151f2 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -3,6 +3,16 @@ config DRM_DW_HDMI
 	depends on DRM
 	select DRM_KMS_HELPER
 
+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 d8a8cfd..5f8e9b3 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -2,3 +2,4 @@ ccflags-y := -Iinclude/drm
 
 obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
 obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
+obj-$(CONFIG_DRM_DW_MIPI_DSI) += dw_mipi_dsi.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..0ff241e
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw_mipi_dsi.c
@@ -0,0 +1,1006 @@
+/*
+ * Synopsys DesignWare(DW) MIPI DSI Host Controller
+ *
+ * Copyright (C) 2011-2015 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;
+	struct clk *pclk;
+
+	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);
+	clk_prepare_enable(dsi->pclk);
+	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->pclk);
+	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);
+	clk_prepare_enable(dsi->pclk);
+	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->pclk);
+	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);
+	clk_prepare_enable(dsi->pclk);
+	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->pclk);
+	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 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,
+};
+
+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;
+
+	bridge->funcs = &dw_mipi_dsi_bridge_funcs;
+	ret = drm_bridge_attach(drm, bridge);
+	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, "ref");
+	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, "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;
+	}
+
+	dsi->pclk = devm_clk_get(dev, "pclk");
+	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);
+	clk_prepare_enable(dsi->pclk);
+	val = dsi_read(dsi, DSI_VERSION);
+	clk_disable_unprepare(dsi->pclk);
+	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 <Ying.Liu@freescale.com>");
+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..17630aa
--- /dev/null
+++ b/include/drm/bridge/dw_mipi_dsi.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014-2015 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


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

* [PATCH RFC v9 12/20] Documentation: dt-bindings: Add bindings for i.MX specific Synopsys DW MIPI DSI driver
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (10 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 11/20] drm/bridge: Add Synopsys DesignWare MIPI DSI host controller driver Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 13/20] drm: imx: Support Synopsys DesignWare MIPI DSI host controller Liu Ying
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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

Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.
 * To address Philipp's comment, mention that a common compatible string
   "snps,dw-mipi-dsi" should be appended.
 * To address Philipp's comment, add a new required clock pclk and clean up
   clock-names.

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       | 81 ++++++++++++++++++++++
 1 file changed, 81 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..4bd8451
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/imx/mipi_dsi.txt
@@ -0,0 +1,81 @@
+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 first compatible string should be "fsl,imx6q-mipi-dsi"
+   for i.MX6q/sdl SoCs.  And, a common compatible string "snps,dw-mipi-dsi"
+   should be appended.
+ - 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's pll reference
+   clock(ref), configuration clock(cfg) and APB clock(pclk), 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", "snps,dw-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>,
+			 <&clks IMX6QDL_CLK_MIPI_IPG>;
+		clock-names = "ref", "cfg", "pclk";
+
+		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


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

* [PATCH RFC v9 13/20] drm: imx: Support Synopsys DesignWare MIPI DSI host controller
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (11 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 12/20] Documentation: dt-bindings: Add bindings for i.MX specific Synopsys DW MIPI DSI driver Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 14/20] Documentation: dt-bindings: Add bindings for Himax HX8369A DRM panel driver Liu Ying
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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 <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.
 * Add driver copyright for 2015.

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 33cdddf..7faeb49 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -53,3 +53,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 f3ecd89..93919b4 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) += dw_hdmi-imx.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..5e6f62d
--- /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-2015 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 <Ying.Liu@freescale.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
-- 
2.1.0


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

* [PATCH RFC v9 14/20] Documentation: dt-bindings: Add bindings for Himax HX8369A DRM panel driver
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (12 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 13/20] drm: imx: Support Synopsys DesignWare MIPI DSI host controller Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-04-09  7:20   ` Thierry Reding
  2015-02-12  6:01 ` [PATCH RFC v9 15/20] drm: panel: Add support for Himax HX8369A MIPI DSI panel Liu Ying
                   ` (6 subsequent siblings)
  20 siblings, 1 reply; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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

Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

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


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

* [PATCH RFC v9 15/20] drm: panel: Add support for Himax HX8369A MIPI DSI panel
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (13 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 14/20] Documentation: dt-bindings: Add bindings for Himax HX8369A DRM panel driver Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-04-09  8:09   ` Thierry Reding
  2015-02-12  6:01 ` [PATCH RFC v9 16/20] ARM: dtsi: imx6qdl: Add support for MIPI DSI host controller Liu Ying
                   ` (5 subsequent siblings)
  20 siblings, 1 reply; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

This patch adds support for Himax HX8369A MIPI DSI panel.

Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.
 * Add driver copyright for 2015.

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 <a.hajda@samsung.com>'.

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 d845837..cd6fbb7 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -17,6 +17,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..649e395
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-himax-hx8369a.c
@@ -0,0 +1,610 @@
+/*
+ * Himax HX8369A panel driver.
+ *
+ * Copyright (C) 2011-2015 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 <Ying.Liu@freescale.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.1.0


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

* [PATCH RFC v9 16/20] ARM: dtsi: imx6qdl: Add support for MIPI DSI host controller
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (14 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 15/20] drm: panel: Add support for Himax HX8369A MIPI DSI panel Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 17/20] ARM: dts: imx6qdl-sabresd: Add support for TRULY TFT480800-16-E MIPI DSI panel Liu Ying
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

This patch adds support for MIPI DSI host controller.

Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.
 * To address Philipp's comment, mention that a common compatible string
   "snps,dw-mipi-dsi" should be appended.
 * To address Philipp's comment, add a new required clock pclk and clean up
   clock-names.

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 | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 55aced8..0a4d7f7 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1020,7 +1020,14 @@
 			mipi_dsi: mipi@021e0000 {
 				#address-cells = <1>;
 				#size-cells = <0>;
+				compatible = "fsl,imx6q-mipi-dsi", "snps,dw-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>,
+					 <&clks IMX6QDL_CLK_MIPI_IPG>;
+				clock-names = "ref", "cfg", "pclk";
 				status = "disabled";
 
 				ports {
-- 
2.1.0


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

* [PATCH RFC v9 17/20] ARM: dts: imx6qdl-sabresd: Add support for TRULY TFT480800-16-E MIPI DSI panel
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (15 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 16/20] ARM: dtsi: imx6qdl: Add support for MIPI DSI host controller Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 18/20] ARM: imx_v6_v7_defconfig: Cleanup for imx drm being moved out of staging Liu Ying
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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 <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

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 f1cd214..9ff4ba5 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -480,6 +480,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 {
@@ -516,6 +523,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


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

* [PATCH RFC v9 18/20] ARM: imx_v6_v7_defconfig: Cleanup for imx drm being moved out of staging
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (16 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 17/20] ARM: dts: imx6qdl-sabresd: Add support for TRULY TFT480800-16-E MIPI DSI panel Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 19/20] ARM: imx_v6_v7_defconfig: Add support for MIPI DSI host controller Liu Ying
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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 <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository,
   so the patch content is different from v8.

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 | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 7c2075a..ec4b255 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -54,7 +54,6 @@ CONFIG_ARM_IMX6Q_CPUFREQ=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 CONFIG_BINFMT_MISC=m
-CONFIG_PM=y
 CONFIG_PM_DEBUG=y
 CONFIG_PM_TEST_SUSPEND=y
 CONFIG_NET=y
@@ -163,13 +162,13 @@ CONFIG_SPI_IMX=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_MC9S08DZ60=y
 CONFIG_GPIO_STMPE=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_IMX=y
 CONFIG_SENSORS_GPIO_FAN=y
 CONFIG_THERMAL=y
 CONFIG_CPU_THERMAL=y
 CONFIG_IMX_THERMAL=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_POWER_RESET=y
-CONFIG_POWER_RESET_IMX=y
 CONFIG_WATCHDOG=y
 CONFIG_IMX2_WDT=y
 CONFIG_MFD_DA9052_I2C=y
@@ -198,7 +197,12 @@ 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_HDMI=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_L4F00242T03=y
 CONFIG_LCD_PLATFORM=y
@@ -257,13 +261,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


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

* [PATCH RFC v9 19/20] ARM: imx_v6_v7_defconfig: Add support for MIPI DSI host controller
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (17 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 18/20] ARM: imx_v6_v7_defconfig: Cleanup for imx drm being moved out of staging Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-02-12  6:01 ` [PATCH RFC v9 20/20] ARM: imx_v6_v7_defconfig: Add support for Himax HX8369A panel Liu Ying
  2015-03-02 13:24 ` [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Shawn Guo
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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 <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

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 ec4b255..9e650e8f 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -203,6 +203,7 @@ CONFIG_DRM_IMX_PARALLEL_DISPLAY=y
 CONFIG_DRM_IMX_TVE=y
 CONFIG_DRM_IMX_LDB=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


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

* [PATCH RFC v9 20/20] ARM: imx_v6_v7_defconfig: Add support for Himax HX8369A panel
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (18 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 19/20] ARM: imx_v6_v7_defconfig: Add support for MIPI DSI host controller Liu Ying
@ 2015-02-12  6:01 ` Liu Ying
  2015-03-02 13:24 ` [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Shawn Guo
  20 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-12  6:01 UTC (permalink / raw)
  To: dri-devel
  Cc: devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, shawn.guo, mturquette, airlied, andy.yan,
	stefan.wahren, a.hajda, sboyd, linux-kernel

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 <Ying.Liu@freescale.com>
---
v8->v9:
 * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

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 9e650e8f..52d70a1 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -197,6 +197,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


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

* Re: [PATCH RFC v9 09/20] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
  2015-02-12  6:01 ` [PATCH RFC v9 09/20] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format Liu Ying
@ 2015-02-12  9:26   ` Daniel Vetter
  2015-02-13  5:01     ` Liu Ying
  2015-03-03 11:07   ` Philipp Zabel
  2015-04-09  7:10   ` Thierry Reding
  2 siblings, 1 reply; 73+ messages in thread
From: Daniel Vetter @ 2015-02-12  9:26 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, stefan.wahren, devicetree, linux, kernel, sboyd,
	linux-kernel, a.hajda, andy.yan, mturquette, linux-arm-kernel

On Thu, Feb 12, 2015 at 02:01:32PM +0800, Liu Ying wrote:
> Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
> ---
> v8->v9:
>  * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.
> 
> 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)

Kerneldoc seems to be missing for this one.
-Daniel

> +{
> +	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
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-12  6:01 ` [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found Liu Ying
@ 2015-02-12  9:33   ` Sascha Hauer
  2015-02-12 10:39     ` Liu Ying
  0 siblings, 1 reply; 73+ messages in thread
From: Sascha Hauer @ 2015-02-12  9:33 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, stefan.wahren, devicetree, linux, kernel, sboyd,
	linux-kernel, a.hajda, andy.yan, mturquette, linux-arm-kernel

On Thu, Feb 12, 2015 at 02:01:24PM +0800, Liu Ying wrote:
> 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.

Please add an explanation why you think the current code is wrong and
what this actually fixes, maybe an example?

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

When getting into the if(!bestdiv) it means that the lowest possible
rate we can archieve is still higher than the target rate, so setting
the parent rate as low as possible seems sane to me. Why do you think
this is wrong? In which case this even makes a difference?

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-12  9:33   ` Sascha Hauer
@ 2015-02-12 10:39     ` Liu Ying
  2015-02-12 12:24       ` Sascha Hauer
  0 siblings, 1 reply; 73+ messages in thread
From: Liu Ying @ 2015-02-12 10:39 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: dri-devel, stefan.wahren, devicetree, linux, kernel, sboyd,
	linux-kernel, a.hajda, andy.yan, mturquette, linux-arm-kernel

On Thu, Feb 12, 2015 at 10:33:56AM +0100, Sascha Hauer wrote:
> On Thu, Feb 12, 2015 at 02:01:24PM +0800, Liu Ying wrote:
> > 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.
> 
> Please add an explanation why you think the current code is wrong and
> what this actually fixes, maybe an example?

The MIPI DSI panel's pixel clock rate is 26.4MHz and it's derived from PLL5 on
the MX6DL SabreSD board.

These are the clock tree summaries with or without the patch applied:
1) With the patch applied:
pll5_bypass_src                       1            1    24000000          0 0
   pll5                               1            1   844800048          0 0
      pll5_bypass                     1            1   844800048          0 0
         pll5_video                   1            1   844800048          0 0
            pll5_post_div             1            1   211200012          0 0
               pll5_video_div           1            1   211200012        0 0
                  ipu1_di0_pre_sel           1            1   211200012   0 0
                     ipu1_di0_pre           1            1    26400002    0 0
                        ipu1_di0_sel           1            1    26400002 0 0
                           ipu1_di0           1            1    26400002  0 0

2) Without the patch applied:
pll5_bypass_src                       1            1    24000000          0 0
   pll5                               1            1   648000000          0 0
      pll5_bypass                     1            1   648000000          0 0
         pll5_video                   1            1   648000000          0 0
            pll5_post_div             1            1   162000000          0 0
               pll5_video_div           1            1    40500000        0 0
                  ipu1_di0_pre_sel           1            1    40500000   0 0
                     ipu1_di0_pre           1            1    20250000    0 0
                        ipu1_di0_sel           1            1    20250000 0 0
                           ipu1_di0           1            1    20250000  0 0

> 
> > 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));
> 
> When getting into the if(!bestdiv) it means that the lowest possible
> rate we can archieve is still higher than the target rate, so setting
> the parent rate as low as possible seems sane to me. Why do you think
> this is wrong? In which case this even makes a difference?

We still should take the little left chance to get a closest target clock
rate we want(26.4MHz, in the example case above), so it looks that the lowest
parent clock rate for being rounded should be MULT_ROUND_UP(rate, bestdiv)
instead of 1Hz.

Regards,
Liu Ying

> 
> Sascha
> 
> -- 
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-12 10:39     ` Liu Ying
@ 2015-02-12 12:24       ` Sascha Hauer
  2015-02-12 12:56         ` Russell King - ARM Linux
  2015-02-21  8:56         ` Uwe Kleine-König
  0 siblings, 2 replies; 73+ messages in thread
From: Sascha Hauer @ 2015-02-12 12:24 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, stefan.wahren, devicetree, linux, kernel, sboyd,
	linux-kernel, a.hajda, andy.yan, mturquette, linux-arm-kernel,
	Tomi Valkeinen

On Thu, Feb 12, 2015 at 06:39:45PM +0800, Liu Ying wrote:
> On Thu, Feb 12, 2015 at 10:33:56AM +0100, Sascha Hauer wrote:
> > On Thu, Feb 12, 2015 at 02:01:24PM +0800, Liu Ying wrote:
> > > 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.
> > 
> > Please add an explanation why you think the current code is wrong and
> > what this actually fixes, maybe an example?
> 
> The MIPI DSI panel's pixel clock rate is 26.4MHz and it's derived from PLL5 on
> the MX6DL SabreSD board.
> 
> These are the clock tree summaries with or without the patch applied:
> 1) With the patch applied:
> pll5_bypass_src                       1            1    24000000          0 0
>    pll5                               1            1   844800048          0 0
>       pll5_bypass                     1            1   844800048          0 0
>          pll5_video                   1            1   844800048          0 0
>             pll5_post_div             1            1   211200012          0 0
>                pll5_video_div           1            1   211200012        0 0
>                   ipu1_di0_pre_sel           1            1   211200012   0 0
>                      ipu1_di0_pre           1            1    26400002    0 0
>                         ipu1_di0_sel           1            1    26400002 0 0
>                            ipu1_di0           1            1    26400002  0 0
> 
> 2) Without the patch applied:
> pll5_bypass_src                       1            1    24000000          0 0
>    pll5                               1            1   648000000          0 0
>       pll5_bypass                     1            1   648000000          0 0
>          pll5_video                   1            1   648000000          0 0
>             pll5_post_div             1            1   162000000          0 0
>                pll5_video_div           1            1    40500000        0 0
>                   ipu1_di0_pre_sel           1            1    40500000   0 0
>                      ipu1_di0_pre           1            1    20250000    0 0
>                         ipu1_di0_sel           1            1    20250000 0 0
>                            ipu1_di0           1            1    20250000  0 0

This seems to be broken since:

| commit b11d282dbea27db1788893115dfca8a7856bf205
| Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
| Date:   Thu Feb 13 12:03:59 2014 +0200
| 
|     clk: divider: fix rate calculation for fractional rates

This patch fixed a case when clk_set_rate(clk_round_rate(rate)) resulted
in a lower frequency than clk_round_rate(rate) returned.

Since then the MULT_ROUND_UP in clk_divider_bestdiv() is inconsistent to
the rest of the divider. Maybe this should be a simple rate * i now, but
I'm unsure what side effects this has.

I think your patch only fixes the behaviour in your case by accident,
it's not a correct fix for this issue.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-12 12:24       ` Sascha Hauer
@ 2015-02-12 12:56         ` Russell King - ARM Linux
  2015-02-12 13:41           ` Sascha Hauer
  2015-02-21  8:56         ` Uwe Kleine-König
  1 sibling, 1 reply; 73+ messages in thread
From: Russell King - ARM Linux @ 2015-02-12 12:56 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Liu Ying, dri-devel, stefan.wahren, devicetree, kernel, sboyd,
	linux-kernel, a.hajda, andy.yan, mturquette, linux-arm-kernel,
	Tomi Valkeinen

On Thu, Feb 12, 2015 at 01:24:05PM +0100, Sascha Hauer wrote:
> On Thu, Feb 12, 2015 at 06:39:45PM +0800, Liu Ying wrote:
> > On Thu, Feb 12, 2015 at 10:33:56AM +0100, Sascha Hauer wrote:
> > > On Thu, Feb 12, 2015 at 02:01:24PM +0800, Liu Ying wrote:
> > > > 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.
> > > 
> > > Please add an explanation why you think the current code is wrong and
> > > what this actually fixes, maybe an example?
> > 
> > The MIPI DSI panel's pixel clock rate is 26.4MHz and it's derived from PLL5 on
> > the MX6DL SabreSD board.
> > 
> > These are the clock tree summaries with or without the patch applied:
> > 1) With the patch applied:
> > pll5_bypass_src                       1            1    24000000          0 0
> >    pll5                               1            1   844800048          0 0
> >       pll5_bypass                     1            1   844800048          0 0
> >          pll5_video                   1            1   844800048          0 0
> >             pll5_post_div             1            1   211200012          0 0
> >                pll5_video_div           1            1   211200012        0 0
> >                   ipu1_di0_pre_sel           1            1   211200012   0 0
> >                      ipu1_di0_pre           1            1    26400002    0 0
> >                         ipu1_di0_sel           1            1    26400002 0 0
> >                            ipu1_di0           1            1    26400002  0 0
> > 
> > 2) Without the patch applied:
> > pll5_bypass_src                       1            1    24000000          0 0
> >    pll5                               1            1   648000000          0 0
> >       pll5_bypass                     1            1   648000000          0 0
> >          pll5_video                   1            1   648000000          0 0
> >             pll5_post_div             1            1   162000000          0 0
> >                pll5_video_div           1            1    40500000        0 0
> >                   ipu1_di0_pre_sel           1            1    40500000   0 0
> >                      ipu1_di0_pre           1            1    20250000    0 0
> >                         ipu1_di0_sel           1            1    20250000 0 0
> >                            ipu1_di0           1            1    20250000  0 0
> 
> This seems to be broken since:
> 
> | commit b11d282dbea27db1788893115dfca8a7856bf205
> | Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
> | Date:   Thu Feb 13 12:03:59 2014 +0200
> | 
> |     clk: divider: fix rate calculation for fractional rates
> 
> This patch fixed a case when clk_set_rate(clk_round_rate(rate)) resulted
> in a lower frequency than clk_round_rate(rate) returned.
> 
> Since then the MULT_ROUND_UP in clk_divider_bestdiv() is inconsistent to
> the rest of the divider. Maybe this should be a simple rate * i now, but
> I'm unsure what side effects this has.
> 
> I think your patch only fixes the behaviour in your case by accident,
> it's not a correct fix for this issue.

Well, it's defined that:

	new_rate = clk_round_rate(clk, rate);

returns the rate which you would get if you did:

	clk_set_rate(clk, rate);
	new_rate = clk_get_rate(clk);

The reasoning here is that clk_round_rate() gives you a way to query what
rate you would get if you were to ask for the rate to be set, without
effecting a change in the hardware.

The idea that you should call clk_round_rate() first before clk_set_rate()
and pass the returned rounded rate into clk_set_rate() is really idiotic
given that.  Please don't do it, and please remove code which does it, and
in review comment on it.  Thanks.

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-12 12:56         ` Russell King - ARM Linux
@ 2015-02-12 13:41           ` Sascha Hauer
  2015-02-12 14:06             ` Liu Ying
  2015-02-13 14:35             ` Tomi Valkeinen
  0 siblings, 2 replies; 73+ messages in thread
From: Sascha Hauer @ 2015-02-12 13:41 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Liu Ying, dri-devel, stefan.wahren, devicetree, kernel, sboyd,
	linux-kernel, a.hajda, andy.yan, mturquette, linux-arm-kernel,
	Tomi Valkeinen

On Thu, Feb 12, 2015 at 12:56:46PM +0000, Russell King - ARM Linux wrote:
> On Thu, Feb 12, 2015 at 01:24:05PM +0100, Sascha Hauer wrote:
> > On Thu, Feb 12, 2015 at 06:39:45PM +0800, Liu Ying wrote:
> > > On Thu, Feb 12, 2015 at 10:33:56AM +0100, Sascha Hauer wrote:
> > > > On Thu, Feb 12, 2015 at 02:01:24PM +0800, Liu Ying wrote:
> > > > > 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.
> > > > 
> > > > Please add an explanation why you think the current code is wrong and
> > > > what this actually fixes, maybe an example?
> > > 
> > > The MIPI DSI panel's pixel clock rate is 26.4MHz and it's derived from PLL5 on
> > > the MX6DL SabreSD board.
> > > 
> > > These are the clock tree summaries with or without the patch applied:
> > > 1) With the patch applied:
> > > pll5_bypass_src                       1            1    24000000          0 0
> > >    pll5                               1            1   844800048          0 0
> > >       pll5_bypass                     1            1   844800048          0 0
> > >          pll5_video                   1            1   844800048          0 0
> > >             pll5_post_div             1            1   211200012          0 0
> > >                pll5_video_div           1            1   211200012        0 0
> > >                   ipu1_di0_pre_sel           1            1   211200012   0 0
> > >                      ipu1_di0_pre           1            1    26400002    0 0
> > >                         ipu1_di0_sel           1            1    26400002 0 0
> > >                            ipu1_di0           1            1    26400002  0 0
> > > 
> > > 2) Without the patch applied:
> > > pll5_bypass_src                       1            1    24000000          0 0
> > >    pll5                               1            1   648000000          0 0
> > >       pll5_bypass                     1            1   648000000          0 0
> > >          pll5_video                   1            1   648000000          0 0
> > >             pll5_post_div             1            1   162000000          0 0
> > >                pll5_video_div           1            1    40500000        0 0
> > >                   ipu1_di0_pre_sel           1            1    40500000   0 0
> > >                      ipu1_di0_pre           1            1    20250000    0 0
> > >                         ipu1_di0_sel           1            1    20250000 0 0
> > >                            ipu1_di0           1            1    20250000  0 0
> > 
> > This seems to be broken since:
> > 
> > | commit b11d282dbea27db1788893115dfca8a7856bf205
> > | Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
> > | Date:   Thu Feb 13 12:03:59 2014 +0200
> > | 
> > |     clk: divider: fix rate calculation for fractional rates
> > 
> > This patch fixed a case when clk_set_rate(clk_round_rate(rate)) resulted
> > in a lower frequency than clk_round_rate(rate) returned.
> > 
> > Since then the MULT_ROUND_UP in clk_divider_bestdiv() is inconsistent to
> > the rest of the divider. Maybe this should be a simple rate * i now, but
> > I'm unsure what side effects this has.
> > 
> > I think your patch only fixes the behaviour in your case by accident,
> > it's not a correct fix for this issue.
> 
> Well, it's defined that:
> 
> 	new_rate = clk_round_rate(clk, rate);
> 
> returns the rate which you would get if you did:
> 
> 	clk_set_rate(clk, rate);
> 	new_rate = clk_get_rate(clk);
> 
> The reasoning here is that clk_round_rate() gives you a way to query what
> rate you would get if you were to ask for the rate to be set, without
> effecting a change in the hardware.
> 
> The idea that you should call clk_round_rate() first before clk_set_rate()
> and pass the returned rounded rate into clk_set_rate() is really idiotic
> given that.  Please don't do it, and please remove code which does it, and
> in review comment on it.  Thanks.

Tomis patch is based on the assumption that clk_set_rate(clk_round_rate(rate))
is equal to clk_round_rate(rate). So when this assumption is wrong then
it should simply be reverted.
So Liu, could you test if reverting Tomis patch fixes your problem?

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-12 13:41           ` Sascha Hauer
@ 2015-02-12 14:06             ` Liu Ying
  2015-02-13  2:58               ` Liu Ying
  2015-02-13 14:35             ` Tomi Valkeinen
  1 sibling, 1 reply; 73+ messages in thread
From: Liu Ying @ 2015-02-12 14:06 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Russell King - ARM Linux, dri-devel, stefan.wahren, devicetree,
	kernel, sboyd, linux-kernel, a.hajda, andy.yan, mturquette,
	linux-arm-kernel, Tomi Valkeinen

On Thu, Feb 12, 2015 at 02:41:31PM +0100, Sascha Hauer wrote:
> On Thu, Feb 12, 2015 at 12:56:46PM +0000, Russell King - ARM Linux wrote:
> > On Thu, Feb 12, 2015 at 01:24:05PM +0100, Sascha Hauer wrote:
> > > On Thu, Feb 12, 2015 at 06:39:45PM +0800, Liu Ying wrote:
> > > > On Thu, Feb 12, 2015 at 10:33:56AM +0100, Sascha Hauer wrote:
> > > > > On Thu, Feb 12, 2015 at 02:01:24PM +0800, Liu Ying wrote:
> > > > > > 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.
> > > > > 
> > > > > Please add an explanation why you think the current code is wrong and
> > > > > what this actually fixes, maybe an example?
> > > > 
> > > > The MIPI DSI panel's pixel clock rate is 26.4MHz and it's derived from PLL5 on
> > > > the MX6DL SabreSD board.
> > > > 
> > > > These are the clock tree summaries with or without the patch applied:
> > > > 1) With the patch applied:
> > > > pll5_bypass_src                       1            1    24000000          0 0
> > > >    pll5                               1            1   844800048          0 0
> > > >       pll5_bypass                     1            1   844800048          0 0
> > > >          pll5_video                   1            1   844800048          0 0
> > > >             pll5_post_div             1            1   211200012          0 0
> > > >                pll5_video_div           1            1   211200012        0 0
> > > >                   ipu1_di0_pre_sel           1            1   211200012   0 0
> > > >                      ipu1_di0_pre           1            1    26400002    0 0
> > > >                         ipu1_di0_sel           1            1    26400002 0 0
> > > >                            ipu1_di0           1            1    26400002  0 0
> > > > 
> > > > 2) Without the patch applied:
> > > > pll5_bypass_src                       1            1    24000000          0 0
> > > >    pll5                               1            1   648000000          0 0
> > > >       pll5_bypass                     1            1   648000000          0 0
> > > >          pll5_video                   1            1   648000000          0 0
> > > >             pll5_post_div             1            1   162000000          0 0
> > > >                pll5_video_div           1            1    40500000        0 0
> > > >                   ipu1_di0_pre_sel           1            1    40500000   0 0
> > > >                      ipu1_di0_pre           1            1    20250000    0 0
> > > >                         ipu1_di0_sel           1            1    20250000 0 0
> > > >                            ipu1_di0           1            1    20250000  0 0
> > > 
> > > This seems to be broken since:
> > > 
> > > | commit b11d282dbea27db1788893115dfca8a7856bf205
> > > | Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
> > > | Date:   Thu Feb 13 12:03:59 2014 +0200
> > > | 
> > > |     clk: divider: fix rate calculation for fractional rates
> > > 
> > > This patch fixed a case when clk_set_rate(clk_round_rate(rate)) resulted
> > > in a lower frequency than clk_round_rate(rate) returned.
> > > 
> > > Since then the MULT_ROUND_UP in clk_divider_bestdiv() is inconsistent to
> > > the rest of the divider. Maybe this should be a simple rate * i now, but
> > > I'm unsure what side effects this has.
> > > 
> > > I think your patch only fixes the behaviour in your case by accident,
> > > it's not a correct fix for this issue.
> > 
> > Well, it's defined that:
> > 
> > 	new_rate = clk_round_rate(clk, rate);
> > 
> > returns the rate which you would get if you did:
> > 
> > 	clk_set_rate(clk, rate);
> > 	new_rate = clk_get_rate(clk);
> > 
> > The reasoning here is that clk_round_rate() gives you a way to query what
> > rate you would get if you were to ask for the rate to be set, without
> > effecting a change in the hardware.
> > 
> > The idea that you should call clk_round_rate() first before clk_set_rate()
> > and pass the returned rounded rate into clk_set_rate() is really idiotic
> > given that.  Please don't do it, and please remove code which does it, and
> > in review comment on it.  Thanks.
> 
> Tomis patch is based on the assumption that clk_set_rate(clk_round_rate(rate))
> is equal to clk_round_rate(rate). So when this assumption is wrong then
> it should simply be reverted.
> So Liu, could you test if reverting Tomis patch fixes your problem?

Yes, I'll test tomorrow when I have access to my board.

Regards,
Liu Ying

> 
> Sascha
> 
> -- 
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-12 14:06             ` Liu Ying
@ 2015-02-13  2:58               ` Liu Ying
  2015-02-13  2:58                 ` Travis
  0 siblings, 1 reply; 73+ messages in thread
From: Liu Ying @ 2015-02-13  2:58 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: stefan.wahren, devicetree, Russell King - ARM Linux, mturquette,
	sboyd, linux-kernel, dri-devel, a.hajda, Tomi Valkeinen, kernel,
	andy.yan, linux-arm-kernel

On Thu, Feb 12, 2015 at 10:06:27PM +0800, Liu Ying wrote:
> On Thu, Feb 12, 2015 at 02:41:31PM +0100, Sascha Hauer wrote:
> > On Thu, Feb 12, 2015 at 12:56:46PM +0000, Russell King - ARM Linux wrote:
> > > On Thu, Feb 12, 2015 at 01:24:05PM +0100, Sascha Hauer wrote:
> > > > On Thu, Feb 12, 2015 at 06:39:45PM +0800, Liu Ying wrote:
> > > > > On Thu, Feb 12, 2015 at 10:33:56AM +0100, Sascha Hauer wrote:
> > > > > > On Thu, Feb 12, 2015 at 02:01:24PM +0800, Liu Ying wrote:
> > > > > > > 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.
> > > > > > 
> > > > > > Please add an explanation why you think the current code is wrong and
> > > > > > what this actually fixes, maybe an example?
> > > > > 
> > > > > The MIPI DSI panel's pixel clock rate is 26.4MHz and it's derived from PLL5 on
> > > > > the MX6DL SabreSD board.
> > > > > 
> > > > > These are the clock tree summaries with or without the patch applied:
> > > > > 1) With the patch applied:
> > > > > pll5_bypass_src                       1            1    24000000          0 0
> > > > >    pll5                               1            1   844800048          0 0
> > > > >       pll5_bypass                     1            1   844800048          0 0
> > > > >          pll5_video                   1            1   844800048          0 0
> > > > >             pll5_post_div             1            1   211200012          0 0
> > > > >                pll5_video_div           1            1   211200012        0 0
> > > > >                   ipu1_di0_pre_sel           1            1   211200012   0 0
> > > > >                      ipu1_di0_pre           1            1    26400002    0 0
> > > > >                         ipu1_di0_sel           1            1    26400002 0 0
> > > > >                            ipu1_di0           1            1    26400002  0 0
> > > > > 
> > > > > 2) Without the patch applied:
> > > > > pll5_bypass_src                       1            1    24000000          0 0
> > > > >    pll5                               1            1   648000000          0 0
> > > > >       pll5_bypass                     1            1   648000000          0 0
> > > > >          pll5_video                   1            1   648000000          0 0
> > > > >             pll5_post_div             1            1   162000000          0 0
> > > > >                pll5_video_div           1            1    40500000        0 0
> > > > >                   ipu1_di0_pre_sel           1            1    40500000   0 0
> > > > >                      ipu1_di0_pre           1            1    20250000    0 0
> > > > >                         ipu1_di0_sel           1            1    20250000 0 0
> > > > >                            ipu1_di0           1            1    20250000  0 0
> > > > 
> > > > This seems to be broken since:
> > > > 
> > > > | commit b11d282dbea27db1788893115dfca8a7856bf205
> > > > | Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
> > > > | Date:   Thu Feb 13 12:03:59 2014 +0200
> > > > | 
> > > > |     clk: divider: fix rate calculation for fractional rates
> > > > 
> > > > This patch fixed a case when clk_set_rate(clk_round_rate(rate)) resulted
> > > > in a lower frequency than clk_round_rate(rate) returned.
> > > > 
> > > > Since then the MULT_ROUND_UP in clk_divider_bestdiv() is inconsistent to
> > > > the rest of the divider. Maybe this should be a simple rate * i now, but
> > > > I'm unsure what side effects this has.
> > > > 
> > > > I think your patch only fixes the behaviour in your case by accident,
> > > > it's not a correct fix for this issue.
> > > 
> > > Well, it's defined that:
> > > 
> > > 	new_rate = clk_round_rate(clk, rate);
> > > 
> > > returns the rate which you would get if you did:
> > > 
> > > 	clk_set_rate(clk, rate);
> > > 	new_rate = clk_get_rate(clk);
> > > 
> > > The reasoning here is that clk_round_rate() gives you a way to query what
> > > rate you would get if you were to ask for the rate to be set, without
> > > effecting a change in the hardware.
> > > 
> > > The idea that you should call clk_round_rate() first before clk_set_rate()
> > > and pass the returned rounded rate into clk_set_rate() is really idiotic
> > > given that.  Please don't do it, and please remove code which does it, and
> > > in review comment on it.  Thanks.
> > 
> > Tomis patch is based on the assumption that clk_set_rate(clk_round_rate(rate))
> > is equal to clk_round_rate(rate). So when this assumption is wrong then
> > it should simply be reverted.
> > So Liu, could you test if reverting Tomis patch fixes your problem?
> 
> Yes, I'll test tomorrow when I have access to my board.

Tomi's patch cannot be reverted directly because of conflicts with the later
patches.  So, I revert all the clock divider driver patches on top of that.
And, yes, after reverting Tomi's patch, I may get the correct 26.4MHz pixel
clock rate.

Regards,
Liu Ying

> 
> Regards,
> Liu Ying
> 
> > 
> > Sascha
> > 
> > -- 
> > Pengutronix e.K.                           |                             |
> > Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-13  2:58               ` Liu Ying
@ 2015-02-13  2:58                 ` Travis
  0 siblings, 0 replies; 73+ messages in thread
From: Travis @ 2015-02-13  2:58 UTC (permalink / raw)
  To: Liu Ying
  Cc: andy.yan, a.hajda, Tomi Valkeinen, Sascha Hauer, linux-kernel,
	devicetree, kernel, stefan.wahren, mturquette, linux-arm-kernel,
	sboyd, dri-devel, Russell King - ARM Linux

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=utf-8, Size: 7585 bytes --]

Travis liked your message with Boxer for Android.

On Feb 12, 2015 8:58 PM, Liu Ying <Ying.Liu@freescale.com> wrote:
>
> On Thu, Feb 12, 2015 at 10:06:27PM +0800, Liu Ying wrote: 
> > On Thu, Feb 12, 2015 at 02:41:31PM +0100, Sascha Hauer wrote: 
> > > On Thu, Feb 12, 2015 at 12:56:46PM +0000, Russell King - ARM Linux wrote: 
> > > > On Thu, Feb 12, 2015 at 01:24:05PM +0100, Sascha Hauer wrote: 
> > > > > On Thu, Feb 12, 2015 at 06:39:45PM +0800, Liu Ying wrote: 
> > > > > > On Thu, Feb 12, 2015 at 10:33:56AM +0100, Sascha Hauer wrote: 
> > > > > > > On Thu, Feb 12, 2015 at 02:01:24PM +0800, Liu Ying wrote: 
> > > > > > > > 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. 
> > > > > > > 
> > > > > > > Please add an explanation why you think the current code is wrong and 
> > > > > > > what this actually fixes, maybe an example? 
> > > > > > 
> > > > > > The MIPI DSI panel's pixel clock rate is 26.4MHz and it's derived from PLL5 on 
> > > > > > the MX6DL SabreSD board. 
> > > > > > 
> > > > > > These are the clock tree summaries with or without the patch applied: 
> > > > > > 1) With the patch applied: 
> > > > > > pll5_bypass_src                       1            1    24000000          0 0 
> > > > > >    pll5                               1            1   844800048          0 0 
> > > > > >       pll5_bypass                     1            1   844800048          0 0 
> > > > > >          pll5_video                   1            1   844800048          0 0 
> > > > > >             pll5_post_div             1            1   211200012          0 0 
> > > > > >                pll5_video_div           1            1   211200012        0 0 
> > > > > >                   ipu1_di0_pre_sel           1            1   211200012   0 0 
> > > > > >                      ipu1_di0_pre           1            1    26400002    0 0 
> > > > > >                         ipu1_di0_sel           1            1    26400002 0 0 
> > > > > >                            ipu1_di0           1            1    26400002  0 0 
> > > > > > 
> > > > > > 2) Without the patch applied: 
> > > > > > pll5_bypass_src                       1            1    24000000          0 0 
> > > > > >    pll5                               1            1   648000000          0 0 
> > > > > >       pll5_bypass                     1            1   648000000          0 0 
> > > > > >          pll5_video                   1            1   648000000          0 0 
> > > > > >             pll5_post_div             1            1   162000000          0 0 
> > > > > >                pll5_video_div           1            1    40500000        0 0 
> > > > > >                   ipu1_di0_pre_sel           1            1    40500000   0 0 
> > > > > >                      ipu1_di0_pre           1            1    20250000    0 0 
> > > > > >                         ipu1_di0_sel           1            1    20250000 0 0 
> > > > > >                            ipu1_di0           1            1    20250000  0 0 
> > > > > 
> > > > > This seems to be broken since: 
> > > > > 
> > > > > | commit b11d282dbea27db1788893115dfca8a7856bf205 
> > > > > | Author: Tomi Valkeinen <tomi.valkeinen@ti.com> 
> > > > > | Date:   Thu Feb 13 12:03:59 2014 +0200 
> > > > > | 
> > > > > |     clk: divider: fix rate calculation for fractional rates 
> > > > > 
> > > > > This patch fixed a case when clk_set_rate(clk_round_rate(rate)) resulted 
> > > > > in a lower frequency than clk_round_rate(rate) returned. 
> > > > > 
> > > > > Since then the MULT_ROUND_UP in clk_divider_bestdiv() is inconsistent to 
> > > > > the rest of the divider. Maybe this should be a simple rate * i now, but 
> > > > > I'm unsure what side effects this has. 
> > > > > 
> > > > > I think your patch only fixes the behaviour in your case by accident, 
> > > > > it's not a correct fix for this issue. 
> > > > 
> > > > Well, it's defined that: 
> > > > 
> > > > new_rate = clk_round_rate(clk, rate); 
> > > > 
> > > > returns the rate which you would get if you did: 
> > > > 
> > > > clk_set_rate(clk, rate); 
> > > > new_rate = clk_get_rate(clk); 
> > > > 
> > > > The reasoning here is that clk_round_rate() gives you a way to query what 
> > > > rate you would get if you were to ask for the rate to be set, without 
> > > > effecting a change in the hardware. 
> > > > 
> > > > The idea that you should call clk_round_rate() first before clk_set_rate() 
> > > > and pass the returned rounded rate into clk_set_rate() is really idiotic 
> > > > given that.  Please don't do it, and please remove code which does it, and 
> > > > in review comment on it.  Thanks. 
> > > 
> > > Tomis patch is based on the assumption that clk_set_rate(clk_round_rate(rate)) 
> > > is equal to clk_round_rate(rate). So when this assumption is wrong then 
> > > it should simply be reverted. 
> > > So Liu, could you test if reverting Tomis patch fixes your problem? 
> > 
> > Yes, I'll test tomorrow when I have access to my board. 
>
> Tomi's patch cannot be reverted directly because of conflicts with the later 
> patches.  So, I revert all the clock divider driver patches on top of that. 
> And, yes, after reverting Tomi's patch, I may get the correct 26.4MHz pixel 
> clock rate. 
>
> Regards, 
> Liu Ying 
>
> > 
> > Regards, 
> > Liu Ying 
> > 
> > > 
> > > Sascha 
> > > 
> > > -- 
> > > Pengutronix e.K.                           |                             | 
> > > Industrial Linux Solutions                 | http://www.pengutronix.de/  | 
> > > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    | 
> > > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 | 
> > _______________________________________________ 
> > dri-devel mailing list 
> > dri-devel@lists.freedesktop.org 
> > http://lists.freedesktop.org/mailman/listinfo/dri-devel 
> -- 
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in 
> the body of a message to majordomo@vger.kernel.org 
> More majordomo info at  http://vger.kernel.org/majordomo-info.html 
> Please read the FAQ at  http://www.tux.org/lkml/ 
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH RFC v9 09/20] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
  2015-02-12  9:26   ` Daniel Vetter
@ 2015-02-13  5:01     ` Liu Ying
  0 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-02-13  5:01 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: dri-devel, stefan.wahren, devicetree, linux, kernel, sboyd,
	linux-kernel, a.hajda, andy.yan, mturquette, linux-arm-kernel

On Thu, Feb 12, 2015 at 10:26:42AM +0100, Daniel Vetter wrote:
> On Thu, Feb 12, 2015 at 02:01:32PM +0800, Liu Ying wrote:
> > Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
> > ---
> > v8->v9:
> >  * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.
> > 
> > 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)
> 
> Kerneldoc seems to be missing for this one.

I'll add it.  Thanks for pointing out this.

Regards,
Liu Ying

> -Daniel
> 
> > +{
> > +	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
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-12 13:41           ` Sascha Hauer
  2015-02-12 14:06             ` Liu Ying
@ 2015-02-13 14:35             ` Tomi Valkeinen
  2015-02-13 18:57               ` Sascha Hauer
  1 sibling, 1 reply; 73+ messages in thread
From: Tomi Valkeinen @ 2015-02-13 14:35 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Russell King - ARM Linux, Liu Ying, dri-devel, stefan.wahren,
	devicetree, kernel, sboyd, linux-kernel, a.hajda, andy.yan,
	mturquette, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 583 bytes --]

On 12/02/15 15:41, Sascha Hauer wrote:

> Tomis patch is based on the assumption that clk_set_rate(clk_round_rate(rate))
> is equal to clk_round_rate(rate). So when this assumption is wrong then
> it should simply be reverted.

When is it not equal?

I agree that doing clk_set_rate(clk, clk_round_rate(clk, rate)) is
pointless, but shouldn't it still work?

And we can forget about clk_round_rate. Without my patch, this would
behave oddly also:

rate = clk_get_rate(clk);
clk_set_rate(clk, rate);

The end result could be something else than 'rate'.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-13 14:35             ` Tomi Valkeinen
@ 2015-02-13 18:57               ` Sascha Hauer
  2015-02-16 11:18                 ` Tomi Valkeinen
  2015-02-16 11:27                 ` Russell King - ARM Linux
  0 siblings, 2 replies; 73+ messages in thread
From: Sascha Hauer @ 2015-02-13 18:57 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: Russell King - ARM Linux, Liu Ying, dri-devel, stefan.wahren,
	devicetree, kernel, sboyd, linux-kernel, a.hajda, andy.yan,
	mturquette, linux-arm-kernel

On Fri, Feb 13, 2015 at 04:35:36PM +0200, Tomi Valkeinen wrote:
> On 12/02/15 15:41, Sascha Hauer wrote:
> 
> > Tomis patch is based on the assumption that clk_set_rate(clk_round_rate(rate))
> > is equal to clk_round_rate(rate). So when this assumption is wrong then
> > it should simply be reverted.
> 
> When is it not equal?
> 
> I agree that doing clk_set_rate(clk, clk_round_rate(clk, rate)) is
> pointless, but shouldn't it still work?
> 
> And we can forget about clk_round_rate. Without my patch, this would
> behave oddly also:
> 
> rate = clk_get_rate(clk);
> clk_set_rate(clk, rate);
> 
> The end result could be something else than 'rate'.

I agree that it's a bit odd, but I think it has to be like this.
Consider that you request a rate of 100Hz, but the clock can only
produce 99.5Hz, so due to rounding clk_round_rate() returns 99Hz.
Now when you request 99Hz from clk_set_rate() the 99.5Hz value
can't be used because it's too high.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-13 18:57               ` Sascha Hauer
@ 2015-02-16 11:18                 ` Tomi Valkeinen
  2015-02-17 10:32                   ` Sascha Hauer
  2015-02-16 11:27                 ` Russell King - ARM Linux
  1 sibling, 1 reply; 73+ messages in thread
From: Tomi Valkeinen @ 2015-02-16 11:18 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Russell King - ARM Linux, Liu Ying, dri-devel, stefan.wahren,
	devicetree, kernel, sboyd, linux-kernel, a.hajda, andy.yan,
	mturquette, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 1347 bytes --]

On 13/02/15 20:57, Sascha Hauer wrote:
> On Fri, Feb 13, 2015 at 04:35:36PM +0200, Tomi Valkeinen wrote:
>> On 12/02/15 15:41, Sascha Hauer wrote:
>>
>>> Tomis patch is based on the assumption that clk_set_rate(clk_round_rate(rate))
>>> is equal to clk_round_rate(rate). So when this assumption is wrong then
>>> it should simply be reverted.
>>
>> When is it not equal?
>>
>> I agree that doing clk_set_rate(clk, clk_round_rate(clk, rate)) is
>> pointless, but shouldn't it still work?
>>
>> And we can forget about clk_round_rate. Without my patch, this would
>> behave oddly also:
>>
>> rate = clk_get_rate(clk);
>> clk_set_rate(clk, rate);
>>
>> The end result could be something else than 'rate'.
> 
> I agree that it's a bit odd, but I think it has to be like this.
> Consider that you request a rate of 100Hz, but the clock can only
> produce 99.5Hz, so due to rounding clk_round_rate() returns 99Hz.
> Now when you request 99Hz from clk_set_rate() the 99.5Hz value
> can't be used because it's too high.

Would that problem better be fixed by changing the clock driver so that
when asked for 99Hz, it would look for rates less than 100Hz?

I think the old behavior was so odd that I would call it broken, so I
hope the current problems can be fixed via some other ways than breaking
it again.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-13 18:57               ` Sascha Hauer
  2015-02-16 11:18                 ` Tomi Valkeinen
@ 2015-02-16 11:27                 ` Russell King - ARM Linux
  2015-02-20 19:13                   ` Mike Turquette
  1 sibling, 1 reply; 73+ messages in thread
From: Russell King - ARM Linux @ 2015-02-16 11:27 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Tomi Valkeinen, stefan.wahren, devicetree, mturquette, sboyd,
	linux-kernel, dri-devel, a.hajda, kernel, andy.yan, Liu Ying,
	linux-arm-kernel

On Fri, Feb 13, 2015 at 07:57:13PM +0100, Sascha Hauer wrote:
> I agree that it's a bit odd, but I think it has to be like this.
> Consider that you request a rate of 100Hz, but the clock can only
> produce 99.5Hz, so due to rounding clk_round_rate() returns 99Hz.
> Now when you request 99Hz from clk_set_rate() the 99.5Hz value
> can't be used because it's too high.

Math rounding rules normally state that anything of .5 and greater
should be rounded up, not rounded down.  So, for 99.5Hz, you really
ought to be returning 100Hz, not 99Hz.

However, you do have a point for 99.4Hz, which would be returned as
99Hz, and when set, it would result in something which isn't 99.4Hz.

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-16 11:18                 ` Tomi Valkeinen
@ 2015-02-17 10:32                   ` Sascha Hauer
  0 siblings, 0 replies; 73+ messages in thread
From: Sascha Hauer @ 2015-02-17 10:32 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: Russell King - ARM Linux, Liu Ying, dri-devel, stefan.wahren,
	devicetree, kernel, sboyd, linux-kernel, a.hajda, andy.yan,
	mturquette, linux-arm-kernel

On Mon, Feb 16, 2015 at 01:18:13PM +0200, Tomi Valkeinen wrote:
> On 13/02/15 20:57, Sascha Hauer wrote:
> > On Fri, Feb 13, 2015 at 04:35:36PM +0200, Tomi Valkeinen wrote:
> >> On 12/02/15 15:41, Sascha Hauer wrote:
> >>
> >>> Tomis patch is based on the assumption that clk_set_rate(clk_round_rate(rate))
> >>> is equal to clk_round_rate(rate). So when this assumption is wrong then
> >>> it should simply be reverted.
> >>
> >> When is it not equal?
> >>
> >> I agree that doing clk_set_rate(clk, clk_round_rate(clk, rate)) is
> >> pointless, but shouldn't it still work?
> >>
> >> And we can forget about clk_round_rate. Without my patch, this would
> >> behave oddly also:
> >>
> >> rate = clk_get_rate(clk);
> >> clk_set_rate(clk, rate);
> >>
> >> The end result could be something else than 'rate'.
> > 
> > I agree that it's a bit odd, but I think it has to be like this.
> > Consider that you request a rate of 100Hz, but the clock can only
> > produce 99.5Hz, so due to rounding clk_round_rate() returns 99Hz.
> > Now when you request 99Hz from clk_set_rate() the 99.5Hz value
> > can't be used because it's too high.
> 
> Would that problem better be fixed by changing the clock driver so that
> when asked for 99Hz, it would look for rates less than 100Hz?
> 
> I think the old behavior was so odd that I would call it broken, so I
> hope the current problems can be fixed via some other ways than breaking
> it again.

I gave it a try, but so far I have no idea how to implement the divider
correctly and bullet proof.

What I have so far is a test which creates some cascaded dividers and sets
rates on them. The test iterates over the frequency range and a) calls
clk_round_rate with the iterator, b) sets the clk to the iterator, c)
sets the clk to the rounded rate.

Be prepared for surprises and try to fix the results... I failed for
now and wonder if the approach to the divider is wrong.

Sascha

>From 58a46b16d4b67d5cd7df4af6deb5b96e19afe230 Mon Sep 17 00:00:00 2001
From: Sascha Hauer <s.hauer@pengutronix.de>
Date: Tue, 17 Feb 2015 11:24:10 +0100
Subject: [PATCH] clk: clk-divider: Add a simple test for dividers

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/clk/clk-divider.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index c0a842b..cd66625 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -463,3 +463,89 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
 			width, clk_divider_flags, table, lock);
 }
 EXPORT_SYMBOL_GPL(clk_register_divider_table);
+
+/*
+ * Simple test of dividers. Try to set rates between 1 and 10000Hz and
+ *  - get output of clk_round_rate()
+ *  - set the current target rate, get the rate
+ *  - set the rate to the rounded rate, get the rate
+ *
+ * Whenever a value changed print the results
+ */
+static void clktest_one(struct clk *clk)
+{
+	int i, ret;
+	unsigned long roundsetrate, last_roundsetrate = 0;
+	unsigned long roundrate, last_roundrate = 0;
+	unsigned long setrate, last_setrate = 0;
+
+	for (i = 1; i < 10000; i++) {
+		roundrate = clk_round_rate(clk, i);
+
+		clk_set_rate(clk, i);
+		setrate = clk_get_rate(clk);
+
+		ret = clk_set_rate(clk, roundrate);
+		if (ret) {
+			printk("clkdivtest: Failed to set rate: %d\n", ret);
+			return;
+		}
+
+		roundsetrate = clk_get_rate(clk);
+
+		if (last_roundsetrate != roundsetrate ||
+				last_roundrate != roundrate ||
+				last_setrate != setrate)
+			printk("target rate: %4d rounded: %4ld set: %4ld round/set: %4ld\n",
+					i, roundrate, setrate, roundsetrate);
+
+		last_roundsetrate = roundsetrate;
+		last_roundrate = roundrate;
+		last_setrate = setrate;
+	}
+}
+
+static int clktest(void)
+{
+	u32 reg_div1 = 0;
+	u32 reg_div2 = 0;
+	u32 reg_div3 = 0;
+	struct clk *clktest_base = ERR_PTR(-ENODEV);
+	struct clk *clktest_div1 = ERR_PTR(-ENODEV);
+	struct clk *clktest_div2 = ERR_PTR(-ENODEV);
+	struct clk *clktest_div3 = ERR_PTR(-ENODEV);
+
+	clktest_base = clk_register_fixed_rate(NULL, "clktest_base", NULL, 0, 10000);
+	clktest_div1 = clk_register_divider(NULL, "clktest_div1", "clktest_base",
+			0, &reg_div1, 0, 4, 0, NULL);
+	clktest_div2 = clk_register_divider(NULL, "clktest_div2", "clktest_div1",
+			CLK_SET_RATE_PARENT, &reg_div2, 0, 4, 0, NULL);
+	clktest_div3 = clk_register_divider(NULL, "clktest_div3", "clktest_div2",
+			CLK_SET_RATE_PARENT, &reg_div3, 0, 4, 0, NULL);
+
+	if (IS_ERR(clktest_base) || IS_ERR(clktest_div1) ||
+			IS_ERR(clktest_div2) || IS_ERR(clktest_div3)) {
+		printk("clkdivtest: Failed to register clocks\n");
+		goto err_out;
+	}
+
+	printk("------------------ Single divider, fin=10000Hz ------------------\n");
+	clktest_one(clktest_div1);
+	printk("--------------- two cascaded dividers, fin=10000Hz --------------\n");
+	clktest_one(clktest_div2);
+	printk("-------------- three cascaded dividers, fin=10000Hz -------------\n");
+	clktest_one(clktest_div3);
+
+err_out:
+	if (!IS_ERR(clktest_base))
+		clk_unregister(clktest_base);
+	if (!IS_ERR(clktest_div1))
+		clk_unregister(clktest_div1);
+	if (!IS_ERR(clktest_div2))
+		clk_unregister(clktest_div2);
+	if (!IS_ERR(clktest_div3))
+		clk_unregister(clktest_div3);
+
+	return 0;
+}
+late_initcall(clktest);
-- 
2.1.4


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-16 11:27                 ` Russell King - ARM Linux
@ 2015-02-20 19:13                   ` Mike Turquette
  2015-02-20 19:20                     ` Russell King - ARM Linux
  0 siblings, 1 reply; 73+ messages in thread
From: Mike Turquette @ 2015-02-20 19:13 UTC (permalink / raw)
  To: Russell King - ARM Linux, Sascha Hauer
  Cc: Tomi Valkeinen, stefan.wahren, devicetree, sboyd, linux-kernel,
	dri-devel, a.hajda, kernel, andy.yan, Liu Ying, linux-arm-kernel

Quoting Russell King - ARM Linux (2015-02-16 03:27:24)
> On Fri, Feb 13, 2015 at 07:57:13PM +0100, Sascha Hauer wrote:
> > I agree that it's a bit odd, but I think it has to be like this.
> > Consider that you request a rate of 100Hz, but the clock can only
> > produce 99.5Hz, so due to rounding clk_round_rate() returns 99Hz.
> > Now when you request 99Hz from clk_set_rate() the 99.5Hz value
> > can't be used because it's too high.
> 
> Math rounding rules normally state that anything of .5 and greater
> should be rounded up, not rounded down.  So, for 99.5Hz, you really
> ought to be returning 100Hz, not 99Hz.
> 
> However, you do have a point for 99.4Hz, which would be returned as
> 99Hz, and when set, it would result in something which isn't 99.4Hz.

More practically, this again raises the issue of whether or not unsigned
long rate should be in millihertz or something other than hertz.

And then that question again raises the issue of making rate 64-bit...

Regards,
Mike

> 
> -- 
> FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
> according to speedtest.net.

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-20 19:13                   ` Mike Turquette
@ 2015-02-20 19:20                     ` Russell King - ARM Linux
  0 siblings, 0 replies; 73+ messages in thread
From: Russell King - ARM Linux @ 2015-02-20 19:20 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Sascha Hauer, Tomi Valkeinen, stefan.wahren, devicetree, sboyd,
	linux-kernel, dri-devel, a.hajda, kernel, andy.yan, Liu Ying,
	linux-arm-kernel

On Fri, Feb 20, 2015 at 11:13:06AM -0800, Mike Turquette wrote:
> Quoting Russell King - ARM Linux (2015-02-16 03:27:24)
> > On Fri, Feb 13, 2015 at 07:57:13PM +0100, Sascha Hauer wrote:
> > > I agree that it's a bit odd, but I think it has to be like this.
> > > Consider that you request a rate of 100Hz, but the clock can only
> > > produce 99.5Hz, so due to rounding clk_round_rate() returns 99Hz.
> > > Now when you request 99Hz from clk_set_rate() the 99.5Hz value
> > > can't be used because it's too high.
> > 
> > Math rounding rules normally state that anything of .5 and greater
> > should be rounded up, not rounded down.  So, for 99.5Hz, you really
> > ought to be returning 100Hz, not 99Hz.
> > 
> > However, you do have a point for 99.4Hz, which would be returned as
> > 99Hz, and when set, it would result in something which isn't 99.4Hz.
> 
> More practically, this again raises the issue of whether or not unsigned
> long rate should be in millihertz or something other than hertz.

You still get the same issue if it's millihertz.  Take 10 2/3rds Hz.
Is 10.666 Hz less than 10 2/3rds Hz?

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

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

* Re: [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found
  2015-02-12 12:24       ` Sascha Hauer
  2015-02-12 12:56         ` Russell King - ARM Linux
@ 2015-02-21  8:56         ` Uwe Kleine-König
  2015-02-21 10:40           ` [PATCH 0/3] clk: divider: three exactness fixes (and a rant) Uwe Kleine-König
  1 sibling, 1 reply; 73+ messages in thread
From: Uwe Kleine-König @ 2015-02-21  8:56 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Liu Ying, stefan.wahren, devicetree, linux, mturquette, sboyd,
	linux-kernel, dri-devel, a.hajda, Tomi Valkeinen, kernel,
	andy.yan, linux-arm-kernel

Hello,

On Thu, Feb 12, 2015 at 01:24:05PM +0100, Sascha Hauer wrote:
> On Thu, Feb 12, 2015 at 06:39:45PM +0800, Liu Ying wrote:
> > On Thu, Feb 12, 2015 at 10:33:56AM +0100, Sascha Hauer wrote:
> > > On Thu, Feb 12, 2015 at 02:01:24PM +0800, Liu Ying wrote:
> > > > 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.
> > > 
> > > Please add an explanation why you think the current code is wrong and
> > > what this actually fixes, maybe an example?
> > 
> > The MIPI DSI panel's pixel clock rate is 26.4MHz and it's derived from PLL5 on
> > the MX6DL SabreSD board.
> > 
> > These are the clock tree summaries with or without the patch applied:
> > 1) With the patch applied:
> > pll5_bypass_src                       1            1    24000000          0 0
> >    pll5                               1            1   844800048          0 0
> >       pll5_bypass                     1            1   844800048          0 0
> >          pll5_video                   1            1   844800048          0 0
> >             pll5_post_div             1            1   211200012          0 0
> >                pll5_video_div           1            1   211200012        0 0
> >                   ipu1_di0_pre_sel           1            1   211200012   0 0
> >                      ipu1_di0_pre           1            1    26400002    0 0
> >                         ipu1_di0_sel           1            1    26400002 0 0
> >                            ipu1_di0           1            1    26400002  0 0
> > 
> > 2) Without the patch applied:
> > pll5_bypass_src                       1            1    24000000          0 0
> >    pll5                               1            1   648000000          0 0
> >       pll5_bypass                     1            1   648000000          0 0
> >          pll5_video                   1            1   648000000          0 0
> >             pll5_post_div             1            1   162000000          0 0
> >                pll5_video_div           1            1    40500000        0 0
> >                   ipu1_di0_pre_sel           1            1    40500000   0 0
> >                      ipu1_di0_pre           1            1    20250000    0 0
> >                         ipu1_di0_sel           1            1    20250000 0 0
> >                            ipu1_di0           1            1    20250000  0 0
> 
> This seems to be broken since:
> 
> | commit b11d282dbea27db1788893115dfca8a7856bf205
> | Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
> | Date:   Thu Feb 13 12:03:59 2014 +0200
> | 
> |     clk: divider: fix rate calculation for fractional rates
> 
> This patch fixed a case when clk_set_rate(clk_round_rate(rate)) resulted
> in a lower frequency than clk_round_rate(rate) returned.
> 
> Since then the MULT_ROUND_UP in clk_divider_bestdiv() is inconsistent to
> the rest of the divider. Maybe this should be a simple rate * i now, but
> I'm unsure what side effects this has.
I think this is the right fix that I found, too, while fixing all
problems that your test code with the three dividers shows (at least the
subset of all problem I was able to identify).

> I think your patch only fixes the behaviour in your case by accident,
> it's not a correct fix for this issue.
Right.

I will follow up with a patch (and two more that fix different things).

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-02-21  8:56         ` Uwe Kleine-König
@ 2015-02-21 10:40           ` Uwe Kleine-König
  2015-02-21 10:40             ` [PATCH 1/3] clk: divider: fix calculation of maximal parent rate for a given divider Uwe Kleine-König
                               ` (4 more replies)
  0 siblings, 5 replies; 73+ messages in thread
From: Uwe Kleine-König @ 2015-02-21 10:40 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd
  Cc: kernel, linux-kernel, linux-arm-kernel, Sören Brinkmann

Hello,

TLDR: only apply patch 1 and rip of CLK_DIVIDER_ROUND_CLOSEST.

I stared at clk-divider.c for some time now given Sascha's failing test
case. I found a fix for the failure (which happens to be what Sascha
suspected).

The other two patches fix problems only present when handling dividers
that have CLK_DIVIDER_ROUND_CLOSEST set. Note that these are still
heavily broken however. So having a 4bit-divider and a parent clk of
10000 (as in Sascha's test case) requesting

	clk_set_rate(clk, 666)

sets the rate to 625 (div=15) instead of 667 (div=16). The reason is the
choice of parent_rate in clk_divider_bestdiv's loop is wrong for
CLK_DIVIDER_ROUND_CLOSEST (with and without patch 1). A fix here is
non-trivial and for sure more than one rate must be tested here. This is
complicated by the fact that clk_round_rate might return a value bigger
than the requested rate which convinces me (once more) that it's a bad
idea to allow that. Even if this was fixed for .round_rate,
clk_divider_set_rate is still broken because it also uses

	div = DIV_ROUND_UP(parent_rate, rate);

to calculate the (pretended) best divider to get near rate.

Note this makes at least two reasons to remove support for
CLK_DIVIDER_ROUND_CLOSEST!

Instead I'd favour creating a function

	clk_round_rate_nearest

as was suggested some time ago by Soren Brinkmann and me[1] that doesn't
need any clk type specific knowledge. This would mean that not the
divider (or clk in general) would have to know that returning a slightly
bigger rate than requested is OK but the caller which is fine (and even
better) in my eyes. This would simplify clk-divider.c (and probably
others) and give support for "nearest match" for all clock types without
type specific implementation. (Note that it might even make sense to use
a different metric for "nearest", instead of minimizing

	abs(target - rate)

you might want to minimize

	abs(target / rate - 1)

instead.

Converting the clk framework to 64 bit rates was discussed earlier
already, too, and I wonder if we should fix rounding issues (a bit) in
the same transition such that 

	clk_set_rate(clk, 333)

allows the clk to be set to 333.3333333333 Hz and let clk_get_rate
return 333 in this case.

Also I'd vote to return 0 or -ESOMETHING if a requested rate is too low
to be set. This would simplify some special casing I think and makes the
request

	clk_round_rate(clk, x) <= x

consistent.

Best regards
Uwe

[1] https://lkml.org/lkml/2014/5/14/698

Uwe Kleine-König (3):
  clk: divider: fix calculation of maximal parent rate for a given
    divider
  clk: divider: fix selection of divider when rounding to closest
  clk: divider: fix calculation of initial best divider when rounding to
    closest

 drivers/clk/clk-divider.c | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

-- 
2.1.4


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

* [PATCH 1/3] clk: divider: fix calculation of maximal parent rate for a given divider
  2015-02-21 10:40           ` [PATCH 0/3] clk: divider: three exactness fixes (and a rant) Uwe Kleine-König
@ 2015-02-21 10:40             ` Uwe Kleine-König
  2015-02-23  7:32               ` Sascha Hauer
  2015-03-05  8:35               ` Uwe Kleine-König
  2015-02-21 10:40             ` [PATCH 2/3] clk: divider: fix selection of divider when rounding to closest Uwe Kleine-König
                               ` (3 subsequent siblings)
  4 siblings, 2 replies; 73+ messages in thread
From: Uwe Kleine-König @ 2015-02-21 10:40 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd
  Cc: kernel, linux-kernel, linux-arm-kernel, Sören Brinkmann

The rate provided at the output of a clk-divider is calculated as:

	DIV_ROUND_UP(parent_rate, div)

since commit b11d282dbea2 (clk: divider: fix rate calculation for
fractional rates). So to yield a rate not bigger than r parent_rate
must be <= r * div.

The effect of choosing a parent rate that is too big as was done before
this patch results in wrongly ruling out good dividers.

Note that this is not a complete fix as __clk_round_rate might return a
value >= its 2nd parameter. Also for dividers with
CLK_DIVIDER_ROUND_CLOSEST set the calculation is not accurate. But this
fixes the test case by Sascha Hauer that uses a chain of three dividers
under a fixed clock.

Fixes: b11d282dbea2 (clk: divider: fix rate calculation for fractional rates)
Suggested-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/clk/clk-divider.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 531d5a48e69f..fbd9e8270791 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -129,12 +129,6 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	return DIV_ROUND_UP(parent_rate, div);
 }
 
-/*
- * The reverse of DIV_ROUND_UP: The maximum number which
- * divided by m is r
- */
-#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
-
 static bool _is_valid_table_div(const struct clk_div_table *table,
 							 unsigned int div)
 {
@@ -300,7 +294,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
 			return i;
 		}
 		parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
-				MULT_ROUND_UP(rate, i));
+					       rate * i);
 		now = DIV_ROUND_UP(parent_rate, i);
 		if (_is_best_div(divider, rate, now, best)) {
 			bestdiv = i;
-- 
2.1.4


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

* [PATCH 2/3] clk: divider: fix selection of divider when rounding to closest
  2015-02-21 10:40           ` [PATCH 0/3] clk: divider: three exactness fixes (and a rant) Uwe Kleine-König
  2015-02-21 10:40             ` [PATCH 1/3] clk: divider: fix calculation of maximal parent rate for a given divider Uwe Kleine-König
@ 2015-02-21 10:40             ` Uwe Kleine-König
  2015-02-23  9:46               ` Maxime Coquelin
  2015-02-21 10:40             ` [PATCH 3/3] clk: divider: fix calculation of initial best " Uwe Kleine-König
                               ` (2 subsequent siblings)
  4 siblings, 1 reply; 73+ messages in thread
From: Uwe Kleine-König @ 2015-02-21 10:40 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd
  Cc: kernel, linux-kernel, linux-arm-kernel, Sören Brinkmann

It's an invalid approach to assume that among two divider values
the one nearer the exact divider is the better one.

Assume a parent rate of 1000 Hz, a divider with CLK_DIVIDER_POWER_OF_TWO
and a target rate of 89 Hz. The exact divider is ~ 11.236 so 8 and 16
are the candidates to choose from yielding rates 125 Hz and 62.5 Hz
respectivly. While 8 is nearer to 11.236 than 16 is, the latter is still
the better divider as 62.5 is nearer to 89 than 125 is.

Fixes: 774b514390b1 (clk: divider: Add round to closest divider)
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/clk/clk-divider.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index fbd9e8270791..66a6211b8834 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -202,6 +202,7 @@ static int _div_round_closest(struct clk_divider *divider,
 		unsigned long parent_rate, unsigned long rate)
 {
 	int up, down, div;
+	unsigned long up_rate, down_rate;
 
 	up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
 
@@ -213,7 +214,10 @@ static int _div_round_closest(struct clk_divider *divider,
 		down = _round_down_table(divider->table, div);
 	}
 
-	return (up - div) <= (div - down) ? up : down;
+	up_rate = DIV_ROUND_UP(parent_rate, up);
+	down_rate = DIV_ROUND_UP(parent_rate, down);
+
+	return (rate - up_rate) <= (down_rate - rate) ? up : down;
 }
 
 static int _div_round(struct clk_divider *divider, unsigned long parent_rate,
-- 
2.1.4


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

* [PATCH 3/3] clk: divider: fix calculation of initial best divider when rounding to closest
  2015-02-21 10:40           ` [PATCH 0/3] clk: divider: three exactness fixes (and a rant) Uwe Kleine-König
  2015-02-21 10:40             ` [PATCH 1/3] clk: divider: fix calculation of maximal parent rate for a given divider Uwe Kleine-König
  2015-02-21 10:40             ` [PATCH 2/3] clk: divider: fix selection of divider when rounding to closest Uwe Kleine-König
@ 2015-02-21 10:40             ` Uwe Kleine-König
  2015-02-23  9:42               ` Maxime Coquelin
  2015-02-23  7:23             ` [PATCH 0/3] clk: divider: three exactness fixes (and a rant) Sascha Hauer
  2015-03-06 18:57             ` Mike Turquette
  4 siblings, 1 reply; 73+ messages in thread
From: Uwe Kleine-König @ 2015-02-21 10:40 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd
  Cc: kernel, linux-kernel, linux-arm-kernel, Sören Brinkmann

Similar to the reasoning for the previous commit

	DIV_ROUND_CLOSEST(parent_rate, rate)

might not be the best integer divisor to get a good approximation for
rate from parent_rate (given the metric for CLK_DIVIDER_ROUND_CLOSEST).

For example assume a parent rate of 1000 Hz and a target rate of 700.
Using DIV_ROUND_CLOSEST the suggested divisor gets calculated to 1
resulting in a target rate of 1000 with a delta of 300 to the desired
rate. With choosing 2 as divisor however the resulting rate is 500 which
is nearer to 700.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/clk/clk-divider.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 66a6211b8834..202a17e9a38b 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -201,17 +201,18 @@ static int _div_round_up(struct clk_divider *divider,
 static int _div_round_closest(struct clk_divider *divider,
 		unsigned long parent_rate, unsigned long rate)
 {
-	int up, down, div;
+	int up, down;
 	unsigned long up_rate, down_rate;
 
-	up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
+	up = DIV_ROUND_UP(parent_rate, rate);
+	down = parent_rate / rate;
 
 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) {
-		up = __roundup_pow_of_two(div);
-		down = __rounddown_pow_of_two(div);
+		up = __roundup_pow_of_two(up);
+		down = __rounddown_pow_of_two(down);
 	} else if (divider->table) {
-		up = _round_up_table(divider->table, div);
-		down = _round_down_table(divider->table, div);
+		up = _round_up_table(divider->table, up);
+		down = _round_down_table(divider->table, down);
 	}
 
 	up_rate = DIV_ROUND_UP(parent_rate, up);
-- 
2.1.4


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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-02-21 10:40           ` [PATCH 0/3] clk: divider: three exactness fixes (and a rant) Uwe Kleine-König
                               ` (2 preceding siblings ...)
  2015-02-21 10:40             ` [PATCH 3/3] clk: divider: fix calculation of initial best " Uwe Kleine-König
@ 2015-02-23  7:23             ` Sascha Hauer
  2015-03-06 18:57             ` Mike Turquette
  4 siblings, 0 replies; 73+ messages in thread
From: Sascha Hauer @ 2015-02-23  7:23 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Mike Turquette, Stephen Boyd, linux-arm-kernel,
	Sören Brinkmann, linux-kernel, kernel

On Sat, Feb 21, 2015 at 11:40:22AM +0100, Uwe Kleine-König wrote:
> Hello,
> 
> TLDR: only apply patch 1 and rip of CLK_DIVIDER_ROUND_CLOSEST.
> 
> I stared at clk-divider.c for some time now given Sascha's failing test
> case. I found a fix for the failure (which happens to be what Sascha
> suspected).
> 
> The other two patches fix problems only present when handling dividers
> that have CLK_DIVIDER_ROUND_CLOSEST set. Note that these are still
> heavily broken however. So having a 4bit-divider and a parent clk of
> 10000 (as in Sascha's test case) requesting
> 
> 	clk_set_rate(clk, 666)
> 
> sets the rate to 625 (div=15) instead of 667 (div=16). The reason is the
> choice of parent_rate in clk_divider_bestdiv's loop is wrong for
> CLK_DIVIDER_ROUND_CLOSEST (with and without patch 1). A fix here is
> non-trivial and for sure more than one rate must be tested here. This is
> complicated by the fact that clk_round_rate might return a value bigger
> than the requested rate which convinces me (once more) that it's a bad
> idea to allow that. Even if this was fixed for .round_rate,
> clk_divider_set_rate is still broken because it also uses
> 
> 	div = DIV_ROUND_UP(parent_rate, rate);
> 
> to calculate the (pretended) best divider to get near rate.
> 
> Note this makes at least two reasons to remove support for
> CLK_DIVIDER_ROUND_CLOSEST!
> 
> Instead I'd favour creating a function
> 
> 	clk_round_rate_nearest

Full ack. It's a clock consumer who wants to decide the rounding
strategy, not the clock itself and for sure not a specific entity of the
clock tree. CLK_DIVIDER_ROUND_CLOSEST should be dropped.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 1/3] clk: divider: fix calculation of maximal parent rate for a given divider
  2015-02-21 10:40             ` [PATCH 1/3] clk: divider: fix calculation of maximal parent rate for a given divider Uwe Kleine-König
@ 2015-02-23  7:32               ` Sascha Hauer
  2015-03-05  8:35               ` Uwe Kleine-König
  1 sibling, 0 replies; 73+ messages in thread
From: Sascha Hauer @ 2015-02-23  7:32 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Mike Turquette, Stephen Boyd, linux-arm-kernel,
	Sören Brinkmann, linux-kernel, kernel

On Sat, Feb 21, 2015 at 11:40:23AM +0100, Uwe Kleine-König wrote:
> The rate provided at the output of a clk-divider is calculated as:
> 
> 	DIV_ROUND_UP(parent_rate, div)
> 
> since commit b11d282dbea2 (clk: divider: fix rate calculation for
> fractional rates). So to yield a rate not bigger than r parent_rate
> must be <= r * div.
> 
> The effect of choosing a parent rate that is too big as was done before
> this patch results in wrongly ruling out good dividers.
> 
> Note that this is not a complete fix as __clk_round_rate might return a
> value >= its 2nd parameter. Also for dividers with
> CLK_DIVIDER_ROUND_CLOSEST set the calculation is not accurate. But this
> fixes the test case by Sascha Hauer that uses a chain of three dividers
> under a fixed clock.
> 
> Fixes: b11d282dbea2 (clk: divider: fix rate calculation for fractional rates)
> Suggested-by: Sascha Hauer <s.hauer@pengutronix.de>
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

Acked-by: Sascha Hauer <s.hauer@pengutronix.de>

This gives clk_round_rate/clk_set_rate on dividers a consistent
behaviour. Also the testcases I posted seem to work fine.

The only thing that might not be nice is that when a divider can only
output fractional rates then the next higher integer value has to be used
for clk_round_rate/clk_set_rate. A consumer should probably make no
assumptions whether 333.333Hz is rounded up or down and use 334Hz to be
sure anyway.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 3/3] clk: divider: fix calculation of initial best divider when rounding to closest
  2015-02-21 10:40             ` [PATCH 3/3] clk: divider: fix calculation of initial best " Uwe Kleine-König
@ 2015-02-23  9:42               ` Maxime Coquelin
  0 siblings, 0 replies; 73+ messages in thread
From: Maxime Coquelin @ 2015-02-23  9:42 UTC (permalink / raw)
  To: Uwe Kleine-König, Mike Turquette, Stephen Boyd
  Cc: linux-arm-kernel, Sören Brinkmann, linux-kernel, kernel

Hi Uwe,

On 02/21/2015 11:40 AM, Uwe Kleine-König wrote:
> Similar to the reasoning for the previous commit
>
> 	DIV_ROUND_CLOSEST(parent_rate, rate)
>
> might not be the best integer divisor to get a good approximation for
> rate from parent_rate (given the metric for CLK_DIVIDER_ROUND_CLOSEST).
>
> For example assume a parent rate of 1000 Hz and a target rate of 700.
> Using DIV_ROUND_CLOSEST the suggested divisor gets calculated to 1
> resulting in a target rate of 1000 with a delta of 300 to the desired
> rate. With choosing 2 as divisor however the resulting rate is 500 which
> is nearer to 700.
>
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
>   drivers/clk/clk-divider.c | 13 +++++++------
>   1 file changed, 7 insertions(+), 6 deletions(-)
>

This is correct. Thanks for fixing this.

You can add my:
Acked-by: Maxime Coquelin <maxime.coquelin@st.com>


Best regards,
Maxime

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

* Re: [PATCH 2/3] clk: divider: fix selection of divider when rounding to closest
  2015-02-21 10:40             ` [PATCH 2/3] clk: divider: fix selection of divider when rounding to closest Uwe Kleine-König
@ 2015-02-23  9:46               ` Maxime Coquelin
  0 siblings, 0 replies; 73+ messages in thread
From: Maxime Coquelin @ 2015-02-23  9:46 UTC (permalink / raw)
  To: Uwe Kleine-König, Mike Turquette, Stephen Boyd
  Cc: linux-arm-kernel, Sören Brinkmann, linux-kernel, kernel

Hello Uwe,

On 02/21/2015 11:40 AM, Uwe Kleine-König wrote:
> It's an invalid approach to assume that among two divider values
> the one nearer the exact divider is the better one.
>
> Assume a parent rate of 1000 Hz, a divider with CLK_DIVIDER_POWER_OF_TWO
> and a target rate of 89 Hz. The exact divider is ~ 11.236 so 8 and 16
> are the candidates to choose from yielding rates 125 Hz and 62.5 Hz
> respectivly. While 8 is nearer to 11.236 than 16 is, the latter is still
> the better divider as 62.5 is nearer to 89 than 125 is.
>
> Fixes: 774b514390b1 (clk: divider: Add round to closest divider)
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
>   drivers/clk/clk-divider.c | 6 +++++-
>   1 file changed, 5 insertions(+), 1 deletion(-)

For this one too, you can add my:
Acked-by: Maxime Coquelin <maxime.coquelin@st.com>

Thanks,
Maxime

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

* Re: [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver
  2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
                   ` (19 preceding siblings ...)
  2015-02-12  6:01 ` [PATCH RFC v9 20/20] ARM: imx_v6_v7_defconfig: Add support for Himax HX8369A panel Liu Ying
@ 2015-03-02 13:24 ` Shawn Guo
  20 siblings, 0 replies; 73+ messages in thread
From: Shawn Guo @ 2015-03-02 13:24 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	thierry.reding, mturquette, airlied, andy.yan, stefan.wahren,
	a.hajda, sboyd, linux-kernel

On Thu, Feb 12, 2015 at 02:01:23PM +0800, Liu Ying wrote:
> Liu Ying (20):
>   clk: divider: Correct parent clk round rate if no bestdiv is normally
>     found

>   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: imx6q: clk: Add support for mipi_ipg clock as a shared clock gate
>   ARM: dts: imx6qdl: Move existing MIPI DSI ports into a new 'ports'
>     node

Applied above 7 i.MX patches (#2 ~ #8).

Shawn

>   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

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

* Re: [PATCH RFC v9 09/20] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
  2015-02-12  6:01 ` [PATCH RFC v9 09/20] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format Liu Ying
  2015-02-12  9:26   ` Daniel Vetter
@ 2015-03-03 11:07   ` Philipp Zabel
  2015-04-03  3:28     ` Liu Ying
  2015-04-09  7:10   ` Thierry Reding
  2 siblings, 1 reply; 73+ messages in thread
From: Philipp Zabel @ 2015-03-03 11:07 UTC (permalink / raw)
  To: Liu Ying, Thierry Reding
  Cc: dri-devel, devicetree, linux-arm-kernel, linux, kernel,
	shawn.guo, mturquette, airlied, andy.yan, stefan.wahren, a.hajda,
	sboyd, linux-kernel

Hi,

Am Donnerstag, den 12.02.2015, 14:01 +0800 schrieb Liu Ying:
> Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
> ---
> v8->v9:
>  * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.

I can't test this myself for lack of hardware, but I see no further
issues with patches 09 - 13 except for the use of
imx_drm_encoder_get_mux_id. I'll either rebase my patches that remove it
or fix it up when applying.

Thierry, may I take these patches through imx-drm, or would you rather I
waited for you to pick up the drm/dsi and drm/bridge patches?

regards
Philipp


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

* Re: [PATCH 1/3] clk: divider: fix calculation of maximal parent rate for a given divider
  2015-02-21 10:40             ` [PATCH 1/3] clk: divider: fix calculation of maximal parent rate for a given divider Uwe Kleine-König
  2015-02-23  7:32               ` Sascha Hauer
@ 2015-03-05  8:35               ` Uwe Kleine-König
  1 sibling, 0 replies; 73+ messages in thread
From: Uwe Kleine-König @ 2015-03-05  8:35 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd
  Cc: linux-arm-kernel, Sören Brinkmann, linux-kernel, kernel

Hello Mike, hello Stephen,

On Sat, Feb 21, 2015 at 11:40:23AM +0100, Uwe Kleine-König wrote:
> The rate provided at the output of a clk-divider is calculated as:
> 
> 	DIV_ROUND_UP(parent_rate, div)
> 
> since commit b11d282dbea2 (clk: divider: fix rate calculation for
> fractional rates). So to yield a rate not bigger than r parent_rate
> must be <= r * div.
> 
> The effect of choosing a parent rate that is too big as was done before
> this patch results in wrongly ruling out good dividers.
> 
> Note that this is not a complete fix as __clk_round_rate might return a
> value >= its 2nd parameter. Also for dividers with
> CLK_DIVIDER_ROUND_CLOSEST set the calculation is not accurate. But this
> fixes the test case by Sascha Hauer that uses a chain of three dividers
> under a fixed clock.
> 
> Fixes: b11d282dbea2 (clk: divider: fix rate calculation for fractional rates)
> Suggested-by: Sascha Hauer <s.hauer@pengutronix.de>
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Gentle ping.

IMHO this is patch should go into 4.0.

Feedback for patches 2 and 3 (or the alternative to rip off specialised
round-closest) would be very welcome, too.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-02-21 10:40           ` [PATCH 0/3] clk: divider: three exactness fixes (and a rant) Uwe Kleine-König
                               ` (3 preceding siblings ...)
  2015-02-23  7:23             ` [PATCH 0/3] clk: divider: three exactness fixes (and a rant) Sascha Hauer
@ 2015-03-06 18:57             ` Mike Turquette
  2015-03-06 19:28               ` Uwe Kleine-König
  2015-03-06 19:44               ` Stephen Boyd
  4 siblings, 2 replies; 73+ messages in thread
From: Mike Turquette @ 2015-03-06 18:57 UTC (permalink / raw)
  To: Uwe Kleine-König, Stephen Boyd
  Cc: kernel, linux-kernel, linux-arm-kernel, Sören Brinkmann

Quoting Uwe Kleine-König (2015-02-21 02:40:22)
> Hello,
> 
> TLDR: only apply patch 1 and rip of CLK_DIVIDER_ROUND_CLOSEST.
> 
> I stared at clk-divider.c for some time now given Sascha's failing test
> case. I found a fix for the failure (which happens to be what Sascha
> suspected).
> 
> The other two patches fix problems only present when handling dividers
> that have CLK_DIVIDER_ROUND_CLOSEST set. Note that these are still
> heavily broken however. So having a 4bit-divider and a parent clk of
> 10000 (as in Sascha's test case) requesting
> 
>         clk_set_rate(clk, 666)
> 
> sets the rate to 625 (div=15) instead of 667 (div=16). The reason is the
> choice of parent_rate in clk_divider_bestdiv's loop is wrong for
> CLK_DIVIDER_ROUND_CLOSEST (with and without patch 1). A fix here is
> non-trivial and for sure more than one rate must be tested here. This is
> complicated by the fact that clk_round_rate might return a value bigger
> than the requested rate which convinces me (once more) that it's a bad
> idea to allow that. Even if this was fixed for .round_rate,
> clk_divider_set_rate is still broken because it also uses
> 
>         div = DIV_ROUND_UP(parent_rate, rate);
> 
> to calculate the (pretended) best divider to get near rate.
> 
> Note this makes at least two reasons to remove support for
> CLK_DIVIDER_ROUND_CLOSEST!
> 
> Instead I'd favour creating a function
> 
>         clk_round_rate_nearest
> 
> as was suggested some time ago by Soren Brinkmann and me[1] that doesn't

Uwe,

Thanks for the fixes. I'm thinking of taking all three for 4.0. I also
agree on clk_round_rate_nearest (along with a _ceil and _floor version
as well). That's something we can do for 4.1 probably.

There are currently 3 users of CLK_DIVIDER_ROUND_CLOSEST:

Loongson
QCOM
ST

So now is probably the right time to remove the flag if we're going to
do it.

What do you think?

Regards,
Mike

> need any clk type specific knowledge. This would mean that not the
> divider (or clk in general) would have to know that returning a slightly
> bigger rate than requested is OK but the caller which is fine (and even
> better) in my eyes. This would simplify clk-divider.c (and probably
> others) and give support for "nearest match" for all clock types without
> type specific implementation. (Note that it might even make sense to use
> a different metric for "nearest", instead of minimizing
> 
>         abs(target - rate)
> 
> you might want to minimize
> 
>         abs(target / rate - 1)
> 
> instead.
> 
> Converting the clk framework to 64 bit rates was discussed earlier
> already, too, and I wonder if we should fix rounding issues (a bit) in
> the same transition such that 
> 
>         clk_set_rate(clk, 333)
> 
> allows the clk to be set to 333.3333333333 Hz and let clk_get_rate
> return 333 in this case.
> 
> Also I'd vote to return 0 or -ESOMETHING if a requested rate is too low
> to be set. This would simplify some special casing I think and makes the
> request
> 
>         clk_round_rate(clk, x) <= x
> 
> consistent.
> 
> Best regards
> Uwe
> 
> [1] https://lkml.org/lkml/2014/5/14/698
> 
> Uwe Kleine-König (3):
>   clk: divider: fix calculation of maximal parent rate for a given
>     divider
>   clk: divider: fix selection of divider when rounding to closest
>   clk: divider: fix calculation of initial best divider when rounding to
>     closest
> 
>  drivers/clk/clk-divider.c | 27 +++++++++++++--------------
>  1 file changed, 13 insertions(+), 14 deletions(-)
> 
> -- 
> 2.1.4
> 

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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-06 18:57             ` Mike Turquette
@ 2015-03-06 19:28               ` Uwe Kleine-König
  2015-03-06 19:40                 ` Stephen Boyd
  2015-03-06 19:44               ` Stephen Boyd
  1 sibling, 1 reply; 73+ messages in thread
From: Uwe Kleine-König @ 2015-03-06 19:28 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Stephen Boyd, linux-arm-kernel, Sören Brinkmann,
	linux-kernel, kernel

Hello Mike,

On Fri, Mar 06, 2015 at 10:57:30AM -0800, Mike Turquette wrote:
> Quoting Uwe Kleine-König (2015-02-21 02:40:22)
> > Hello,
> > 
> > TLDR: only apply patch 1 and rip of CLK_DIVIDER_ROUND_CLOSEST.
> > 
> > I stared at clk-divider.c for some time now given Sascha's failing test
> > case. I found a fix for the failure (which happens to be what Sascha
> > suspected).
> > 
> > The other two patches fix problems only present when handling dividers
> > that have CLK_DIVIDER_ROUND_CLOSEST set. Note that these are still
> > heavily broken however. So having a 4bit-divider and a parent clk of
> > 10000 (as in Sascha's test case) requesting
> > 
> >         clk_set_rate(clk, 666)
> > 
> > sets the rate to 625 (div=15) instead of 667 (div=16). The reason is the
> > choice of parent_rate in clk_divider_bestdiv's loop is wrong for
> > CLK_DIVIDER_ROUND_CLOSEST (with and without patch 1). A fix here is
> > non-trivial and for sure more than one rate must be tested here. This is
> > complicated by the fact that clk_round_rate might return a value bigger
> > than the requested rate which convinces me (once more) that it's a bad
> > idea to allow that. Even if this was fixed for .round_rate,
> > clk_divider_set_rate is still broken because it also uses
> > 
> >         div = DIV_ROUND_UP(parent_rate, rate);
> > 
> > to calculate the (pretended) best divider to get near rate.
> > 
> > Note this makes at least two reasons to remove support for
> > CLK_DIVIDER_ROUND_CLOSEST!
> > 
> > Instead I'd favour creating a function
> > 
> >         clk_round_rate_nearest
> > 
> > as was suggested some time ago by Soren Brinkmann and me[1] that doesn't
> 
> Uwe,
> 
> Thanks for the fixes. I'm thinking of taking all three for 4.0. I also
> agree on clk_round_rate_nearest (along with a _ceil and _floor version
> as well). That's something we can do for 4.1 probably.
I'd say that we make round_rate the _floor version. I guess in most
cases that already does the right thing. Also I think 4.1 is very
ambitious, so my suggestion for 4.1 is:

 - add a WARN_ON_ONCE to clk_round_rate catching calls that return a
   value bigger than requested.
 - implement clk_round_rate_nearest using clk_round_rate and the
   assumption that it returns a value that is <= the requested rate.
   I think without that there are too many special cases to handle and
   probably not even a reliable way to determine the nearest rate.
 - while we're at it tightening the requirements for clk_round_rate
   let's also specify the expected rounding. I'd vote for the
   mathematical rounding, that is

   	clk_round_rate(someclk, 333)

   explicitly is allowed to return a rate bigger than 333 as long as it
   is less than 333.5.

At one point while developing patch 1 I had the dividers fixed for the
rounding issue. I think I still have that patch somewhere so can post it
as RFC.

> There are currently 3 users of CLK_DIVIDER_ROUND_CLOSEST:
> 
> Loongson
> QCOM
> ST
> 
> So now is probably the right time to remove the flag if we're going to
> do it.
"now" is before we have clk_round_rate_nearest, right?
So what do you want to do with these three users? Move them to the
default implementation?

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-06 19:28               ` Uwe Kleine-König
@ 2015-03-06 19:40                 ` Stephen Boyd
  2015-03-09  9:58                   ` Philipp Zabel
  0 siblings, 1 reply; 73+ messages in thread
From: Stephen Boyd @ 2015-03-06 19:40 UTC (permalink / raw)
  To: Uwe Kleine-König, Mike Turquette
  Cc: linux-arm-kernel, Sören Brinkmann, linux-kernel, kernel

On 03/06/15 11:28, Uwe Kleine-König wrote:
> Hello Mike,
>
> On Fri, Mar 06, 2015 at 10:57:30AM -0800, Mike Turquette wrote:
>> Quoting Uwe Kleine-König (2015-02-21 02:40:22)
>>> Hello,
>>>
>>> TLDR: only apply patch 1 and rip of CLK_DIVIDER_ROUND_CLOSEST.
>>>
>>> I stared at clk-divider.c for some time now given Sascha's failing test
>>> case. I found a fix for the failure (which happens to be what Sascha
>>> suspected).
>>>
>>> The other two patches fix problems only present when handling dividers
>>> that have CLK_DIVIDER_ROUND_CLOSEST set. Note that these are still
>>> heavily broken however. So having a 4bit-divider and a parent clk of
>>> 10000 (as in Sascha's test case) requesting
>>>
>>>         clk_set_rate(clk, 666)
>>>
>>> sets the rate to 625 (div=15) instead of 667 (div=16). The reason is the
>>> choice of parent_rate in clk_divider_bestdiv's loop is wrong for
>>> CLK_DIVIDER_ROUND_CLOSEST (with and without patch 1). A fix here is
>>> non-trivial and for sure more than one rate must be tested here. This is
>>> complicated by the fact that clk_round_rate might return a value bigger
>>> than the requested rate which convinces me (once more) that it's a bad
>>> idea to allow that. Even if this was fixed for .round_rate,
>>> clk_divider_set_rate is still broken because it also uses
>>>
>>>         div = DIV_ROUND_UP(parent_rate, rate);
>>>
>>> to calculate the (pretended) best divider to get near rate.
>>>
>>> Note this makes at least two reasons to remove support for
>>> CLK_DIVIDER_ROUND_CLOSEST!
>>>
>>> Instead I'd favour creating a function
>>>
>>>         clk_round_rate_nearest
>>>
>>> as was suggested some time ago by Soren Brinkmann and me[1] that doesn't
>> Uwe,
>>
>> Thanks for the fixes. I'm thinking of taking all three for 4.0. I also
>> agree on clk_round_rate_nearest (along with a _ceil and _floor version
>> as well). That's something we can do for 4.1 probably.
> I'd say that we make round_rate the _floor version. I guess in most
> cases that already does the right thing. Also I think 4.1 is very
> ambitious, so my suggestion for 4.1 is:
>
>  - add a WARN_ON_ONCE to clk_round_rate catching calls that return a
>    value bigger than requested.
>  - implement clk_round_rate_nearest using clk_round_rate and the
>    assumption that it returns a value that is <= the requested rate.
>    I think without that there are too many special cases to handle and
>    probably not even a reliable way to determine the nearest rate.
>  - while we're at it tightening the requirements for clk_round_rate
>    let's also specify the expected rounding. I'd vote for the
>    mathematical rounding, that is
>
>    	clk_round_rate(someclk, 333)
>
>    explicitly is allowed to return a rate bigger than 333 as long as it
>    is less than 333.5.
>
> At one point while developing patch 1 I had the dividers fixed for the
> rounding issue. I think I still have that patch somewhere so can post it
> as RFC.
>

Why do we need clk_round_rate_nearest? We have rate constraints now so
drivers should be moving towards requesting a rate that's within a
tolerance they can accept if they even care to enforce anything like
that. Eventually clk_round_rate() returning a value smaller or larger
than what it's called with won't matter as long as what the
implementation does fits within the constraints that consumers specify.
It may even be possible to remove clk_round_rate() as a consumer API.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-06 18:57             ` Mike Turquette
  2015-03-06 19:28               ` Uwe Kleine-König
@ 2015-03-06 19:44               ` Stephen Boyd
  2015-03-06 21:09                 ` Uwe Kleine-König
  1 sibling, 1 reply; 73+ messages in thread
From: Stephen Boyd @ 2015-03-06 19:44 UTC (permalink / raw)
  To: Mike Turquette, Uwe Kleine-König
  Cc: kernel, linux-kernel, linux-arm-kernel, Sören Brinkmann

On 03/06/15 10:57, Mike Turquette wrote:
>
> Uwe,
>
> Thanks for the fixes. I'm thinking of taking all three for 4.0. I also
> agree on clk_round_rate_nearest (along with a _ceil and _floor version
> as well). That's something we can do for 4.1 probably.
>
> There are currently 3 users of CLK_DIVIDER_ROUND_CLOSEST:
>
> Loongson
> QCOM
> ST
>
> So now is probably the right time to remove the flag if we're going to
> do it.
>
> What do you think?
>

I may have had to do divider round closest on qcom platforms because of
the problem these patches are for. I'll have to go back and look.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-06 19:44               ` Stephen Boyd
@ 2015-03-06 21:09                 ` Uwe Kleine-König
  0 siblings, 0 replies; 73+ messages in thread
From: Uwe Kleine-König @ 2015-03-06 21:09 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Mike Turquette, linux-arm-kernel, Sören Brinkmann,
	linux-kernel, kernel

On Fri, Mar 06, 2015 at 11:44:05AM -0800, Stephen Boyd wrote:
> On 03/06/15 10:57, Mike Turquette wrote:
> >
> > Uwe,
> >
> > Thanks for the fixes. I'm thinking of taking all three for 4.0. I also
> > agree on clk_round_rate_nearest (along with a _ceil and _floor version
> > as well). That's something we can do for 4.1 probably.
> >
> > There are currently 3 users of CLK_DIVIDER_ROUND_CLOSEST:
> >
> > Loongson
> > QCOM
> > ST
> >
> > So now is probably the right time to remove the flag if we're going to
> > do it.
> >
> > What do you think?
> >
> 
> I may have had to do divider round closest on qcom platforms because of
> the problem these patches are for. I'll have to go back and look.
When you do that, also check if it works for you. I think the
implementation is broken for most of the cases.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-06 19:40                 ` Stephen Boyd
@ 2015-03-09  9:58                   ` Philipp Zabel
  2015-03-09 19:05                     ` Stephen Boyd
  0 siblings, 1 reply; 73+ messages in thread
From: Philipp Zabel @ 2015-03-09  9:58 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Uwe Kleine-König, Mike Turquette, kernel,
	Sören Brinkmann, linux-arm-kernel, linux-kernel

Am Freitag, den 06.03.2015, 11:40 -0800 schrieb Stephen Boyd:
> On 03/06/15 11:28, Uwe Kleine-König wrote:
> > Hello Mike,
> >
> > On Fri, Mar 06, 2015 at 10:57:30AM -0800, Mike Turquette wrote:
> >> Quoting Uwe Kleine-König (2015-02-21 02:40:22)
> >>> Hello,
> >>>
> >>> TLDR: only apply patch 1 and rip of CLK_DIVIDER_ROUND_CLOSEST.
> >>>
> >>> I stared at clk-divider.c for some time now given Sascha's failing test
> >>> case. I found a fix for the failure (which happens to be what Sascha
> >>> suspected).
> >>>
> >>> The other two patches fix problems only present when handling dividers
> >>> that have CLK_DIVIDER_ROUND_CLOSEST set. Note that these are still
> >>> heavily broken however. So having a 4bit-divider and a parent clk of
> >>> 10000 (as in Sascha's test case) requesting
> >>>
> >>>         clk_set_rate(clk, 666)
> >>>
> >>> sets the rate to 625 (div=15) instead of 667 (div=16). The reason is the
> >>> choice of parent_rate in clk_divider_bestdiv's loop is wrong for
> >>> CLK_DIVIDER_ROUND_CLOSEST (with and without patch 1). A fix here is
> >>> non-trivial and for sure more than one rate must be tested here. This is
> >>> complicated by the fact that clk_round_rate might return a value bigger
> >>> than the requested rate which convinces me (once more) that it's a bad
> >>> idea to allow that. Even if this was fixed for .round_rate,
> >>> clk_divider_set_rate is still broken because it also uses
> >>>
> >>>         div = DIV_ROUND_UP(parent_rate, rate);
> >>>
> >>> to calculate the (pretended) best divider to get near rate.
> >>>
> >>> Note this makes at least two reasons to remove support for
> >>> CLK_DIVIDER_ROUND_CLOSEST!
> >>>
> >>> Instead I'd favour creating a function
> >>>
> >>>         clk_round_rate_nearest
> >>>
> >>> as was suggested some time ago by Soren Brinkmann and me[1] that doesn't
> >> Uwe,
> >>
> >> Thanks for the fixes. I'm thinking of taking all three for 4.0. I also
> >> agree on clk_round_rate_nearest (along with a _ceil and _floor version
> >> as well). That's something we can do for 4.1 probably.
> > I'd say that we make round_rate the _floor version. I guess in most
> > cases that already does the right thing. Also I think 4.1 is very
> > ambitious, so my suggestion for 4.1 is:
> >
> >  - add a WARN_ON_ONCE to clk_round_rate catching calls that return a
> >    value bigger than requested.
> >  - implement clk_round_rate_nearest using clk_round_rate and the
> >    assumption that it returns a value that is <= the requested rate.
> >    I think without that there are too many special cases to handle and
> >    probably not even a reliable way to determine the nearest rate.
> >  - while we're at it tightening the requirements for clk_round_rate
> >    let's also specify the expected rounding. I'd vote for the
> >    mathematical rounding, that is
> >
> >    	clk_round_rate(someclk, 333)
> >
> >    explicitly is allowed to return a rate bigger than 333 as long as it
> >    is less than 333.5.
> >
> > At one point while developing patch 1 I had the dividers fixed for the
> > rounding issue. I think I still have that patch somewhere so can post it
> > as RFC.
> >
> 
> Why do we need clk_round_rate_nearest? We have rate constraints now so
> drivers should be moving towards requesting a rate that's within a
> tolerance they can accept if they even care to enforce anything like
> that. Eventually clk_round_rate() returning a value smaller or larger
> than what it's called with won't matter as long as what the
> implementation does fits within the constraints that consumers specify.
> It may even be possible to remove clk_round_rate() as a consumer API.

If I have to provide a panel pixel clock I usually want to get a rate as
close as possible to the specified typical rate, but within the
specified limits.

Assume a panel with 70 MHz ideal pixel clock and a valid range of 60 MHz
to 80 MHz. If the clock supply supports two frequencies within that
range, 60 MHz and 72 MHz, I'd prefer 72 MHz to be chosen over 60 Mhz.

regards
Philipp


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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-09  9:58                   ` Philipp Zabel
@ 2015-03-09 19:05                     ` Stephen Boyd
  2015-03-09 20:23                       ` Uwe Kleine-König
  2015-03-09 21:07                       ` Mike Turquette
  0 siblings, 2 replies; 73+ messages in thread
From: Stephen Boyd @ 2015-03-09 19:05 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Uwe Kleine-König, Mike Turquette, kernel,
	Sören Brinkmann, linux-arm-kernel, linux-kernel

On 03/09/15 02:58, Philipp Zabel wrote:
> Am Freitag, den 06.03.2015, 11:40 -0800 schrieb Stephen Boyd:
>> On 03/06/15 11:28, Uwe Kleine-König wrote:
>>> Hello Mike,
>>>
>>> On Fri, Mar 06, 2015 at 10:57:30AM -0800, Mike Turquette wrote:
>>>> Quoting Uwe Kleine-König (2015-02-21 02:40:22)
>>>>> Hello,
>>>>>
>>>>> TLDR: only apply patch 1 and rip of CLK_DIVIDER_ROUND_CLOSEST.
>>>>>
>>>>> I stared at clk-divider.c for some time now given Sascha's failing test
>>>>> case. I found a fix for the failure (which happens to be what Sascha
>>>>> suspected).
>>>>>
>>>>> The other two patches fix problems only present when handling dividers
>>>>> that have CLK_DIVIDER_ROUND_CLOSEST set. Note that these are still
>>>>> heavily broken however. So having a 4bit-divider and a parent clk of
>>>>> 10000 (as in Sascha's test case) requesting
>>>>>
>>>>>         clk_set_rate(clk, 666)
>>>>>
>>>>> sets the rate to 625 (div=15) instead of 667 (div=16). The reason is the
>>>>> choice of parent_rate in clk_divider_bestdiv's loop is wrong for
>>>>> CLK_DIVIDER_ROUND_CLOSEST (with and without patch 1). A fix here is
>>>>> non-trivial and for sure more than one rate must be tested here. This is
>>>>> complicated by the fact that clk_round_rate might return a value bigger
>>>>> than the requested rate which convinces me (once more) that it's a bad
>>>>> idea to allow that. Even if this was fixed for .round_rate,
>>>>> clk_divider_set_rate is still broken because it also uses
>>>>>
>>>>>         div = DIV_ROUND_UP(parent_rate, rate);
>>>>>
>>>>> to calculate the (pretended) best divider to get near rate.
>>>>>
>>>>> Note this makes at least two reasons to remove support for
>>>>> CLK_DIVIDER_ROUND_CLOSEST!
>>>>>
>>>>> Instead I'd favour creating a function
>>>>>
>>>>>         clk_round_rate_nearest
>>>>>
>>>>> as was suggested some time ago by Soren Brinkmann and me[1] that doesn't
>>>> Uwe,
>>>>
>>>> Thanks for the fixes. I'm thinking of taking all three for 4.0. I also
>>>> agree on clk_round_rate_nearest (along with a _ceil and _floor version
>>>> as well). That's something we can do for 4.1 probably.
>>> I'd say that we make round_rate the _floor version. I guess in most
>>> cases that already does the right thing. Also I think 4.1 is very
>>> ambitious, so my suggestion for 4.1 is:
>>>
>>>  - add a WARN_ON_ONCE to clk_round_rate catching calls that return a
>>>    value bigger than requested.
>>>  - implement clk_round_rate_nearest using clk_round_rate and the
>>>    assumption that it returns a value that is <= the requested rate.
>>>    I think without that there are too many special cases to handle and
>>>    probably not even a reliable way to determine the nearest rate.
>>>  - while we're at it tightening the requirements for clk_round_rate
>>>    let's also specify the expected rounding. I'd vote for the
>>>    mathematical rounding, that is
>>>
>>>    	clk_round_rate(someclk, 333)
>>>
>>>    explicitly is allowed to return a rate bigger than 333 as long as it
>>>    is less than 333.5.
>>>
>>> At one point while developing patch 1 I had the dividers fixed for the
>>> rounding issue. I think I still have that patch somewhere so can post it
>>> as RFC.
>>>
>> Why do we need clk_round_rate_nearest? We have rate constraints now so
>> drivers should be moving towards requesting a rate that's within a
>> tolerance they can accept if they even care to enforce anything like
>> that. Eventually clk_round_rate() returning a value smaller or larger
>> than what it's called with won't matter as long as what the
>> implementation does fits within the constraints that consumers specify.
>> It may even be possible to remove clk_round_rate() as a consumer API.
> If I have to provide a panel pixel clock I usually want to get a rate as
> close as possible to the specified typical rate, but within the
> specified limits.
>
> Assume a panel with 70 MHz ideal pixel clock and a valid range of 60 MHz
> to 80 MHz. If the clock supply supports two frequencies within that
> range, 60 MHz and 72 MHz, I'd prefer 72 MHz to be chosen over 60 Mhz.
>
>

Hm.. Maybe we should tweak the arguments to clk_set_range() to have a
"typical" rate? So instead of the current API:

  int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned
long max)

we should have

 int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned
long typical, unsigned long max)

with the semantics that we'll set the rate within the min,max
constraints and try to get the rate as close to the typical rate as
possible? That would match quite a few datasheets out there that specify
these triplets.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-09 19:05                     ` Stephen Boyd
@ 2015-03-09 20:23                       ` Uwe Kleine-König
  2015-03-09 21:07                       ` Mike Turquette
  1 sibling, 0 replies; 73+ messages in thread
From: Uwe Kleine-König @ 2015-03-09 20:23 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Philipp Zabel, Mike Turquette, kernel, Sören Brinkmann,
	linux-arm-kernel, linux-kernel

Hello Stephen,

On Mon, Mar 09, 2015 at 12:05:34PM -0700, Stephen Boyd wrote:
> On 03/09/15 02:58, Philipp Zabel wrote:
> > Am Freitag, den 06.03.2015, 11:40 -0800 schrieb Stephen Boyd:
> >> On 03/06/15 11:28, Uwe Kleine-König wrote:
> >>> Hello Mike,
> >>>
> >>> On Fri, Mar 06, 2015 at 10:57:30AM -0800, Mike Turquette wrote:
> >>>> Quoting Uwe Kleine-König (2015-02-21 02:40:22)
> >>>>> Hello,
> >>>>>
> >>>>> TLDR: only apply patch 1 and rip of CLK_DIVIDER_ROUND_CLOSEST.
> >>>>>
> >>>>> I stared at clk-divider.c for some time now given Sascha's failing test
> >>>>> case. I found a fix for the failure (which happens to be what Sascha
> >>>>> suspected).
> >>>>>
> >>>>> The other two patches fix problems only present when handling dividers
> >>>>> that have CLK_DIVIDER_ROUND_CLOSEST set. Note that these are still
> >>>>> heavily broken however. So having a 4bit-divider and a parent clk of
> >>>>> 10000 (as in Sascha's test case) requesting
> >>>>>
> >>>>>         clk_set_rate(clk, 666)
> >>>>>
> >>>>> sets the rate to 625 (div=15) instead of 667 (div=16). The reason is the
> >>>>> choice of parent_rate in clk_divider_bestdiv's loop is wrong for
> >>>>> CLK_DIVIDER_ROUND_CLOSEST (with and without patch 1). A fix here is
> >>>>> non-trivial and for sure more than one rate must be tested here. This is
> >>>>> complicated by the fact that clk_round_rate might return a value bigger
> >>>>> than the requested rate which convinces me (once more) that it's a bad
> >>>>> idea to allow that. Even if this was fixed for .round_rate,
> >>>>> clk_divider_set_rate is still broken because it also uses
> >>>>>
> >>>>>         div = DIV_ROUND_UP(parent_rate, rate);
> >>>>>
> >>>>> to calculate the (pretended) best divider to get near rate.
> >>>>>
> >>>>> Note this makes at least two reasons to remove support for
> >>>>> CLK_DIVIDER_ROUND_CLOSEST!
> >>>>>
> >>>>> Instead I'd favour creating a function
> >>>>>
> >>>>>         clk_round_rate_nearest
> >>>>>
> >>>>> as was suggested some time ago by Soren Brinkmann and me[1] that doesn't
> >>>> Uwe,
> >>>>
> >>>> Thanks for the fixes. I'm thinking of taking all three for 4.0. I also
> >>>> agree on clk_round_rate_nearest (along with a _ceil and _floor version
> >>>> as well). That's something we can do for 4.1 probably.
> >>> I'd say that we make round_rate the _floor version. I guess in most
> >>> cases that already does the right thing. Also I think 4.1 is very
> >>> ambitious, so my suggestion for 4.1 is:
> >>>
> >>>  - add a WARN_ON_ONCE to clk_round_rate catching calls that return a
> >>>    value bigger than requested.
> >>>  - implement clk_round_rate_nearest using clk_round_rate and the
> >>>    assumption that it returns a value that is <= the requested rate.
> >>>    I think without that there are too many special cases to handle and
> >>>    probably not even a reliable way to determine the nearest rate.
> >>>  - while we're at it tightening the requirements for clk_round_rate
> >>>    let's also specify the expected rounding. I'd vote for the
> >>>    mathematical rounding, that is
> >>>
> >>>    	clk_round_rate(someclk, 333)
> >>>
> >>>    explicitly is allowed to return a rate bigger than 333 as long as it
> >>>    is less than 333.5.
> >>>
> >>> At one point while developing patch 1 I had the dividers fixed for the
> >>> rounding issue. I think I still have that patch somewhere so can post it
> >>> as RFC.
> >>>
> >> Why do we need clk_round_rate_nearest? We have rate constraints now so
> >> drivers should be moving towards requesting a rate that's within a
> >> tolerance they can accept if they even care to enforce anything like
> >> that. Eventually clk_round_rate() returning a value smaller or larger
> >> than what it's called with won't matter as long as what the
> >> implementation does fits within the constraints that consumers specify.
> >> It may even be possible to remove clk_round_rate() as a consumer API.
> > If I have to provide a panel pixel clock I usually want to get a rate as
> > close as possible to the specified typical rate, but within the
> > specified limits.
> >
> > Assume a panel with 70 MHz ideal pixel clock and a valid range of 60 MHz
> > to 80 MHz. If the clock supply supports two frequencies within that
> > range, 60 MHz and 72 MHz, I'd prefer 72 MHz to be chosen over 60 Mhz.
> >
> >
> 
> Hm.. Maybe we should tweak the arguments to clk_set_range() to have a
> "typical" rate? So instead of the current API:
> 
>   int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned
> long max)

Looking at the current implementation of clk_set_rate_range I wonder how
it should be used. The "usual" code flow goes through

	ret = clk_core_set_rate_nolock(clk->core, clk->core->req_rate);

without modifying clk->core->req_rate first. So after

	clk_set_rate(clk, 50);

a call to

	clk_set_rate_range(clk, 100, 200);

returns -EINVAL (at least if determine_rate isn't implemented). Is
this intended? This even happens if the clk could provide a rate between
100 and 200. Also if I first call set_rate_range and then set_rate, the
clk's members for min and max are unaffected by the latter call, right?

> we should have
> 
>  int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned
> long typical, unsigned long max)
> 
> with the semantics that we'll set the rate within the min,max
> constraints and try to get the rate as close to the typical rate as
> possible? That would match quite a few datasheets out there that specify
> these triplets.
And according to which metric do you determine "close"? Consider a clock
that can provide 900 Hz and 1110 Hz (but nothing in between). Which one
do you consider closer if 1000 Hz are requested?
On the first look 900 Hz looks better because

	abs(1000 - 900) < abs(1000 - 1110)

but if you look at the respective cycle times we get:

	1 / 900 Hz = 1.111 ms
	1 / 1110 Hz = 0.901 ms

so 1110 Hz is better according to the metric

	abs(1 / 1000 - 1 / 1110) < abs(1 / 1000 - 1 / 900)

. Maybe even other metrics might be sensible for certain scenarios[1]?
That convinces me that it's better to be able to query a clock for
possible rates (.round_rate) and get the logic to determine "close" into
a single helper (well, one per metric) in the clk core. This is much
better because then you have a single complex function instead of one
per clk implementation.

And then to keep the complexity at a sane level it would be great if you
could assume e.g. that .round_rate always rounds down.

Best regards
Uwe

[1] I first thought about minimizing abs(1 - rate / optrate), but that
    is equivalent to minimizing abs(optrate - rate).

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-09 19:05                     ` Stephen Boyd
  2015-03-09 20:23                       ` Uwe Kleine-König
@ 2015-03-09 21:07                       ` Mike Turquette
  2015-03-09 21:58                         ` Uwe Kleine-König
  1 sibling, 1 reply; 73+ messages in thread
From: Mike Turquette @ 2015-03-09 21:07 UTC (permalink / raw)
  To: Stephen Boyd, Philipp Zabel
  Cc: Uwe Kleine-König, kernel, Sören Brinkmann,
	linux-arm-kernel, linux-kernel

Quoting Stephen Boyd (2015-03-09 12:05:34)
> On 03/09/15 02:58, Philipp Zabel wrote:
> > Am Freitag, den 06.03.2015, 11:40 -0800 schrieb Stephen Boyd:
> >> On 03/06/15 11:28, Uwe Kleine-König wrote:
> >>> Hello Mike,
> >>>
> >>> On Fri, Mar 06, 2015 at 10:57:30AM -0800, Mike Turquette wrote:
> >>>> Quoting Uwe Kleine-König (2015-02-21 02:40:22)
> >>>>> Hello,
> >>>>>
> >>>>> TLDR: only apply patch 1 and rip of CLK_DIVIDER_ROUND_CLOSEST.
> >>>>>
> >>>>> I stared at clk-divider.c for some time now given Sascha's failing test
> >>>>> case. I found a fix for the failure (which happens to be what Sascha
> >>>>> suspected).
> >>>>>
> >>>>> The other two patches fix problems only present when handling dividers
> >>>>> that have CLK_DIVIDER_ROUND_CLOSEST set. Note that these are still
> >>>>> heavily broken however. So having a 4bit-divider and a parent clk of
> >>>>> 10000 (as in Sascha's test case) requesting
> >>>>>
> >>>>>         clk_set_rate(clk, 666)
> >>>>>
> >>>>> sets the rate to 625 (div=15) instead of 667 (div=16). The reason is the
> >>>>> choice of parent_rate in clk_divider_bestdiv's loop is wrong for
> >>>>> CLK_DIVIDER_ROUND_CLOSEST (with and without patch 1). A fix here is
> >>>>> non-trivial and for sure more than one rate must be tested here. This is
> >>>>> complicated by the fact that clk_round_rate might return a value bigger
> >>>>> than the requested rate which convinces me (once more) that it's a bad
> >>>>> idea to allow that. Even if this was fixed for .round_rate,
> >>>>> clk_divider_set_rate is still broken because it also uses
> >>>>>
> >>>>>         div = DIV_ROUND_UP(parent_rate, rate);
> >>>>>
> >>>>> to calculate the (pretended) best divider to get near rate.
> >>>>>
> >>>>> Note this makes at least two reasons to remove support for
> >>>>> CLK_DIVIDER_ROUND_CLOSEST!
> >>>>>
> >>>>> Instead I'd favour creating a function
> >>>>>
> >>>>>         clk_round_rate_nearest
> >>>>>
> >>>>> as was suggested some time ago by Soren Brinkmann and me[1] that doesn't
> >>>> Uwe,
> >>>>
> >>>> Thanks for the fixes. I'm thinking of taking all three for 4.0. I also
> >>>> agree on clk_round_rate_nearest (along with a _ceil and _floor version
> >>>> as well). That's something we can do for 4.1 probably.
> >>> I'd say that we make round_rate the _floor version. I guess in most
> >>> cases that already does the right thing. Also I think 4.1 is very
> >>> ambitious, so my suggestion for 4.1 is:
> >>>
> >>>  - add a WARN_ON_ONCE to clk_round_rate catching calls that return a
> >>>    value bigger than requested.
> >>>  - implement clk_round_rate_nearest using clk_round_rate and the
> >>>    assumption that it returns a value that is <= the requested rate.
> >>>    I think without that there are too many special cases to handle and
> >>>    probably not even a reliable way to determine the nearest rate.
> >>>  - while we're at it tightening the requirements for clk_round_rate
> >>>    let's also specify the expected rounding. I'd vote for the
> >>>    mathematical rounding, that is
> >>>
> >>>     clk_round_rate(someclk, 333)
> >>>
> >>>    explicitly is allowed to return a rate bigger than 333 as long as it
> >>>    is less than 333.5.
> >>>
> >>> At one point while developing patch 1 I had the dividers fixed for the
> >>> rounding issue. I think I still have that patch somewhere so can post it
> >>> as RFC.
> >>>
> >> Why do we need clk_round_rate_nearest? We have rate constraints now so
> >> drivers should be moving towards requesting a rate that's within a
> >> tolerance they can accept if they even care to enforce anything like
> >> that. Eventually clk_round_rate() returning a value smaller or larger
> >> than what it's called with won't matter as long as what the
> >> implementation does fits within the constraints that consumers specify.
> >> It may even be possible to remove clk_round_rate() as a consumer API.
> > If I have to provide a panel pixel clock I usually want to get a rate as
> > close as possible to the specified typical rate, but within the
> > specified limits.
> >
> > Assume a panel with 70 MHz ideal pixel clock and a valid range of 60 MHz
> > to 80 MHz. If the clock supply supports two frequencies within that
> > range, 60 MHz and 72 MHz, I'd prefer 72 MHz to be chosen over 60 Mhz.
> >
> >
> 
> Hm.. Maybe we should tweak the arguments to clk_set_range() to have a
> "typical" rate? So instead of the current API:
> 
>   int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned
> long max)
> 
> we should have
> 
>  int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned
> long typical, unsigned long max)
> 
> with the semantics that we'll set the rate within the min,max
> constraints and try to get the rate as close to the typical rate as
> possible? That would match quite a few datasheets out there that specify
> these triplets.

This suffers from the same problem that round_rate has today, which is
the question of rounding policy. When you say that we want to get as
close as possible, how do we decide between equivalent values? We need
to make a default policy, document it and stick to it. E.g:

clk_set_rate_range(clk, 100, 110, 120);

Let's say that round_rate gives us possible values of 108 and 112, both
of which are two Hz away from the typical value of 110Hz. One is not
closer than the other. Which do we choose? Let's figure out a sane
default to the question and document it very loudly in the code.

For the sake of consistency I think we should choose the slower value
since this is what a normal clk_round_rate should do stay within spec.
Obviously either rate (108 or 112) would be in spec, since they are
within the min/max range. But if a normal call to clk_round_rate should
choose a ceiling value by default (which I think it should) then
probably the range stuff should as well, just to keep us from confusing
ourselves.

Regards,
Mike

> 
> -- 
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 

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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-09 21:07                       ` Mike Turquette
@ 2015-03-09 21:58                         ` Uwe Kleine-König
  2015-03-09 22:40                           ` Stephen Boyd
  0 siblings, 1 reply; 73+ messages in thread
From: Uwe Kleine-König @ 2015-03-09 21:58 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Stephen Boyd, Philipp Zabel, linux-arm-kernel, linux-kernel,
	Sören Brinkmann, kernel

On Mon, Mar 09, 2015 at 02:07:35PM -0700, Mike Turquette wrote:
> Quoting Stephen Boyd (2015-03-09 12:05:34)
> > On 03/09/15 02:58, Philipp Zabel wrote:
> > > Am Freitag, den 06.03.2015, 11:40 -0800 schrieb Stephen Boyd:
> > >> On 03/06/15 11:28, Uwe Kleine-König wrote:
> > >>> Hello Mike,
> > >>>
> > >>> On Fri, Mar 06, 2015 at 10:57:30AM -0800, Mike Turquette wrote:
> > >>>> Quoting Uwe Kleine-König (2015-02-21 02:40:22)
> > >>>>> Hello,
> > >>>>>
> > >>>>> TLDR: only apply patch 1 and rip of CLK_DIVIDER_ROUND_CLOSEST.
> > >>>>>
> > >>>>> I stared at clk-divider.c for some time now given Sascha's failing test
> > >>>>> case. I found a fix for the failure (which happens to be what Sascha
> > >>>>> suspected).
> > >>>>>
> > >>>>> The other two patches fix problems only present when handling dividers
> > >>>>> that have CLK_DIVIDER_ROUND_CLOSEST set. Note that these are still
> > >>>>> heavily broken however. So having a 4bit-divider and a parent clk of
> > >>>>> 10000 (as in Sascha's test case) requesting
> > >>>>>
> > >>>>>         clk_set_rate(clk, 666)
> > >>>>>
> > >>>>> sets the rate to 625 (div=15) instead of 667 (div=16). The reason is the
> > >>>>> choice of parent_rate in clk_divider_bestdiv's loop is wrong for
> > >>>>> CLK_DIVIDER_ROUND_CLOSEST (with and without patch 1). A fix here is
> > >>>>> non-trivial and for sure more than one rate must be tested here. This is
> > >>>>> complicated by the fact that clk_round_rate might return a value bigger
> > >>>>> than the requested rate which convinces me (once more) that it's a bad
> > >>>>> idea to allow that. Even if this was fixed for .round_rate,
> > >>>>> clk_divider_set_rate is still broken because it also uses
> > >>>>>
> > >>>>>         div = DIV_ROUND_UP(parent_rate, rate);
> > >>>>>
> > >>>>> to calculate the (pretended) best divider to get near rate.
> > >>>>>
> > >>>>> Note this makes at least two reasons to remove support for
> > >>>>> CLK_DIVIDER_ROUND_CLOSEST!
> > >>>>>
> > >>>>> Instead I'd favour creating a function
> > >>>>>
> > >>>>>         clk_round_rate_nearest
> > >>>>>
> > >>>>> as was suggested some time ago by Soren Brinkmann and me[1] that doesn't
> > >>>> Uwe,
> > >>>>
> > >>>> Thanks for the fixes. I'm thinking of taking all three for 4.0. I also
> > >>>> agree on clk_round_rate_nearest (along with a _ceil and _floor version
> > >>>> as well). That's something we can do for 4.1 probably.
> > >>> I'd say that we make round_rate the _floor version. I guess in most
> > >>> cases that already does the right thing. Also I think 4.1 is very
> > >>> ambitious, so my suggestion for 4.1 is:
> > >>>
> > >>>  - add a WARN_ON_ONCE to clk_round_rate catching calls that return a
> > >>>    value bigger than requested.
> > >>>  - implement clk_round_rate_nearest using clk_round_rate and the
> > >>>    assumption that it returns a value that is <= the requested rate.
> > >>>    I think without that there are too many special cases to handle and
> > >>>    probably not even a reliable way to determine the nearest rate.
> > >>>  - while we're at it tightening the requirements for clk_round_rate
> > >>>    let's also specify the expected rounding. I'd vote for the
> > >>>    mathematical rounding, that is
> > >>>
> > >>>     clk_round_rate(someclk, 333)
> > >>>
> > >>>    explicitly is allowed to return a rate bigger than 333 as long as it
> > >>>    is less than 333.5.
> > >>>
> > >>> At one point while developing patch 1 I had the dividers fixed for the
> > >>> rounding issue. I think I still have that patch somewhere so can post it
> > >>> as RFC.
> > >>>
> > >> Why do we need clk_round_rate_nearest? We have rate constraints now so
> > >> drivers should be moving towards requesting a rate that's within a
> > >> tolerance they can accept if they even care to enforce anything like
> > >> that. Eventually clk_round_rate() returning a value smaller or larger
> > >> than what it's called with won't matter as long as what the
> > >> implementation does fits within the constraints that consumers specify.
> > >> It may even be possible to remove clk_round_rate() as a consumer API.
> > > If I have to provide a panel pixel clock I usually want to get a rate as
> > > close as possible to the specified typical rate, but within the
> > > specified limits.
> > >
> > > Assume a panel with 70 MHz ideal pixel clock and a valid range of 60 MHz
> > > to 80 MHz. If the clock supply supports two frequencies within that
> > > range, 60 MHz and 72 MHz, I'd prefer 72 MHz to be chosen over 60 Mhz.
> > >
> > >
> > 
> > Hm.. Maybe we should tweak the arguments to clk_set_range() to have a
> > "typical" rate? So instead of the current API:
> > 
> >   int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned
> > long max)
> > 
> > we should have
> > 
> >  int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned
> > long typical, unsigned long max)
> > 
> > with the semantics that we'll set the rate within the min,max
> > constraints and try to get the rate as close to the typical rate as
> > possible? That would match quite a few datasheets out there that specify
> > these triplets.
> 
> This suffers from the same problem that round_rate has today, which is
> the question of rounding policy. When you say that we want to get as
> close as possible, how do we decide between equivalent values? We need
> to make a default policy, document it and stick to it. E.g:
> 
> clk_set_rate_range(clk, 100, 110, 120);
> 
> Let's say that round_rate gives us possible values of 108 and 112, both
> of which are two Hz away from the typical value of 110Hz. One is not
> closer than the other. Which do we choose? Let's figure out a sane
> default to the question and document it very loudly in the code.
> 
> For the sake of consistency I think we should choose the slower value
> since this is what a normal clk_round_rate should do stay within spec.
> Obviously either rate (108 or 112) would be in spec, since they are
> within the min/max range. But if a normal call to clk_round_rate should
> choose a ceiling value by default (which I think it should) then
> probably the range stuff should as well, just to keep us from confusing
> ourselves.
If you see

	round_rate(110) = 108

it would be fortunate to know if you get 108 because the next available
greater rate is > 112 or because the implementation rounds down always
(which would mean that 111 is possible, too). For the "easy" consumers
this probably doesn't matter much, but if you do things that affects
a considerable part of the clock tree, you really want to know more
about the behaviour of round_rate to effectively work with its results.

So yes, please let us pick ceiling for round_rate (i.e. a fixed policy
for all clks) and then it should even be possible to make
clk_set_rate_range a generic function that doesn't need the min and max
members in the clk struct and the respective parameters to
determine_rate.

What should a clock that can only provide 100 Hz return on

	clk_round_rate(clk, 60);

? 0? -ESOMETHING (for SOMETHING = ...?)?

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-09 21:58                         ` Uwe Kleine-König
@ 2015-03-09 22:40                           ` Stephen Boyd
  2015-03-09 23:34                             ` Uwe Kleine-König
  0 siblings, 1 reply; 73+ messages in thread
From: Stephen Boyd @ 2015-03-09 22:40 UTC (permalink / raw)
  To: Uwe Kleine-König, Mike Turquette
  Cc: Philipp Zabel, linux-arm-kernel, linux-kernel,
	Sören Brinkmann, kernel

On 03/09/15 14:58, Uwe Kleine-König wrote:
>
> If you see
>
> 	round_rate(110) = 108
>
> it would be fortunate to know if you get 108 because the next available
> greater rate is > 112 or because the implementation rounds down always
> (which would mean that 111 is possible, too). For the "easy" consumers
> this probably doesn't matter much, but if you do things that affects
> a considerable part of the clock tree, you really want to know more
> about the behaviour of round_rate to effectively work with its results.
>
> So yes, please let us pick ceiling for round_rate (i.e. a fixed policy
> for all clks) and then it should even be possible to make
> clk_set_rate_range a generic function that doesn't need the min and max
> members in the clk struct and the respective parameters to
> determine_rate.
>
> What should a clock that can only provide 100 Hz return on
>
> 	clk_round_rate(clk, 60);
>
> ? 0? -ESOMETHING (for SOMETHING = ...?)?
>

Do you have any real world use cases, or is this just all theoretical?
At least in Philipp's panel case we can discuss how to make an API that
works properly. These other examples are either completely theoretical
or taken out of context and so it's unclear how they matter in practice.

Ideally I'd like an API to exist that doesn't require going back and
forth with the framework (i.e. it's "atomic" and doesn't require calling
clk_round_rate() in a loop) and that allows consumers to properly
express what they want. Right now we have a way to say min/max and a
typical rate is in the works. If we need to declare some sort of clock
provider rounding policy then we've failed to provide an API that
properly expresses all the requirements that the consumer has. It
probably means we're missing some key parameter that consumers know but
we don't accept. Maybe some more concrete examples will help clarify
what this is.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-09 22:40                           ` Stephen Boyd
@ 2015-03-09 23:34                             ` Uwe Kleine-König
  2015-03-12  1:21                               ` Stephen Boyd
  0 siblings, 1 reply; 73+ messages in thread
From: Uwe Kleine-König @ 2015-03-09 23:34 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Mike Turquette, Philipp Zabel, linux-arm-kernel, linux-kernel,
	Sören Brinkmann, kernel

Hello Stephen,

On Mon, Mar 09, 2015 at 03:40:29PM -0700, Stephen Boyd wrote:
> On 03/09/15 14:58, Uwe Kleine-König wrote:
> > If you see
> >
> > 	round_rate(110) = 108
> >
> > it would be fortunate to know if you get 108 because the next available
> > greater rate is > 112 or because the implementation rounds down always
> > (which would mean that 111 is possible, too). For the "easy" consumers
> > this probably doesn't matter much, but if you do things that affects
> > a considerable part of the clock tree, you really want to know more
> > about the behaviour of round_rate to effectively work with its results.
> >
> > So yes, please let us pick ceiling for round_rate (i.e. a fixed policy
> > for all clks) and then it should even be possible to make
> > clk_set_rate_range a generic function that doesn't need the min and max
> > members in the clk struct and the respective parameters to
> > determine_rate.
> >
> > What should a clock that can only provide 100 Hz return on
> >
> > 	clk_round_rate(clk, 60);
> >
> > ? 0? -ESOMETHING (for SOMETHING = ...?)?
> >
> 
> Do you have any real world use cases, or is this just all theoretical?
The question about clk_round_rate(fixed_clk_100hz, 60) is an
implementation detail that we must handle after agreeing that
clk_round_rate should always round down. I faced that when I tried to
implement this rounding requirement for dividers.

> At least in Philipp's panel case we can discuss how to make an API that
> works properly. These other examples are either completely theoretical
> or taken out of context and so it's unclear how they matter in practice.
We can stick to Philipp's panel case if you want. Philipp wants to find
a rate between 100 Hz and 120 Hz and likes 110 Hz most. And the lower
abs(1 / 110 - 1 / r) the better. Let's assume the clk is provided by a
fixed clk with 10000 Hz that goes through two 4bit-dividers. (So no,
that's not a real world use case, but I imagine that something like that
can occur and should definitely be possible to handle.) Something
similar happens if you have for example an i2c bus device that has a
built-in divider. For the lowest consumer the situation is easy most of
the time: It wants a certain frequency to update a panel, or it wants at
most 100 kHz on the i2c bus. But already for the divider one step up
the clk tree it's not that easy any more.

> Ideally I'd like an API to exist that doesn't require going back and
> forth with the framework (i.e. it's "atomic" and doesn't require calling
> clk_round_rate() in a loop) and that allows consumers to properly
Why is calling "clk_round_rate() in a loop" bad? In some situations you
won't be able to do something different.

> express what they want. Right now we have a way to say min/max and a
> typical rate is in the works. If we need to declare some sort of clock
> provider rounding policy then we've failed to provide an API that
> properly expresses all the requirements that the consumer has. It
I think you don't want a way to express: "I want a frequency that I
can divide down to 110 Hz with a divider picked from [1 ... 16].".
And even if we somehow manage to create something like that in a sane
way, I think the only reliable and maintainable way to get there is to
not ask all clock types to implement this functionality.
That is, I want the complexity at a single place in the framework and
only ask easy things from the clk type implementors. A .round_rate
callback is easy for most clk types. .determine_rate a bit less and it
already promotes boilerplate because each implementation has to check
for min_rate and max_rate. And .determine_rate as it is today doesn't
even support the typical value yet.

> probably means we're missing some key parameter that consumers know but
> we don't accept. Maybe some more concrete examples will help clarify
> what this is.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-09 23:34                             ` Uwe Kleine-König
@ 2015-03-12  1:21                               ` Stephen Boyd
  2015-03-12  8:57                                 ` Philipp Zabel
  0 siblings, 1 reply; 73+ messages in thread
From: Stephen Boyd @ 2015-03-12  1:21 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Mike Turquette, Philipp Zabel, linux-arm-kernel, linux-kernel,
	Sören Brinkmann, kernel

On 03/09/15 16:34, Uwe Kleine-König wrote:
> Hello Stephen,
>
> On Mon, Mar 09, 2015 at 03:40:29PM -0700, Stephen Boyd wrote:
>> On 03/09/15 14:58, Uwe Kleine-König wrote:
>>> If you see
>>>
>>> 	round_rate(110) = 108
>>>
>>> it would be fortunate to know if you get 108 because the next available
>>> greater rate is > 112 or because the implementation rounds down always
>>> (which would mean that 111 is possible, too). For the "easy" consumers
>>> this probably doesn't matter much, but if you do things that affects
>>> a considerable part of the clock tree, you really want to know more
>>> about the behaviour of round_rate to effectively work with its results.
>>>
>>> So yes, please let us pick ceiling for round_rate (i.e. a fixed policy
>>> for all clks) and then it should even be possible to make
>>> clk_set_rate_range a generic function that doesn't need the min and max
>>> members in the clk struct and the respective parameters to
>>> determine_rate.
>>>
>>> What should a clock that can only provide 100 Hz return on
>>>
>>> 	clk_round_rate(clk, 60);
>>>
>>> ? 0? -ESOMETHING (for SOMETHING = ...?)?
>>>
>> Do you have any real world use cases, or is this just all theoretical?
> The question about clk_round_rate(fixed_clk_100hz, 60) is an
> implementation detail that we must handle after agreeing that
> clk_round_rate should always round down. I faced that when I tried to
> implement this rounding requirement for dividers.
>
>> At least in Philipp's panel case we can discuss how to make an API that
>> works properly. These other examples are either completely theoretical
>> or taken out of context and so it's unclear how they matter in practice.
> We can stick to Philipp's panel case if you want. Philipp wants to find
> a rate between 100 Hz and 120 Hz and likes 110 Hz most. 

Why does Philipp like 110Hz the most? Where is the desire for that rate
coming from?

> And the lower
> abs(1 / 110 - 1 / r) the better. 

Similarly, where is this requirement coming from? Some datasheet? Or is
it just some arbitrary decision we've made that may not hold true for
all consumers?

> Let's assume the clk is provided by a
> fixed clk with 10000 Hz that goes through two 4bit-dividers. (So no,
> that's not a real world use case, but I imagine that something like that
> can occur and should definitely be possible to handle.) Something
> similar happens if you have for example an i2c bus device that has a
> built-in divider. For the lowest consumer the situation is easy most of
> the time: It wants a certain frequency to update a panel, or it wants at
> most 100 kHz on the i2c bus. But already for the divider one step up
> the clk tree it's not that easy any more.
>
>> Ideally I'd like an API to exist that doesn't require going back and
>> forth with the framework (i.e. it's "atomic" and doesn't require calling
>> clk_round_rate() in a loop) and that allows consumers to properly
> Why is calling "clk_round_rate() in a loop" bad? In some situations you
> won't be able to do something different.

The problem is open coding that loop all over the kernel in slightly
different ways. Plus it doesn't even work for some platforms where the
parent for a clock could change between the call to clk_round_rate() and
clk_set_rate() and then clk_set_rate() would do something completely
different. It would be nice if clk_round_rate() was considered "stable"
but unfortunately on these platforms it isn't. This is the "atomic"
problem I mentioned.

>
>> express what they want. Right now we have a way to say min/max and a
>> typical rate is in the works. If we need to declare some sort of clock
>> provider rounding policy then we've failed to provide an API that
>> properly expresses all the requirements that the consumer has. It
> I think you don't want a way to express: "I want a frequency that I
> can divide down to 110 Hz with a divider picked from [1 ... 16].".
> And even if we somehow manage to create something like that in a sane
> way, I think the only reliable and maintainable way to get there is to
> not ask all clock types to implement this functionality.

No we don't want anything like consumers asking for a rate with a set of
division ratios.

> That is, I want the complexity at a single place in the framework and
> only ask easy things from the clk type implementors. A .round_rate
> callback is easy for most clk types. .determine_rate a bit less and it
> already promotes boilerplate because each implementation has to check
> for min_rate and max_rate. And .determine_rate as it is today doesn't
> even support the typical value yet.

Now we seem to be talking about framework internal details. We needed to
push the min/max (and typical if/when we add it) into the
.determine_rate ops because .determine_rate is 1) the replacement for
.round_rate and 2) may need to query a number of parent clocks to figure
out what rate is supported and make sure it fits within the constraints
it requires. To consolidate all this logic into one place on top of
.round_rate would completely miss the 'mux' capabilities of clocks. We
could have added min/max to .round_rate but that would have been hugely
invasive so it was deemed easier to fix up the handful of
.determine_rate ops for this new feature.

I don't see how .round_rate or .determine_rate is any harder to
implement than the other but I'm probably biased. Most likely we should
make the arguments to .determine_rate into a struct so that it doesn't
keep requiring a flag day to change parameters passed there. We can
probably allow .determine_rate to return values outside min/max too and
check it in the framework when we get the rate back if that's a concern.
I don't see a way around the min/max check if an op calls
__clk_determine_rate() on its parent though.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-12  1:21                               ` Stephen Boyd
@ 2015-03-12  8:57                                 ` Philipp Zabel
  2015-03-13  7:50                                   ` Uwe Kleine-König
  0 siblings, 1 reply; 73+ messages in thread
From: Philipp Zabel @ 2015-03-12  8:57 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Uwe Kleine-König, Mike Turquette, linux-arm-kernel,
	linux-kernel, Sören Brinkmann, kernel

Hi Stephen,

Am Mittwoch, den 11.03.2015, 18:21 -0700 schrieb Stephen Boyd:
[...]
> Why does Philipp like 110Hz the most? Where is the desire for that rate
> coming from?
> 
> > And the lower
> > abs(1 / 110 - 1 / r) the better. 
> 
> Similarly, where is this requirement coming from? Some datasheet? Or is
> it just some arbitrary decision we've made that may not hold true for
> all consumers?

In my panel example the datasheet usually documents the typical pixel
clock and vertical and horizontal timings that exactly result in the
nominal panel refresh rate, currently most often 60 Hz.

In this use case, the driver doesn't want the pixel clock to stay below
a hard frequency limit, but to get as close as possible to the target
frequency, either above or below, so the relative error to the nominal
panel refresh rate stays as small as possible. Thus for a fictional
target rate of 110 Hz, I'd like to minimize abs((round_rate / 110) - 1).

regards
Philipp


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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-12  8:57                                 ` Philipp Zabel
@ 2015-03-13  7:50                                   ` Uwe Kleine-König
  2015-03-13  8:13                                     ` Philipp Zabel
  0 siblings, 1 reply; 73+ messages in thread
From: Uwe Kleine-König @ 2015-03-13  7:50 UTC (permalink / raw)
  To: Philipp Zabel, Stephen Boyd
  Cc: Mike Turquette, linux-arm-kernel, linux-kernel,
	Sören Brinkmann, kernel

On Thu, Mar 12, 2015 at 09:57:53AM +0100, Philipp Zabel wrote:
> Am Mittwoch, den 11.03.2015, 18:21 -0700 schrieb Stephen Boyd:
> [...]
> > Why does Philipp like 110Hz the most? Where is the desire for that rate
> > coming from?
> > 
> > > And the lower
> > > abs(1 / 110 - 1 / r) the better. 
> > 
> > Similarly, where is this requirement coming from? Some datasheet? Or is
> > it just some arbitrary decision we've made that may not hold true for
> > all consumers?
It's not comming from a datasheet. But that's what I guess is the right
metric for quite some cases. E.g. an UART sample rate and I also
wouldn't be surprised if Philipp's panel example would call for this
metric, too.

For an UART running with say 38400 Bd you want to sample with a freqency
of 38400 Hz (not considering oversampling, but that is only a factor
that doesn't makes my reasoning wrong). If you now consider 38401 Hz and
38399 Hz the respective deltas are 1 Hz. But if you look at the time
between two samples we have:

	38401 Hz -> 26.04098852 us -> delta: 0.6781507 ns
	38400 Hz -> 26.04166667 us
	38399 Hz -> 26.04234485 us -> delta: 0.6781861 ns

So with 38401 it takes a little longer until the slightly deviating rate
results in sampling the wrong bit.

> In this use case, the driver doesn't want the pixel clock to stay below
> a hard frequency limit, but to get as close as possible to the target
> frequency, either above or below, so the relative error to the nominal
> panel refresh rate stays as small as possible. Thus for a fictional
> target rate of 110 Hz, I'd like to minimize abs((round_rate / 110) - 1).
Note that minimizing

	abs((round_rate / 110) - 1)

is equivalent to minimizing

	abs(round_rate - 110)

.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 0/3] clk: divider: three exactness fixes (and a rant)
  2015-03-13  7:50                                   ` Uwe Kleine-König
@ 2015-03-13  8:13                                     ` Philipp Zabel
  0 siblings, 0 replies; 73+ messages in thread
From: Philipp Zabel @ 2015-03-13  8:13 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Stephen Boyd, Mike Turquette, linux-arm-kernel, linux-kernel,
	Sören Brinkmann, kernel

Am Freitag, den 13.03.2015, 08:50 +0100 schrieb Uwe Kleine-König:
> On Thu, Mar 12, 2015 at 09:57:53AM +0100, Philipp Zabel wrote:
> > Am Mittwoch, den 11.03.2015, 18:21 -0700 schrieb Stephen Boyd:
> > [...]
> > > Why does Philipp like 110Hz the most? Where is the desire for that rate
> > > coming from?
> > > 
> > > > And the lower
> > > > abs(1 / 110 - 1 / r) the better. 
> > > 
> > > Similarly, where is this requirement coming from? Some datasheet? Or is
> > > it just some arbitrary decision we've made that may not hold true for
> > > all consumers?
> It's not comming from a datasheet. But that's what I guess is the right
> metric for quite some cases. E.g. an UART sample rate and I also
> wouldn't be surprised if Philipp's panel example would call for this
> metric, too.
> 
> For an UART running with say 38400 Bd you want to sample with a freqency
> of 38400 Hz (not considering oversampling, but that is only a factor
> that doesn't makes my reasoning wrong). If you now consider 38401 Hz and
> 38399 Hz the respective deltas are 1 Hz. But if you look at the time
> between two samples we have:
> 
> 	38401 Hz -> 26.04098852 us -> delta: 0.6781507 ns
> 	38400 Hz -> 26.04166667 us
> 	38399 Hz -> 26.04234485 us -> delta: 0.6781861 ns
> 
> So with 38401 it takes a little longer until the slightly deviating rate
> results in sampling the wrong bit.
> 
> > In this use case, the driver doesn't want the pixel clock to stay below
> > a hard frequency limit, but to get as close as possible to the target
> > frequency, either above or below, so the relative error to the nominal
> > panel refresh rate stays as small as possible. Thus for a fictional
> > target rate of 110 Hz, I'd like to minimize abs((round_rate / 110) - 1).
> Note that minimizing
> 
> 	abs((round_rate / 110) - 1)
> 
> is equivalent to minimizing
> 
> 	abs(round_rate - 110)

Of course, and you're right, I should want to minimize the delta of the
interval time, not of the rate so that if playing back a video stream at
exactly the nominal frequency, it takes as long as possible until I have
to drop or duplicate a frame to stay in sync.

regards
Philipp


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

* Re: [PATCH RFC v9 09/20] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
  2015-03-03 11:07   ` Philipp Zabel
@ 2015-04-03  3:28     ` Liu Ying
  0 siblings, 0 replies; 73+ messages in thread
From: Liu Ying @ 2015-04-03  3:28 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Liu Ying, Thierry Reding, stefan.wahren, devicetree,
	Russell King - ARM Linux, sboyd, linux-kernel, dri-devel,
	a.hajda, kernel, andy.yan, Mike Turquette, linux-arm-kernel

Hi Thierry,

2015-03-03 19:07 GMT+08:00 Philipp Zabel <p.zabel@pengutronix.de>:
> Hi,
>
> Am Donnerstag, den 12.02.2015, 14:01 +0800 schrieb Liu Ying:
>> Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
>> ---
>> v8->v9:
>>  * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.
>
> I can't test this myself for lack of hardware, but I see no further
> issues with patches 09 - 13 except for the use of
> imx_drm_encoder_get_mux_id. I'll either rebase my patches that remove it
> or fix it up when applying.
>
> Thierry, may I take these patches through imx-drm, or would you rather I
> waited for you to pick up the drm/dsi and drm/bridge patches?

Gentle ping.  What's your opinion on the patches Philipp mentioned?

Regards,
Liu Ying

>
> regards
> Philipp
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel



-- 
Best Regards,
Liu Ying

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

* Re: [PATCH RFC v9 09/20] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
  2015-02-12  6:01 ` [PATCH RFC v9 09/20] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format Liu Ying
  2015-02-12  9:26   ` Daniel Vetter
  2015-03-03 11:07   ` Philipp Zabel
@ 2015-04-09  7:10   ` Thierry Reding
  2 siblings, 0 replies; 73+ messages in thread
From: Thierry Reding @ 2015-04-09  7:10 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	shawn.guo, mturquette, airlied, andy.yan, stefan.wahren, a.hajda,
	sboyd, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 788 bytes --]

On Thu, Feb 12, 2015 at 02:01:32PM +0800, Liu Ying wrote:
> Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
> ---
> v8->v9:
>  * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.
> 
> 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(+)

Acked-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH RFC v9 14/20] Documentation: dt-bindings: Add bindings for Himax HX8369A DRM panel driver
  2015-02-12  6:01 ` [PATCH RFC v9 14/20] Documentation: dt-bindings: Add bindings for Himax HX8369A DRM panel driver Liu Ying
@ 2015-04-09  7:20   ` Thierry Reding
  0 siblings, 0 replies; 73+ messages in thread
From: Thierry Reding @ 2015-04-09  7:20 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	shawn.guo, mturquette, airlied, andy.yan, stefan.wahren, a.hajda,
	sboyd, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 3620 bytes --]

On Thu, Feb 12, 2015 at 02:01:37PM +0800, Liu Ying wrote:
> This patch adds device tree bindings for Himax HX8369A DRM panel driver.
> 
> Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
> ---
> v8->v9:
>  * Rebase onto the imx-drm/next branch of Philipp Zabel's open git repository.
> 
> 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.

This doesn't make much sense. The binding is supposed to describe the
hardware, so saying "only video mode is supported" is weird. Perhaps if
you have no way to test other modes you could reword as:

	This version of the device tree binding only specifies MIPI DSI
	video mode.

Then again, would the device tree content be different based on the
video mode?

> +Required properties:
> +  - compatible: should be a panel's compatible string

I don't understand this. If this chip isn't a panel, why should the
compatible string contain the panel's compatible string? Is this some
kind of bridge chip that can drive different panels? I guess I'll see
when I look at the driver.

Anyway, if it isn't a panel it shouldn't have the 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>;
> +	};

Again this doesn't make sense. You're mixing two things here: the HIMAX
chip that is presumably a bridge and the panel connected to it.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH RFC v9 15/20] drm: panel: Add support for Himax HX8369A MIPI DSI panel
  2015-02-12  6:01 ` [PATCH RFC v9 15/20] drm: panel: Add support for Himax HX8369A MIPI DSI panel Liu Ying
@ 2015-04-09  8:09   ` Thierry Reding
  0 siblings, 0 replies; 73+ messages in thread
From: Thierry Reding @ 2015-04-09  8:09 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	shawn.guo, mturquette, airlied, andy.yan, stefan.wahren, a.hajda,
	sboyd, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 10851 bytes --]

On Thu, Feb 12, 2015 at 02:01:38PM +0800, Liu Ying wrote:
> This patch adds support for Himax HX8369A MIPI DSI panel.

If we're going to go ahead with this solution, this should read
something like:

	Add support for panels driven by the Himax HX8369A MIPI DSI
	bridge.

> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index d845837..cd6fbb7 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -17,6 +17,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"

Same here.

> diff --git a/drivers/gpu/drm/panel/panel-himax-hx8369a.c b/drivers/gpu/drm/panel/panel-himax-hx8369a.c
[...]
> +struct hx8369a {
> +	struct device *dev;
> +	struct drm_panel panel;

Maybe put this first in the structure so that the container_of() further
below can be optimized away in most cases? Also, can you not reuse the
dev field of struct drm_panel instead of adding another reference to it
in the driver-private structure?

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

The only purpose of this field seems to be to temporarily store a value
that you could just as well simply return. See below.

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

I think I'd put this error message into the caller. See below.

> +#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"); \

That's not necessarily true. The stack is usually much larger than 64
bytes. But this seems to be common practice with MIPI DSI drivers, so
you get to keep it if you really must have it. Note that the compiler
will usually complain itself if you exceed the stack size, so this is
somewhat redundant.

> +static int hx8369a_dsi_set_display_related_register(struct hx8369a *ctx)
> +{
> +	u8 sec_p = (ctx->res_sel << 4) | 0x03;

You could call hx8369a_vm_to_res_sel() here and return the proper value
rather than taking it from the driver-private data.

> +static int hx8369a_dsi_set_mipi(struct hx8369a *ctx)
> +{
> +	u8 eleventh_p = ctx->pd->dsi_lanes == 2 ? 0x11 : 0x10;

I wish datasheets would be more verbose so that we could avoid this kind
of meaningless names. Is there really no more documentation for any of
these commands than just a fixed set of values with maybe one or two
variable parameters?

If we ever need to support more than one panel with this driver this
could get tricky.

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

This looks like something that could be extracted into a common helper.
But that can be done separately and when a clear pattern emerges.

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

I think you should be able to output an error message here in the form
of:

	dev_err(ctx->panel.dev, "%ps() failed: %d\n", funcs[i], ret);

%ps should print the name associated with the funcs[i] symbol. That way
you can remove error reporting from the low-level macro/function.

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

Why this wrapper? Since you already have the struct mipi_dsi_device *,
can't you just do:

	ret = mipi_dsi_set_maximum_return_packet_size(dsi, 4);

instead?

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

Is brightness control something that you'd like to export to userspace
using the backlight class perhaps?

> +static int hx8369a_dsi_prepare(struct drm_panel *panel)
> +{
> +	struct hx8369a *ctx = panel_to_hx8369a(panel);
> +
> +	return hx8369a_dsi_set_sequence(ctx);
> +}

Why the indirection? Can't you just expand this function here? It isn't
called anywhere else, so you gain nothing by putting it into a separate
function.

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

Perhaps use gpiod_set_value_cansleep() to make this work with I2C GPIO
expanders as well? You're sleeping in this function already, so it
shouldn't be called from interrupt context anyway.

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

Why not make this return an integer and remove the need for the res_sel
field? Also, perhaps you'll want to error-check to make sure somebody
isn't passing in an unsupported mode?

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

i should be unsigned.

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

You should move this check up, before the allocation so that you can
avoid it if not needed. Then again, I don't see a case where of_id would
actually be NULL, so you might as well just skip the check. If somebody
really added an entry with NULL data, they'll realize their mistake soon
enough.

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

This should be dev_err(). Also the message is confusing because it could
produce something like:

	"cannot get reset-gpios -517"

and it isn't immediately obvious if -517 is a bogus GPIO number or an
error code. A better error message would be, in my opinion:

	"cannot get reset GPIO: %ld\n"

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

Should be dev_err() here, too. Also the names are somewhat confusing
because they refer to a non-existing DT property. Perhaps it'd be better
to name them after what the datasheet has. If the datasheet names them
BS[0..3] for example, maybe make the error message:

	dev_err(dev, "failed to get BS[%u] GPIO: %ld\n", i,
		PTR_ERR(ctx->bs_gpio[i]));

> +			return PTR_ERR(ctx->bs_gpio[i]);
> +		}
> +	}

You don't seem to be using these GPIOs either. I understand that you're
only supporting a single mode, but maybe it'd be better to check that
the chip is properly connected by matching the BS to the MIPI DSI video
mode enum value.

> +	ret = hx8369a_power_on(ctx);
> +	if (ret < 0) {
> +		dev_err(dev, "cannot power on\n");
> +		return ret;
> +	}

Why power on here? Can't you postpone that until the panel is actually
used (for example in ->prepare())?

> +static struct mipi_dsi_driver hx8369a_dsi_driver = {
> +	.probe = hx8369a_dsi_probe,
> +	.remove = hx8369a_dsi_remove,
> +	.driver = {
> +		.name = "panel-hx8369a-dsi",

Are there variants of hx8369a that don't use DSI as their control
interface? If not, I'd simply omit the -dsi suffix.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH RFC v9 11/20] drm/bridge: Add Synopsys DesignWare MIPI DSI host controller driver
  2015-02-12  6:01 ` [PATCH RFC v9 11/20] drm/bridge: Add Synopsys DesignWare MIPI DSI host controller driver Liu Ying
@ 2015-04-09  8:43   ` Thierry Reding
  2015-04-16  5:39     ` Archit Taneja
  0 siblings, 1 reply; 73+ messages in thread
From: Thierry Reding @ 2015-04-09  8:43 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, devicetree, linux-arm-kernel, linux, kernel, p.zabel,
	shawn.guo, mturquette, airlied, andy.yan, stefan.wahren, a.hajda,
	sboyd, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1115 bytes --]

On Thu, Feb 12, 2015 at 02:01:34PM +0800, Liu Ying wrote:
[...]
> diff --git a/drivers/gpu/drm/bridge/dw_mipi_dsi.c b/drivers/gpu/drm/bridge/dw_mipi_dsi.c
[...]
> +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;
> +	struct clk *pclk;
> +
> +	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;
> +};

While reviewing this I kept thinking whether this is really the right
architectural design. This driver is a MIPI DSI host, a connector and
a bridge, all in one. But it seems to me like it should really be an
encoder/connector and a MIPI DSI host. Why the need for a bridge? The
bridge abstraction targets blocks outside of the SoC, but it is my
understanding that these DesignWare IP blocks are designed into SoCs.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH RFC v9 11/20] drm/bridge: Add Synopsys DesignWare MIPI DSI host controller driver
  2015-04-09  8:43   ` Thierry Reding
@ 2015-04-16  5:39     ` Archit Taneja
  2015-04-22 12:13       ` Heiko Stübner
  0 siblings, 1 reply; 73+ messages in thread
From: Archit Taneja @ 2015-04-16  5:39 UTC (permalink / raw)
  To: Thierry Reding, Liu Ying
  Cc: stefan.wahren, devicetree, linux, sboyd, linux-kernel, dri-devel,
	a.hajda, kernel, andy.yan, mturquette, linux-arm-kernel



On 04/09/2015 02:13 PM, Thierry Reding wrote:
> On Thu, Feb 12, 2015 at 02:01:34PM +0800, Liu Ying wrote:
> [...]
>> diff --git a/drivers/gpu/drm/bridge/dw_mipi_dsi.c b/drivers/gpu/drm/bridge/dw_mipi_dsi.c
> [...]
>> +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;
>> +	struct clk *pclk;
>> +
>> +	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;
>> +};
>
> While reviewing this I kept thinking whether this is really the right
> architectural design. This driver is a MIPI DSI host, a connector and
> a bridge, all in one. But it seems to me like it should really be an
> encoder/connector and a MIPI DSI host. Why the need for a bridge? The
> bridge abstraction targets blocks outside of the SoC, but it is my
> understanding that these DesignWare IP blocks are designed into SoCs.
>

The msm driver uses bridges for blocks within the SoC too. We have too 
many sub blocks in the display controller that use up crtcs and encoder 
entities. A bridge is the only option one has if an encoder in the 
display chain is already taken.

In the above designware configuration, if some one created a board that 
used an external chip to further convert DSI to some other output 
format, then we would be completely exhausted of all entities.

I posted a patch that allows us to create a chain of bridges for such 
cases. It seems to work well as an interim solution. Ideally, it would 
be better if we could make bridge a special case of an encoder, and let 
one encoder connect to another encoder.

Such a thing would also help us unify i2c slave encoders and bridge 
drivers too. A chip designed as an i2c slave encoder would work well 
with a drm driver that doesn't have an encoder, but won't work for SoCs 
SoCs that already have an encoder and were expecting a bridge entity 
instead.

Archit

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH RFC v9 11/20] drm/bridge: Add Synopsys DesignWare MIPI DSI host controller driver
  2015-04-16  5:39     ` Archit Taneja
@ 2015-04-22 12:13       ` Heiko Stübner
  0 siblings, 0 replies; 73+ messages in thread
From: Heiko Stübner @ 2015-04-22 12:13 UTC (permalink / raw)
  To: dri-devel
  Cc: Archit Taneja, Thierry Reding, Liu Ying, stefan.wahren,
	devicetree, linux, mturquette, sboyd, linux-kernel, a.hajda,
	kernel, andy.yan, linux-arm-kernel

Am Donnerstag, 16. April 2015, 11:09:58 schrieb Archit Taneja:
> On 04/09/2015 02:13 PM, Thierry Reding wrote:
> > On Thu, Feb 12, 2015 at 02:01:34PM +0800, Liu Ying wrote:
> > [...]
> > 
> >> diff --git a/drivers/gpu/drm/bridge/dw_mipi_dsi.c
> >> b/drivers/gpu/drm/bridge/dw_mipi_dsi.c> 
> > [...]
> > 
> >> +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;
> >> +	struct clk *pclk;
> >> +
> >> +	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;
> >> +};
> > 
> > While reviewing this I kept thinking whether this is really the right
> > architectural design. This driver is a MIPI DSI host, a connector and
> > a bridge, all in one. But it seems to me like it should really be an
> > encoder/connector and a MIPI DSI host. Why the need for a bridge? The
> > bridge abstraction targets blocks outside of the SoC, but it is my
> > understanding that these DesignWare IP blocks are designed into SoCs.
> 
> The msm driver uses bridges for blocks within the SoC too. We have too
> many sub blocks in the display controller that use up crtcs and encoder
> entities. A bridge is the only option one has if an encoder in the
> display chain is already taken.
> 
> In the above designware configuration, if some one created a board that
> used an external chip to further convert DSI to some other output
> format, then we would be completely exhausted of all entities.
> 
> I posted a patch that allows us to create a chain of bridges for such
> cases. It seems to work well as an interim solution. Ideally, it would
> be better if we could make bridge a special case of an encoder, and let
> one encoder connect to another encoder.
> 
> Such a thing would also help us unify i2c slave encoders and bridge
> drivers too. A chip designed as an i2c slave encoder would work well
> with a drm driver that doesn't have an encoder, but won't work for SoCs
> SoCs that already have an encoder and were expecting a bridge entity
> instead.

Yeah, having encoder-after-encoder chains would be great. I have the same 
issue on Rockchip where on the rk3288 the lvds-IP hogs the lcd-pins of the soc 
which are used both for panels as well as external encoders, while on the 
older Rockchip SoCs these pins are used by external encoders directly.

So in my current (pending review) patchset the lvds acts as encoder for panels 
and as bridge if external encoders are in use.

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

end of thread, other threads:[~2015-04-22 12:14 UTC | newest]

Thread overview: 73+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-12  6:01 [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 01/20] clk: divider: Correct parent clk round rate if no bestdiv is normally found Liu Ying
2015-02-12  9:33   ` Sascha Hauer
2015-02-12 10:39     ` Liu Ying
2015-02-12 12:24       ` Sascha Hauer
2015-02-12 12:56         ` Russell King - ARM Linux
2015-02-12 13:41           ` Sascha Hauer
2015-02-12 14:06             ` Liu Ying
2015-02-13  2:58               ` Liu Ying
2015-02-13  2:58                 ` Travis
2015-02-13 14:35             ` Tomi Valkeinen
2015-02-13 18:57               ` Sascha Hauer
2015-02-16 11:18                 ` Tomi Valkeinen
2015-02-17 10:32                   ` Sascha Hauer
2015-02-16 11:27                 ` Russell King - ARM Linux
2015-02-20 19:13                   ` Mike Turquette
2015-02-20 19:20                     ` Russell King - ARM Linux
2015-02-21  8:56         ` Uwe Kleine-König
2015-02-21 10:40           ` [PATCH 0/3] clk: divider: three exactness fixes (and a rant) Uwe Kleine-König
2015-02-21 10:40             ` [PATCH 1/3] clk: divider: fix calculation of maximal parent rate for a given divider Uwe Kleine-König
2015-02-23  7:32               ` Sascha Hauer
2015-03-05  8:35               ` Uwe Kleine-König
2015-02-21 10:40             ` [PATCH 2/3] clk: divider: fix selection of divider when rounding to closest Uwe Kleine-König
2015-02-23  9:46               ` Maxime Coquelin
2015-02-21 10:40             ` [PATCH 3/3] clk: divider: fix calculation of initial best " Uwe Kleine-König
2015-02-23  9:42               ` Maxime Coquelin
2015-02-23  7:23             ` [PATCH 0/3] clk: divider: three exactness fixes (and a rant) Sascha Hauer
2015-03-06 18:57             ` Mike Turquette
2015-03-06 19:28               ` Uwe Kleine-König
2015-03-06 19:40                 ` Stephen Boyd
2015-03-09  9:58                   ` Philipp Zabel
2015-03-09 19:05                     ` Stephen Boyd
2015-03-09 20:23                       ` Uwe Kleine-König
2015-03-09 21:07                       ` Mike Turquette
2015-03-09 21:58                         ` Uwe Kleine-König
2015-03-09 22:40                           ` Stephen Boyd
2015-03-09 23:34                             ` Uwe Kleine-König
2015-03-12  1:21                               ` Stephen Boyd
2015-03-12  8:57                                 ` Philipp Zabel
2015-03-13  7:50                                   ` Uwe Kleine-König
2015-03-13  8:13                                     ` Philipp Zabel
2015-03-06 19:44               ` Stephen Boyd
2015-03-06 21:09                 ` Uwe Kleine-König
2015-02-12  6:01 ` [PATCH RFC v9 02/20] ARM: imx6q: Add GPR3 MIPI muxing control register field shift bits definition Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 03/20] ARM: imx6q: clk: Add the video_27m clock Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 04/20] ARM: imx6q: clk: Change hdmi_isfr clock's parent to be " Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 05/20] ARM: imx6q: clk: Change hsi_tx clock to be a shared clock gate Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 06/20] ARM: imx6q: clk: Add support for mipi_core_cfg clock as " Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 07/20] ARM: imx6q: clk: Add support for mipi_ipg " Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 08/20] ARM: dts: imx6qdl: Move existing MIPI DSI ports into a new 'ports' node Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 09/20] drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format Liu Ying
2015-02-12  9:26   ` Daniel Vetter
2015-02-13  5:01     ` Liu Ying
2015-03-03 11:07   ` Philipp Zabel
2015-04-03  3:28     ` Liu Ying
2015-04-09  7:10   ` Thierry Reding
2015-02-12  6:01 ` [PATCH RFC v9 10/20] Documentation: dt-bindings: Add bindings for Synopsys DW MIPI DSI DRM bridge driver Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 11/20] drm/bridge: Add Synopsys DesignWare MIPI DSI host controller driver Liu Ying
2015-04-09  8:43   ` Thierry Reding
2015-04-16  5:39     ` Archit Taneja
2015-04-22 12:13       ` Heiko Stübner
2015-02-12  6:01 ` [PATCH RFC v9 12/20] Documentation: dt-bindings: Add bindings for i.MX specific Synopsys DW MIPI DSI driver Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 13/20] drm: imx: Support Synopsys DesignWare MIPI DSI host controller Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 14/20] Documentation: dt-bindings: Add bindings for Himax HX8369A DRM panel driver Liu Ying
2015-04-09  7:20   ` Thierry Reding
2015-02-12  6:01 ` [PATCH RFC v9 15/20] drm: panel: Add support for Himax HX8369A MIPI DSI panel Liu Ying
2015-04-09  8:09   ` Thierry Reding
2015-02-12  6:01 ` [PATCH RFC v9 16/20] ARM: dtsi: imx6qdl: Add support for MIPI DSI host controller Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 17/20] ARM: dts: imx6qdl-sabresd: Add support for TRULY TFT480800-16-E MIPI DSI panel Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 18/20] ARM: imx_v6_v7_defconfig: Cleanup for imx drm being moved out of staging Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 19/20] ARM: imx_v6_v7_defconfig: Add support for MIPI DSI host controller Liu Ying
2015-02-12  6:01 ` [PATCH RFC v9 20/20] ARM: imx_v6_v7_defconfig: Add support for Himax HX8369A panel Liu Ying
2015-03-02 13:24 ` [PATCH RFC v9 00/20] Add support for i.MX MIPI DSI DRM driver Shawn Guo

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