Hi all,
this patchset is a next attempt to add the tc358764 driver.
The previous one can be found here:
https://lists.freedesktop.org/archives/dri-devel/2014-February/053705.html
Back then, TC358764 was added as a panel driver.
The bridge is supposed to be a DSI peripheral. Currently exynos_dsi accepts only panels
as its peripherals. Therefore, some logic in exynos_dsi had to be ammended. That is implemented
in first 3 patches.
Apart from the driver this patchset adds support for BOE HV070WSA-100 panel, which is used by
TC358764 and dts nodes to exynos5250.dtsi and exynos5250-arndale.dtsi.
Best regards,
Maciej Purski
---
Changes in v3:
- call drm_bridge_enable() and drm_bridge_pre_enable() in exynos_drm_dsi_enable()
and make the bridge invisible for the framework in order to prevent it from
being enabled by the framework
- expand panel binding description
- fix tc358744 binding, make port 1 mandatory and port 0 optional
- get rid of useless select VIDEOMODE_HELPERS in bridge Kconfig
- add missing SPDX license to drm/bridge/tc358764.c
- use mipi_dsi_generic_read() and mipi_dsi_generic_write() helpers
in toshiba driver's read, write functions
- fix commit messages
Changes in v2:
- fix commits authorship
- don't call pm_runtime_put_sync() in exyons_dsi_disable(), if pm_runtime_get_sync()
has not been called
- squash dts commits
- merge some redundant regulators in tc358764 bindings and in DTS
- fix kbuild robot errors
Andrzej Hajda (6):
dt-bindings: display: add DT bindings for BOE HV070WSA-100 panel
drm/panel: add support for BOE HV070WSA-100 panel to simple-panel
dt-bindings: tc358754: add DT bindings
drm/bridge: tc358764: Add DSI to LVDS bridge driver
ARM: dts: exynos5250: add DSI node
ARM: dts: exynos5250-arndale: add DSI and panel nodes
Maciej Purski (3):
drm/exynos: rename "bridge_node" to "mic_bridge_node"
drm/exynos: move connector creation to attach callback
drm/exynos: enable out_bridge in exynos_dsi_enable()
.../bindings/display/bridge/toshiba,tc358764.txt | 35 ++
.../bindings/display/panel/boe,hv070wsa-100.txt | 28 ++
arch/arm/boot/dts/exynos5250-arndale.dts | 61 +++
arch/arm/boot/dts/exynos5250.dtsi | 21 +
drivers/gpu/drm/bridge/Kconfig | 8 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/tc358764.c | 521 +++++++++++++++++++++
drivers/gpu/drm/exynos/exynos_drm_dsi.c | 88 ++--
drivers/gpu/drm/panel/panel-simple.c | 25 +
9 files changed, 755 insertions(+), 33 deletions(-)
create mode 100644 Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt
create mode 100644 Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt
create mode 100644 drivers/gpu/drm/bridge/tc358764.c
--
2.7.4
When adding support for peripheral out bridges, the "bridge" name
becomes imprecise as it refers to a different device than the
"out_bridge".
Signed-off-by: Maciej Purski <[email protected]>
---
drivers/gpu/drm/exynos/exynos_drm_dsi.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index eae44fd..9599e6b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -279,7 +279,7 @@ struct exynos_dsi {
struct list_head transfer_list;
const struct exynos_dsi_driver_data *driver_data;
- struct device_node *bridge_node;
+ struct device_node *mic_bridge_node;
};
#define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
@@ -1631,7 +1631,7 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
if (ret < 0)
return ret;
- dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
+ dsi->mic_bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
return 0;
}
@@ -1642,7 +1642,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
struct drm_encoder *encoder = dev_get_drvdata(dev);
struct exynos_dsi *dsi = encoder_to_dsi(encoder);
struct drm_device *drm_dev = data;
- struct drm_bridge *bridge;
+ struct drm_bridge *mic_bridge;
int ret;
drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs,
@@ -1661,10 +1661,10 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
return ret;
}
- if (dsi->bridge_node) {
- bridge = of_drm_find_bridge(dsi->bridge_node);
- if (bridge)
- drm_bridge_attach(encoder, bridge, NULL);
+ if (dsi->mic_bridge_node) {
+ mic_bridge = of_drm_find_bridge(dsi->mic_bridge_node);
+ if (mic_bridge)
+ drm_bridge_attach(encoder, mic_bridge, NULL);
}
return mipi_dsi_host_register(&dsi->dsi_host);
@@ -1783,7 +1783,7 @@ static int exynos_dsi_remove(struct platform_device *pdev)
{
struct exynos_dsi *dsi = platform_get_drvdata(pdev);
- of_node_put(dsi->bridge_node);
+ of_node_put(dsi->mic_bridge_node);
pm_runtime_disable(&pdev->dev);
--
2.7.4
From: Andrzej Hajda <[email protected]>
The patch adds bridge and panel nodes.
It adds also DSI properties specific for arndale board and
regulators required by the bridge.
Signed-off-by: Andrzej Hajda <[email protected]>
Signed-off-by: Maciej Purski <[email protected]>
---
arch/arm/boot/dts/exynos5250-arndale.dts | 61 ++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
index 7a8a5c5..816d89d 100644
--- a/arch/arm/boot/dts/exynos5250-arndale.dts
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -71,6 +71,17 @@
};
};
+ panel: panel {
+ compatible = "boe,hv070wsa-100";
+ power-supply = <&vcc_3v3_reg>;
+ enable-gpios = <&gpd1 3 GPIO_ACTIVE_HIGH>;
+ port {
+ panel_ep: endpoint {
+ remote-endpoint = <&bridge_out_ep>;
+ };
+ };
+ };
+
regulators {
compatible = "simple-bus";
#address-cells = <1>;
@@ -97,6 +108,30 @@
reg = <2>;
regulator-name = "hdmi-en";
};
+
+ vcc_1v2_reg: regulator@3 {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ regulator-name = "VCC_1V2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ vcc_1v8_reg: regulator@4 {
+ compatible = "regulator-fixed";
+ reg = <4>;
+ regulator-name = "VCC_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vcc_3v3_reg: regulator@5 {
+ compatible = "regulator-fixed";
+ reg = <5>;
+ regulator-name = "VCC_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
};
fixed-rate-clocks {
@@ -119,6 +154,32 @@
cpu0-supply = <&buck2_reg>;
};
+&dsi_0 {
+ vddcore-supply = <&ldo8_reg>;
+ vddio-supply = <&ldo10_reg>;
+ samsung,pll-clock-frequency = <24000000>;
+ samsung,burst-clock-frequency = <320000000>;
+ samsung,esc-clock-frequency = <10000000>;
+ status = "okay";
+
+ bridge@0 {
+ reg = <0>;
+ compatible = "toshiba,tc358764";
+ vddc-supply = <&vcc_1v2_reg>;
+ vddio-supply = <&vcc_1v8_reg>;
+ vddlvds-supply = <&vcc_3v3_reg>;
+ reset-gpios = <&gpd1 6 GPIO_ACTIVE_LOW>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@1 {
+ reg = <1>;
+ bridge_out_ep: endpoint {
+ remote-endpoint = <&panel_ep>;
+ };
+ };
+ };
+};
+
&dp {
status = "okay";
samsung,color-space = <0>;
--
2.7.4
From: Andrzej Hajda <[email protected]>
Add a drm_bridge driver for the Toshiba TC358764 DSI to LVDS bridge.
Signed-off-by: Andrzej Hajda <[email protected]>
Signed-off-by: Maciej Purski <[email protected]>
---
drivers/gpu/drm/bridge/Kconfig | 8 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/tc358764.c | 521 ++++++++++++++++++++++++++++++++++++++
3 files changed, 530 insertions(+)
create mode 100644 drivers/gpu/drm/bridge/tc358764.c
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index fa2c799..f3da8a7 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -110,6 +110,14 @@ config DRM_THINE_THC63LVD1024
---help---
Thine THC63LVD1024 LVDS/parallel converter driver.
+config DRM_TOSHIBA_TC358764
+ tristate "TC358764 DSI/LVDS bridge"
+ depends on DRM && DRM_PANEL
+ depends on OF
+ select DRM_MIPI_DSI
+ help
+ Toshiba TC358764 DSI/LVDS bridge driver.
+
config DRM_TOSHIBA_TC358767
tristate "Toshiba TC358767 eDP bridge"
depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 35f88d4..bf7c0ce 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
obj-$(CONFIG_DRM_SII902X) += sii902x.o
obj-$(CONFIG_DRM_SII9234) += sii9234.o
obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o
+obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o
obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c
new file mode 100644
index 0000000..0aee155
--- /dev/null
+++ b/drivers/gpu/drm/bridge/tc358764.c
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd
+ *
+ * Authors:
+ * Andrzej Hajda <[email protected]>
+ * Maciej Purski <[email protected]>
+ *
+ * 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 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ *
+ */
+
+#include <drm/drm_atomic_helper.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/of_graph.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
+#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
+
+/* PPI layer registers */
+#define PPI_STARTPPI 0x0104 /* START control bit */
+#define PPI_LPTXTIMECNT 0x0114 /* LPTX timing signal */
+#define PPI_LANEENABLE 0x0134 /* Enables each lane */
+#define PPI_TX_RX_TA 0x013C /* BTA timing parameters */
+#define PPI_D0S_CLRSIPOCOUNT 0x0164 /* Assertion timer for Lane 0 */
+#define PPI_D1S_CLRSIPOCOUNT 0x0168 /* Assertion timer for Lane 1 */
+#define PPI_D2S_CLRSIPOCOUNT 0x016C /* Assertion timer for Lane 2 */
+#define PPI_D3S_CLRSIPOCOUNT 0x0170 /* Assertion timer for Lane 3 */
+#define PPI_START_FUNCTION 1
+
+/* DSI layer registers */
+#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX */
+#define DSI_LANEENABLE 0x0210 /* Enables each lane */
+#define DSI_RX_START 1
+
+/* Video path registers */
+#define VP_CTRL 0x0450 /* Video Path Control */
+#define VP_CTRL_MSF(v) FLD_VAL(v, 0, 0) /* Magic square in RGB666 */
+#define VP_CTRL_VTGEN(v) FLD_VAL(v, 4, 4) /* Use chip clock for timing */
+#define VP_CTRL_EVTMODE(v) FLD_VAL(v, 5, 5) /* Event mode */
+#define VP_CTRL_RGB888(v) FLD_VAL(v, 8, 8) /* RGB888 mode */
+#define VP_CTRL_VSDELAY(v) FLD_VAL(v, 31, 20) /* VSYNC delay */
+#define VP_CTRL_HSPOL BIT(17) /* Polarity of HSYNC signal */
+#define VP_CTRL_DEPOL BIT(18) /* Polarity of DE signal */
+#define VP_CTRL_VSPOL BIT(19) /* Polarity of VSYNC signal */
+#define VP_HTIM1 0x0454 /* Horizontal Timing Control 1 */
+#define VP_HTIM1_HBP(v) FLD_VAL(v, 24, 16)
+#define VP_HTIM1_HSYNC(v) FLD_VAL(v, 8, 0)
+#define VP_HTIM2 0x0458 /* Horizontal Timing Control 2 */
+#define VP_HTIM2_HFP(v) FLD_VAL(v, 24, 16)
+#define VP_HTIM2_HACT(v) FLD_VAL(v, 10, 0)
+#define VP_VTIM1 0x045C /* Vertical Timing Control 1 */
+#define VP_VTIM1_VBP(v) FLD_VAL(v, 23, 16)
+#define VP_VTIM1_VSYNC(v) FLD_VAL(v, 7, 0)
+#define VP_VTIM2 0x0460 /* Vertical Timing Control 2 */
+#define VP_VTIM2_VFP(v) FLD_VAL(v, 23, 16)
+#define VP_VTIM2_VACT(v) FLD_VAL(v, 10, 0)
+#define VP_VFUEN 0x0464 /* Video Frame Timing Update Enable */
+
+/* LVDS registers */
+#define LV_MX0003 0x0480 /* Mux input bit 0 to 3 */
+#define LV_MX0407 0x0484 /* Mux input bit 4 to 7 */
+#define LV_MX0811 0x0488 /* Mux input bit 8 to 11 */
+#define LV_MX1215 0x048C /* Mux input bit 12 to 15 */
+#define LV_MX1619 0x0490 /* Mux input bit 16 to 19 */
+#define LV_MX2023 0x0494 /* Mux input bit 20 to 23 */
+#define LV_MX2427 0x0498 /* Mux input bit 24 to 27 */
+#define LV_MX(b0, b1, b2, b3) (FLD_VAL(b0, 4, 0) | FLD_VAL(b1, 12, 8) | \
+ FLD_VAL(b2, 20, 16) | FLD_VAL(b3, 28, 24))
+
+/* Input bit numbers used in mux registers */
+enum {
+ LVI_R0,
+ LVI_R1,
+ LVI_R2,
+ LVI_R3,
+ LVI_R4,
+ LVI_R5,
+ LVI_R6,
+ LVI_R7,
+ LVI_G0,
+ LVI_G1,
+ LVI_G2,
+ LVI_G3,
+ LVI_G4,
+ LVI_G5,
+ LVI_G6,
+ LVI_G7,
+ LVI_B0,
+ LVI_B1,
+ LVI_B2,
+ LVI_B3,
+ LVI_B4,
+ LVI_B5,
+ LVI_B6,
+ LVI_B7,
+ LVI_HS,
+ LVI_VS,
+ LVI_DE,
+ LVI_L0
+};
+
+#define LV_CFG 0x049C /* LVDS Configuration */
+#define LV_PHY0 0x04A0 /* LVDS PHY 0 */
+#define LV_PHY0_RST(v) FLD_VAL(v, 22, 22) /* PHY reset */
+#define LV_PHY0_IS(v) FLD_VAL(v, 15, 14)
+#define LV_PHY0_ND(v) FLD_VAL(v, 4, 0) /* Frequency range select */
+#define LV_PHY0_PRBS_ON(v) FLD_VAL(v, 20, 16) /* Clock/Data Flag pins */
+
+/* System registers */
+#define SYS_RST 0x0504 /* System Reset */
+#define SYS_ID 0x0580 /* System ID */
+
+#define SYS_RST_I2CS BIT(0) /* Reset I2C-Slave controller */
+#define SYS_RST_I2CM BIT(1) /* Reset I2C-Master controller */
+#define SYS_RST_LCD BIT(2) /* Reset LCD controller */
+#define SYS_RST_BM BIT(3) /* Reset Bus Management controller */
+#define SYS_RST_DSIRX BIT(4) /* Reset DSI-RX and App controller */
+#define SYS_RST_REG BIT(5) /* Reset Register module */
+
+#define LPX_PERIOD 2
+#define TTA_SURE 3
+#define TTA_GET 0x20000
+
+/* Lane enable PPI and DSI register bits */
+#define LANEENABLE_CLEN BIT(0)
+#define LANEENABLE_L0EN BIT(1)
+#define LANEENABLE_L1EN BIT(2)
+#define LANEENABLE_L2EN BIT(3)
+#define LANEENABLE_L3EN BIT(4)
+
+/* LVCFG fields */
+#define LV_CFG_LVEN BIT(0)
+#define LV_CFG_LVDLINK BIT(1)
+#define LV_CFG_CLKPOL1 BIT(2)
+#define LV_CFG_CLKPOL2 BIT(3)
+
+static const char * const tc358764_supplies[] = {
+ "vddc", "vddio", "vddmipi", "vddlvds133", "vddlvds112"
+};
+
+struct tc358764 {
+ struct device *dev;
+ struct drm_bridge bridge;
+ struct drm_connector connector;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(tc358764_supplies)];
+ struct gpio_desc *gpio_reset;
+
+ struct drm_panel *panel;
+};
+
+static int tc358764_read(struct tc358764 *ctx, u16 addr, u32 *val)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ ssize_t ret;
+
+ cpu_to_le16s(&addr);
+ ret = mipi_dsi_generic_read(dsi, &addr, sizeof(addr), val, sizeof(val));
+ if (ret >= 0)
+ le32_to_cpus(val);
+
+ dev_dbg(ctx->dev, "read: %d, addr: %d\n", addr, *val);
+
+ return ret;
+}
+
+static int tc358764_write(struct tc358764 *ctx, u16 addr, u32 val)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ ssize_t ret;
+ u8 data[6];
+
+ data[0] = addr;
+ data[1] = addr >> 8;
+ data[2] = val;
+ data[3] = val >> 8;
+ data[4] = val >> 16;
+ data[5] = val >> 24;
+
+ ret = mipi_dsi_generic_write(dsi, data, sizeof(data));
+
+ return ret;
+}
+
+static inline struct tc358764 *bridge_to_tc358764(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct tc358764, bridge);
+}
+
+static inline
+struct tc358764 *connector_to_tc358764(struct drm_connector *connector)
+{
+ return container_of(connector, struct tc358764, connector);
+}
+
+static int tc358764_init(struct tc358764 *ctx)
+{
+ u32 v = 0;
+
+ tc358764_read(ctx, SYS_ID, &v);
+ dev_info(ctx->dev, "ID: %#x\n", v);
+
+ /* configure PPI counters */
+ tc358764_write(ctx, PPI_TX_RX_TA, TTA_GET | TTA_SURE);
+ tc358764_write(ctx, PPI_LPTXTIMECNT, LPX_PERIOD);
+ tc358764_write(ctx, PPI_D0S_CLRSIPOCOUNT, 5);
+ tc358764_write(ctx, PPI_D1S_CLRSIPOCOUNT, 5);
+ tc358764_write(ctx, PPI_D2S_CLRSIPOCOUNT, 5);
+ tc358764_write(ctx, PPI_D3S_CLRSIPOCOUNT, 5);
+
+ /* enable four data lanes and clock lane */
+ tc358764_write(ctx, PPI_LANEENABLE, LANEENABLE_L3EN | LANEENABLE_L2EN |
+ LANEENABLE_L1EN | LANEENABLE_L0EN | LANEENABLE_CLEN);
+ tc358764_write(ctx, DSI_LANEENABLE, LANEENABLE_L3EN | LANEENABLE_L2EN |
+ LANEENABLE_L1EN | LANEENABLE_L0EN | LANEENABLE_CLEN);
+
+ /* start */
+ tc358764_write(ctx, PPI_STARTPPI, PPI_START_FUNCTION);
+ tc358764_write(ctx, DSI_STARTDSI, DSI_RX_START);
+
+ /* configure video path */
+ tc358764_write(ctx, VP_CTRL, VP_CTRL_VSDELAY(15) | VP_CTRL_RGB888(1) |
+ VP_CTRL_EVTMODE(1) | VP_CTRL_HSPOL | VP_CTRL_VSPOL);
+
+ /* reset PHY */
+ tc358764_write(ctx, LV_PHY0, LV_PHY0_RST(1) |
+ LV_PHY0_PRBS_ON(4) | LV_PHY0_IS(2) | LV_PHY0_ND(6));
+ tc358764_write(ctx, LV_PHY0, LV_PHY0_PRBS_ON(4) | LV_PHY0_IS(2) |
+ LV_PHY0_ND(6));
+
+ /* reset bridge */
+ tc358764_write(ctx, SYS_RST, SYS_RST_LCD);
+
+ /* set bit order */
+ tc358764_write(ctx, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3));
+ tc358764_write(ctx, LV_MX0407, LV_MX(LVI_R4, LVI_R7, LVI_R5, LVI_G0));
+ tc358764_write(ctx, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_G6, LVI_G7));
+ tc358764_write(ctx, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0));
+ tc358764_write(ctx, LV_MX1619, LV_MX(LVI_B6, LVI_B7, LVI_B1, LVI_B2));
+ tc358764_write(ctx, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0));
+ tc358764_write(ctx, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R6));
+ tc358764_write(ctx, LV_CFG, LV_CFG_CLKPOL2 | LV_CFG_CLKPOL1 |
+ LV_CFG_LVEN);
+
+ return 0;
+}
+
+static void tc358764_reset(struct tc358764 *ctx)
+{
+ msleep(20);
+ gpiod_set_value(ctx->gpio_reset, 0);
+ msleep(20);
+ gpiod_set_value(ctx->gpio_reset, 1);
+ msleep(40);
+}
+
+static void tc358764_poweroff(struct tc358764 *ctx)
+{
+ int ret;
+
+ tc358764_reset(ctx);
+
+ drm_panel_disable(ctx->panel);
+ msleep(40);
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ if (ret < 0)
+ dev_err(ctx->dev, "error disabling regulators (%d)\n", ret);
+}
+
+static int tc358764_get_modes(struct drm_connector *connector)
+{
+ struct tc358764 *ctx = connector_to_tc358764(connector);
+
+ if (ctx->panel && ctx->panel->funcs && ctx->panel->funcs->get_modes)
+ return ctx->panel->funcs->get_modes(ctx->panel);
+
+ return 0;
+}
+
+static const
+struct drm_connector_helper_funcs tc358764_connector_helper_funcs = {
+ .get_modes = tc358764_get_modes,
+};
+
+static const struct drm_connector_funcs tc358764_connector_funcs = {
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static void tc358764_disable(struct drm_bridge *bridge)
+{
+ struct tc358764 *ctx = bridge_to_tc358764(bridge);
+
+ tc358764_poweroff(ctx);
+}
+
+static void tc358764_pre_enable(struct drm_bridge *bridge)
+{
+ struct tc358764 *ctx = bridge_to_tc358764(bridge);
+ int ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies),
+ ctx->supplies);
+ if (ret < 0)
+ dev_err(ctx->dev, "error enabling regulators (%d)\n", ret);
+
+ tc358764_reset(ctx);
+ tc358764_init(ctx);
+}
+
+static void tc358764_enable(struct drm_bridge *bridge)
+{
+ struct tc358764 *ctx = bridge_to_tc358764(bridge);
+ int ret;
+
+ drm_panel_prepare(ctx->panel);
+
+ ret = drm_panel_enable(ctx->panel);
+ if (ret < 0)
+ pr_err("panel enable failed\n");
+
+ msleep(40);
+}
+
+static int tc358764_attach(struct drm_bridge *bridge)
+{
+ struct tc358764 *ctx = bridge_to_tc358764(bridge);
+ struct drm_device *drm = bridge->dev;
+ int ret;
+
+ if (!bridge->encoder) {
+ DRM_ERROR("Encoder not found\n");
+ return -ENODEV;
+ }
+
+ ctx->connector.polled = DRM_CONNECTOR_POLL_HPD;
+ ret = drm_connector_init(drm, &ctx->connector,
+ &tc358764_connector_funcs,
+ DRM_MODE_CONNECTOR_LVDS);
+ if (ret) {
+ DRM_ERROR("Failed to initialize connector\n");
+ return ret;
+ }
+
+ drm_connector_helper_add(&ctx->connector,
+ &tc358764_connector_helper_funcs);
+
+ drm_mode_connector_attach_encoder(&ctx->connector, bridge->encoder);
+
+ if (ctx->panel)
+ drm_panel_attach(ctx->panel, &ctx->connector);
+
+ drm_atomic_helper_connector_reset(&ctx->connector);
+ drm_connector_register(&ctx->connector);
+
+ return 0;
+}
+
+static const struct drm_bridge_funcs tc358764_bridge_funcs = {
+ .disable = tc358764_disable,
+ .enable = tc358764_enable,
+ .pre_enable = tc358764_pre_enable,
+ .attach = tc358764_attach,
+};
+
+static struct device_node *tc358764_of_find_panel_node(struct device *dev)
+{
+ struct device_node *np, *ep;
+
+ ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);
+ if (!ep) {
+ pr_err("failed to get endpoint\n");
+ return NULL;
+ }
+
+ np = of_graph_get_remote_port_parent(ep);
+
+ return np;
+}
+
+static int tc358764_parse_dt(struct tc358764 *ctx)
+{
+ struct device *dev = ctx->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *lvds;
+
+ ctx->gpio_reset = devm_gpiod_get_from_of_node(dev, np, "reset", 0,
+ GPIOD_OUT_LOW,
+ "tc358764-reset");
+ if (IS_ERR(ctx->gpio_reset)) {
+ dev_err(dev, "no reset GPIO pin provided\n");
+ return PTR_ERR(ctx->gpio_reset);
+ }
+
+ lvds = tc358764_of_find_panel_node(ctx->dev);
+ if (!lvds) {
+ dev_err(dev, "cannot find panel node\n");
+ return -EINVAL;
+ }
+
+ ctx->panel = of_drm_find_panel(lvds);
+ if (!ctx->panel) {
+ dev_err(dev, "panel not registered\n");
+ return -EPROBE_DEFER;
+ }
+
+ return 0;
+}
+
+static int tc358764_configure_regulators(struct tc358764 *ctx)
+{
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(ctx->supplies); ++i)
+ ctx->supplies[i].supply = tc358764_supplies[i];
+
+ ret = devm_regulator_bulk_get(ctx->dev, ARRAY_SIZE(ctx->supplies),
+ ctx->supplies);
+ if (ret < 0)
+ dev_err(ctx->dev, "failed to get regulators: %d\n", ret);
+
+ return ret;
+}
+
+static int tc358764_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct tc358764 *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(dev, sizeof(struct tc358764), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ ctx->dev = dev;
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST
+ | MIPI_DSI_MODE_VIDEO_AUTO_VERT | MIPI_DSI_MODE_LPM;
+
+ ret = tc358764_parse_dt(ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = tc358764_configure_regulators(ctx);
+ if (ret < 0)
+ return ret;
+
+ ctx->bridge.funcs = &tc358764_bridge_funcs;
+ ctx->bridge.of_node = dev->of_node;
+
+ drm_bridge_add(&ctx->bridge);
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ drm_bridge_remove(&ctx->bridge);
+ dev_err(dev, "failed to attach dsi\n");
+ }
+
+ return ret;
+}
+
+static int tc358764_remove(struct mipi_dsi_device *dsi)
+{
+ struct tc358764 *ctx = mipi_dsi_get_drvdata(dsi);
+
+ tc358764_poweroff(ctx);
+
+ mipi_dsi_detach(dsi);
+ drm_bridge_remove(&ctx->bridge);
+
+ return 0;
+}
+
+static const struct of_device_id tc358764_of_match[] = {
+ { .compatible = "toshiba,tc358764" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tc358764_of_match);
+
+static struct mipi_dsi_driver tc358764_driver = {
+ .probe = tc358764_probe,
+ .remove = tc358764_remove,
+ .driver = {
+ .name = "tc358764",
+ .owner = THIS_MODULE,
+ .of_match_table = tc358764_of_match,
+ },
+};
+module_mipi_dsi_driver(tc358764_driver);
+
+MODULE_AUTHOR("Andrzej Hajda <[email protected]>");
+MODULE_AUTHOR("Maciej Purski <[email protected]>");
+MODULE_DESCRIPTION("MIPI-DSI based Driver for TC358764 DSI/LVDS Bridge");
+MODULE_LICENSE("GPL v2");
--
2.7.4
As the out bridge will not be enabled directly by the framework,
it should be enabled by DSI. Exynos_dsi_enable() should handle a case,
when there is an out_bridge connected as a DSI peripheral.
Signed-off-by: Maciej Purski <[email protected]>
---
drivers/gpu/drm/exynos/exynos_drm_dsi.c | 34 +++++++++++++++++++++------------
1 file changed, 22 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index c0408c0..8aa7ace 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1386,25 +1386,33 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
dsi->state |= DSIM_STATE_ENABLED;
- ret = drm_panel_prepare(dsi->panel);
- if (ret < 0) {
- dsi->state &= ~DSIM_STATE_ENABLED;
- pm_runtime_put_sync(dsi->dev);
- return;
+ if (dsi->panel) {
+ ret = drm_panel_prepare(dsi->panel);
+ if (ret < 0) {
+ dsi->state &= ~DSIM_STATE_ENABLED;
+ return;
+ }
}
+ if (dsi->out_bridge)
+ drm_bridge_pre_enable(dsi->out_bridge);
+
exynos_dsi_set_display_mode(dsi);
exynos_dsi_set_display_enable(dsi, true);
- ret = drm_panel_enable(dsi->panel);
- if (ret < 0) {
- dsi->state &= ~DSIM_STATE_ENABLED;
- exynos_dsi_set_display_enable(dsi, false);
- drm_panel_unprepare(dsi->panel);
- pm_runtime_put_sync(dsi->dev);
- return;
+ if (dsi->panel) {
+ ret = drm_panel_enable(dsi->panel);
+ if (ret < 0) {
+ dsi->state &= ~DSIM_STATE_ENABLED;
+ exynos_dsi_set_display_enable(dsi, false);
+ drm_panel_unprepare(dsi->panel);
+ return;
+ }
}
+ if (dsi->out_bridge)
+ drm_bridge_enable(dsi->out_bridge);
+
dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
}
@@ -1418,8 +1426,10 @@ static void exynos_dsi_disable(struct drm_encoder *encoder)
dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
drm_panel_disable(dsi->panel);
+ drm_bridge_disable(dsi->out_bridge);
exynos_dsi_set_display_enable(dsi, false);
drm_panel_unprepare(dsi->panel);
+ drm_bridge_post_disable(dsi->out_bridge);
dsi->state &= ~DSIM_STATE_ENABLED;
--
2.7.4
The current implementation assumes that the only possible peripheral
device for DSIM is a panel. Using an output bridge child device
should also be possible.
If an output bridge is available, don't create a new connector.
Instead, call drm_bridge_attach() and set encoder's bridge to NULL
in order to avoid an out bridge from being visible by the framework, as
the DSI bus needs control on enabling its child output bridge.
Such sequence is required by Toshiba TC358764 bridge, which is a DSI
peripheral bridge device.
Signed-off-by: Maciej Purski <[email protected]>
---
drivers/gpu/drm/exynos/exynos_drm_dsi.c | 38 ++++++++++++++++++++++-----------
1 file changed, 25 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 9599e6b..c0408c0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -255,6 +255,7 @@ struct exynos_dsi {
struct mipi_dsi_host dsi_host;
struct drm_connector connector;
struct drm_panel *panel;
+ struct drm_bridge *out_bridge;
struct device *dev;
void __iomem *reg_base;
@@ -1499,7 +1500,30 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct exynos_dsi *dsi = host_to_dsi(host);
- struct drm_device *drm = dsi->connector.dev;
+ struct drm_encoder *encoder = &dsi->encoder;
+ struct drm_device *drm = encoder->dev;
+ struct drm_bridge *out_bridge;
+
+ out_bridge = of_drm_find_bridge(device->dev.of_node);
+ if (out_bridge) {
+ drm_bridge_attach(encoder, out_bridge, NULL);
+ dsi->out_bridge = out_bridge;
+ encoder->bridge = NULL;
+ } else {
+ int ret = exynos_dsi_create_connector(encoder);
+
+ if (ret) {
+ DRM_ERROR("failed to create connector ret = %d\n", ret);
+ drm_encoder_cleanup(encoder);
+ return ret;
+ }
+
+ dsi->panel = of_drm_find_panel(device->dev.of_node);
+ if (dsi->panel) {
+ drm_panel_attach(dsi->panel, &dsi->connector);
+ dsi->connector.status = connector_status_connected;
+ }
+ }
/*
* This is a temporary solution and should be made by more generic way.
@@ -1518,11 +1542,6 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
dsi->lanes = device->lanes;
dsi->format = device->format;
dsi->mode_flags = device->mode_flags;
- dsi->panel = of_drm_find_panel(device->dev.of_node);
- if (dsi->panel) {
- drm_panel_attach(dsi->panel, &dsi->connector);
- dsi->connector.status = connector_status_connected;
- }
exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode =
!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO);
@@ -1654,13 +1673,6 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
if (ret < 0)
return ret;
- ret = exynos_dsi_create_connector(encoder);
- if (ret) {
- DRM_ERROR("failed to create connector ret = %d\n", ret);
- drm_encoder_cleanup(encoder);
- return ret;
- }
-
if (dsi->mic_bridge_node) {
mic_bridge = of_drm_find_bridge(dsi->mic_bridge_node);
if (mic_bridge)
--
2.7.4
From: Andrzej Hajda <[email protected]>
The patch adds bindings to BOE HV070-WSA WSVGA panel.
Bindings are compatible with simple panel bindings.
Signed-off-by: Andrzej Hajda <[email protected]>
Signed-off-by: Maciej Purski <[email protected]>
---
.../bindings/display/panel/boe,hv070wsa-100.txt | 28 ++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt
diff --git a/Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt b/Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt
new file mode 100644
index 0000000..9e8eea8
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt
@@ -0,0 +1,28 @@
+BOE HV070WSA-100 7.01" WSVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "boe,hv070wsa-100"
+- power-supply: regulator to provide the VCC supply voltage (3.3 volts)
+- enable-gpio: GPIO pin to enable and disable panel (active high)
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
+
+The device node can contain one 'port' child node with one child
+'endpoint' node, according to the bindings defined in [1]. This
+node should describe panel's video bus.
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+ panel: panel {
+ compatible = "boe,hv070wsa-100";
+ power-supply = <&vcc_3v3_reg>;
+ enable-gpios = <&gpd1 3 GPIO_ACTIVE_HIGH>;
+ port {
+ panel_ep: endpoint {
+ remote-endpoint = <&bridge_out_ep>;
+ };
+ };
+ };
--
2.7.4
From: Andrzej Hajda <[email protected]>
The patch adds common part of DSI node for Exynos5250 platforms
and a required mipi-phy node.
Signed-off-by: Andrzej Hajda <[email protected]>
Signed-off-by: Maciej Purski <[email protected]>
---
arch/arm/boot/dts/exynos5250.dtsi | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index 2daf505..9965eca 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -733,6 +733,27 @@
#phy-cells = <0>;
};
+ mipi_phy: video-phy@10040710 {
+ compatible = "samsung,s5pv210-mipi-video-phy";
+ reg = <0x10040710 0x100>;
+ #phy-cells = <1>;
+ syscon = <&pmu_system_controller>;
+ };
+
+ dsi_0: dsi@14500000 {
+ compatible = "samsung,exynos4210-mipi-dsi";
+ reg = <0x14500000 0x10000>;
+ interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+ samsung,power-domain = <&pd_disp1>;
+ phys = <&mipi_phy 3>;
+ phy-names = "dsim";
+ clocks = <&clock CLK_DSIM0>, <&clock CLK_SCLK_MIPI1>;
+ clock-names = "bus_clk", "sclk_mipi";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
adc: adc@12d10000 {
compatible = "samsung,exynos-adc-v1";
reg = <0x12D10000 0x100>;
--
2.7.4
From: Andrzej Hajda <[email protected]>
The patch adds bindings to Toshiba DSI/LVDS bridge TC358764.
Bindings describe power supplies, reset gpio and video interfaces.
Signed-off-by: Andrzej Hajda <[email protected]>
Signed-off-by: Maciej Purski <[email protected]>
---
.../bindings/display/bridge/toshiba,tc358764.txt | 35 ++++++++++++++++++++++
1 file changed, 35 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt
diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt
new file mode 100644
index 0000000..8f9abf2
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt
@@ -0,0 +1,35 @@
+TC358764 MIPI-DSI to LVDS panel bridge
+
+Required properties:
+ - compatible: "toshiba,tc358764"
+ - reg: the virtual channel number of a DSI peripheral
+ - vddc-supply: core voltage supply, 1.2V
+ - vddio-supply: I/O voltage supply, 1.8V or 3.3V
+ - vddlvds-supply: LVDS1/2 voltage supply, 3.3V
+ - reset-gpios: a GPIO spec for the reset pin
+
+The device node can contain following 'port' child nodes,
+according to the OF graph bindings defined in [1]:
+ 0: DSI Input, not required, if the bridge is DSI controlled
+ 1: LVDS Output, mandatory
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+ bridge@0 {
+ reg = <0>;
+ compatible = "toshiba,tc358764";
+ vddc-supply = <&vcc_1v2_reg>;
+ vddio-supply = <&vcc_1v8_reg>;
+ vddlvds-supply = <&vcc_3v3_reg>;
+ reset-gpios = <&gpd1 6 GPIO_ACTIVE_LOW>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@1 {
+ reg = <1>;
+ lvds_ep: endpoint {
+ remote-endpoint = <&panel_ep>;
+ };
+ };
+ };
--
2.7.4
From: Andrzej Hajda <[email protected]>
The patch adds support for BOE HV070WSA-100 WSVGA 7.01 inch panel
in panel-simple driver. The panel is used in Exynos5250-arndale boards.
Signed-off-by: Andrzej Hajda <[email protected]>
Signed-off-by: Maciej Purski <[email protected]>
---
drivers/gpu/drm/panel/panel-simple.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index cbf1ab4..d5da58d 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -745,6 +745,28 @@ static const struct panel_desc avic_tm070ddh03 = {
},
};
+static const struct drm_display_mode boe_hv070wsa_mode = {
+ .clock = 40800,
+ .hdisplay = 1024,
+ .hsync_start = 1024 + 90,
+ .hsync_end = 1024 + 90 + 90,
+ .htotal = 1024 + 90 + 90 + 90,
+ .vdisplay = 600,
+ .vsync_start = 600 + 3,
+ .vsync_end = 600 + 3 + 4,
+ .vtotal = 600 + 3 + 4 + 3,
+ .vrefresh = 60,
+};
+
+static const struct panel_desc boe_hv070wsa = {
+ .modes = &boe_hv070wsa_mode,
+ .num_modes = 1,
+ .size = {
+ .width = 154,
+ .height = 90,
+ },
+};
+
static const struct drm_display_mode boe_nv101wxmn51_modes[] = {
{
.clock = 71900,
@@ -2113,6 +2135,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "avic,tm070ddh03",
.data = &avic_tm070ddh03,
}, {
+ .compatible = "boe,hv070wsa-100",
+ .data = &boe_hv070wsa
+ }, {
.compatible = "boe,nv101wxmn51",
.data = &boe_nv101wxmn51,
}, {
--
2.7.4
Hi Andrzej,
I love your patch! Perhaps something to improve:
[auto build test WARNING on v4.18-rc1]
[also build test WARNING on next-20180619]
[cannot apply to drm-exynos/exynos-drm/for-next robh/for-next drm/drm-next]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Maciej-Purski/drm-exynos-rename-bridge_node-to-mic_bridge_node/20180619-175136
coccinelle warnings: (new ones prefixed by >>)
>> drivers/gpu/drm/bridge/tc358764.c:179:60-66: ERROR: application of sizeof to pointer
Please review and possibly fold the followup patch.
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
From: kbuild test robot <[email protected]>
drivers/gpu/drm/bridge/tc358764.c:179:60-66: ERROR: application of sizeof to pointer
sizeof when applied to a pointer typed expression gives the size of
the pointer
Generated by: scripts/coccinelle/misc/noderef.cocci
Fixes: 147fe90c9d51 ("drm/bridge: tc358764: Add DSI to LVDS bridge driver")
CC: Andrzej Hajda <[email protected]>
Signed-off-by: kbuild test robot <[email protected]>
---
tc358764.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/gpu/drm/bridge/tc358764.c
+++ b/drivers/gpu/drm/bridge/tc358764.c
@@ -176,7 +176,8 @@ static int tc358764_read(struct tc358764
ssize_t ret;
cpu_to_le16s(&addr);
- ret = mipi_dsi_generic_read(dsi, &addr, sizeof(addr), val, sizeof(val));
+ ret = mipi_dsi_generic_read(dsi, &addr, sizeof(addr), val,
+ sizeof(*val));
if (ret >= 0)
le32_to_cpus(val);
On Tue, Jun 19, 2018 at 10:19:25AM +0200, Maciej Purski wrote:
> From: Andrzej Hajda <[email protected]>
>
> The patch adds bindings to BOE HV070-WSA WSVGA panel.
> Bindings are compatible with simple panel bindings.
>
> Signed-off-by: Andrzej Hajda <[email protected]>
> Signed-off-by: Maciej Purski <[email protected]>
> ---
> .../bindings/display/panel/boe,hv070wsa-100.txt | 28 ++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt
>
> diff --git a/Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt b/Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt
> new file mode 100644
> index 0000000..9e8eea8
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt
> @@ -0,0 +1,28 @@
> +BOE HV070WSA-100 7.01" WSVGA TFT LCD panel
> +
> +Required properties:
> +- compatible: should be "boe,hv070wsa-100"
> +- power-supply: regulator to provide the VCC supply voltage (3.3 volts)
> +- enable-gpio: GPIO pin to enable and disable panel (active high)
enable-gpios
With that,
Reviewed-by: Rob Herring <[email protected]>
On Tue, Jun 19, 2018 at 10:19:27AM +0200, Maciej Purski wrote:
> From: Andrzej Hajda <[email protected]>
>
> The patch adds bindings to Toshiba DSI/LVDS bridge TC358764.
> Bindings describe power supplies, reset gpio and video interfaces.
>
> Signed-off-by: Andrzej Hajda <[email protected]>
> Signed-off-by: Maciej Purski <[email protected]>
> ---
> .../bindings/display/bridge/toshiba,tc358764.txt | 35 ++++++++++++++++++++++
> 1 file changed, 35 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt
Reviewed-by: Rob Herring <[email protected]>
On Tue, Jun 19, 2018 at 10:19:29AM +0200, Maciej Purski wrote:
> From: Andrzej Hajda <[email protected]>
>
> The patch adds common part of DSI node for Exynos5250 platforms
> and a required mipi-phy node.
>
> Signed-off-by: Andrzej Hajda <[email protected]>
> Signed-off-by: Maciej Purski <[email protected]>
> ---
> arch/arm/boot/dts/exynos5250.dtsi | 21 +++++++++++++++++++++
> 1 file changed, 21 insertions(+)
>
I see that bindings got Rob's ack but kbuild complained about driver
changes so I guess you are going resend everything? I'll wait with
applying these for v4.
Best regards,
Krzysztof
On 19.06.2018 10:19, Maciej Purski wrote:
> From: Andrzej Hajda <[email protected]>
>
> Add a drm_bridge driver for the Toshiba TC358764 DSI to LVDS bridge.
>
> Signed-off-by: Andrzej Hajda <[email protected]>
> Signed-off-by: Maciej Purski <[email protected]>
> ---
> drivers/gpu/drm/bridge/Kconfig | 8 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> drivers/gpu/drm/bridge/tc358764.c | 521 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 530 insertions(+)
> create mode 100644 drivers/gpu/drm/bridge/tc358764.c
>
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index fa2c799..f3da8a7 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -110,6 +110,14 @@ config DRM_THINE_THC63LVD1024
> ---help---
> Thine THC63LVD1024 LVDS/parallel converter driver.
>
> +config DRM_TOSHIBA_TC358764
> + tristate "TC358764 DSI/LVDS bridge"
> + depends on DRM && DRM_PANEL
> + depends on OF
> + select DRM_MIPI_DSI
> + help
> + Toshiba TC358764 DSI/LVDS bridge driver.
> +
> config DRM_TOSHIBA_TC358767
> tristate "Toshiba TC358767 eDP bridge"
> depends on OF
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> index 35f88d4..bf7c0ce 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -10,6 +10,7 @@ obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
> obj-$(CONFIG_DRM_SII902X) += sii902x.o
> obj-$(CONFIG_DRM_SII9234) += sii9234.o
> obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o
> +obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o
> obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
> obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
> obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
> diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c
> new file mode 100644
> index 0000000..0aee155
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/tc358764.c
> @@ -0,0 +1,521 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2018 Samsung Electronics Co., Ltd
> + *
> + * Authors:
> + * Andrzej Hajda <[email protected]>
> + * Maciej Purski <[email protected]>
> + *
> + * 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 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.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.
You should drop license blob if SPDX identifer provided, see for example
drivers/gpu/drm/i915/intel_hdcp.c
> + *
> + */
> +
> +#include <drm/drm_atomic_helper.h>
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_panel.h>
> +
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +
> +#include <linux/gpio/consumer.h>
> +#include <linux/of_graph.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <video/mipi_display.h>
You can order it alphabetically.
> +
> +#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
> +#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
> +
> +/* PPI layer registers */
> +#define PPI_STARTPPI 0x0104 /* START control bit */
> +#define PPI_LPTXTIMECNT 0x0114 /* LPTX timing signal */
> +#define PPI_LANEENABLE 0x0134 /* Enables each lane */
> +#define PPI_TX_RX_TA 0x013C /* BTA timing parameters */
> +#define PPI_D0S_CLRSIPOCOUNT 0x0164 /* Assertion timer for Lane 0 */
> +#define PPI_D1S_CLRSIPOCOUNT 0x0168 /* Assertion timer for Lane 1 */
> +#define PPI_D2S_CLRSIPOCOUNT 0x016C /* Assertion timer for Lane 2 */
> +#define PPI_D3S_CLRSIPOCOUNT 0x0170 /* Assertion timer for Lane 3 */
> +#define PPI_START_FUNCTION 1
> +
> +/* DSI layer registers */
> +#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX */
> +#define DSI_LANEENABLE 0x0210 /* Enables each lane */
> +#define DSI_RX_START 1
> +
> +/* Video path registers */
> +#define VP_CTRL 0x0450 /* Video Path Control */
> +#define VP_CTRL_MSF(v) FLD_VAL(v, 0, 0) /* Magic square in RGB666 */
> +#define VP_CTRL_VTGEN(v) FLD_VAL(v, 4, 4) /* Use chip clock for timing */
> +#define VP_CTRL_EVTMODE(v) FLD_VAL(v, 5, 5) /* Event mode */
> +#define VP_CTRL_RGB888(v) FLD_VAL(v, 8, 8) /* RGB888 mode */
> +#define VP_CTRL_VSDELAY(v) FLD_VAL(v, 31, 20) /* VSYNC delay */
> +#define VP_CTRL_HSPOL BIT(17) /* Polarity of HSYNC signal */
> +#define VP_CTRL_DEPOL BIT(18) /* Polarity of DE signal */
> +#define VP_CTRL_VSPOL BIT(19) /* Polarity of VSYNC signal */
> +#define VP_HTIM1 0x0454 /* Horizontal Timing Control 1 */
> +#define VP_HTIM1_HBP(v) FLD_VAL(v, 24, 16)
> +#define VP_HTIM1_HSYNC(v) FLD_VAL(v, 8, 0)
> +#define VP_HTIM2 0x0458 /* Horizontal Timing Control 2 */
> +#define VP_HTIM2_HFP(v) FLD_VAL(v, 24, 16)
> +#define VP_HTIM2_HACT(v) FLD_VAL(v, 10, 0)
> +#define VP_VTIM1 0x045C /* Vertical Timing Control 1 */
> +#define VP_VTIM1_VBP(v) FLD_VAL(v, 23, 16)
> +#define VP_VTIM1_VSYNC(v) FLD_VAL(v, 7, 0)
> +#define VP_VTIM2 0x0460 /* Vertical Timing Control 2 */
> +#define VP_VTIM2_VFP(v) FLD_VAL(v, 23, 16)
> +#define VP_VTIM2_VACT(v) FLD_VAL(v, 10, 0)
> +#define VP_VFUEN 0x0464 /* Video Frame Timing Update Enable */
> +
> +/* LVDS registers */
> +#define LV_MX0003 0x0480 /* Mux input bit 0 to 3 */
> +#define LV_MX0407 0x0484 /* Mux input bit 4 to 7 */
> +#define LV_MX0811 0x0488 /* Mux input bit 8 to 11 */
> +#define LV_MX1215 0x048C /* Mux input bit 12 to 15 */
> +#define LV_MX1619 0x0490 /* Mux input bit 16 to 19 */
> +#define LV_MX2023 0x0494 /* Mux input bit 20 to 23 */
> +#define LV_MX2427 0x0498 /* Mux input bit 24 to 27 */
> +#define LV_MX(b0, b1, b2, b3) (FLD_VAL(b0, 4, 0) | FLD_VAL(b1, 12, 8) | \
> + FLD_VAL(b2, 20, 16) | FLD_VAL(b3, 28, 24))
> +
> +/* Input bit numbers used in mux registers */
> +enum {
> + LVI_R0,
> + LVI_R1,
> + LVI_R2,
> + LVI_R3,
> + LVI_R4,
> + LVI_R5,
> + LVI_R6,
> + LVI_R7,
> + LVI_G0,
> + LVI_G1,
> + LVI_G2,
> + LVI_G3,
> + LVI_G4,
> + LVI_G5,
> + LVI_G6,
> + LVI_G7,
> + LVI_B0,
> + LVI_B1,
> + LVI_B2,
> + LVI_B3,
> + LVI_B4,
> + LVI_B5,
> + LVI_B6,
> + LVI_B7,
> + LVI_HS,
> + LVI_VS,
> + LVI_DE,
> + LVI_L0
> +};
> +
> +#define LV_CFG 0x049C /* LVDS Configuration */
> +#define LV_PHY0 0x04A0 /* LVDS PHY 0 */
> +#define LV_PHY0_RST(v) FLD_VAL(v, 22, 22) /* PHY reset */
> +#define LV_PHY0_IS(v) FLD_VAL(v, 15, 14)
> +#define LV_PHY0_ND(v) FLD_VAL(v, 4, 0) /* Frequency range select */
> +#define LV_PHY0_PRBS_ON(v) FLD_VAL(v, 20, 16) /* Clock/Data Flag pins */
> +
> +/* System registers */
> +#define SYS_RST 0x0504 /* System Reset */
> +#define SYS_ID 0x0580 /* System ID */
> +
> +#define SYS_RST_I2CS BIT(0) /* Reset I2C-Slave controller */
> +#define SYS_RST_I2CM BIT(1) /* Reset I2C-Master controller */
> +#define SYS_RST_LCD BIT(2) /* Reset LCD controller */
> +#define SYS_RST_BM BIT(3) /* Reset Bus Management controller */
> +#define SYS_RST_DSIRX BIT(4) /* Reset DSI-RX and App controller */
> +#define SYS_RST_REG BIT(5) /* Reset Register module */
> +
> +#define LPX_PERIOD 2
> +#define TTA_SURE 3
> +#define TTA_GET 0x20000
> +
> +/* Lane enable PPI and DSI register bits */
> +#define LANEENABLE_CLEN BIT(0)
> +#define LANEENABLE_L0EN BIT(1)
> +#define LANEENABLE_L1EN BIT(2)
> +#define LANEENABLE_L2EN BIT(3)
> +#define LANEENABLE_L3EN BIT(4)
> +
> +/* LVCFG fields */
> +#define LV_CFG_LVEN BIT(0)
> +#define LV_CFG_LVDLINK BIT(1)
> +#define LV_CFG_CLKPOL1 BIT(2)
> +#define LV_CFG_CLKPOL2 BIT(3)
> +
> +static const char * const tc358764_supplies[] = {
> + "vddc", "vddio", "vddmipi", "vddlvds133", "vddlvds112"
> +};
> +
> +struct tc358764 {
> + struct device *dev;
> + struct drm_bridge bridge;
> + struct drm_connector connector;
> + struct regulator_bulk_data supplies[ARRAY_SIZE(tc358764_supplies)];
> + struct gpio_desc *gpio_reset;
> +
> + struct drm_panel *panel;
> +};
> +
> +static int tc358764_read(struct tc358764 *ctx, u16 addr, u32 *val)
> +{
> + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
> + ssize_t ret;
> +
> + cpu_to_le16s(&addr);
> + ret = mipi_dsi_generic_read(dsi, &addr, sizeof(addr), val, sizeof(val));
As robot complained it should be sizeof(*val).
> + if (ret >= 0)
> + le32_to_cpus(val);
> +
> + dev_dbg(ctx->dev, "read: %d, addr: %d\n", addr, *val);
> +
> + return ret;
> +}
> +
> +static int tc358764_write(struct tc358764 *ctx, u16 addr, u32 val)
> +{
> + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
> + ssize_t ret;
> + u8 data[6];
> +
> + data[0] = addr;
> + data[1] = addr >> 8;
> + data[2] = val;
> + data[3] = val >> 8;
> + data[4] = val >> 16;
> + data[5] = val >> 24;
> +
> + ret = mipi_dsi_generic_write(dsi, data, sizeof(data));
> +
> + return ret;
> +}
> +
> +static inline struct tc358764 *bridge_to_tc358764(struct drm_bridge *bridge)
> +{
> + return container_of(bridge, struct tc358764, bridge);
> +}
> +
> +static inline
> +struct tc358764 *connector_to_tc358764(struct drm_connector *connector)
> +{
> + return container_of(connector, struct tc358764, connector);
> +}
> +
> +static int tc358764_init(struct tc358764 *ctx)
> +{
> + u32 v = 0;
> +
> + tc358764_read(ctx, SYS_ID, &v);
There is no error handling, here and below.
> + dev_info(ctx->dev, "ID: %#x\n", v);
> +
> + /* configure PPI counters */
> + tc358764_write(ctx, PPI_TX_RX_TA, TTA_GET | TTA_SURE);
> + tc358764_write(ctx, PPI_LPTXTIMECNT, LPX_PERIOD);
> + tc358764_write(ctx, PPI_D0S_CLRSIPOCOUNT, 5);
> + tc358764_write(ctx, PPI_D1S_CLRSIPOCOUNT, 5);
> + tc358764_write(ctx, PPI_D2S_CLRSIPOCOUNT, 5);
> + tc358764_write(ctx, PPI_D3S_CLRSIPOCOUNT, 5);
> +
> + /* enable four data lanes and clock lane */
> + tc358764_write(ctx, PPI_LANEENABLE, LANEENABLE_L3EN | LANEENABLE_L2EN |
> + LANEENABLE_L1EN | LANEENABLE_L0EN | LANEENABLE_CLEN);
> + tc358764_write(ctx, DSI_LANEENABLE, LANEENABLE_L3EN | LANEENABLE_L2EN |
> + LANEENABLE_L1EN | LANEENABLE_L0EN | LANEENABLE_CLEN);
> +
> + /* start */
> + tc358764_write(ctx, PPI_STARTPPI, PPI_START_FUNCTION);
> + tc358764_write(ctx, DSI_STARTDSI, DSI_RX_START);
> +
> + /* configure video path */
> + tc358764_write(ctx, VP_CTRL, VP_CTRL_VSDELAY(15) | VP_CTRL_RGB888(1) |
> + VP_CTRL_EVTMODE(1) | VP_CTRL_HSPOL | VP_CTRL_VSPOL);
> +
> + /* reset PHY */
> + tc358764_write(ctx, LV_PHY0, LV_PHY0_RST(1) |
> + LV_PHY0_PRBS_ON(4) | LV_PHY0_IS(2) | LV_PHY0_ND(6));
> + tc358764_write(ctx, LV_PHY0, LV_PHY0_PRBS_ON(4) | LV_PHY0_IS(2) |
> + LV_PHY0_ND(6));
> +
> + /* reset bridge */
> + tc358764_write(ctx, SYS_RST, SYS_RST_LCD);
> +
> + /* set bit order */
> + tc358764_write(ctx, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3));
> + tc358764_write(ctx, LV_MX0407, LV_MX(LVI_R4, LVI_R7, LVI_R5, LVI_G0));
> + tc358764_write(ctx, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_G6, LVI_G7));
> + tc358764_write(ctx, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0));
> + tc358764_write(ctx, LV_MX1619, LV_MX(LVI_B6, LVI_B7, LVI_B1, LVI_B2));
> + tc358764_write(ctx, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0));
> + tc358764_write(ctx, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R6));
> + tc358764_write(ctx, LV_CFG, LV_CFG_CLKPOL2 | LV_CFG_CLKPOL1 |
> + LV_CFG_LVEN);
> +
> + return 0;
> +}
> +
> +static void tc358764_reset(struct tc358764 *ctx)
> +{
> + msleep(20);
> + gpiod_set_value(ctx->gpio_reset, 0);
> + msleep(20);
> + gpiod_set_value(ctx->gpio_reset, 1);
> + msleep(40);
> +}
> +
> +static void tc358764_poweroff(struct tc358764 *ctx)
> +{
> + int ret;
> +
> + tc358764_reset(ctx);
> +
> + drm_panel_disable(ctx->panel);
I do not see drm_panel_unprepare, it should be called from post_disable
callback.
> + msleep(40);
> +
> + ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> + if (ret < 0)
> + dev_err(ctx->dev, "error disabling regulators (%d)\n", ret);
> +}
> +
> +static int tc358764_get_modes(struct drm_connector *connector)
> +{
> + struct tc358764 *ctx = connector_to_tc358764(connector);
> +
> + if (ctx->panel && ctx->panel->funcs && ctx->panel->funcs->get_modes)
> + return ctx->panel->funcs->get_modes(ctx->panel);
drm_panel_get_modes
> +
> + return 0;
> +}
> +
> +static const
> +struct drm_connector_helper_funcs tc358764_connector_helper_funcs = {
> + .get_modes = tc358764_get_modes,
> +};
> +
> +static const struct drm_connector_funcs tc358764_connector_funcs = {
> + .fill_modes = drm_helper_probe_single_connector_modes,
> + .destroy = drm_connector_cleanup,
> + .reset = drm_atomic_helper_connector_reset,
> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static void tc358764_disable(struct drm_bridge *bridge)
> +{
> + struct tc358764 *ctx = bridge_to_tc358764(bridge);
> +
> + tc358764_poweroff(ctx);
> +}
> +
> +static void tc358764_pre_enable(struct drm_bridge *bridge)
> +{
> + struct tc358764 *ctx = bridge_to_tc358764(bridge);
> + int ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies),
> + ctx->supplies);
> + if (ret < 0)
> + dev_err(ctx->dev, "error enabling regulators (%d)\n", ret);
> +
> + tc358764_reset(ctx);
> + tc358764_init(ctx);
> +}
> +
> +static void tc358764_enable(struct drm_bridge *bridge)
> +{
> + struct tc358764 *ctx = bridge_to_tc358764(bridge);
> + int ret;
> +
> + drm_panel_prepare(ctx->panel);
drm_panel_prepare should be called from pre_enable.
> +
> + ret = drm_panel_enable(ctx->panel);
> + if (ret < 0)
> + pr_err("panel enable failed\n");
> +
> + msleep(40);
> +}
> +
> +static int tc358764_attach(struct drm_bridge *bridge)
> +{
> + struct tc358764 *ctx = bridge_to_tc358764(bridge);
> + struct drm_device *drm = bridge->dev;
> + int ret;
> +
> + if (!bridge->encoder) {
> + DRM_ERROR("Encoder not found\n");
> + return -ENODEV;
> + }
> +
> + ctx->connector.polled = DRM_CONNECTOR_POLL_HPD;
> + ret = drm_connector_init(drm, &ctx->connector,
> + &tc358764_connector_funcs,
> + DRM_MODE_CONNECTOR_LVDS);
> + if (ret) {
> + DRM_ERROR("Failed to initialize connector\n");
> + return ret;
> + }
> +
> + drm_connector_helper_add(&ctx->connector,
> + &tc358764_connector_helper_funcs);
> +
> + drm_mode_connector_attach_encoder(&ctx->connector, bridge->encoder);
> +
> + if (ctx->panel)
> + drm_panel_attach(ctx->panel, &ctx->connector);
Could ctx->panel be NULL here?
> +
> + drm_atomic_helper_connector_reset(&ctx->connector);
> + drm_connector_register(&ctx->connector);
> +
> + return 0;
> +}
> +
> +static const struct drm_bridge_funcs tc358764_bridge_funcs = {
> + .disable = tc358764_disable,
> + .enable = tc358764_enable,
> + .pre_enable = tc358764_pre_enable,
> + .attach = tc358764_attach,
> +};
> +
> +static struct device_node *tc358764_of_find_panel_node(struct device *dev)
> +{
> + struct device_node *np, *ep;
> +
> + ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);
> + if (!ep) {
> + pr_err("failed to get endpoint\n");
> + return NULL;
> + }
> +
> + np = of_graph_get_remote_port_parent(ep);
> +
> + return np;
> +}
There is already helper for it.
> +
> +static int tc358764_parse_dt(struct tc358764 *ctx)
> +{
> + struct device *dev = ctx->dev;
> + struct device_node *np = dev->of_node;
> + struct device_node *lvds;
> +
> + ctx->gpio_reset = devm_gpiod_get_from_of_node(dev, np, "reset", 0,
> + GPIOD_OUT_LOW,
> + "tc358764-reset");
> + if (IS_ERR(ctx->gpio_reset)) {
> + dev_err(dev, "no reset GPIO pin provided\n");
> + return PTR_ERR(ctx->gpio_reset);
> + }
> +
> + lvds = tc358764_of_find_panel_node(ctx->dev);
> + if (!lvds) {
> + dev_err(dev, "cannot find panel node\n");
> + return -EINVAL;
> + }
> +
> + ctx->panel = of_drm_find_panel(lvds);
Or even for it: drm_of_find_panel_or_bridge.
> + if (!ctx->panel) {
> + dev_err(dev, "panel not registered\n");
> + return -EPROBE_DEFER;
> + }
> +
> + return 0;
> +}
> +
> +static int tc358764_configure_regulators(struct tc358764 *ctx)
> +{
> + int i, ret;
> +
> + for (i = 0; i < ARRAY_SIZE(ctx->supplies); ++i)
> + ctx->supplies[i].supply = tc358764_supplies[i];
> +
> + ret = devm_regulator_bulk_get(ctx->dev, ARRAY_SIZE(ctx->supplies),
> + ctx->supplies);
> + if (ret < 0)
> + dev_err(ctx->dev, "failed to get regulators: %d\n", ret);
> +
> + return ret;
> +}
> +
> +static int tc358764_probe(struct mipi_dsi_device *dsi)
> +{
> + struct device *dev = &dsi->dev;
> + struct tc358764 *ctx;
> + int ret;
> +
> + ctx = devm_kzalloc(dev, sizeof(struct tc358764), GFP_KERNEL);
> + if (!ctx)
> + return -ENOMEM;
> +
> + mipi_dsi_set_drvdata(dsi, ctx);
> +
> + ctx->dev = dev;
> +
> + dsi->lanes = 4;
> + dsi->format = MIPI_DSI_FMT_RGB888;
> + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST
> + | MIPI_DSI_MODE_VIDEO_AUTO_VERT | MIPI_DSI_MODE_LPM;
> +
> + ret = tc358764_parse_dt(ctx);
> + if (ret < 0)
> + return ret;
> +
> + ret = tc358764_configure_regulators(ctx);
> + if (ret < 0)
> + return ret;
> +
> + ctx->bridge.funcs = &tc358764_bridge_funcs;
> + ctx->bridge.of_node = dev->of_node;
> +
> + drm_bridge_add(&ctx->bridge);
> +
> + ret = mipi_dsi_attach(dsi);
> + if (ret < 0) {
> + drm_bridge_remove(&ctx->bridge);
> + dev_err(dev, "failed to attach dsi\n");
> + }
> +
> + return ret;
> +}
> +
> +static int tc358764_remove(struct mipi_dsi_device *dsi)
> +{
> + struct tc358764 *ctx = mipi_dsi_get_drvdata(dsi);
> +
> + tc358764_poweroff(ctx);
It should be dropped, dsi host will do it properly if neccesary from the
call below.
Regards
Andrzej
> +
> + mipi_dsi_detach(dsi);
> + drm_bridge_remove(&ctx->bridge);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id tc358764_of_match[] = {
> + { .compatible = "toshiba,tc358764" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, tc358764_of_match);
> +
> +static struct mipi_dsi_driver tc358764_driver = {
> + .probe = tc358764_probe,
> + .remove = tc358764_remove,
> + .driver = {
> + .name = "tc358764",
> + .owner = THIS_MODULE,
> + .of_match_table = tc358764_of_match,
> + },
> +};
> +module_mipi_dsi_driver(tc358764_driver);
> +
> +MODULE_AUTHOR("Andrzej Hajda <[email protected]>");
> +MODULE_AUTHOR("Maciej Purski <[email protected]>");
> +MODULE_DESCRIPTION("MIPI-DSI based Driver for TC358764 DSI/LVDS Bridge");
> +MODULE_LICENSE("GPL v2");
On Tue, Jun 19, 2018 at 10:19:25AM +0200, Maciej Purski wrote:
> From: Andrzej Hajda <[email protected]>
>
> The patch adds bindings to BOE HV070-WSA WSVGA panel.
> Bindings are compatible with simple panel bindings.
>
> Signed-off-by: Andrzej Hajda <[email protected]>
> Signed-off-by: Maciej Purski <[email protected]>
> ---
> .../bindings/display/panel/boe,hv070wsa-100.txt | 28 ++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt
Applied with the fix as requested by Rob.
Thierry
On Tue, Jun 19, 2018 at 10:19:26AM +0200, Maciej Purski wrote:
> From: Andrzej Hajda <[email protected]>
>
> The patch adds support for BOE HV070WSA-100 WSVGA 7.01 inch panel
> in panel-simple driver. The panel is used in Exynos5250-arndale boards.
>
> Signed-off-by: Andrzej Hajda <[email protected]>
> Signed-off-by: Maciej Purski <[email protected]>
> ---
> drivers/gpu/drm/panel/panel-simple.c | 25 +++++++++++++++++++++++++
> 1 file changed, 25 insertions(+)
Applied, thanks.
Thierry
Hi,
2018년 06월 19일 17:19에 Maciej Purski 이(가) 쓴 글:
> When adding support for peripheral out bridges, the "bridge" name
> becomes imprecise as it refers to a different device than the
> "out_bridge".
Could you give me more details? I'm afriad that I don't understand what you say.
And in case of Exynos5433 SoC, SMIES(Samsung Mobile Image Enhancement System) can be located between DECON and MIPI-DSI devices also.
Therefore, having specific name isn't reasonable.
Thanks,
Inki Dae
>
> Signed-off-by: Maciej Purski <[email protected]>
> ---
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 16 ++++++++--------
> 1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index eae44fd..9599e6b 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -279,7 +279,7 @@ struct exynos_dsi {
> struct list_head transfer_list;
>
> const struct exynos_dsi_driver_data *driver_data;
> - struct device_node *bridge_node;
> + struct device_node *mic_bridge_node;
> };
>
> #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
> @@ -1631,7 +1631,7 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
> if (ret < 0)
> return ret;
>
> - dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
> + dsi->mic_bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
>
> return 0;
> }
> @@ -1642,7 +1642,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
> struct drm_encoder *encoder = dev_get_drvdata(dev);
> struct exynos_dsi *dsi = encoder_to_dsi(encoder);
> struct drm_device *drm_dev = data;
> - struct drm_bridge *bridge;
> + struct drm_bridge *mic_bridge;
> int ret;
>
> drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs,
> @@ -1661,10 +1661,10 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
> return ret;
> }
>
> - if (dsi->bridge_node) {
> - bridge = of_drm_find_bridge(dsi->bridge_node);
> - if (bridge)
> - drm_bridge_attach(encoder, bridge, NULL);
> + if (dsi->mic_bridge_node) {
> + mic_bridge = of_drm_find_bridge(dsi->mic_bridge_node);
> + if (mic_bridge)
> + drm_bridge_attach(encoder, mic_bridge, NULL);
> }
>
> return mipi_dsi_host_register(&dsi->dsi_host);
> @@ -1783,7 +1783,7 @@ static int exynos_dsi_remove(struct platform_device *pdev)
> {
> struct exynos_dsi *dsi = platform_get_drvdata(pdev);
>
> - of_node_put(dsi->bridge_node);
> + of_node_put(dsi->mic_bridge_node);
>
> pm_runtime_disable(&pdev->dev);
>
>
Hi,
2018년 06월 19일 17:19에 Maciej Purski 이(가) 쓴 글:
> As the out bridge will not be enabled directly by the framework,
> it should be enabled by DSI. Exynos_dsi_enable() should handle a case,
> when there is an out_bridge connected as a DSI peripheral.
>
> Signed-off-by: Maciej Purski <[email protected]>
> ---
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 34 +++++++++++++++++++++------------
> 1 file changed, 22 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index c0408c0..8aa7ace 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1386,25 +1386,33 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
>
> dsi->state |= DSIM_STATE_ENABLED;
>
> - ret = drm_panel_prepare(dsi->panel);
> - if (ret < 0) {
> - dsi->state &= ~DSIM_STATE_ENABLED;
> - pm_runtime_put_sync(dsi->dev);
> - return;
> + if (dsi->panel) {
> + ret = drm_panel_prepare(dsi->panel);
> + if (ret < 0) {
> + dsi->state &= ~DSIM_STATE_ENABLED;
Why did you remove pm_runtime_put_sync call?
> + return;
> + }
> }
>
> + if (dsi->out_bridge)
> + drm_bridge_pre_enable(dsi->out_bridge);
> +
> exynos_dsi_set_display_mode(dsi);
> exynos_dsi_set_display_enable(dsi, true);
>
> - ret = drm_panel_enable(dsi->panel);
> - if (ret < 0) {
> - dsi->state &= ~DSIM_STATE_ENABLED;
> - exynos_dsi_set_display_enable(dsi, false);
> - drm_panel_unprepare(dsi->panel);
> - pm_runtime_put_sync(dsi->dev);
> - return;
> + if (dsi->panel) {
> + ret = drm_panel_enable(dsi->panel);
> + if (ret < 0) {
> + dsi->state &= ~DSIM_STATE_ENABLED;
> + exynos_dsi_set_display_enable(dsi, false);
> + drm_panel_unprepare(dsi->panel);
Ditto.
Thanks,
Inki Dae
> + return;
> + }
> }
>
> + if (dsi->out_bridge)
> + drm_bridge_enable(dsi->out_bridge);
> +
> dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
> }
>
> @@ -1418,8 +1426,10 @@ static void exynos_dsi_disable(struct drm_encoder *encoder)
> dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
>
> drm_panel_disable(dsi->panel);
> + drm_bridge_disable(dsi->out_bridge);
> exynos_dsi_set_display_enable(dsi, false);
> drm_panel_unprepare(dsi->panel);
> + drm_bridge_post_disable(dsi->out_bridge);
>
> dsi->state &= ~DSIM_STATE_ENABLED;
>
>
Hi,
2018년 06월 19일 17:19에 Maciej Purski 이(가) 쓴 글:
> The current implementation assumes that the only possible peripheral
> device for DSIM is a panel. Using an output bridge child device
> should also be possible.
>
> If an output bridge is available, don't create a new connector.
> Instead, call drm_bridge_attach() and set encoder's bridge to NULL
> in order to avoid an out bridge from being visible by the framework, as
> the DSI bus needs control on enabling its child output bridge.
>
> Such sequence is required by Toshiba TC358764 bridge, which is a DSI
> peripheral bridge device.
Right, we should consider DSI to LVDS bridge.
Thanks,
Inki Dae
>
> Signed-off-by: Maciej Purski <[email protected]>
> ---
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 38 ++++++++++++++++++++++-----------
> 1 file changed, 25 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index 9599e6b..c0408c0 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -255,6 +255,7 @@ struct exynos_dsi {
> struct mipi_dsi_host dsi_host;
> struct drm_connector connector;
> struct drm_panel *panel;
> + struct drm_bridge *out_bridge;
> struct device *dev;
>
> void __iomem *reg_base;
> @@ -1499,7 +1500,30 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
> struct mipi_dsi_device *device)
> {
> struct exynos_dsi *dsi = host_to_dsi(host);
> - struct drm_device *drm = dsi->connector.dev;
> + struct drm_encoder *encoder = &dsi->encoder;
> + struct drm_device *drm = encoder->dev;
> + struct drm_bridge *out_bridge;
> +
> + out_bridge = of_drm_find_bridge(device->dev.of_node);
> + if (out_bridge) {
> + drm_bridge_attach(encoder, out_bridge, NULL);
> + dsi->out_bridge = out_bridge;
> + encoder->bridge = NULL;
> + } else {
> + int ret = exynos_dsi_create_connector(encoder);
> +
> + if (ret) {
> + DRM_ERROR("failed to create connector ret = %d\n", ret);
> + drm_encoder_cleanup(encoder);
> + return ret;
> + }
> +
> + dsi->panel = of_drm_find_panel(device->dev.of_node);
> + if (dsi->panel) {
> + drm_panel_attach(dsi->panel, &dsi->connector);
> + dsi->connector.status = connector_status_connected;
> + }
> + }
>
> /*
> * This is a temporary solution and should be made by more generic way.
> @@ -1518,11 +1542,6 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
> dsi->lanes = device->lanes;
> dsi->format = device->format;
> dsi->mode_flags = device->mode_flags;
> - dsi->panel = of_drm_find_panel(device->dev.of_node);
> - if (dsi->panel) {
> - drm_panel_attach(dsi->panel, &dsi->connector);
> - dsi->connector.status = connector_status_connected;
> - }
> exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode =
> !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO);
>
> @@ -1654,13 +1673,6 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
> if (ret < 0)
> return ret;
>
> - ret = exynos_dsi_create_connector(encoder);
> - if (ret) {
> - DRM_ERROR("failed to create connector ret = %d\n", ret);
> - drm_encoder_cleanup(encoder);
> - return ret;
> - }
> -
> if (dsi->mic_bridge_node) {
> mic_bridge = of_drm_find_bridge(dsi->mic_bridge_node);
> if (mic_bridge)
>
2018년 07월 24일 17:04에 Inki Dae 이(가) 쓴 글:
> Hi,
>
> 2018년 06월 19일 17:19에 Maciej Purski 이(가) 쓴 글:
>> The current implementation assumes that the only possible peripheral
>> device for DSIM is a panel. Using an output bridge child device
>> should also be possible.
>>
>> If an output bridge is available, don't create a new connector.
>> Instead, call drm_bridge_attach() and set encoder's bridge to NULL
>> in order to avoid an out bridge from being visible by the framework, as
>> the DSI bus needs control on enabling its child output bridge.
>>
>> Such sequence is required by Toshiba TC358764 bridge, which is a DSI
>> peripheral bridge device.
>
> Right, we should consider DSI to LVDS bridge.
In addition, could you update below binding document?
Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt
Thanks,
Inki Dae
>
> Thanks,
> Inki Dae
>
>>
>> Signed-off-by: Maciej Purski <[email protected]>
>> ---
>> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 38 ++++++++++++++++++++++-----------
>> 1 file changed, 25 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>> index 9599e6b..c0408c0 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>> @@ -255,6 +255,7 @@ struct exynos_dsi {
>> struct mipi_dsi_host dsi_host;
>> struct drm_connector connector;
>> struct drm_panel *panel;
>> + struct drm_bridge *out_bridge;
>> struct device *dev;
>>
>> void __iomem *reg_base;
>> @@ -1499,7 +1500,30 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
>> struct mipi_dsi_device *device)
>> {
>> struct exynos_dsi *dsi = host_to_dsi(host);
>> - struct drm_device *drm = dsi->connector.dev;
>> + struct drm_encoder *encoder = &dsi->encoder;
>> + struct drm_device *drm = encoder->dev;
>> + struct drm_bridge *out_bridge;
>> +
>> + out_bridge = of_drm_find_bridge(device->dev.of_node);
>> + if (out_bridge) {
>> + drm_bridge_attach(encoder, out_bridge, NULL);
>> + dsi->out_bridge = out_bridge;
>> + encoder->bridge = NULL;
>> + } else {
>> + int ret = exynos_dsi_create_connector(encoder);
>> +
>> + if (ret) {
>> + DRM_ERROR("failed to create connector ret = %d\n", ret);
>> + drm_encoder_cleanup(encoder);
>> + return ret;
>> + }
>> +
>> + dsi->panel = of_drm_find_panel(device->dev.of_node);
>> + if (dsi->panel) {
>> + drm_panel_attach(dsi->panel, &dsi->connector);
>> + dsi->connector.status = connector_status_connected;
>> + }
>> + }
>>
>> /*
>> * This is a temporary solution and should be made by more generic way.
>> @@ -1518,11 +1542,6 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
>> dsi->lanes = device->lanes;
>> dsi->format = device->format;
>> dsi->mode_flags = device->mode_flags;
>> - dsi->panel = of_drm_find_panel(device->dev.of_node);
>> - if (dsi->panel) {
>> - drm_panel_attach(dsi->panel, &dsi->connector);
>> - dsi->connector.status = connector_status_connected;
>> - }
>> exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode =
>> !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO);
>>
>> @@ -1654,13 +1673,6 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
>> if (ret < 0)
>> return ret;
>>
>> - ret = exynos_dsi_create_connector(encoder);
>> - if (ret) {
>> - DRM_ERROR("failed to create connector ret = %d\n", ret);
>> - drm_encoder_cleanup(encoder);
>> - return ret;
>> - }
>> -
>> if (dsi->mic_bridge_node) {
>> mic_bridge = of_drm_find_bridge(dsi->mic_bridge_node);
>> if (mic_bridge)
>>
On 24.07.2018 09:49, Inki Dae wrote:
> Hi,
>
> 2018년 06월 19일 17:19에 Maciej Purski 이(가) 쓴 글:
>> When adding support for peripheral out bridges, the "bridge" name
>> becomes imprecise as it refers to a different device than the
>> "out_bridge".
> Could you give me more details? I'm afriad that I don't understand what you say.
The problem is that MIC is an input bridge and now we will have also
output bridge (Toshiba DSI/LVDS converter).
So we will have to distinguish them.
>
> And in case of Exynos5433 SoC, SMIES(Samsung Mobile Image Enhancement System) can be located between DECON and MIPI-DSI devices also.
> Therefore, having specific name isn't reasonable.
So probably in_bridge would be a better name. I will rephrase message
and bridge name.
Regars
Andrzej
>
> Thanks,
> Inki Dae
>
>> Signed-off-by: Maciej Purski <[email protected]>
>> ---
>> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 16 ++++++++--------
>> 1 file changed, 8 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>> index eae44fd..9599e6b 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>> @@ -279,7 +279,7 @@ struct exynos_dsi {
>> struct list_head transfer_list;
>>
>> const struct exynos_dsi_driver_data *driver_data;
>> - struct device_node *bridge_node;
>> + struct device_node *mic_bridge_node;
>> };
>>
>> #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
>> @@ -1631,7 +1631,7 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
>> if (ret < 0)
>> return ret;
>>
>> - dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
>> + dsi->mic_bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
>>
>> return 0;
>> }
>> @@ -1642,7 +1642,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
>> struct drm_encoder *encoder = dev_get_drvdata(dev);
>> struct exynos_dsi *dsi = encoder_to_dsi(encoder);
>> struct drm_device *drm_dev = data;
>> - struct drm_bridge *bridge;
>> + struct drm_bridge *mic_bridge;
>> int ret;
>>
>> drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs,
>> @@ -1661,10 +1661,10 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
>> return ret;
>> }
>>
>> - if (dsi->bridge_node) {
>> - bridge = of_drm_find_bridge(dsi->bridge_node);
>> - if (bridge)
>> - drm_bridge_attach(encoder, bridge, NULL);
>> + if (dsi->mic_bridge_node) {
>> + mic_bridge = of_drm_find_bridge(dsi->mic_bridge_node);
>> + if (mic_bridge)
>> + drm_bridge_attach(encoder, mic_bridge, NULL);
>> }
>>
>> return mipi_dsi_host_register(&dsi->dsi_host);
>> @@ -1783,7 +1783,7 @@ static int exynos_dsi_remove(struct platform_device *pdev)
>> {
>> struct exynos_dsi *dsi = platform_get_drvdata(pdev);
>>
>> - of_node_put(dsi->bridge_node);
>> + of_node_put(dsi->mic_bridge_node);
>>
>> pm_runtime_disable(&pdev->dev);
>>
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
2018년 07월 25일 17:11에 Andrzej Hajda 이(가) 쓴 글:
> On 24.07.2018 09:49, Inki Dae wrote:
>> Hi,
>>
>> 2018년 06월 19일 17:19에 Maciej Purski 이(가) 쓴 글:
>>> When adding support for peripheral out bridges, the "bridge" name
>>> becomes imprecise as it refers to a different device than the
>>> "out_bridge".
>> Could you give me more details? I'm afriad that I don't understand what you say.
>
> The problem is that MIC is an input bridge and now we will have also
> output bridge (Toshiba DSI/LVDS converter).
> So we will have to distinguish them.
>
>>
>> And in case of Exynos5433 SoC, SMIES(Samsung Mobile Image Enhancement System) can be located between DECON and MIPI-DSI devices also.
>> Therefore, having specific name isn't reasonable.
>
> So probably in_bridge would be a better name. I will rephrase message
> and bridge name.
Good idea. :)
Thanks,
Inki Dae
>
> Regars
> Andrzej
>
>
>>
>> Thanks,
>> Inki Dae
>>
>>> Signed-off-by: Maciej Purski <[email protected]>
>>> ---
>>> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 16 ++++++++--------
>>> 1 file changed, 8 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>>> index eae44fd..9599e6b 100644
>>> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>>> @@ -279,7 +279,7 @@ struct exynos_dsi {
>>> struct list_head transfer_list;
>>>
>>> const struct exynos_dsi_driver_data *driver_data;
>>> - struct device_node *bridge_node;
>>> + struct device_node *mic_bridge_node;
>>> };
>>>
>>> #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
>>> @@ -1631,7 +1631,7 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
>>> if (ret < 0)
>>> return ret;
>>>
>>> - dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
>>> + dsi->mic_bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
>>>
>>> return 0;
>>> }
>>> @@ -1642,7 +1642,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
>>> struct drm_encoder *encoder = dev_get_drvdata(dev);
>>> struct exynos_dsi *dsi = encoder_to_dsi(encoder);
>>> struct drm_device *drm_dev = data;
>>> - struct drm_bridge *bridge;
>>> + struct drm_bridge *mic_bridge;
>>> int ret;
>>>
>>> drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs,
>>> @@ -1661,10 +1661,10 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
>>> return ret;
>>> }
>>>
>>> - if (dsi->bridge_node) {
>>> - bridge = of_drm_find_bridge(dsi->bridge_node);
>>> - if (bridge)
>>> - drm_bridge_attach(encoder, bridge, NULL);
>>> + if (dsi->mic_bridge_node) {
>>> + mic_bridge = of_drm_find_bridge(dsi->mic_bridge_node);
>>> + if (mic_bridge)
>>> + drm_bridge_attach(encoder, mic_bridge, NULL);
>>> }
>>>
>>> return mipi_dsi_host_register(&dsi->dsi_host);
>>> @@ -1783,7 +1783,7 @@ static int exynos_dsi_remove(struct platform_device *pdev)
>>> {
>>> struct exynos_dsi *dsi = platform_get_drvdata(pdev);
>>>
>>> - of_node_put(dsi->bridge_node);
>>> + of_node_put(dsi->mic_bridge_node);
>>>
>>> pm_runtime_disable(&pdev->dev);
>>>
>>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>