All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V9 00/14] drm/exynos: few patches to enhance bridge chip support
@ 2015-01-20 16:38 ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree
  Cc: kgene.kim, inki.dae, thierry.reding, daniel.vetter, seanpaul,
	ajaynumb, jg1.han, bhushan.r, prashanth.g, Ajay Kumar

This series is based on v3.19-rc5 tag of Linux-next tree at:
git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git

Changes since V2:
	-- Address comments from Jingoo Han for ps8622 driver
	-- Address comments from Daniel, Rob and Thierry regarding
	   bridge chaining
	-- Address comments from Thierry regarding the names for
	   new drm_panel functions

Changes since V3:
	-- Remove hotplug based initialization of exynos_dp
	-- Make exynos_dp work directly with drm_panel, remove
	   dependency on panel_binder
	-- Minor cleanups in panel_binder and panel_lvds driver

Changes since V4:
	-- Use gpiod interface for panel-lvds and ps8622 drivers.
	-- Address comments from Javier.
	-- Fix compilation issues when PANEL_BINDER is selected as module.
	-- Split Documentation patches from driver patches.
	-- Rebase on top of the tree.

Changes since V5:
	-- Modify bridge drivers to support driver model.
	-- Drop the concept of bridge chain(sincle there are no 2 real bridges)
	   Hence drop bridge-panel_binder layer.
	-- Drop panel-lvds driver and accomadate the required changes in
	   panel-simple driver.
	-- Use gpiod interface in ptn3460 driver.
	-- Address all comments by Thierry Reding for V5 series.
	-- Address comments from Sean Paul for exynos_dp_commit issue.

Changes since V6:
	-- Panel patches were separated and they are merged already.
	-- Fix few issues with ptn3460, before modifying the bridge core.
	-- Modify drm_bridge as per Thierry's comments for V6 series.
	-- Add drm_bridge changes minimally without breaking existing code.
	-- Add new features for ptn3460, step-by-step.
	-- Address comments from Thierry and Andreas for ptn3460 and ps8622.
	-- Split documentation patches from driver patches.

Changes since V7:
	-- Address comments from Tomi and Laurent:
		-- Use videoports and endpoints to represent the connection between
		   encoder, bridge and the panel, instead of using phandles.
	-- Address comments from Daniel:
		-- Make the patch description more descriptive.
		-- remove device pointer from drm_bridge, and just use
		   device_node instead.
		-- don't pass encoder pointer to bridge_attach.
	-- Address comments from Sean Paul:
		-- Remove bridge from mode_config, and pull out drm_bridge
		   functions from drm_crtc.c to drm_bridge.c

Changes since V8:
	-- Rebase on top of linux-next v3.19-rc5.
	-- Add Acked-by and Tested-by tags.

Ajay Kumar (13):
  [PATCH V9 1/14] drm/bridge: ptn3460: Few trivial cleanups
  [PATCH V9 2/14] drm/bridge: do not pass drm_bridge_funcs to drm_bridge_init
  [PATCH V9 3/14] drm/bridge: make bridge registration independent of drm flow
  [PATCH V9 4/14] drm/bridge: ptn3460: Convert to i2c driver model
  [PATCH V9 5/14] drm/exynos: dp: support drm_bridge
  [PATCH V9 6/14] drm/bridge: ptn3460: support drm_panel
  [PATCH V9 7/14] drm/bridge: ptn3460: probe connector at the end of bridge attach
  [PATCH V9 8/14] drm/bridge: ptn3460: use gpiod interface
  [PATCH V9 9/14] Documentation: drm: bridge: move to video/bridge
  [PATCH V9 10/14] Documentation: devicetree: Add vendor prefix for parade
  [PATCH V9 11/14] Documentation: bridge: Add documentation for ps8622 DT properties
  [PATCH V9 13/14] ARM: dts: snow: represent the connection between bridge and panel
    using videoport and endpoints
  [PATCH V9 14/14] ARM: dts: peach-pit: represent the connection between bridge and
    panel using videoport and endpoints

Vincent Palatin (1):
  [PATCH V9 12/14] drm/bridge: Add i2c based driver for ps8622/ps8625 bridge

 .../devicetree/bindings/drm/bridge/ptn3460.txt     |   27 -
 .../devicetree/bindings/vendor-prefixes.txt        |    1 +
 .../devicetree/bindings/video/bridge/ps8622.txt    |   31 +
 .../devicetree/bindings/video/bridge/ptn3460.txt   |   39 ++
 .../devicetree/bindings/video/exynos_dp.txt        |   12 +
 arch/arm/boot/dts/exynos5250-snow.dts              |   30 +-
 arch/arm/boot/dts/exynos5420-peach-pit.dts         |   31 +-
 drivers/gpu/drm/Makefile                           |    2 +-
 drivers/gpu/drm/bridge/Kconfig                     |   12 +
 drivers/gpu/drm/bridge/Makefile                    |    1 +
 drivers/gpu/drm/bridge/ps8622.c                    |  684 ++++++++++++++++++++
 drivers/gpu/drm/bridge/ptn3460.c                   |  310 +++++----
 drivers/gpu/drm/drm_bridge.c                       |   91 +++
 drivers/gpu/drm/drm_crtc.c                         |   70 --
 drivers/gpu/drm/exynos/exynos_dp_core.c            |   53 +-
 drivers/gpu/drm/exynos/exynos_dp_core.h            |    1 +
 drivers/gpu/drm/msm/hdmi/hdmi.c                    |    4 +-
 drivers/gpu/drm/msm/hdmi/hdmi.h                    |    1 +
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c             |    7 +-
 drivers/gpu/drm/sti/sti_hda.c                      |   11 +-
 drivers/gpu/drm/sti/sti_hdmi.c                     |   11 +-
 include/drm/bridge/ptn3460.h                       |    8 +
 include/drm/drm_crtc.h                             |   27 +-
 23 files changed, 1181 insertions(+), 283 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
 create mode 100644 Documentation/devicetree/bindings/video/bridge/ps8622.txt
 create mode 100644 Documentation/devicetree/bindings/video/bridge/ptn3460.txt
 create mode 100644 drivers/gpu/drm/bridge/ps8622.c
 create mode 100644 drivers/gpu/drm/drm_bridge.c

-- 
1.7.9.5

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

* [PATCH V9 00/14] drm/exynos: few patches to enhance bridge chip support
@ 2015-01-20 16:38 ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

This series is based on v3.19-rc5 tag of Linux-next tree at:
git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git

Changes since V2:
	-- Address comments from Jingoo Han for ps8622 driver
	-- Address comments from Daniel, Rob and Thierry regarding
	   bridge chaining
	-- Address comments from Thierry regarding the names for
	   new drm_panel functions

Changes since V3:
	-- Remove hotplug based initialization of exynos_dp
	-- Make exynos_dp work directly with drm_panel, remove
	   dependency on panel_binder
	-- Minor cleanups in panel_binder and panel_lvds driver

Changes since V4:
	-- Use gpiod interface for panel-lvds and ps8622 drivers.
	-- Address comments from Javier.
	-- Fix compilation issues when PANEL_BINDER is selected as module.
	-- Split Documentation patches from driver patches.
	-- Rebase on top of the tree.

Changes since V5:
	-- Modify bridge drivers to support driver model.
	-- Drop the concept of bridge chain(sincle there are no 2 real bridges)
	   Hence drop bridge-panel_binder layer.
	-- Drop panel-lvds driver and accomadate the required changes in
	   panel-simple driver.
	-- Use gpiod interface in ptn3460 driver.
	-- Address all comments by Thierry Reding for V5 series.
	-- Address comments from Sean Paul for exynos_dp_commit issue.

Changes since V6:
	-- Panel patches were separated and they are merged already.
	-- Fix few issues with ptn3460, before modifying the bridge core.
	-- Modify drm_bridge as per Thierry's comments for V6 series.
	-- Add drm_bridge changes minimally without breaking existing code.
	-- Add new features for ptn3460, step-by-step.
	-- Address comments from Thierry and Andreas for ptn3460 and ps8622.
	-- Split documentation patches from driver patches.

Changes since V7:
	-- Address comments from Tomi and Laurent:
		-- Use videoports and endpoints to represent the connection between
		   encoder, bridge and the panel, instead of using phandles.
	-- Address comments from Daniel:
		-- Make the patch description more descriptive.
		-- remove device pointer from drm_bridge, and just use
		   device_node instead.
		-- don't pass encoder pointer to bridge_attach.
	-- Address comments from Sean Paul:
		-- Remove bridge from mode_config, and pull out drm_bridge
		   functions from drm_crtc.c to drm_bridge.c

Changes since V8:
	-- Rebase on top of linux-next v3.19-rc5.
	-- Add Acked-by and Tested-by tags.

Ajay Kumar (13):
  [PATCH V9 1/14] drm/bridge: ptn3460: Few trivial cleanups
  [PATCH V9 2/14] drm/bridge: do not pass drm_bridge_funcs to drm_bridge_init
  [PATCH V9 3/14] drm/bridge: make bridge registration independent of drm flow
  [PATCH V9 4/14] drm/bridge: ptn3460: Convert to i2c driver model
  [PATCH V9 5/14] drm/exynos: dp: support drm_bridge
  [PATCH V9 6/14] drm/bridge: ptn3460: support drm_panel
  [PATCH V9 7/14] drm/bridge: ptn3460: probe connector at the end of bridge attach
  [PATCH V9 8/14] drm/bridge: ptn3460: use gpiod interface
  [PATCH V9 9/14] Documentation: drm: bridge: move to video/bridge
  [PATCH V9 10/14] Documentation: devicetree: Add vendor prefix for parade
  [PATCH V9 11/14] Documentation: bridge: Add documentation for ps8622 DT properties
  [PATCH V9 13/14] ARM: dts: snow: represent the connection between bridge and panel
    using videoport and endpoints
  [PATCH V9 14/14] ARM: dts: peach-pit: represent the connection between bridge and
    panel using videoport and endpoints

Vincent Palatin (1):
  [PATCH V9 12/14] drm/bridge: Add i2c based driver for ps8622/ps8625 bridge

 .../devicetree/bindings/drm/bridge/ptn3460.txt     |   27 -
 .../devicetree/bindings/vendor-prefixes.txt        |    1 +
 .../devicetree/bindings/video/bridge/ps8622.txt    |   31 +
 .../devicetree/bindings/video/bridge/ptn3460.txt   |   39 ++
 .../devicetree/bindings/video/exynos_dp.txt        |   12 +
 arch/arm/boot/dts/exynos5250-snow.dts              |   30 +-
 arch/arm/boot/dts/exynos5420-peach-pit.dts         |   31 +-
 drivers/gpu/drm/Makefile                           |    2 +-
 drivers/gpu/drm/bridge/Kconfig                     |   12 +
 drivers/gpu/drm/bridge/Makefile                    |    1 +
 drivers/gpu/drm/bridge/ps8622.c                    |  684 ++++++++++++++++++++
 drivers/gpu/drm/bridge/ptn3460.c                   |  310 +++++----
 drivers/gpu/drm/drm_bridge.c                       |   91 +++
 drivers/gpu/drm/drm_crtc.c                         |   70 --
 drivers/gpu/drm/exynos/exynos_dp_core.c            |   53 +-
 drivers/gpu/drm/exynos/exynos_dp_core.h            |    1 +
 drivers/gpu/drm/msm/hdmi/hdmi.c                    |    4 +-
 drivers/gpu/drm/msm/hdmi/hdmi.h                    |    1 +
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c             |    7 +-
 drivers/gpu/drm/sti/sti_hda.c                      |   11 +-
 drivers/gpu/drm/sti/sti_hdmi.c                     |   11 +-
 include/drm/bridge/ptn3460.h                       |    8 +
 include/drm/drm_crtc.h                             |   27 +-
 23 files changed, 1181 insertions(+), 283 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
 create mode 100644 Documentation/devicetree/bindings/video/bridge/ps8622.txt
 create mode 100644 Documentation/devicetree/bindings/video/bridge/ptn3460.txt
 create mode 100644 drivers/gpu/drm/bridge/ps8622.c
 create mode 100644 drivers/gpu/drm/drm_bridge.c

-- 
1.7.9.5

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

* [PATCH V9 01/14] drm/bridge: ptn3460: Few trivial cleanups
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38   ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree
  Cc: kgene.kim, inki.dae, thierry.reding, daniel.vetter, seanpaul,
	ajaynumb, jg1.han, bhushan.r, prashanth.g, Ajay Kumar

This patch does the following changes:
	-- Use usleep_range instead of udelay.
	-- Remove driver_private member from ptn3460 structure.
	-- Make all possible functions and structures static.
	-- Use dev_err for non-DRM errors.
	-- Arrange header files alphabetically.
	-- s/edid/EDID in all error messages.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/bridge/ptn3460.c |   95 +++++++++++++++++++-------------------
 1 file changed, 48 insertions(+), 47 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/
gpu/drm/bridge/ptn3460.c
index d466696..4db38e1 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -13,19 +13,19 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
 
-#include "drmP.h"
-#include "drm_edid.h"
+#include "bridge/ptn3460.h"
+
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
-
-#include "bridge/ptn3460.h"
+#include "drm_edid.h"
+#include "drmP.h"
 
 #define PTN3460_EDID_ADDR			0x0
 #define PTN3460_EDID_EMULATION_ADDR		0x84
@@ -37,7 +37,7 @@ struct ptn3460_bridge {
 	struct drm_connector connector;
 	struct i2c_client *client;
 	struct drm_encoder *encoder;
-	struct drm_bridge *bridge;
+	struct drm_bridge bridge;
 	struct edid *edid;
 	int gpio_pd_n;
 	int gpio_rst_n;
@@ -45,6 +45,18 @@ struct ptn3460_bridge {
 	bool enabled;
 };
 
+static inline struct ptn3460_bridge *
+		bridge_to_ptn3460(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct ptn3460_bridge, bridge);
+}
+
+static inline struct ptn3460_bridge *
+		connector_to_ptn3460(struct drm_connector *connector)
+{
+	return container_of(connector, struct ptn3460_bridge, connector);
+}
+
 static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr,
 		u8 *buf, int len)
 {
@@ -92,7 +104,7 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
 	ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR,
 			ptn_bridge->edid_emulation);
 	if (ret) {
-		DRM_ERROR("Failed to transfer edid to sram, ret=%d\n", ret);
+		DRM_ERROR("Failed to transfer EDID to sram, ret=%d\n", ret);
 		return ret;
 	}
 
@@ -102,7 +114,7 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
 
 	ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val);
 	if (ret) {
-		DRM_ERROR("Failed to write edid value, ret=%d\n", ret);
+		DRM_ERROR("Failed to write EDID value, ret=%d\n", ret);
 		return ret;
 	}
 
@@ -111,7 +123,7 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
 
 static void ptn3460_pre_enable(struct drm_bridge *bridge)
 {
-	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
 	int ret;
 
 	if (ptn_bridge->enabled)
@@ -122,7 +134,7 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
 
 	if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
 		gpio_set_value(ptn_bridge->gpio_rst_n, 0);
-		udelay(10);
+		usleep_range(10, 20);
 		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
 	}
 
@@ -135,7 +147,7 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
 
 	ret = ptn3460_select_edid(ptn_bridge);
 	if (ret)
-		DRM_ERROR("Select edid failed ret=%d\n", ret);
+		DRM_ERROR("Select EDID failed ret=%d\n", ret);
 
 	ptn_bridge->enabled = true;
 }
@@ -146,7 +158,7 @@ static void ptn3460_enable(struct drm_bridge *bridge)
 
 static void ptn3460_disable(struct drm_bridge *bridge)
 {
-	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
 
 	if (!ptn_bridge->enabled)
 		return;
@@ -164,9 +176,9 @@ static void ptn3460_post_disable(struct drm_bridge *bridge)
 {
 }
 
-void ptn3460_bridge_destroy(struct drm_bridge *bridge)
+static void ptn3460_bridge_destroy(struct drm_bridge *bridge)
 {
-	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
 
 	drm_bridge_cleanup(bridge);
 	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
@@ -176,7 +188,7 @@ void ptn3460_bridge_destroy(struct drm_bridge *bridge)
 	/* Nothing else to free, we've got devm allocated memory */
 }
 
-struct drm_bridge_funcs ptn3460_bridge_funcs = {
+static struct drm_bridge_funcs ptn3460_bridge_funcs = {
 	.pre_enable = ptn3460_pre_enable,
 	.enable = ptn3460_enable,
 	.disable = ptn3460_disable,
@@ -184,24 +196,24 @@ struct drm_bridge_funcs ptn3460_bridge_funcs = {
 	.destroy = ptn3460_bridge_destroy,
 };
 
-int ptn3460_get_modes(struct drm_connector *connector)
+static int ptn3460_get_modes(struct drm_connector *connector)
 {
 	struct ptn3460_bridge *ptn_bridge;
 	u8 *edid;
-	int ret, num_modes;
+	int ret, num_modes = 0;
 	bool power_off;
 
-	ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
+	ptn_bridge = connector_to_ptn3460(connector);
 
 	if (ptn_bridge->edid)
 		return drm_add_edid_modes(connector, ptn_bridge->edid);
 
 	power_off = !ptn_bridge->enabled;
-	ptn3460_pre_enable(ptn_bridge->bridge);
+	ptn3460_pre_enable(&ptn_bridge->bridge);
 
 	edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
 	if (!edid) {
-		DRM_ERROR("Failed to allocate edid\n");
+		DRM_ERROR("Failed to allocate EDID\n");
 		return 0;
 	}
 
@@ -209,7 +221,6 @@ int ptn3460_get_modes(struct drm_connector *connector)
 			EDID_LENGTH);
 	if (ret) {
 		kfree(edid);
-		num_modes = 0;
 		goto out;
 	}
 
@@ -220,37 +231,35 @@ int ptn3460_get_modes(struct drm_connector *connector)
 
 out:
 	if (power_off)
-		ptn3460_disable(ptn_bridge->bridge);
+		ptn3460_disable(&ptn_bridge->bridge);
 
 	return num_modes;
 }
 
-struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
+static struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
 {
-	struct ptn3460_bridge *ptn_bridge;
-
-	ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
+	struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector);
 
 	return ptn_bridge->encoder;
 }
 
-struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
+static struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
 	.get_modes = ptn3460_get_modes,
 	.best_encoder = ptn3460_best_encoder,
 };
 
-enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
+static enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
 		bool force)
 {
 	return connector_status_connected;
 }
 
-void ptn3460_connector_destroy(struct drm_connector *connector)
+static void ptn3460_connector_destroy(struct drm_connector *connector)
 {
 	drm_connector_cleanup(connector);
 }
 
-struct drm_connector_funcs ptn3460_connector_funcs = {
+static struct drm_connector_funcs ptn3460_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = ptn3460_detect,
@@ -261,30 +270,22 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 		struct i2c_client *client, struct device_node *node)
 {
 	int ret;
-	struct drm_bridge *bridge;
 	struct ptn3460_bridge *ptn_bridge;
 
-	bridge = devm_kzalloc(dev->dev, sizeof(*bridge), GFP_KERNEL);
-	if (!bridge) {
-		DRM_ERROR("Failed to allocate drm bridge\n");
-		return -ENOMEM;
-	}
-
 	ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL);
 	if (!ptn_bridge) {
-		DRM_ERROR("Failed to allocate ptn bridge\n");
 		return -ENOMEM;
 	}
 
 	ptn_bridge->client = client;
 	ptn_bridge->encoder = encoder;
-	ptn_bridge->bridge = bridge;
 	ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0);
 	if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
 		ret = gpio_request_one(ptn_bridge->gpio_pd_n,
 				GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
 		if (ret) {
-			DRM_ERROR("Request powerdown-gpio failed (%d)\n", ret);
+			dev_err(&client->dev,
+				"Request powerdown-gpio failed (%d)\n", ret);
 			return ret;
 		}
 	}
@@ -298,7 +299,8 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 		ret = gpio_request_one(ptn_bridge->gpio_rst_n,
 				GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
 		if (ret) {
-			DRM_ERROR("Request reset-gpio failed (%d)\n", ret);
+			dev_err(&client->dev,
+				"Request reset-gpio failed (%d)\n", ret);
 			gpio_free(ptn_bridge->gpio_pd_n);
 			return ret;
 		}
@@ -307,18 +309,17 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 	ret = of_property_read_u32(node, "edid-emulation",
 			&ptn_bridge->edid_emulation);
 	if (ret) {
-		DRM_ERROR("Can't read edid emulation value\n");
+		dev_err(&client->dev, "Can't read EDID emulation value\n");
 		goto err;
 	}
 
-	ret = drm_bridge_init(dev, bridge, &ptn3460_bridge_funcs);
+	ret = drm_bridge_init(dev, &ptn_bridge->bridge, &ptn3460_bridge_funcs);
 	if (ret) {
 		DRM_ERROR("Failed to initialize bridge with drm\n");
 		goto err;
 	}
 
-	bridge->driver_private = ptn_bridge;
-	encoder->bridge = bridge;
+	encoder->bridge = &ptn_bridge->bridge;
 
 	ret = drm_connector_init(dev, &ptn_bridge->connector,
 			&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
-- 
1.7.9.5

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

* [PATCH V9 01/14] drm/bridge: ptn3460: Few trivial cleanups
@ 2015-01-20 16:38   ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

This patch does the following changes:
	-- Use usleep_range instead of udelay.
	-- Remove driver_private member from ptn3460 structure.
	-- Make all possible functions and structures static.
	-- Use dev_err for non-DRM errors.
	-- Arrange header files alphabetically.
	-- s/edid/EDID in all error messages.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/bridge/ptn3460.c |   95 +++++++++++++++++++-------------------
 1 file changed, 48 insertions(+), 47 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/
gpu/drm/bridge/ptn3460.c
index d466696..4db38e1 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -13,19 +13,19 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
 
-#include "drmP.h"
-#include "drm_edid.h"
+#include "bridge/ptn3460.h"
+
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
-
-#include "bridge/ptn3460.h"
+#include "drm_edid.h"
+#include "drmP.h"
 
 #define PTN3460_EDID_ADDR			0x0
 #define PTN3460_EDID_EMULATION_ADDR		0x84
@@ -37,7 +37,7 @@ struct ptn3460_bridge {
 	struct drm_connector connector;
 	struct i2c_client *client;
 	struct drm_encoder *encoder;
-	struct drm_bridge *bridge;
+	struct drm_bridge bridge;
 	struct edid *edid;
 	int gpio_pd_n;
 	int gpio_rst_n;
@@ -45,6 +45,18 @@ struct ptn3460_bridge {
 	bool enabled;
 };
 
+static inline struct ptn3460_bridge *
+		bridge_to_ptn3460(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct ptn3460_bridge, bridge);
+}
+
+static inline struct ptn3460_bridge *
+		connector_to_ptn3460(struct drm_connector *connector)
+{
+	return container_of(connector, struct ptn3460_bridge, connector);
+}
+
 static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr,
 		u8 *buf, int len)
 {
@@ -92,7 +104,7 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
 	ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR,
 			ptn_bridge->edid_emulation);
 	if (ret) {
-		DRM_ERROR("Failed to transfer edid to sram, ret=%d\n", ret);
+		DRM_ERROR("Failed to transfer EDID to sram, ret=%d\n", ret);
 		return ret;
 	}
 
@@ -102,7 +114,7 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
 
 	ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val);
 	if (ret) {
-		DRM_ERROR("Failed to write edid value, ret=%d\n", ret);
+		DRM_ERROR("Failed to write EDID value, ret=%d\n", ret);
 		return ret;
 	}
 
@@ -111,7 +123,7 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
 
 static void ptn3460_pre_enable(struct drm_bridge *bridge)
 {
-	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
 	int ret;
 
 	if (ptn_bridge->enabled)
@@ -122,7 +134,7 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
 
 	if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
 		gpio_set_value(ptn_bridge->gpio_rst_n, 0);
-		udelay(10);
+		usleep_range(10, 20);
 		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
 	}
 
@@ -135,7 +147,7 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
 
 	ret = ptn3460_select_edid(ptn_bridge);
 	if (ret)
-		DRM_ERROR("Select edid failed ret=%d\n", ret);
+		DRM_ERROR("Select EDID failed ret=%d\n", ret);
 
 	ptn_bridge->enabled = true;
 }
@@ -146,7 +158,7 @@ static void ptn3460_enable(struct drm_bridge *bridge)
 
 static void ptn3460_disable(struct drm_bridge *bridge)
 {
-	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
 
 	if (!ptn_bridge->enabled)
 		return;
@@ -164,9 +176,9 @@ static void ptn3460_post_disable(struct drm_bridge *bridge)
 {
 }
 
-void ptn3460_bridge_destroy(struct drm_bridge *bridge)
+static void ptn3460_bridge_destroy(struct drm_bridge *bridge)
 {
-	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
 
 	drm_bridge_cleanup(bridge);
 	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
@@ -176,7 +188,7 @@ void ptn3460_bridge_destroy(struct drm_bridge *bridge)
 	/* Nothing else to free, we've got devm allocated memory */
 }
 
-struct drm_bridge_funcs ptn3460_bridge_funcs = {
+static struct drm_bridge_funcs ptn3460_bridge_funcs = {
 	.pre_enable = ptn3460_pre_enable,
 	.enable = ptn3460_enable,
 	.disable = ptn3460_disable,
@@ -184,24 +196,24 @@ struct drm_bridge_funcs ptn3460_bridge_funcs = {
 	.destroy = ptn3460_bridge_destroy,
 };
 
-int ptn3460_get_modes(struct drm_connector *connector)
+static int ptn3460_get_modes(struct drm_connector *connector)
 {
 	struct ptn3460_bridge *ptn_bridge;
 	u8 *edid;
-	int ret, num_modes;
+	int ret, num_modes = 0;
 	bool power_off;
 
-	ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
+	ptn_bridge = connector_to_ptn3460(connector);
 
 	if (ptn_bridge->edid)
 		return drm_add_edid_modes(connector, ptn_bridge->edid);
 
 	power_off = !ptn_bridge->enabled;
-	ptn3460_pre_enable(ptn_bridge->bridge);
+	ptn3460_pre_enable(&ptn_bridge->bridge);
 
 	edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
 	if (!edid) {
-		DRM_ERROR("Failed to allocate edid\n");
+		DRM_ERROR("Failed to allocate EDID\n");
 		return 0;
 	}
 
@@ -209,7 +221,6 @@ int ptn3460_get_modes(struct drm_connector *connector)
 			EDID_LENGTH);
 	if (ret) {
 		kfree(edid);
-		num_modes = 0;
 		goto out;
 	}
 
@@ -220,37 +231,35 @@ int ptn3460_get_modes(struct drm_connector *connector)
 
 out:
 	if (power_off)
-		ptn3460_disable(ptn_bridge->bridge);
+		ptn3460_disable(&ptn_bridge->bridge);
 
 	return num_modes;
 }
 
-struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
+static struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
 {
-	struct ptn3460_bridge *ptn_bridge;
-
-	ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
+	struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector);
 
 	return ptn_bridge->encoder;
 }
 
-struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
+static struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
 	.get_modes = ptn3460_get_modes,
 	.best_encoder = ptn3460_best_encoder,
 };
 
-enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
+static enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
 		bool force)
 {
 	return connector_status_connected;
 }
 
-void ptn3460_connector_destroy(struct drm_connector *connector)
+static void ptn3460_connector_destroy(struct drm_connector *connector)
 {
 	drm_connector_cleanup(connector);
 }
 
-struct drm_connector_funcs ptn3460_connector_funcs = {
+static struct drm_connector_funcs ptn3460_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = ptn3460_detect,
@@ -261,30 +270,22 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 		struct i2c_client *client, struct device_node *node)
 {
 	int ret;
-	struct drm_bridge *bridge;
 	struct ptn3460_bridge *ptn_bridge;
 
-	bridge = devm_kzalloc(dev->dev, sizeof(*bridge), GFP_KERNEL);
-	if (!bridge) {
-		DRM_ERROR("Failed to allocate drm bridge\n");
-		return -ENOMEM;
-	}
-
 	ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL);
 	if (!ptn_bridge) {
-		DRM_ERROR("Failed to allocate ptn bridge\n");
 		return -ENOMEM;
 	}
 
 	ptn_bridge->client = client;
 	ptn_bridge->encoder = encoder;
-	ptn_bridge->bridge = bridge;
 	ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0);
 	if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
 		ret = gpio_request_one(ptn_bridge->gpio_pd_n,
 				GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
 		if (ret) {
-			DRM_ERROR("Request powerdown-gpio failed (%d)\n", ret);
+			dev_err(&client->dev,
+				"Request powerdown-gpio failed (%d)\n", ret);
 			return ret;
 		}
 	}
@@ -298,7 +299,8 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 		ret = gpio_request_one(ptn_bridge->gpio_rst_n,
 				GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
 		if (ret) {
-			DRM_ERROR("Request reset-gpio failed (%d)\n", ret);
+			dev_err(&client->dev,
+				"Request reset-gpio failed (%d)\n", ret);
 			gpio_free(ptn_bridge->gpio_pd_n);
 			return ret;
 		}
@@ -307,18 +309,17 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 	ret = of_property_read_u32(node, "edid-emulation",
 			&ptn_bridge->edid_emulation);
 	if (ret) {
-		DRM_ERROR("Can't read edid emulation value\n");
+		dev_err(&client->dev, "Can't read EDID emulation value\n");
 		goto err;
 	}
 
-	ret = drm_bridge_init(dev, bridge, &ptn3460_bridge_funcs);
+	ret = drm_bridge_init(dev, &ptn_bridge->bridge, &ptn3460_bridge_funcs);
 	if (ret) {
 		DRM_ERROR("Failed to initialize bridge with drm\n");
 		goto err;
 	}
 
-	bridge->driver_private = ptn_bridge;
-	encoder->bridge = bridge;
+	encoder->bridge = &ptn_bridge->bridge;
 
 	ret = drm_connector_init(dev, &ptn_bridge->connector,
 			&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
-- 
1.7.9.5

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

* [PATCH V9 02/14] drm/bridge: do not pass drm_bridge_funcs to drm_bridge_init
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38   ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree
  Cc: kgene.kim, inki.dae, thierry.reding, daniel.vetter, seanpaul,
	ajaynumb, jg1.han, bhushan.r, prashanth.g, Ajay Kumar

Assign the pointer to bridge ops structure(drm_bridge_funcs) in
the bridge driver itself, instead of passing it to drm_bridge_init.

This will allow bridge driver developer to pack bridge private
information inside the bridge object and pass only the drm-relevant
information to drm_bridge_init.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/bridge/ptn3460.c       |    3 ++-
 drivers/gpu/drm/drm_crtc.c             |    5 +----
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c |    3 ++-
 drivers/gpu/drm/sti/sti_hda.c          |    3 ++-
 drivers/gpu/drm/sti/sti_hdmi.c         |    3 ++-
 include/drm/drm_crtc.h                 |    3 +--
 6 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index 4db38e1..a2ddc8d 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -313,7 +313,8 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 		goto err;
 	}
 
-	ret = drm_bridge_init(dev, &ptn_bridge->bridge, &ptn3460_bridge_funcs);
+	ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
+	ret = drm_bridge_init(dev, &ptn_bridge->bridge);
 	if (ret) {
 		DRM_ERROR("Failed to initialize bridge with drm\n");
 		goto err;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index caec5c3..4acd693 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1030,7 +1030,6 @@ EXPORT_SYMBOL(drm_connector_unplug_all);
  * drm_bridge_init - initialize a drm transcoder/bridge
  * @dev: drm device
  * @bridge: transcoder/bridge to set up
- * @funcs: bridge function table
  *
  * Initialises a preallocated bridge. Bridges should be
  * subclassed as part of driver connector objects.
@@ -1038,8 +1037,7 @@ EXPORT_SYMBOL(drm_connector_unplug_all);
  * Returns:
  * Zero on success, error code on failure.
  */
-int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
-		const struct drm_bridge_funcs *funcs)
+int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge)
 {
 	int ret;
 
@@ -1050,7 +1048,6 @@ int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
 		goto out;
 
 	bridge->dev = dev;
-	bridge->funcs = funcs;
 
 	list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
 	dev->mode_config.num_bridge++;
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 6902ad6..52ed2b5 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -220,8 +220,9 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
 	hdmi_bridge->hdmi = hdmi;
 
 	bridge = &hdmi_bridge->base;
+	bridge->funcs = &hdmi_bridge_funcs;
 
-	drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs);
+	drm_bridge_init(hdmi->dev, bridge);
 
 	return bridge;
 
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 2ae9a9b..6cf145d 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -664,7 +664,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
 		return -ENOMEM;
 
 	bridge->driver_private = hda;
-	drm_bridge_init(drm_dev, bridge, &sti_hda_bridge_funcs);
+	bridge->funcs = &sti_hda_bridge_funcs;
+	drm_bridge_init(drm_dev, bridge);
 
 	encoder->bridge = bridge;
 	connector->encoder = encoder;
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index d032e02..74e943e 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -635,7 +635,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
 		goto err_adapt;
 
 	bridge->driver_private = hdmi;
-	drm_bridge_init(drm_dev, bridge, &sti_hdmi_bridge_funcs);
+	bridge->funcs = &sti_hdmi_bridge_funcs;
+	drm_bridge_init(drm_dev, bridge);
 
 	encoder->bridge = bridge;
 	connector->encoder = encoder;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index f444263..e43d9e5 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -1209,8 +1209,7 @@ extern unsigned int drm_connector_index(struct drm_connector *connector);
 /* helper to unplug all connectors from sysfs for device */
 extern void drm_connector_unplug_all(struct drm_device *dev);
 
-extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
-			   const struct drm_bridge_funcs *funcs);
+extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge);
 extern void drm_bridge_cleanup(struct drm_bridge *bridge);
 
 extern int drm_encoder_init(struct drm_device *dev,
-- 
1.7.9.5

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

* [PATCH V9 02/14] drm/bridge: do not pass drm_bridge_funcs to drm_bridge_init
@ 2015-01-20 16:38   ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

Assign the pointer to bridge ops structure(drm_bridge_funcs) in
the bridge driver itself, instead of passing it to drm_bridge_init.

This will allow bridge driver developer to pack bridge private
information inside the bridge object and pass only the drm-relevant
information to drm_bridge_init.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/bridge/ptn3460.c       |    3 ++-
 drivers/gpu/drm/drm_crtc.c             |    5 +----
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c |    3 ++-
 drivers/gpu/drm/sti/sti_hda.c          |    3 ++-
 drivers/gpu/drm/sti/sti_hdmi.c         |    3 ++-
 include/drm/drm_crtc.h                 |    3 +--
 6 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index 4db38e1..a2ddc8d 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -313,7 +313,8 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 		goto err;
 	}
 
-	ret = drm_bridge_init(dev, &ptn_bridge->bridge, &ptn3460_bridge_funcs);
+	ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
+	ret = drm_bridge_init(dev, &ptn_bridge->bridge);
 	if (ret) {
 		DRM_ERROR("Failed to initialize bridge with drm\n");
 		goto err;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index caec5c3..4acd693 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1030,7 +1030,6 @@ EXPORT_SYMBOL(drm_connector_unplug_all);
  * drm_bridge_init - initialize a drm transcoder/bridge
  * @dev: drm device
  * @bridge: transcoder/bridge to set up
- * @funcs: bridge function table
  *
  * Initialises a preallocated bridge. Bridges should be
  * subclassed as part of driver connector objects.
@@ -1038,8 +1037,7 @@ EXPORT_SYMBOL(drm_connector_unplug_all);
  * Returns:
  * Zero on success, error code on failure.
  */
-int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
-		const struct drm_bridge_funcs *funcs)
+int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge)
 {
 	int ret;
 
@@ -1050,7 +1048,6 @@ int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
 		goto out;
 
 	bridge->dev = dev;
-	bridge->funcs = funcs;
 
 	list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
 	dev->mode_config.num_bridge++;
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 6902ad6..52ed2b5 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -220,8 +220,9 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
 	hdmi_bridge->hdmi = hdmi;
 
 	bridge = &hdmi_bridge->base;
+	bridge->funcs = &hdmi_bridge_funcs;
 
-	drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs);
+	drm_bridge_init(hdmi->dev, bridge);
 
 	return bridge;
 
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 2ae9a9b..6cf145d 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -664,7 +664,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
 		return -ENOMEM;
 
 	bridge->driver_private = hda;
-	drm_bridge_init(drm_dev, bridge, &sti_hda_bridge_funcs);
+	bridge->funcs = &sti_hda_bridge_funcs;
+	drm_bridge_init(drm_dev, bridge);
 
 	encoder->bridge = bridge;
 	connector->encoder = encoder;
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index d032e02..74e943e 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -635,7 +635,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
 		goto err_adapt;
 
 	bridge->driver_private = hdmi;
-	drm_bridge_init(drm_dev, bridge, &sti_hdmi_bridge_funcs);
+	bridge->funcs = &sti_hdmi_bridge_funcs;
+	drm_bridge_init(drm_dev, bridge);
 
 	encoder->bridge = bridge;
 	connector->encoder = encoder;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index f444263..e43d9e5 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -1209,8 +1209,7 @@ extern unsigned int drm_connector_index(struct drm_connector *connector);
 /* helper to unplug all connectors from sysfs for device */
 extern void drm_connector_unplug_all(struct drm_device *dev);
 
-extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
-			   const struct drm_bridge_funcs *funcs);
+extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge);
 extern void drm_bridge_cleanup(struct drm_bridge *bridge);
 
 extern int drm_encoder_init(struct drm_device *dev,
-- 
1.7.9.5

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

* [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38     ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: kgene.kim-Sze3O3UU22JBDgjK7y7TUQ,
	inki.dae-Sze3O3UU22JBDgjK7y7TUQ,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, daniel.vetter-/w4YWyX8dFk,
	seanpaul-hpIqsD4AKlfQT0dZR+AlfA, ajaynumb-Re5JQEeQqe8AvxtiuMwx3w,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, bhushan.r-Sze3O3UU22JBDgjK7y7TUQ,
	prashanth.g-Sze3O3UU22JBDgjK7y7TUQ, Ajay Kumar

Currently, third party bridge drivers(ptn3460) are dependent
on the corresponding encoder driver init, since bridge driver
needs a drm_device pointer to finish drm initializations.
The encoder driver passes the drm_device pointer to the
bridge driver. Because of this dependency, third party drivers
like ptn3460 doesn't adhere to the driver model.

In this patch, we reframe the bridge registration framework
so that bridge initialization is split into 2 steps, and
bridge registration happens independent of drm flow:
--Step 1: gather all the bridge settings independent of drm and
	  add the bridge onto a global list of bridges.
--Step 2: when the encoder driver is probed, call drm_bridge_attach
	  for the corresponding bridge so that the bridge receives
	  drm_device pointer and continues with connector and other
	  drm initializations.

The old set of bridge helpers are removed, and a set of new helpers
are added to accomplish the 2 step initialization.

The bridge devices register themselves onto global list of bridges
when they get probed by calling "drm_bridge_add".

The parent encoder driver waits till the bridge is available
in the lookup table(by calling "of_drm_find_bridge") and then
continues with its initialization.

The encoder driver should also call "drm_bridge_attach" to pass
on the drm_device to the bridge object.

drm_bridge_attach inturn calls "bridge->funcs->attach" so that
bridge can continue with drm related initializations.

Signed-off-by: Ajay Kumar <ajaykumar.rs-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Acked-by: Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Tested-by: Rahul Sharma <rahul.sharma-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Tested-by: Javier Martinez Canillas <javier.martinez-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
Tested-by: Gustavo Padovan <gustavo.padovan-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
Tested-by: Sjoerd Simons <sjoerd.simons-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
---
 drivers/gpu/drm/Makefile               |    2 +-
 drivers/gpu/drm/bridge/ptn3460.c       |   27 +++++-----
 drivers/gpu/drm/drm_bridge.c           |   91 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_crtc.c             |   67 -----------------------
 drivers/gpu/drm/msm/hdmi/hdmi.c        |    4 +-
 drivers/gpu/drm/msm/hdmi/hdmi.h        |    1 +
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c |    6 +--
 drivers/gpu/drm/sti/sti_hda.c          |   10 +---
 drivers/gpu/drm/sti/sti_hdmi.c         |   10 +---
 include/drm/bridge/ptn3460.h           |    8 +++
 include/drm/drm_crtc.h                 |   26 ++++-----
 11 files changed, 133 insertions(+), 119 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_bridge.c

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e620807..c83ef2d 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -14,7 +14,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
 		drm_trace_points.o drm_global.o drm_prime.o \
 		drm_rect.o drm_vma_manager.o drm_flip_work.o \
-		drm_modeset_lock.o drm_atomic.o
+		drm_modeset_lock.o drm_atomic.o drm_bridge.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index a2ddc8d..4a818c1 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -176,24 +176,11 @@ static void ptn3460_post_disable(struct drm_bridge *bridge)
 {
 }
 
-static void ptn3460_bridge_destroy(struct drm_bridge *bridge)
-{
-	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
-
-	drm_bridge_cleanup(bridge);
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_free(ptn_bridge->gpio_pd_n);
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
-		gpio_free(ptn_bridge->gpio_rst_n);
-	/* Nothing else to free, we've got devm allocated memory */
-}
-
 static struct drm_bridge_funcs ptn3460_bridge_funcs = {
 	.pre_enable = ptn3460_pre_enable,
 	.enable = ptn3460_enable,
 	.disable = ptn3460_disable,
 	.post_disable = ptn3460_post_disable,
-	.destroy = ptn3460_bridge_destroy,
 };
 
 static int ptn3460_get_modes(struct drm_connector *connector)
@@ -314,7 +301,7 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 	}
 
 	ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
-	ret = drm_bridge_init(dev, &ptn_bridge->bridge);
+	ret = drm_bridge_attach(dev, &ptn_bridge->bridge);
 	if (ret) {
 		DRM_ERROR("Failed to initialize bridge with drm\n");
 		goto err;
@@ -343,3 +330,15 @@ err:
 	return ret;
 }
 EXPORT_SYMBOL(ptn3460_init);
+
+void ptn3460_destroy(struct drm_bridge *bridge)
+{
+	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+
+	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
+		gpio_free(ptn_bridge->gpio_pd_n);
+	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
+		gpio_free(ptn_bridge->gpio_rst_n);
+	/* Nothing else to free, we've got devm allocated memory */
+}
+EXPORT_SYMBOL(ptn3460_destroy);
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
new file mode 100644
index 0000000..d1187e5
--- /dev/null
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <drm/drm_crtc.h>
+
+#include "drm/drmP.h"
+
+static DEFINE_MUTEX(bridge_lock);
+static LIST_HEAD(bridge_list);
+
+int drm_bridge_add(struct drm_bridge *bridge)
+{
+	mutex_lock(&bridge_lock);
+	list_add_tail(&bridge->list, &bridge_list);
+	mutex_unlock(&bridge_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_bridge_add);
+
+void drm_bridge_remove(struct drm_bridge *bridge)
+{
+	mutex_lock(&bridge_lock);
+	list_del_init(&bridge->list);
+	mutex_unlock(&bridge_lock);
+}
+EXPORT_SYMBOL(drm_bridge_remove);
+
+extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
+{
+	if (!dev || !bridge)
+		return -EINVAL;
+
+	if (bridge->dev)
+		return -EBUSY;
+
+	bridge->dev = dev;
+
+	if (bridge->funcs->attach)
+		return bridge->funcs->attach(bridge);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_bridge_attach);
+
+#ifdef CONFIG_OF
+struct drm_bridge *of_drm_find_bridge(struct device_node *np)
+{
+	struct drm_bridge *bridge;
+
+	mutex_lock(&bridge_lock);
+
+	list_for_each_entry(bridge, &bridge_list, list) {
+		if (bridge->of_node == np) {
+			mutex_unlock(&bridge_lock);
+			return bridge;
+		}
+	}
+
+	mutex_unlock(&bridge_lock);
+	return NULL;
+}
+EXPORT_SYMBOL(of_drm_find_bridge);
+#endif
+
+MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
+MODULE_DESCRIPTION("DRM bridge infrastructure");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index af57103..bb8e31e 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1028,58 +1028,6 @@ void drm_connector_unplug_all(struct drm_device *dev)
 EXPORT_SYMBOL(drm_connector_unplug_all);
 
 /**
- * drm_bridge_init - initialize a drm transcoder/bridge
- * @dev: drm device
- * @bridge: transcoder/bridge to set up
- *
- * Initialises a preallocated bridge. Bridges should be
- * subclassed as part of driver connector objects.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge)
-{
-	int ret;
-
-	drm_modeset_lock_all(dev);
-
-	ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE);
-	if (ret)
-		goto out;
-
-	bridge->dev = dev;
-
-	list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
-	dev->mode_config.num_bridge++;
-
- out:
-	drm_modeset_unlock_all(dev);
-	return ret;
-}
-EXPORT_SYMBOL(drm_bridge_init);
-
-/**
- * drm_bridge_cleanup - cleans up an initialised bridge
- * @bridge: bridge to cleanup
- *
- * Cleans up the bridge but doesn't free the object.
- */
-void drm_bridge_cleanup(struct drm_bridge *bridge)
-{
-	struct drm_device *dev = bridge->dev;
-
-	drm_modeset_lock_all(dev);
-	drm_mode_object_put(dev, &bridge->base);
-	list_del(&bridge->head);
-	dev->mode_config.num_bridge--;
-	drm_modeset_unlock_all(dev);
-
-	memset(bridge, 0, sizeof(*bridge));
-}
-EXPORT_SYMBOL(drm_bridge_cleanup);
-
-/**
  * drm_encoder_init - Init a preallocated encoder
  * @dev: drm device
  * @encoder: the encoder to init
@@ -1594,7 +1542,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
 	total_objects += dev->mode_config.num_crtc;
 	total_objects += dev->mode_config.num_connector;
 	total_objects += dev->mode_config.num_encoder;
-	total_objects += dev->mode_config.num_bridge;
 
 	group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
 	if (!group->id_list)
@@ -1603,7 +1550,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
 	group->num_crtcs = 0;
 	group->num_connectors = 0;
 	group->num_encoders = 0;
-	group->num_bridges = 0;
 	return 0;
 }
 
@@ -1623,7 +1569,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
 	struct drm_crtc *crtc;
 	struct drm_encoder *encoder;
 	struct drm_connector *connector;
-	struct drm_bridge *bridge;
 	int ret;
 
 	if ((ret = drm_mode_group_init(dev, group)))
@@ -1640,11 +1585,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
 		group->id_list[group->num_crtcs + group->num_encoders +
 			       group->num_connectors++] = connector->base.id;
 
-	list_for_each_entry(bridge, &dev->mode_config.bridge_list, head)
-		group->id_list[group->num_crtcs + group->num_encoders +
-			       group->num_connectors + group->num_bridges++] =
-					bridge->base.id;
-
 	return 0;
 }
 EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
@@ -5208,7 +5148,6 @@ void drm_mode_config_init(struct drm_device *dev)
 	INIT_LIST_HEAD(&dev->mode_config.fb_list);
 	INIT_LIST_HEAD(&dev->mode_config.crtc_list);
 	INIT_LIST_HEAD(&dev->mode_config.connector_list);
-	INIT_LIST_HEAD(&dev->mode_config.bridge_list);
 	INIT_LIST_HEAD(&dev->mode_config.encoder_list);
 	INIT_LIST_HEAD(&dev->mode_config.property_list);
 	INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
@@ -5249,7 +5188,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
 	struct drm_connector *connector, *ot;
 	struct drm_crtc *crtc, *ct;
 	struct drm_encoder *encoder, *enct;
-	struct drm_bridge *bridge, *brt;
 	struct drm_framebuffer *fb, *fbt;
 	struct drm_property *property, *pt;
 	struct drm_property_blob *blob, *bt;
@@ -5260,11 +5198,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
 		encoder->funcs->destroy(encoder);
 	}
 
-	list_for_each_entry_safe(bridge, brt,
-				 &dev->mode_config.bridge_list, head) {
-		bridge->funcs->destroy(bridge);
-	}
-
 	list_for_each_entry_safe(connector, ot,
 				 &dev->mode_config.connector_list, head) {
 		connector->funcs->destroy(connector);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 062c687..95f7b8d 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -247,9 +247,9 @@ int hdmi_modeset_init(struct hdmi *hdmi,
 	return 0;
 
 fail:
-	/* bridge/connector are normally destroyed by drm: */
+	/* bridge is normally destroyed by drm: */
 	if (hdmi->bridge) {
-		hdmi->bridge->funcs->destroy(hdmi->bridge);
+		hdmi_bridge_destroy(hdmi->bridge);
 		hdmi->bridge = NULL;
 	}
 	if (hdmi->connector) {
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 43e654f..4d4cad4 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -146,6 +146,7 @@ void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
  */
 
 struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
+void hdmi_bridge_destroy(struct drm_bridge *bridge);
 
 /*
  * hdmi connector:
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 52ed2b5..d6f8d58 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -23,10 +23,9 @@ struct hdmi_bridge {
 };
 #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
 
-static void hdmi_bridge_destroy(struct drm_bridge *bridge)
+void hdmi_bridge_destroy(struct drm_bridge *bridge)
 {
 	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
-	drm_bridge_cleanup(bridge);
 	kfree(hdmi_bridge);
 }
 
@@ -200,7 +199,6 @@ static const struct drm_bridge_funcs hdmi_bridge_funcs = {
 		.disable = hdmi_bridge_disable,
 		.post_disable = hdmi_bridge_post_disable,
 		.mode_set = hdmi_bridge_mode_set,
-		.destroy = hdmi_bridge_destroy,
 };
 
 
@@ -222,7 +220,7 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
 	bridge = &hdmi_bridge->base;
 	bridge->funcs = &hdmi_bridge_funcs;
 
-	drm_bridge_init(hdmi->dev, bridge);
+	drm_bridge_attach(hdmi->dev, bridge);
 
 	return bridge;
 
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 6cf145d..a9bbb08 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -508,19 +508,12 @@ static void sti_hda_bridge_nope(struct drm_bridge *bridge)
 	/* do nothing */
 }
 
-static void sti_hda_brigde_destroy(struct drm_bridge *bridge)
-{
-	drm_bridge_cleanup(bridge);
-	kfree(bridge);
-}
-
 static const struct drm_bridge_funcs sti_hda_bridge_funcs = {
 	.pre_enable = sti_hda_pre_enable,
 	.enable = sti_hda_bridge_nope,
 	.disable = sti_hda_disable,
 	.post_disable = sti_hda_bridge_nope,
 	.mode_set = sti_hda_set_mode,
-	.destroy = sti_hda_brigde_destroy,
 };
 
 static int sti_hda_connector_get_modes(struct drm_connector *connector)
@@ -665,7 +658,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
 
 	bridge->driver_private = hda;
 	bridge->funcs = &sti_hda_bridge_funcs;
-	drm_bridge_init(drm_dev, bridge);
+	drm_bridge_attach(drm_dev, bridge);
 
 	encoder->bridge = bridge;
 	connector->encoder = encoder;
@@ -694,7 +687,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
 err_sysfs:
 	drm_connector_unregister(drm_connector);
 err_connector:
-	drm_bridge_cleanup(bridge);
 	drm_connector_cleanup(drm_connector);
 	return -EINVAL;
 }
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 74e943e..e840ca5d 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -463,19 +463,12 @@ static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
 	/* do nothing */
 }
 
-static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge)
-{
-	drm_bridge_cleanup(bridge);
-	kfree(bridge);
-}
-
 static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
 	.pre_enable = sti_hdmi_pre_enable,
 	.enable = sti_hdmi_bridge_nope,
 	.disable = sti_hdmi_disable,
 	.post_disable = sti_hdmi_bridge_nope,
 	.mode_set = sti_hdmi_set_mode,
-	.destroy = sti_hdmi_brigde_destroy,
 };
 
 static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -636,7 +629,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
 
 	bridge->driver_private = hdmi;
 	bridge->funcs = &sti_hdmi_bridge_funcs;
-	drm_bridge_init(drm_dev, bridge);
+	drm_bridge_attach(drm_dev, bridge);
 
 	encoder->bridge = bridge;
 	connector->encoder = encoder;
@@ -668,7 +661,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
 err_sysfs:
 	drm_connector_unregister(drm_connector);
 err_connector:
-	drm_bridge_cleanup(bridge);
 	drm_connector_cleanup(drm_connector);
 err_adapt:
 	put_device(&hdmi->ddc_adapt->dev);
diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h
index ff62344..b11f8e1 100644
--- a/include/drm/bridge/ptn3460.h
+++ b/include/drm/bridge/ptn3460.h
@@ -15,6 +15,7 @@
 #define _DRM_BRIDGE_PTN3460_H_
 
 struct drm_device;
+struct drm_bridge;
 struct drm_encoder;
 struct i2c_client;
 struct device_node;
@@ -23,6 +24,9 @@ struct device_node;
 
 int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 		struct i2c_client *client, struct device_node *node);
+
+void ptn3460_destroy(struct drm_bridge *bridge);
+
 #else
 
 static inline int ptn3460_init(struct drm_device *dev,
@@ -32,6 +36,10 @@ static inline int ptn3460_init(struct drm_device *dev,
 	return 0;
 }
 
+static inline void ptn3460_destroy(struct drm_bridge *bridge)
+{
+}
+
 #endif
 
 #endif
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 5b8f254..cc369f3 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -813,15 +813,16 @@ struct drm_plane {
 
 /**
  * struct drm_bridge_funcs - drm_bridge control functions
+ * @attach: Called during drm_bridge_attach
  * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
  * @disable: Called right before encoder prepare, disables the bridge
  * @post_disable: Called right after encoder prepare, for lockstepped disable
  * @mode_set: Set this mode to the bridge
  * @pre_enable: Called right before encoder commit, for lockstepped commit
  * @enable: Called right after encoder commit, enables the bridge
- * @destroy: make object go away
  */
 struct drm_bridge_funcs {
+	int (*attach)(struct drm_bridge *bridge);
 	bool (*mode_fixup)(struct drm_bridge *bridge,
 			   const struct drm_display_mode *mode,
 			   struct drm_display_mode *adjusted_mode);
@@ -832,22 +833,24 @@ struct drm_bridge_funcs {
 			 struct drm_display_mode *adjusted_mode);
 	void (*pre_enable)(struct drm_bridge *bridge);
 	void (*enable)(struct drm_bridge *bridge);
-	void (*destroy)(struct drm_bridge *bridge);
 };
 
 /**
  * struct drm_bridge - central DRM bridge control structure
  * @dev: DRM device this bridge belongs to
- * @head: list management
+ * @of_node: device node pointer to the bridge
+ * @list: to keep track of all added bridges
  * @base: base mode object
  * @funcs: control functions
  * @driver_private: pointer to the bridge driver's internal context
  */
 struct drm_bridge {
 	struct drm_device *dev;
-	struct list_head head;
-
-	struct drm_mode_object base;
+	struct drm_encoder *encoder;
+#ifdef CONFIG_OF
+	struct device_node *of_node;
+#endif
+	struct list_head list;
 
 	const struct drm_bridge_funcs *funcs;
 	void *driver_private;
@@ -950,7 +953,6 @@ struct drm_mode_group {
 	uint32_t num_crtcs;
 	uint32_t num_encoders;
 	uint32_t num_connectors;
-	uint32_t num_bridges;
 
 	/* list of object IDs for this group */
 	uint32_t *id_list;
@@ -969,8 +971,6 @@ struct drm_mode_group {
  * @fb_list: list of framebuffers available
  * @num_connector: number of connectors on this device
  * @connector_list: list of connector objects
- * @num_bridge: number of bridges on this device
- * @bridge_list: list of bridge objects
  * @num_encoder: number of encoders on this device
  * @encoder_list: list of encoder objects
  * @num_overlay_plane: number of overlay planes on this device
@@ -1015,8 +1015,6 @@ struct drm_mode_config {
 
 	int num_connector;
 	struct list_head connector_list;
-	int num_bridge;
-	struct list_head bridge_list;
 	int num_encoder;
 	struct list_head encoder_list;
 
@@ -1153,8 +1151,10 @@ extern unsigned int drm_connector_index(struct drm_connector *connector);
 /* helper to unplug all connectors from sysfs for device */
 extern void drm_connector_unplug_all(struct drm_device *dev);
 
-extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge);
-extern void drm_bridge_cleanup(struct drm_bridge *bridge);
+extern int drm_bridge_add(struct drm_bridge *bridge);
+extern void drm_bridge_remove(struct drm_bridge *bridge);
+extern struct drm_bridge *of_drm_find_bridge(struct device_node *np);
+extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
 
 extern int drm_encoder_init(struct drm_device *dev,
 			    struct drm_encoder *encoder,
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
@ 2015-01-20 16:38     ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

Currently, third party bridge drivers(ptn3460) are dependent
on the corresponding encoder driver init, since bridge driver
needs a drm_device pointer to finish drm initializations.
The encoder driver passes the drm_device pointer to the
bridge driver. Because of this dependency, third party drivers
like ptn3460 doesn't adhere to the driver model.

In this patch, we reframe the bridge registration framework
so that bridge initialization is split into 2 steps, and
bridge registration happens independent of drm flow:
--Step 1: gather all the bridge settings independent of drm and
	  add the bridge onto a global list of bridges.
--Step 2: when the encoder driver is probed, call drm_bridge_attach
	  for the corresponding bridge so that the bridge receives
	  drm_device pointer and continues with connector and other
	  drm initializations.

The old set of bridge helpers are removed, and a set of new helpers
are added to accomplish the 2 step initialization.

The bridge devices register themselves onto global list of bridges
when they get probed by calling "drm_bridge_add".

The parent encoder driver waits till the bridge is available
in the lookup table(by calling "of_drm_find_bridge") and then
continues with its initialization.

The encoder driver should also call "drm_bridge_attach" to pass
on the drm_device to the bridge object.

drm_bridge_attach inturn calls "bridge->funcs->attach" so that
bridge can continue with drm related initializations.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/Makefile               |    2 +-
 drivers/gpu/drm/bridge/ptn3460.c       |   27 +++++-----
 drivers/gpu/drm/drm_bridge.c           |   91 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_crtc.c             |   67 -----------------------
 drivers/gpu/drm/msm/hdmi/hdmi.c        |    4 +-
 drivers/gpu/drm/msm/hdmi/hdmi.h        |    1 +
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c |    6 +--
 drivers/gpu/drm/sti/sti_hda.c          |   10 +---
 drivers/gpu/drm/sti/sti_hdmi.c         |   10 +---
 include/drm/bridge/ptn3460.h           |    8 +++
 include/drm/drm_crtc.h                 |   26 ++++-----
 11 files changed, 133 insertions(+), 119 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_bridge.c

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e620807..c83ef2d 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -14,7 +14,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
 		drm_trace_points.o drm_global.o drm_prime.o \
 		drm_rect.o drm_vma_manager.o drm_flip_work.o \
-		drm_modeset_lock.o drm_atomic.o
+		drm_modeset_lock.o drm_atomic.o drm_bridge.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index a2ddc8d..4a818c1 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -176,24 +176,11 @@ static void ptn3460_post_disable(struct drm_bridge *bridge)
 {
 }
 
-static void ptn3460_bridge_destroy(struct drm_bridge *bridge)
-{
-	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
-
-	drm_bridge_cleanup(bridge);
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_free(ptn_bridge->gpio_pd_n);
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
-		gpio_free(ptn_bridge->gpio_rst_n);
-	/* Nothing else to free, we've got devm allocated memory */
-}
-
 static struct drm_bridge_funcs ptn3460_bridge_funcs = {
 	.pre_enable = ptn3460_pre_enable,
 	.enable = ptn3460_enable,
 	.disable = ptn3460_disable,
 	.post_disable = ptn3460_post_disable,
-	.destroy = ptn3460_bridge_destroy,
 };
 
 static int ptn3460_get_modes(struct drm_connector *connector)
@@ -314,7 +301,7 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 	}
 
 	ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
-	ret = drm_bridge_init(dev, &ptn_bridge->bridge);
+	ret = drm_bridge_attach(dev, &ptn_bridge->bridge);
 	if (ret) {
 		DRM_ERROR("Failed to initialize bridge with drm\n");
 		goto err;
@@ -343,3 +330,15 @@ err:
 	return ret;
 }
 EXPORT_SYMBOL(ptn3460_init);
+
+void ptn3460_destroy(struct drm_bridge *bridge)
+{
+	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+
+	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
+		gpio_free(ptn_bridge->gpio_pd_n);
+	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
+		gpio_free(ptn_bridge->gpio_rst_n);
+	/* Nothing else to free, we've got devm allocated memory */
+}
+EXPORT_SYMBOL(ptn3460_destroy);
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
new file mode 100644
index 0000000..d1187e5
--- /dev/null
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <drm/drm_crtc.h>
+
+#include "drm/drmP.h"
+
+static DEFINE_MUTEX(bridge_lock);
+static LIST_HEAD(bridge_list);
+
+int drm_bridge_add(struct drm_bridge *bridge)
+{
+	mutex_lock(&bridge_lock);
+	list_add_tail(&bridge->list, &bridge_list);
+	mutex_unlock(&bridge_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_bridge_add);
+
+void drm_bridge_remove(struct drm_bridge *bridge)
+{
+	mutex_lock(&bridge_lock);
+	list_del_init(&bridge->list);
+	mutex_unlock(&bridge_lock);
+}
+EXPORT_SYMBOL(drm_bridge_remove);
+
+extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
+{
+	if (!dev || !bridge)
+		return -EINVAL;
+
+	if (bridge->dev)
+		return -EBUSY;
+
+	bridge->dev = dev;
+
+	if (bridge->funcs->attach)
+		return bridge->funcs->attach(bridge);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_bridge_attach);
+
+#ifdef CONFIG_OF
+struct drm_bridge *of_drm_find_bridge(struct device_node *np)
+{
+	struct drm_bridge *bridge;
+
+	mutex_lock(&bridge_lock);
+
+	list_for_each_entry(bridge, &bridge_list, list) {
+		if (bridge->of_node == np) {
+			mutex_unlock(&bridge_lock);
+			return bridge;
+		}
+	}
+
+	mutex_unlock(&bridge_lock);
+	return NULL;
+}
+EXPORT_SYMBOL(of_drm_find_bridge);
+#endif
+
+MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
+MODULE_DESCRIPTION("DRM bridge infrastructure");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index af57103..bb8e31e 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1028,58 +1028,6 @@ void drm_connector_unplug_all(struct drm_device *dev)
 EXPORT_SYMBOL(drm_connector_unplug_all);
 
 /**
- * drm_bridge_init - initialize a drm transcoder/bridge
- * @dev: drm device
- * @bridge: transcoder/bridge to set up
- *
- * Initialises a preallocated bridge. Bridges should be
- * subclassed as part of driver connector objects.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge)
-{
-	int ret;
-
-	drm_modeset_lock_all(dev);
-
-	ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE);
-	if (ret)
-		goto out;
-
-	bridge->dev = dev;
-
-	list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
-	dev->mode_config.num_bridge++;
-
- out:
-	drm_modeset_unlock_all(dev);
-	return ret;
-}
-EXPORT_SYMBOL(drm_bridge_init);
-
-/**
- * drm_bridge_cleanup - cleans up an initialised bridge
- * @bridge: bridge to cleanup
- *
- * Cleans up the bridge but doesn't free the object.
- */
-void drm_bridge_cleanup(struct drm_bridge *bridge)
-{
-	struct drm_device *dev = bridge->dev;
-
-	drm_modeset_lock_all(dev);
-	drm_mode_object_put(dev, &bridge->base);
-	list_del(&bridge->head);
-	dev->mode_config.num_bridge--;
-	drm_modeset_unlock_all(dev);
-
-	memset(bridge, 0, sizeof(*bridge));
-}
-EXPORT_SYMBOL(drm_bridge_cleanup);
-
-/**
  * drm_encoder_init - Init a preallocated encoder
  * @dev: drm device
  * @encoder: the encoder to init
@@ -1594,7 +1542,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
 	total_objects += dev->mode_config.num_crtc;
 	total_objects += dev->mode_config.num_connector;
 	total_objects += dev->mode_config.num_encoder;
-	total_objects += dev->mode_config.num_bridge;
 
 	group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
 	if (!group->id_list)
@@ -1603,7 +1550,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
 	group->num_crtcs = 0;
 	group->num_connectors = 0;
 	group->num_encoders = 0;
-	group->num_bridges = 0;
 	return 0;
 }
 
@@ -1623,7 +1569,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
 	struct drm_crtc *crtc;
 	struct drm_encoder *encoder;
 	struct drm_connector *connector;
-	struct drm_bridge *bridge;
 	int ret;
 
 	if ((ret = drm_mode_group_init(dev, group)))
@@ -1640,11 +1585,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
 		group->id_list[group->num_crtcs + group->num_encoders +
 			       group->num_connectors++] = connector->base.id;
 
-	list_for_each_entry(bridge, &dev->mode_config.bridge_list, head)
-		group->id_list[group->num_crtcs + group->num_encoders +
-			       group->num_connectors + group->num_bridges++] =
-					bridge->base.id;
-
 	return 0;
 }
 EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
@@ -5208,7 +5148,6 @@ void drm_mode_config_init(struct drm_device *dev)
 	INIT_LIST_HEAD(&dev->mode_config.fb_list);
 	INIT_LIST_HEAD(&dev->mode_config.crtc_list);
 	INIT_LIST_HEAD(&dev->mode_config.connector_list);
-	INIT_LIST_HEAD(&dev->mode_config.bridge_list);
 	INIT_LIST_HEAD(&dev->mode_config.encoder_list);
 	INIT_LIST_HEAD(&dev->mode_config.property_list);
 	INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
@@ -5249,7 +5188,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
 	struct drm_connector *connector, *ot;
 	struct drm_crtc *crtc, *ct;
 	struct drm_encoder *encoder, *enct;
-	struct drm_bridge *bridge, *brt;
 	struct drm_framebuffer *fb, *fbt;
 	struct drm_property *property, *pt;
 	struct drm_property_blob *blob, *bt;
@@ -5260,11 +5198,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
 		encoder->funcs->destroy(encoder);
 	}
 
-	list_for_each_entry_safe(bridge, brt,
-				 &dev->mode_config.bridge_list, head) {
-		bridge->funcs->destroy(bridge);
-	}
-
 	list_for_each_entry_safe(connector, ot,
 				 &dev->mode_config.connector_list, head) {
 		connector->funcs->destroy(connector);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 062c687..95f7b8d 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -247,9 +247,9 @@ int hdmi_modeset_init(struct hdmi *hdmi,
 	return 0;
 
 fail:
-	/* bridge/connector are normally destroyed by drm: */
+	/* bridge is normally destroyed by drm: */
 	if (hdmi->bridge) {
-		hdmi->bridge->funcs->destroy(hdmi->bridge);
+		hdmi_bridge_destroy(hdmi->bridge);
 		hdmi->bridge = NULL;
 	}
 	if (hdmi->connector) {
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 43e654f..4d4cad4 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -146,6 +146,7 @@ void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
  */
 
 struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
+void hdmi_bridge_destroy(struct drm_bridge *bridge);
 
 /*
  * hdmi connector:
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 52ed2b5..d6f8d58 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -23,10 +23,9 @@ struct hdmi_bridge {
 };
 #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
 
-static void hdmi_bridge_destroy(struct drm_bridge *bridge)
+void hdmi_bridge_destroy(struct drm_bridge *bridge)
 {
 	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
-	drm_bridge_cleanup(bridge);
 	kfree(hdmi_bridge);
 }
 
@@ -200,7 +199,6 @@ static const struct drm_bridge_funcs hdmi_bridge_funcs = {
 		.disable = hdmi_bridge_disable,
 		.post_disable = hdmi_bridge_post_disable,
 		.mode_set = hdmi_bridge_mode_set,
-		.destroy = hdmi_bridge_destroy,
 };
 
 
@@ -222,7 +220,7 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
 	bridge = &hdmi_bridge->base;
 	bridge->funcs = &hdmi_bridge_funcs;
 
-	drm_bridge_init(hdmi->dev, bridge);
+	drm_bridge_attach(hdmi->dev, bridge);
 
 	return bridge;
 
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 6cf145d..a9bbb08 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -508,19 +508,12 @@ static void sti_hda_bridge_nope(struct drm_bridge *bridge)
 	/* do nothing */
 }
 
-static void sti_hda_brigde_destroy(struct drm_bridge *bridge)
-{
-	drm_bridge_cleanup(bridge);
-	kfree(bridge);
-}
-
 static const struct drm_bridge_funcs sti_hda_bridge_funcs = {
 	.pre_enable = sti_hda_pre_enable,
 	.enable = sti_hda_bridge_nope,
 	.disable = sti_hda_disable,
 	.post_disable = sti_hda_bridge_nope,
 	.mode_set = sti_hda_set_mode,
-	.destroy = sti_hda_brigde_destroy,
 };
 
 static int sti_hda_connector_get_modes(struct drm_connector *connector)
@@ -665,7 +658,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
 
 	bridge->driver_private = hda;
 	bridge->funcs = &sti_hda_bridge_funcs;
-	drm_bridge_init(drm_dev, bridge);
+	drm_bridge_attach(drm_dev, bridge);
 
 	encoder->bridge = bridge;
 	connector->encoder = encoder;
@@ -694,7 +687,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
 err_sysfs:
 	drm_connector_unregister(drm_connector);
 err_connector:
-	drm_bridge_cleanup(bridge);
 	drm_connector_cleanup(drm_connector);
 	return -EINVAL;
 }
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 74e943e..e840ca5d 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -463,19 +463,12 @@ static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
 	/* do nothing */
 }
 
-static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge)
-{
-	drm_bridge_cleanup(bridge);
-	kfree(bridge);
-}
-
 static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
 	.pre_enable = sti_hdmi_pre_enable,
 	.enable = sti_hdmi_bridge_nope,
 	.disable = sti_hdmi_disable,
 	.post_disable = sti_hdmi_bridge_nope,
 	.mode_set = sti_hdmi_set_mode,
-	.destroy = sti_hdmi_brigde_destroy,
 };
 
 static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -636,7 +629,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
 
 	bridge->driver_private = hdmi;
 	bridge->funcs = &sti_hdmi_bridge_funcs;
-	drm_bridge_init(drm_dev, bridge);
+	drm_bridge_attach(drm_dev, bridge);
 
 	encoder->bridge = bridge;
 	connector->encoder = encoder;
@@ -668,7 +661,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
 err_sysfs:
 	drm_connector_unregister(drm_connector);
 err_connector:
-	drm_bridge_cleanup(bridge);
 	drm_connector_cleanup(drm_connector);
 err_adapt:
 	put_device(&hdmi->ddc_adapt->dev);
diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h
index ff62344..b11f8e1 100644
--- a/include/drm/bridge/ptn3460.h
+++ b/include/drm/bridge/ptn3460.h
@@ -15,6 +15,7 @@
 #define _DRM_BRIDGE_PTN3460_H_
 
 struct drm_device;
+struct drm_bridge;
 struct drm_encoder;
 struct i2c_client;
 struct device_node;
@@ -23,6 +24,9 @@ struct device_node;
 
 int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 		struct i2c_client *client, struct device_node *node);
+
+void ptn3460_destroy(struct drm_bridge *bridge);
+
 #else
 
 static inline int ptn3460_init(struct drm_device *dev,
@@ -32,6 +36,10 @@ static inline int ptn3460_init(struct drm_device *dev,
 	return 0;
 }
 
+static inline void ptn3460_destroy(struct drm_bridge *bridge)
+{
+}
+
 #endif
 
 #endif
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 5b8f254..cc369f3 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -813,15 +813,16 @@ struct drm_plane {
 
 /**
  * struct drm_bridge_funcs - drm_bridge control functions
+ * @attach: Called during drm_bridge_attach
  * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
  * @disable: Called right before encoder prepare, disables the bridge
  * @post_disable: Called right after encoder prepare, for lockstepped disable
  * @mode_set: Set this mode to the bridge
  * @pre_enable: Called right before encoder commit, for lockstepped commit
  * @enable: Called right after encoder commit, enables the bridge
- * @destroy: make object go away
  */
 struct drm_bridge_funcs {
+	int (*attach)(struct drm_bridge *bridge);
 	bool (*mode_fixup)(struct drm_bridge *bridge,
 			   const struct drm_display_mode *mode,
 			   struct drm_display_mode *adjusted_mode);
@@ -832,22 +833,24 @@ struct drm_bridge_funcs {
 			 struct drm_display_mode *adjusted_mode);
 	void (*pre_enable)(struct drm_bridge *bridge);
 	void (*enable)(struct drm_bridge *bridge);
-	void (*destroy)(struct drm_bridge *bridge);
 };
 
 /**
  * struct drm_bridge - central DRM bridge control structure
  * @dev: DRM device this bridge belongs to
- * @head: list management
+ * @of_node: device node pointer to the bridge
+ * @list: to keep track of all added bridges
  * @base: base mode object
  * @funcs: control functions
  * @driver_private: pointer to the bridge driver's internal context
  */
 struct drm_bridge {
 	struct drm_device *dev;
-	struct list_head head;
-
-	struct drm_mode_object base;
+	struct drm_encoder *encoder;
+#ifdef CONFIG_OF
+	struct device_node *of_node;
+#endif
+	struct list_head list;
 
 	const struct drm_bridge_funcs *funcs;
 	void *driver_private;
@@ -950,7 +953,6 @@ struct drm_mode_group {
 	uint32_t num_crtcs;
 	uint32_t num_encoders;
 	uint32_t num_connectors;
-	uint32_t num_bridges;
 
 	/* list of object IDs for this group */
 	uint32_t *id_list;
@@ -969,8 +971,6 @@ struct drm_mode_group {
  * @fb_list: list of framebuffers available
  * @num_connector: number of connectors on this device
  * @connector_list: list of connector objects
- * @num_bridge: number of bridges on this device
- * @bridge_list: list of bridge objects
  * @num_encoder: number of encoders on this device
  * @encoder_list: list of encoder objects
  * @num_overlay_plane: number of overlay planes on this device
@@ -1015,8 +1015,6 @@ struct drm_mode_config {
 
 	int num_connector;
 	struct list_head connector_list;
-	int num_bridge;
-	struct list_head bridge_list;
 	int num_encoder;
 	struct list_head encoder_list;
 
@@ -1153,8 +1151,10 @@ extern unsigned int drm_connector_index(struct drm_connector *connector);
 /* helper to unplug all connectors from sysfs for device */
 extern void drm_connector_unplug_all(struct drm_device *dev);
 
-extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge);
-extern void drm_bridge_cleanup(struct drm_bridge *bridge);
+extern int drm_bridge_add(struct drm_bridge *bridge);
+extern void drm_bridge_remove(struct drm_bridge *bridge);
+extern struct drm_bridge *of_drm_find_bridge(struct device_node *np);
+extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
 
 extern int drm_encoder_init(struct drm_device *dev,
 			    struct drm_encoder *encoder,
-- 
1.7.9.5

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

* [PATCH V9 04/14] drm/bridge: ptn3460: Convert to i2c driver model
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38   ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree
  Cc: kgene.kim, inki.dae, thierry.reding, daniel.vetter, seanpaul,
	ajaynumb, jg1.han, bhushan.r, prashanth.g, Ajay Kumar

Use drm_bridge helpers to modify the driver to support
i2c driver model.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/bridge/Kconfig          |    2 +
 drivers/gpu/drm/bridge/ptn3460.c        |  124 +++++++++++++++++++++----------
 drivers/gpu/drm/exynos/exynos_dp_core.c |   22 ------
 3 files changed, 86 insertions(+), 62 deletions(-)

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 884923f..4254c2b 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -1,5 +1,7 @@
 config DRM_PTN3460
 	tristate "PTN3460 DP/LVDS bridge"
 	depends on DRM
+	depends on OF && I2C
 	select DRM_KMS_HELPER
 	---help---
+	  ptn3460 eDP-LVDS bridge chip driver.
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index 4a818c1..7adeb60 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -36,7 +36,6 @@
 struct ptn3460_bridge {
 	struct drm_connector connector;
 	struct i2c_client *client;
-	struct drm_encoder *encoder;
 	struct drm_bridge bridge;
 	struct edid *edid;
 	int gpio_pd_n;
@@ -176,13 +175,6 @@ static void ptn3460_post_disable(struct drm_bridge *bridge)
 {
 }
 
-static struct drm_bridge_funcs ptn3460_bridge_funcs = {
-	.pre_enable = ptn3460_pre_enable,
-	.enable = ptn3460_enable,
-	.disable = ptn3460_disable,
-	.post_disable = ptn3460_post_disable,
-};
-
 static int ptn3460_get_modes(struct drm_connector *connector)
 {
 	struct ptn3460_bridge *ptn_bridge;
@@ -227,7 +219,7 @@ static struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
 {
 	struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector);
 
-	return ptn_bridge->encoder;
+	return ptn_bridge->bridge.encoder;
 }
 
 static struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
@@ -253,31 +245,66 @@ static struct drm_connector_funcs ptn3460_connector_funcs = {
 	.destroy = ptn3460_connector_destroy,
 };
 
-int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
-		struct i2c_client *client, struct device_node *node)
+int ptn3460_bridge_attach(struct drm_bridge *bridge)
 {
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
 	int ret;
+
+	if (!bridge->encoder) {
+		DRM_ERROR("Parent encoder object not found");
+		return -ENODEV;
+	}
+
+	ret = drm_connector_init(bridge->dev, &ptn_bridge->connector,
+			&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+	if (ret) {
+		DRM_ERROR("Failed to initialize connector with drm\n");
+		return ret;
+	}
+	drm_connector_helper_add(&ptn_bridge->connector,
+					&ptn3460_connector_helper_funcs);
+	drm_connector_register(&ptn_bridge->connector);
+	drm_mode_connector_attach_encoder(&ptn_bridge->connector,
+							bridge->encoder);
+
+	return ret;
+}
+
+static struct drm_bridge_funcs ptn3460_bridge_funcs = {
+	.pre_enable = ptn3460_pre_enable,
+	.enable = ptn3460_enable,
+	.disable = ptn3460_disable,
+	.post_disable = ptn3460_post_disable,
+	.attach = ptn3460_bridge_attach,
+};
+
+static int ptn3460_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
 	struct ptn3460_bridge *ptn_bridge;
+	int ret;
 
-	ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL);
+	ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
 	if (!ptn_bridge) {
 		return -ENOMEM;
 	}
 
 	ptn_bridge->client = client;
-	ptn_bridge->encoder = encoder;
-	ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0);
+	ptn_bridge->gpio_pd_n = of_get_named_gpio(dev->of_node,
+							"powerdown-gpio", 0);
 	if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
 		ret = gpio_request_one(ptn_bridge->gpio_pd_n,
 				GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
 		if (ret) {
-			dev_err(&client->dev,
-				"Request powerdown-gpio failed (%d)\n", ret);
+			dev_err(dev, "Request powerdown-gpio failed (%d)\n",
+									ret);
 			return ret;
 		}
 	}
 
-	ptn_bridge->gpio_rst_n = of_get_named_gpio(node, "reset-gpio", 0);
+	ptn_bridge->gpio_rst_n = of_get_named_gpio(dev->of_node,
+							"reset-gpio", 0);
 	if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
 		/*
 		 * Request the reset pin low to avoid the bridge being
@@ -286,39 +313,27 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 		ret = gpio_request_one(ptn_bridge->gpio_rst_n,
 				GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
 		if (ret) {
-			dev_err(&client->dev,
-				"Request reset-gpio failed (%d)\n", ret);
+			dev_err(dev, "Request reset-gpio failed (%d)\n", ret);
 			gpio_free(ptn_bridge->gpio_pd_n);
 			return ret;
 		}
 	}
 
-	ret = of_property_read_u32(node, "edid-emulation",
+	ret = of_property_read_u32(dev->of_node, "edid-emulation",
 			&ptn_bridge->edid_emulation);
 	if (ret) {
-		dev_err(&client->dev, "Can't read EDID emulation value\n");
+		dev_err(dev, "Can't read EDID emulation value\n");
 		goto err;
 	}
 
 	ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
-	ret = drm_bridge_attach(dev, &ptn_bridge->bridge);
+	ret = drm_bridge_add(&ptn_bridge->bridge);
 	if (ret) {
-		DRM_ERROR("Failed to initialize bridge with drm\n");
+		DRM_ERROR("Failed to add bridge\n");
 		goto err;
 	}
 
-	encoder->bridge = &ptn_bridge->bridge;
-
-	ret = drm_connector_init(dev, &ptn_bridge->connector,
-			&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
-	if (ret) {
-		DRM_ERROR("Failed to initialize connector with drm\n");
-		goto err;
-	}
-	drm_connector_helper_add(&ptn_bridge->connector,
-			&ptn3460_connector_helper_funcs);
-	drm_connector_register(&ptn_bridge->connector);
-	drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder);
+	i2c_set_clientdata(client, ptn_bridge);
 
 	return 0;
 
@@ -329,16 +344,45 @@ err:
 		gpio_free(ptn_bridge->gpio_rst_n);
 	return ret;
 }
-EXPORT_SYMBOL(ptn3460_init);
 
-void ptn3460_destroy(struct drm_bridge *bridge)
+static int ptn3460_remove(struct i2c_client *client)
 {
-	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+	struct ptn3460_bridge *ptn_bridge = i2c_get_clientdata(client);
+
+	drm_bridge_remove(&ptn_bridge->bridge);
 
 	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
 		gpio_free(ptn_bridge->gpio_pd_n);
 	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
 		gpio_free(ptn_bridge->gpio_rst_n);
-	/* Nothing else to free, we've got devm allocated memory */
+
+	return 0;
 }
-EXPORT_SYMBOL(ptn3460_destroy);
+
+static const struct i2c_device_id ptn3460_i2c_table[] = {
+	{"nxp,ptn3460", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table);
+
+static const struct of_device_id ptn3460_match[] = {
+	{ .compatible = "nxp,ptn3460" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ptn3460_match);
+
+static struct i2c_driver ptn3460_driver = {
+	.id_table	= ptn3460_i2c_table,
+	.probe		= ptn3460_probe,
+	.remove		= ptn3460_remove,
+	.driver		= {
+		.name	= "nxp,ptn3460",
+		.owner	= THIS_MODULE,
+		.of_match_table = ptn3460_match,
+	},
+};
+module_i2c_driver(ptn3460_driver);
+
+MODULE_AUTHOR("Sean Paul <seanpaul@chromium.org>");
+MODULE_DESCRIPTION("NXP ptn3460 eDP-LVDS converter driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index 34d46aa..27e3d27 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -993,32 +993,10 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
 	.best_encoder = exynos_dp_best_encoder,
 };
 
-static bool find_bridge(const char *compat, struct bridge_init *bridge)
-{
-	bridge->client = NULL;
-	bridge->node = of_find_compatible_node(NULL, NULL, compat);
-	if (!bridge->node)
-		return false;
-
-	bridge->client = of_find_i2c_device_by_node(bridge->node);
-	if (!bridge->client)
-		return false;
-
-	return true;
-}
-
 /* returns the number of bridges attached */
 static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
 		struct drm_encoder *encoder)
 {
-	struct bridge_init bridge;
-	int ret;
-
-	if (find_bridge("nxp,ptn3460", &bridge)) {
-		ret = ptn3460_init(dev, encoder, bridge.client, bridge.node);
-		if (!ret)
-			return 1;
-	}
 	return 0;
 }
 
-- 
1.7.9.5

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

* [PATCH V9 04/14] drm/bridge: ptn3460: Convert to i2c driver model
@ 2015-01-20 16:38   ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

Use drm_bridge helpers to modify the driver to support
i2c driver model.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/bridge/Kconfig          |    2 +
 drivers/gpu/drm/bridge/ptn3460.c        |  124 +++++++++++++++++++++----------
 drivers/gpu/drm/exynos/exynos_dp_core.c |   22 ------
 3 files changed, 86 insertions(+), 62 deletions(-)

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 884923f..4254c2b 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -1,5 +1,7 @@
 config DRM_PTN3460
 	tristate "PTN3460 DP/LVDS bridge"
 	depends on DRM
+	depends on OF && I2C
 	select DRM_KMS_HELPER
 	---help---
+	  ptn3460 eDP-LVDS bridge chip driver.
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index 4a818c1..7adeb60 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -36,7 +36,6 @@
 struct ptn3460_bridge {
 	struct drm_connector connector;
 	struct i2c_client *client;
-	struct drm_encoder *encoder;
 	struct drm_bridge bridge;
 	struct edid *edid;
 	int gpio_pd_n;
@@ -176,13 +175,6 @@ static void ptn3460_post_disable(struct drm_bridge *bridge)
 {
 }
 
-static struct drm_bridge_funcs ptn3460_bridge_funcs = {
-	.pre_enable = ptn3460_pre_enable,
-	.enable = ptn3460_enable,
-	.disable = ptn3460_disable,
-	.post_disable = ptn3460_post_disable,
-};
-
 static int ptn3460_get_modes(struct drm_connector *connector)
 {
 	struct ptn3460_bridge *ptn_bridge;
@@ -227,7 +219,7 @@ static struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
 {
 	struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector);
 
-	return ptn_bridge->encoder;
+	return ptn_bridge->bridge.encoder;
 }
 
 static struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
@@ -253,31 +245,66 @@ static struct drm_connector_funcs ptn3460_connector_funcs = {
 	.destroy = ptn3460_connector_destroy,
 };
 
-int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
-		struct i2c_client *client, struct device_node *node)
+int ptn3460_bridge_attach(struct drm_bridge *bridge)
 {
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
 	int ret;
+
+	if (!bridge->encoder) {
+		DRM_ERROR("Parent encoder object not found");
+		return -ENODEV;
+	}
+
+	ret = drm_connector_init(bridge->dev, &ptn_bridge->connector,
+			&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+	if (ret) {
+		DRM_ERROR("Failed to initialize connector with drm\n");
+		return ret;
+	}
+	drm_connector_helper_add(&ptn_bridge->connector,
+					&ptn3460_connector_helper_funcs);
+	drm_connector_register(&ptn_bridge->connector);
+	drm_mode_connector_attach_encoder(&ptn_bridge->connector,
+							bridge->encoder);
+
+	return ret;
+}
+
+static struct drm_bridge_funcs ptn3460_bridge_funcs = {
+	.pre_enable = ptn3460_pre_enable,
+	.enable = ptn3460_enable,
+	.disable = ptn3460_disable,
+	.post_disable = ptn3460_post_disable,
+	.attach = ptn3460_bridge_attach,
+};
+
+static int ptn3460_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
 	struct ptn3460_bridge *ptn_bridge;
+	int ret;
 
-	ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL);
+	ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
 	if (!ptn_bridge) {
 		return -ENOMEM;
 	}
 
 	ptn_bridge->client = client;
-	ptn_bridge->encoder = encoder;
-	ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0);
+	ptn_bridge->gpio_pd_n = of_get_named_gpio(dev->of_node,
+							"powerdown-gpio", 0);
 	if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
 		ret = gpio_request_one(ptn_bridge->gpio_pd_n,
 				GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
 		if (ret) {
-			dev_err(&client->dev,
-				"Request powerdown-gpio failed (%d)\n", ret);
+			dev_err(dev, "Request powerdown-gpio failed (%d)\n",
+									ret);
 			return ret;
 		}
 	}
 
-	ptn_bridge->gpio_rst_n = of_get_named_gpio(node, "reset-gpio", 0);
+	ptn_bridge->gpio_rst_n = of_get_named_gpio(dev->of_node,
+							"reset-gpio", 0);
 	if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
 		/*
 		 * Request the reset pin low to avoid the bridge being
@@ -286,39 +313,27 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 		ret = gpio_request_one(ptn_bridge->gpio_rst_n,
 				GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
 		if (ret) {
-			dev_err(&client->dev,
-				"Request reset-gpio failed (%d)\n", ret);
+			dev_err(dev, "Request reset-gpio failed (%d)\n", ret);
 			gpio_free(ptn_bridge->gpio_pd_n);
 			return ret;
 		}
 	}
 
-	ret = of_property_read_u32(node, "edid-emulation",
+	ret = of_property_read_u32(dev->of_node, "edid-emulation",
 			&ptn_bridge->edid_emulation);
 	if (ret) {
-		dev_err(&client->dev, "Can't read EDID emulation value\n");
+		dev_err(dev, "Can't read EDID emulation value\n");
 		goto err;
 	}
 
 	ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
-	ret = drm_bridge_attach(dev, &ptn_bridge->bridge);
+	ret = drm_bridge_add(&ptn_bridge->bridge);
 	if (ret) {
-		DRM_ERROR("Failed to initialize bridge with drm\n");
+		DRM_ERROR("Failed to add bridge\n");
 		goto err;
 	}
 
-	encoder->bridge = &ptn_bridge->bridge;
-
-	ret = drm_connector_init(dev, &ptn_bridge->connector,
-			&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
-	if (ret) {
-		DRM_ERROR("Failed to initialize connector with drm\n");
-		goto err;
-	}
-	drm_connector_helper_add(&ptn_bridge->connector,
-			&ptn3460_connector_helper_funcs);
-	drm_connector_register(&ptn_bridge->connector);
-	drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder);
+	i2c_set_clientdata(client, ptn_bridge);
 
 	return 0;
 
@@ -329,16 +344,45 @@ err:
 		gpio_free(ptn_bridge->gpio_rst_n);
 	return ret;
 }
-EXPORT_SYMBOL(ptn3460_init);
 
-void ptn3460_destroy(struct drm_bridge *bridge)
+static int ptn3460_remove(struct i2c_client *client)
 {
-	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+	struct ptn3460_bridge *ptn_bridge = i2c_get_clientdata(client);
+
+	drm_bridge_remove(&ptn_bridge->bridge);
 
 	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
 		gpio_free(ptn_bridge->gpio_pd_n);
 	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
 		gpio_free(ptn_bridge->gpio_rst_n);
-	/* Nothing else to free, we've got devm allocated memory */
+
+	return 0;
 }
-EXPORT_SYMBOL(ptn3460_destroy);
+
+static const struct i2c_device_id ptn3460_i2c_table[] = {
+	{"nxp,ptn3460", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table);
+
+static const struct of_device_id ptn3460_match[] = {
+	{ .compatible = "nxp,ptn3460" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ptn3460_match);
+
+static struct i2c_driver ptn3460_driver = {
+	.id_table	= ptn3460_i2c_table,
+	.probe		= ptn3460_probe,
+	.remove		= ptn3460_remove,
+	.driver		= {
+		.name	= "nxp,ptn3460",
+		.owner	= THIS_MODULE,
+		.of_match_table = ptn3460_match,
+	},
+};
+module_i2c_driver(ptn3460_driver);
+
+MODULE_AUTHOR("Sean Paul <seanpaul@chromium.org>");
+MODULE_DESCRIPTION("NXP ptn3460 eDP-LVDS converter driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index 34d46aa..27e3d27 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -993,32 +993,10 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
 	.best_encoder = exynos_dp_best_encoder,
 };
 
-static bool find_bridge(const char *compat, struct bridge_init *bridge)
-{
-	bridge->client = NULL;
-	bridge->node = of_find_compatible_node(NULL, NULL, compat);
-	if (!bridge->node)
-		return false;
-
-	bridge->client = of_find_i2c_device_by_node(bridge->node);
-	if (!bridge->client)
-		return false;
-
-	return true;
-}
-
 /* returns the number of bridges attached */
 static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
 		struct drm_encoder *encoder)
 {
-	struct bridge_init bridge;
-	int ret;
-
-	if (find_bridge("nxp,ptn3460", &bridge)) {
-		ret = ptn3460_init(dev, encoder, bridge.client, bridge.node);
-		if (!ret)
-			return 1;
-	}
 	return 0;
 }
 
-- 
1.7.9.5

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

* [PATCH V9 05/14] drm/exynos: dp: support drm_bridge
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38     ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: kgene.kim-Sze3O3UU22JBDgjK7y7TUQ,
	inki.dae-Sze3O3UU22JBDgjK7y7TUQ,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, daniel.vetter-/w4YWyX8dFk,
	seanpaul-hpIqsD4AKlfQT0dZR+AlfA, ajaynumb-Re5JQEeQqe8AvxtiuMwx3w,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, bhushan.r-Sze3O3UU22JBDgjK7y7TUQ,
	prashanth.g-Sze3O3UU22JBDgjK7y7TUQ, Ajay Kumar

Modify driver to support drm_bridge.

Signed-off-by: Ajay Kumar <ajaykumar.rs-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Tested-by: Rahul Sharma <rahul.sharma-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Tested-by: Javier Martinez Canillas <javier.martinez-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
Tested-by: Gustavo Padovan <gustavo.padovan-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
Tested-by: Sjoerd Simons <sjoerd.simons-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
---
 .../devicetree/bindings/video/exynos_dp.txt        |   12 +++++++
 drivers/gpu/drm/exynos/exynos_dp_core.c            |   37 ++++++++++++++++----
 drivers/gpu/drm/exynos/exynos_dp_core.h            |    1 +
 3 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/video/exynos_dp.txt b/Documentation/devicetree/bindings/video/exynos_dp.txt
index 53dbccf..7a3a9cd 100644
--- a/Documentation/devicetree/bindings/video/exynos_dp.txt
+++ b/Documentation/devicetree/bindings/video/exynos_dp.txt
@@ -66,6 +66,10 @@ Optional properties for dp-controller:
 		Hotplug detect GPIO.
 			Indicates which GPIO should be used for hotplug
 			detection
+	-video interfaces: Device node can contain video interface port
+			    nodes according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
 
 Example:
 
@@ -105,4 +109,12 @@ Board Specific portion:
 				vsync-len = <6>;
 			};
 		};
+
+		ports {
+			port@0 {
+				dp_out: endpoint {
+					remote-endpoint = <&bridge_in>;
+				};
+			};
+		};
 	};
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index 27e3d27..46f1497 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
+#include <linux/of_graph.h>
 #include <linux/gpio.h>
 #include <linux/component.h>
 #include <linux/phy/phy.h>
@@ -994,9 +995,19 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
 };
 
 /* returns the number of bridges attached */
-static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
+static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp,
 		struct drm_encoder *encoder)
 {
+	int ret;
+
+	encoder->bridge = dp->bridge;
+	dp->bridge->encoder = encoder;
+	ret = drm_bridge_attach(encoder->dev, dp->bridge);
+	if (ret) {
+		DRM_ERROR("Failed to attach bridge to drm\n");
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -1010,9 +1021,11 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display,
 	dp->encoder = encoder;
 
 	/* Pre-empt DP connector creation if there's a bridge */
-	ret = exynos_drm_attach_lcd_bridge(dp->drm_dev, encoder);
-	if (ret)
-		return 0;
+	if (dp->bridge) {
+		ret = exynos_drm_attach_lcd_bridge(dp, encoder);
+		if (!ret)
+			return 0;
+	}
 
 	connector->polled = DRM_CONNECTOR_POLL_HPD;
 
@@ -1219,7 +1232,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 		}
 	}
 
-	if (!dp->panel) {
+	if (!dp->panel && !dp->bridge) {
 		ret = exynos_dp_dt_parse_panel(dp);
 		if (ret)
 			return ret;
@@ -1303,7 +1316,7 @@ static const struct component_ops exynos_dp_ops = {
 static int exynos_dp_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *panel_node;
+	struct device_node *panel_node, *bridge_node, *endpoint;
 	struct exynos_dp_device *dp;
 	int ret;
 
@@ -1329,6 +1342,18 @@ static int exynos_dp_probe(struct platform_device *pdev)
 			return -EPROBE_DEFER;
 	}
 
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (endpoint) {
+		bridge_node = of_graph_get_remote_port_parent(endpoint);
+		if (bridge_node) {
+			dp->bridge = of_drm_find_bridge(bridge_node);
+			of_node_put(bridge_node);
+			if (!dp->bridge)
+				return -EPROBE_DEFER;
+		} else
+			return -EPROBE_DEFER;
+	}
+
 	ret = component_add(&pdev->dev, &exynos_dp_ops);
 	if (ret)
 		exynos_drm_component_del(&pdev->dev,
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
index 164f171..a4e7996 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.h
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.h
@@ -153,6 +153,7 @@ struct exynos_dp_device {
 	struct drm_connector	connector;
 	struct drm_encoder	*encoder;
 	struct drm_panel	*panel;
+	struct drm_bridge	*bridge;
 	struct clk		*clock;
 	unsigned int		irq;
 	void __iomem		*reg_base;
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH V9 05/14] drm/exynos: dp: support drm_bridge
@ 2015-01-20 16:38     ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

Modify driver to support drm_bridge.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 .../devicetree/bindings/video/exynos_dp.txt        |   12 +++++++
 drivers/gpu/drm/exynos/exynos_dp_core.c            |   37 ++++++++++++++++----
 drivers/gpu/drm/exynos/exynos_dp_core.h            |    1 +
 3 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/video/exynos_dp.txt b/Documentation/devicetree/bindings/video/exynos_dp.txt
index 53dbccf..7a3a9cd 100644
--- a/Documentation/devicetree/bindings/video/exynos_dp.txt
+++ b/Documentation/devicetree/bindings/video/exynos_dp.txt
@@ -66,6 +66,10 @@ Optional properties for dp-controller:
 		Hotplug detect GPIO.
 			Indicates which GPIO should be used for hotplug
 			detection
+	-video interfaces: Device node can contain video interface port
+			    nodes according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
 
 Example:
 
@@ -105,4 +109,12 @@ Board Specific portion:
 				vsync-len = <6>;
 			};
 		};
+
+		ports {
+			port at 0 {
+				dp_out: endpoint {
+					remote-endpoint = <&bridge_in>;
+				};
+			};
+		};
 	};
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index 27e3d27..46f1497 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
+#include <linux/of_graph.h>
 #include <linux/gpio.h>
 #include <linux/component.h>
 #include <linux/phy/phy.h>
@@ -994,9 +995,19 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
 };
 
 /* returns the number of bridges attached */
-static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
+static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp,
 		struct drm_encoder *encoder)
 {
+	int ret;
+
+	encoder->bridge = dp->bridge;
+	dp->bridge->encoder = encoder;
+	ret = drm_bridge_attach(encoder->dev, dp->bridge);
+	if (ret) {
+		DRM_ERROR("Failed to attach bridge to drm\n");
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -1010,9 +1021,11 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display,
 	dp->encoder = encoder;
 
 	/* Pre-empt DP connector creation if there's a bridge */
-	ret = exynos_drm_attach_lcd_bridge(dp->drm_dev, encoder);
-	if (ret)
-		return 0;
+	if (dp->bridge) {
+		ret = exynos_drm_attach_lcd_bridge(dp, encoder);
+		if (!ret)
+			return 0;
+	}
 
 	connector->polled = DRM_CONNECTOR_POLL_HPD;
 
@@ -1219,7 +1232,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 		}
 	}
 
-	if (!dp->panel) {
+	if (!dp->panel && !dp->bridge) {
 		ret = exynos_dp_dt_parse_panel(dp);
 		if (ret)
 			return ret;
@@ -1303,7 +1316,7 @@ static const struct component_ops exynos_dp_ops = {
 static int exynos_dp_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *panel_node;
+	struct device_node *panel_node, *bridge_node, *endpoint;
 	struct exynos_dp_device *dp;
 	int ret;
 
@@ -1329,6 +1342,18 @@ static int exynos_dp_probe(struct platform_device *pdev)
 			return -EPROBE_DEFER;
 	}
 
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (endpoint) {
+		bridge_node = of_graph_get_remote_port_parent(endpoint);
+		if (bridge_node) {
+			dp->bridge = of_drm_find_bridge(bridge_node);
+			of_node_put(bridge_node);
+			if (!dp->bridge)
+				return -EPROBE_DEFER;
+		} else
+			return -EPROBE_DEFER;
+	}
+
 	ret = component_add(&pdev->dev, &exynos_dp_ops);
 	if (ret)
 		exynos_drm_component_del(&pdev->dev,
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
index 164f171..a4e7996 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.h
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.h
@@ -153,6 +153,7 @@ struct exynos_dp_device {
 	struct drm_connector	connector;
 	struct drm_encoder	*encoder;
 	struct drm_panel	*panel;
+	struct drm_bridge	*bridge;
 	struct clk		*clock;
 	unsigned int		irq;
 	void __iomem		*reg_base;
-- 
1.7.9.5

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

* [PATCH V9 06/14] drm/bridge: ptn3460: support drm_panel
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38   ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree
  Cc: kgene.kim, inki.dae, thierry.reding, daniel.vetter, seanpaul,
	ajaynumb, jg1.han, bhushan.r, prashanth.g, Ajay Kumar

Add drm_panel calls to the driver to make the panel and
bridge work together in tandem.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 .../devicetree/bindings/drm/bridge/ptn3460.txt     |   12 ++++++
 drivers/gpu/drm/bridge/Kconfig                     |    1 +
 drivers/gpu/drm/bridge/ptn3460.c                   |   42 ++++++++++++++++++++
 3 files changed, 55 insertions(+)

diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
index 52b93b2..663fe6c 100644
--- a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
+++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
@@ -17,6 +17,11 @@ Required properties:
 		|   6   |  1600x900  | ChiMei M215HGE   |
 		+-------+------------+------------------+
 
+	- video interfaces: Device node can contain video interface port
+			    nodes for panel according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
 Example:
 	lvds-bridge@20 {
 		compatible = "nxp,ptn3460";
@@ -24,4 +29,11 @@ Example:
 		powerdown-gpio = <&gpy2 5 1 0 0>;
 		reset-gpio = <&gpx1 5 1 0 0>;
 		edid-emulation = <5>;
+		ports {
+			port@0 {
+				bridge_out: endpoint {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+		};
 	};
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 4254c2b..8b426e2 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -3,5 +3,6 @@ config DRM_PTN3460
 	depends on DRM
 	depends on OF && I2C
 	select DRM_KMS_HELPER
+	select DRM_PANEL
 	---help---
 	  ptn3460 eDP-LVDS bridge chip driver.
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index 7adeb60..e6d5ae7 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -19,6 +19,9 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
+#include <linux/of_graph.h>
+
+#include <drm/drm_panel.h>
 
 #include "bridge/ptn3460.h"
 
@@ -38,6 +41,7 @@ struct ptn3460_bridge {
 	struct i2c_client *client;
 	struct drm_bridge bridge;
 	struct edid *edid;
+	struct drm_panel *panel;
 	int gpio_pd_n;
 	int gpio_rst_n;
 	u32 edid_emulation;
@@ -137,6 +141,11 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
 		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
 	}
 
+	if (drm_panel_prepare(ptn_bridge->panel)) {
+		DRM_ERROR("failed to prepare panel\n");
+		return;
+	}
+
 	/*
 	 * There's a bug in the PTN chip where it falsely asserts hotplug before
 	 * it is fully functional. We're forced to wait for the maximum start up
@@ -153,6 +162,12 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
 
 static void ptn3460_enable(struct drm_bridge *bridge)
 {
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
+
+	if (drm_panel_enable(ptn_bridge->panel)) {
+		DRM_ERROR("failed to enable panel\n");
+		return;
+	}
 }
 
 static void ptn3460_disable(struct drm_bridge *bridge)
@@ -164,6 +179,11 @@ static void ptn3460_disable(struct drm_bridge *bridge)
 
 	ptn_bridge->enabled = false;
 
+	if (drm_panel_disable(ptn_bridge->panel)) {
+		DRM_ERROR("failed to disable panel\n");
+		return;
+	}
+
 	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
 		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
 
@@ -173,6 +193,12 @@ static void ptn3460_disable(struct drm_bridge *bridge)
 
 static void ptn3460_post_disable(struct drm_bridge *bridge)
 {
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
+
+	if (drm_panel_unprepare(ptn_bridge->panel)) {
+		DRM_ERROR("failed to unprepare panel\n");
+		return;
+	}
 }
 
 static int ptn3460_get_modes(struct drm_connector *connector)
@@ -267,6 +293,9 @@ int ptn3460_bridge_attach(struct drm_bridge *bridge)
 	drm_mode_connector_attach_encoder(&ptn_bridge->connector,
 							bridge->encoder);
 
+	if (ptn_bridge->panel)
+		drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector);
+
 	return ret;
 }
 
@@ -283,6 +312,7 @@ static int ptn3460_probe(struct i2c_client *client,
 {
 	struct device *dev = &client->dev;
 	struct ptn3460_bridge *ptn_bridge;
+	struct device_node *endpoint, *panel_node;
 	int ret;
 
 	ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
@@ -290,6 +320,17 @@ static int ptn3460_probe(struct i2c_client *client,
 		return -ENOMEM;
 	}
 
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (endpoint) {
+		panel_node = of_graph_get_remote_port_parent(endpoint);
+		if (panel_node) {
+			ptn_bridge->panel = of_drm_find_panel(panel_node);
+			of_node_put(panel_node);
+			if (!ptn_bridge->panel)
+				return -EPROBE_DEFER;
+		}
+	}
+
 	ptn_bridge->client = client;
 	ptn_bridge->gpio_pd_n = of_get_named_gpio(dev->of_node,
 							"powerdown-gpio", 0);
@@ -327,6 +368,7 @@ static int ptn3460_probe(struct i2c_client *client,
 	}
 
 	ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
+	ptn_bridge->bridge.of_node = dev->of_node;
 	ret = drm_bridge_add(&ptn_bridge->bridge);
 	if (ret) {
 		DRM_ERROR("Failed to add bridge\n");
-- 
1.7.9.5

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

* [PATCH V9 06/14] drm/bridge: ptn3460: support drm_panel
@ 2015-01-20 16:38   ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

Add drm_panel calls to the driver to make the panel and
bridge work together in tandem.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 .../devicetree/bindings/drm/bridge/ptn3460.txt     |   12 ++++++
 drivers/gpu/drm/bridge/Kconfig                     |    1 +
 drivers/gpu/drm/bridge/ptn3460.c                   |   42 ++++++++++++++++++++
 3 files changed, 55 insertions(+)

diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
index 52b93b2..663fe6c 100644
--- a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
+++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
@@ -17,6 +17,11 @@ Required properties:
 		|   6   |  1600x900  | ChiMei M215HGE   |
 		+-------+------------+------------------+
 
+	- video interfaces: Device node can contain video interface port
+			    nodes for panel according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
 Example:
 	lvds-bridge at 20 {
 		compatible = "nxp,ptn3460";
@@ -24,4 +29,11 @@ Example:
 		powerdown-gpio = <&gpy2 5 1 0 0>;
 		reset-gpio = <&gpx1 5 1 0 0>;
 		edid-emulation = <5>;
+		ports {
+			port at 0 {
+				bridge_out: endpoint {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+		};
 	};
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 4254c2b..8b426e2 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -3,5 +3,6 @@ config DRM_PTN3460
 	depends on DRM
 	depends on OF && I2C
 	select DRM_KMS_HELPER
+	select DRM_PANEL
 	---help---
 	  ptn3460 eDP-LVDS bridge chip driver.
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index 7adeb60..e6d5ae7 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -19,6 +19,9 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
+#include <linux/of_graph.h>
+
+#include <drm/drm_panel.h>
 
 #include "bridge/ptn3460.h"
 
@@ -38,6 +41,7 @@ struct ptn3460_bridge {
 	struct i2c_client *client;
 	struct drm_bridge bridge;
 	struct edid *edid;
+	struct drm_panel *panel;
 	int gpio_pd_n;
 	int gpio_rst_n;
 	u32 edid_emulation;
@@ -137,6 +141,11 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
 		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
 	}
 
+	if (drm_panel_prepare(ptn_bridge->panel)) {
+		DRM_ERROR("failed to prepare panel\n");
+		return;
+	}
+
 	/*
 	 * There's a bug in the PTN chip where it falsely asserts hotplug before
 	 * it is fully functional. We're forced to wait for the maximum start up
@@ -153,6 +162,12 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
 
 static void ptn3460_enable(struct drm_bridge *bridge)
 {
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
+
+	if (drm_panel_enable(ptn_bridge->panel)) {
+		DRM_ERROR("failed to enable panel\n");
+		return;
+	}
 }
 
 static void ptn3460_disable(struct drm_bridge *bridge)
@@ -164,6 +179,11 @@ static void ptn3460_disable(struct drm_bridge *bridge)
 
 	ptn_bridge->enabled = false;
 
+	if (drm_panel_disable(ptn_bridge->panel)) {
+		DRM_ERROR("failed to disable panel\n");
+		return;
+	}
+
 	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
 		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
 
@@ -173,6 +193,12 @@ static void ptn3460_disable(struct drm_bridge *bridge)
 
 static void ptn3460_post_disable(struct drm_bridge *bridge)
 {
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
+
+	if (drm_panel_unprepare(ptn_bridge->panel)) {
+		DRM_ERROR("failed to unprepare panel\n");
+		return;
+	}
 }
 
 static int ptn3460_get_modes(struct drm_connector *connector)
@@ -267,6 +293,9 @@ int ptn3460_bridge_attach(struct drm_bridge *bridge)
 	drm_mode_connector_attach_encoder(&ptn_bridge->connector,
 							bridge->encoder);
 
+	if (ptn_bridge->panel)
+		drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector);
+
 	return ret;
 }
 
@@ -283,6 +312,7 @@ static int ptn3460_probe(struct i2c_client *client,
 {
 	struct device *dev = &client->dev;
 	struct ptn3460_bridge *ptn_bridge;
+	struct device_node *endpoint, *panel_node;
 	int ret;
 
 	ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
@@ -290,6 +320,17 @@ static int ptn3460_probe(struct i2c_client *client,
 		return -ENOMEM;
 	}
 
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (endpoint) {
+		panel_node = of_graph_get_remote_port_parent(endpoint);
+		if (panel_node) {
+			ptn_bridge->panel = of_drm_find_panel(panel_node);
+			of_node_put(panel_node);
+			if (!ptn_bridge->panel)
+				return -EPROBE_DEFER;
+		}
+	}
+
 	ptn_bridge->client = client;
 	ptn_bridge->gpio_pd_n = of_get_named_gpio(dev->of_node,
 							"powerdown-gpio", 0);
@@ -327,6 +368,7 @@ static int ptn3460_probe(struct i2c_client *client,
 	}
 
 	ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
+	ptn_bridge->bridge.of_node = dev->of_node;
 	ret = drm_bridge_add(&ptn_bridge->bridge);
 	if (ret) {
 		DRM_ERROR("Failed to add bridge\n");
-- 
1.7.9.5

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

* [PATCH V9 07/14] drm/bridge: ptn3460: probe connector at the end of bridge attach
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38   ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree
  Cc: kgene.kim, inki.dae, thierry.reding, daniel.vetter, seanpaul,
	ajaynumb, jg1.han, bhushan.r, prashanth.g, Ajay Kumar

Force bridge connector detection at the end of the bridge attach.
This is needed to detect the bridge connector early.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/bridge/ptn3460.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index e6d5ae7..9f800a1 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -281,6 +281,7 @@ int ptn3460_bridge_attach(struct drm_bridge *bridge)
 		return -ENODEV;
 	}
 
+	ptn_bridge->connector.polled = DRM_CONNECTOR_POLL_HPD;
 	ret = drm_connector_init(bridge->dev, &ptn_bridge->connector,
 			&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
 	if (ret) {
@@ -296,6 +297,8 @@ int ptn3460_bridge_attach(struct drm_bridge *bridge)
 	if (ptn_bridge->panel)
 		drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector);
 
+	drm_helper_hpd_irq_event(ptn_bridge->connector.dev);
+
 	return ret;
 }
 
-- 
1.7.9.5

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

* [PATCH V9 07/14] drm/bridge: ptn3460: probe connector at the end of bridge attach
@ 2015-01-20 16:38   ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

Force bridge connector detection at the end of the bridge attach.
This is needed to detect the bridge connector early.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/bridge/ptn3460.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index e6d5ae7..9f800a1 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -281,6 +281,7 @@ int ptn3460_bridge_attach(struct drm_bridge *bridge)
 		return -ENODEV;
 	}
 
+	ptn_bridge->connector.polled = DRM_CONNECTOR_POLL_HPD;
 	ret = drm_connector_init(bridge->dev, &ptn_bridge->connector,
 			&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
 	if (ret) {
@@ -296,6 +297,8 @@ int ptn3460_bridge_attach(struct drm_bridge *bridge)
 	if (ptn_bridge->panel)
 		drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector);
 
+	drm_helper_hpd_irq_event(ptn_bridge->connector.dev);
+
 	return ret;
 }
 
-- 
1.7.9.5

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

* [PATCH V9 08/14] drm/bridge: ptn3460: use gpiod interface
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38   ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree
  Cc: kgene.kim, inki.dae, thierry.reding, daniel.vetter, seanpaul,
	ajaynumb, jg1.han, bhushan.r, prashanth.g, Ajay Kumar

Modify driver to support gpiod interface.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/bridge/ptn3460.c |   88 ++++++++++++++++----------------------
 1 file changed, 36 insertions(+), 52 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index 9f800a1..826833e 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -42,8 +42,8 @@ struct ptn3460_bridge {
 	struct drm_bridge bridge;
 	struct edid *edid;
 	struct drm_panel *panel;
-	int gpio_pd_n;
-	int gpio_rst_n;
+	struct gpio_desc *gpio_pd_n;
+	struct gpio_desc *gpio_rst_n;
 	u32 edid_emulation;
 	bool enabled;
 };
@@ -132,14 +132,11 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
 	if (ptn_bridge->enabled)
 		return;
 
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_set_value(ptn_bridge->gpio_pd_n, 1);
+	gpiod_set_value(ptn_bridge->gpio_pd_n, 1);
 
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
-		gpio_set_value(ptn_bridge->gpio_rst_n, 0);
-		usleep_range(10, 20);
-		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
-	}
+	gpiod_set_value(ptn_bridge->gpio_rst_n, 0);
+	usleep_range(10, 20);
+	gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
 
 	if (drm_panel_prepare(ptn_bridge->panel)) {
 		DRM_ERROR("failed to prepare panel\n");
@@ -184,11 +181,8 @@ static void ptn3460_disable(struct drm_bridge *bridge)
 		return;
 	}
 
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
-		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
-
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_set_value(ptn_bridge->gpio_pd_n, 0);
+	gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
+	gpiod_set_value(ptn_bridge->gpio_pd_n, 0);
 }
 
 static void ptn3460_post_disable(struct drm_bridge *bridge)
@@ -335,39 +329,41 @@ static int ptn3460_probe(struct i2c_client *client,
 	}
 
 	ptn_bridge->client = client;
-	ptn_bridge->gpio_pd_n = of_get_named_gpio(dev->of_node,
-							"powerdown-gpio", 0);
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
-		ret = gpio_request_one(ptn_bridge->gpio_pd_n,
-				GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
-		if (ret) {
-			dev_err(dev, "Request powerdown-gpio failed (%d)\n",
-									ret);
-			return ret;
-		}
+
+	ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown");
+	if (IS_ERR(ptn_bridge->gpio_pd_n)) {
+		ret = PTR_ERR(ptn_bridge->gpio_pd_n);
+		dev_err(dev, "cannot get gpio_pd_n %d\n", ret);
+		return ret;
 	}
 
-	ptn_bridge->gpio_rst_n = of_get_named_gpio(dev->of_node,
-							"reset-gpio", 0);
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
-		/*
-		 * Request the reset pin low to avoid the bridge being
-		 * initialized prematurely
-		 */
-		ret = gpio_request_one(ptn_bridge->gpio_rst_n,
-				GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
-		if (ret) {
-			dev_err(dev, "Request reset-gpio failed (%d)\n", ret);
-			gpio_free(ptn_bridge->gpio_pd_n);
-			return ret;
-		}
+	ret = gpiod_direction_output(ptn_bridge->gpio_pd_n, 1);
+	if (ret) {
+		DRM_ERROR("cannot configure gpio_pd_n\n");
+		return ret;
+	}
+
+	ptn_bridge->gpio_rst_n = devm_gpiod_get(&client->dev, "reset");
+	if (IS_ERR(ptn_bridge->gpio_rst_n)) {
+		ret = PTR_ERR(ptn_bridge->gpio_rst_n);
+		DRM_ERROR("cannot get gpio_rst_n %d\n", ret);
+		return ret;
+	}
+	/*
+	 * Request the reset pin low to avoid the bridge being
+	 * initialized prematurely
+	 */
+	ret = gpiod_direction_output(ptn_bridge->gpio_rst_n, 0);
+	if (ret) {
+		DRM_ERROR("cannot configure gpio_rst_n\n");
+		return ret;
 	}
 
 	ret = of_property_read_u32(dev->of_node, "edid-emulation",
 			&ptn_bridge->edid_emulation);
 	if (ret) {
 		dev_err(dev, "Can't read EDID emulation value\n");
-		goto err;
+		return ret;
 	}
 
 	ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
@@ -375,19 +371,12 @@ static int ptn3460_probe(struct i2c_client *client,
 	ret = drm_bridge_add(&ptn_bridge->bridge);
 	if (ret) {
 		DRM_ERROR("Failed to add bridge\n");
-		goto err;
+		return ret;
 	}
 
 	i2c_set_clientdata(client, ptn_bridge);
 
 	return 0;
-
-err:
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_free(ptn_bridge->gpio_pd_n);
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
-		gpio_free(ptn_bridge->gpio_rst_n);
-	return ret;
 }
 
 static int ptn3460_remove(struct i2c_client *client)
@@ -396,11 +385,6 @@ static int ptn3460_remove(struct i2c_client *client)
 
 	drm_bridge_remove(&ptn_bridge->bridge);
 
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_free(ptn_bridge->gpio_pd_n);
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
-		gpio_free(ptn_bridge->gpio_rst_n);
-
 	return 0;
 }
 
-- 
1.7.9.5

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

* [PATCH V9 08/14] drm/bridge: ptn3460: use gpiod interface
@ 2015-01-20 16:38   ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

Modify driver to support gpiod interface.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/bridge/ptn3460.c |   88 ++++++++++++++++----------------------
 1 file changed, 36 insertions(+), 52 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index 9f800a1..826833e 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -42,8 +42,8 @@ struct ptn3460_bridge {
 	struct drm_bridge bridge;
 	struct edid *edid;
 	struct drm_panel *panel;
-	int gpio_pd_n;
-	int gpio_rst_n;
+	struct gpio_desc *gpio_pd_n;
+	struct gpio_desc *gpio_rst_n;
 	u32 edid_emulation;
 	bool enabled;
 };
@@ -132,14 +132,11 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
 	if (ptn_bridge->enabled)
 		return;
 
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_set_value(ptn_bridge->gpio_pd_n, 1);
+	gpiod_set_value(ptn_bridge->gpio_pd_n, 1);
 
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
-		gpio_set_value(ptn_bridge->gpio_rst_n, 0);
-		usleep_range(10, 20);
-		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
-	}
+	gpiod_set_value(ptn_bridge->gpio_rst_n, 0);
+	usleep_range(10, 20);
+	gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
 
 	if (drm_panel_prepare(ptn_bridge->panel)) {
 		DRM_ERROR("failed to prepare panel\n");
@@ -184,11 +181,8 @@ static void ptn3460_disable(struct drm_bridge *bridge)
 		return;
 	}
 
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
-		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
-
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_set_value(ptn_bridge->gpio_pd_n, 0);
+	gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
+	gpiod_set_value(ptn_bridge->gpio_pd_n, 0);
 }
 
 static void ptn3460_post_disable(struct drm_bridge *bridge)
@@ -335,39 +329,41 @@ static int ptn3460_probe(struct i2c_client *client,
 	}
 
 	ptn_bridge->client = client;
-	ptn_bridge->gpio_pd_n = of_get_named_gpio(dev->of_node,
-							"powerdown-gpio", 0);
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
-		ret = gpio_request_one(ptn_bridge->gpio_pd_n,
-				GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
-		if (ret) {
-			dev_err(dev, "Request powerdown-gpio failed (%d)\n",
-									ret);
-			return ret;
-		}
+
+	ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown");
+	if (IS_ERR(ptn_bridge->gpio_pd_n)) {
+		ret = PTR_ERR(ptn_bridge->gpio_pd_n);
+		dev_err(dev, "cannot get gpio_pd_n %d\n", ret);
+		return ret;
 	}
 
-	ptn_bridge->gpio_rst_n = of_get_named_gpio(dev->of_node,
-							"reset-gpio", 0);
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
-		/*
-		 * Request the reset pin low to avoid the bridge being
-		 * initialized prematurely
-		 */
-		ret = gpio_request_one(ptn_bridge->gpio_rst_n,
-				GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
-		if (ret) {
-			dev_err(dev, "Request reset-gpio failed (%d)\n", ret);
-			gpio_free(ptn_bridge->gpio_pd_n);
-			return ret;
-		}
+	ret = gpiod_direction_output(ptn_bridge->gpio_pd_n, 1);
+	if (ret) {
+		DRM_ERROR("cannot configure gpio_pd_n\n");
+		return ret;
+	}
+
+	ptn_bridge->gpio_rst_n = devm_gpiod_get(&client->dev, "reset");
+	if (IS_ERR(ptn_bridge->gpio_rst_n)) {
+		ret = PTR_ERR(ptn_bridge->gpio_rst_n);
+		DRM_ERROR("cannot get gpio_rst_n %d\n", ret);
+		return ret;
+	}
+	/*
+	 * Request the reset pin low to avoid the bridge being
+	 * initialized prematurely
+	 */
+	ret = gpiod_direction_output(ptn_bridge->gpio_rst_n, 0);
+	if (ret) {
+		DRM_ERROR("cannot configure gpio_rst_n\n");
+		return ret;
 	}
 
 	ret = of_property_read_u32(dev->of_node, "edid-emulation",
 			&ptn_bridge->edid_emulation);
 	if (ret) {
 		dev_err(dev, "Can't read EDID emulation value\n");
-		goto err;
+		return ret;
 	}
 
 	ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
@@ -375,19 +371,12 @@ static int ptn3460_probe(struct i2c_client *client,
 	ret = drm_bridge_add(&ptn_bridge->bridge);
 	if (ret) {
 		DRM_ERROR("Failed to add bridge\n");
-		goto err;
+		return ret;
 	}
 
 	i2c_set_clientdata(client, ptn_bridge);
 
 	return 0;
-
-err:
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_free(ptn_bridge->gpio_pd_n);
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
-		gpio_free(ptn_bridge->gpio_rst_n);
-	return ret;
 }
 
 static int ptn3460_remove(struct i2c_client *client)
@@ -396,11 +385,6 @@ static int ptn3460_remove(struct i2c_client *client)
 
 	drm_bridge_remove(&ptn_bridge->bridge);
 
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_free(ptn_bridge->gpio_pd_n);
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
-		gpio_free(ptn_bridge->gpio_rst_n);
-
 	return 0;
 }
 
-- 
1.7.9.5

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

* [PATCH V9 09/14] Documentation: drm: bridge: move to video/bridge
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38   ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree
  Cc: kgene.kim, inki.dae, thierry.reding, daniel.vetter, seanpaul,
	ajaynumb, jg1.han, bhushan.r, prashanth.g, Ajay Kumar

Move drm/bridge documentation to video/bridge.
Also, add proper documentation for gpios used by ptn3460.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 .../devicetree/bindings/drm/bridge/ptn3460.txt     |   39 --------------------
 .../devicetree/bindings/video/bridge/ptn3460.txt   |   39 ++++++++++++++++++++
 2 files changed, 39 insertions(+), 39 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
 create mode 100644 Documentation/devicetree/bindings/video/bridge/ptn3460.txt

diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
deleted file mode 100644
index 663fe6c..0000000
--- a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-ptn3460 bridge bindings
-
-Required properties:
-	- compatible: "nxp,ptn3460"
-	- reg: i2c address of the bridge
-	- powerdown-gpio: OF device-tree gpio specification
-	- reset-gpio: OF device-tree gpio specification
-	- edid-emulation: The EDID emulation entry to use
-		+-------+------------+------------------+
-		| Value | Resolution | Description      |
-		|   0   |  1024x768  | NXP Generic      |
-		|   1   |  1920x1080 | NXP Generic      |
-		|   2   |  1920x1080 | NXP Generic      |
-		|   3   |  1600x900  | Samsung LTM200KT |
-		|   4   |  1920x1080 | Samsung LTM230HT |
-		|   5   |  1366x768  | NXP Generic      |
-		|   6   |  1600x900  | ChiMei M215HGE   |
-		+-------+------------+------------------+
-
-	- video interfaces: Device node can contain video interface port
-			    nodes for panel according to [1].
-
-[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
-
-Example:
-	lvds-bridge@20 {
-		compatible = "nxp,ptn3460";
-		reg = <0x20>;
-		powerdown-gpio = <&gpy2 5 1 0 0>;
-		reset-gpio = <&gpx1 5 1 0 0>;
-		edid-emulation = <5>;
-		ports {
-			port@0 {
-				bridge_out: endpoint {
-					remote-endpoint = <&panel_in>;
-				};
-			};
-		};
-	};
diff --git a/Documentation/devicetree/bindings/video/bridge/ptn3460.txt b/Documentation/devicetree/bindings/video/bridge/ptn3460.txt
new file mode 100644
index 0000000..361971b
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/bridge/ptn3460.txt
@@ -0,0 +1,39 @@
+ptn3460 bridge bindings
+
+Required properties:
+	- compatible: "nxp,ptn3460"
+	- reg: i2c address of the bridge
+	- powerdown-gpio: OF device-tree gpio specification  for PD_N pin.
+	- reset-gpio: OF device-tree gpio specification for RST_N pin.
+	- edid-emulation: The EDID emulation entry to use
+		+-------+------------+------------------+
+		| Value | Resolution | Description      |
+		|   0   |  1024x768  | NXP Generic      |
+		|   1   |  1920x1080 | NXP Generic      |
+		|   2   |  1920x1080 | NXP Generic      |
+		|   3   |  1600x900  | Samsung LTM200KT |
+		|   4   |  1920x1080 | Samsung LTM230HT |
+		|   5   |  1366x768  | NXP Generic      |
+		|   6   |  1600x900  | ChiMei M215HGE   |
+		+-------+------------+------------------+
+
+	- video interfaces: Device node can contain video interface port
+			    nodes for panel according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+	lvds-bridge@20 {
+		compatible = "nxp,ptn3460";
+		reg = <0x20>;
+		powerdown-gpio = <&gpy2 5 1 0 0>;
+		reset-gpio = <&gpx1 5 1 0 0>;
+		edid-emulation = <5>;
+		ports {
+			port@0 {
+				bridge_out: endpoint {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+		};
+	};
-- 
1.7.9.5

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

* [PATCH V9 09/14] Documentation: drm: bridge: move to video/bridge
@ 2015-01-20 16:38   ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

Move drm/bridge documentation to video/bridge.
Also, add proper documentation for gpios used by ptn3460.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 .../devicetree/bindings/drm/bridge/ptn3460.txt     |   39 --------------------
 .../devicetree/bindings/video/bridge/ptn3460.txt   |   39 ++++++++++++++++++++
 2 files changed, 39 insertions(+), 39 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
 create mode 100644 Documentation/devicetree/bindings/video/bridge/ptn3460.txt

diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
deleted file mode 100644
index 663fe6c..0000000
--- a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-ptn3460 bridge bindings
-
-Required properties:
-	- compatible: "nxp,ptn3460"
-	- reg: i2c address of the bridge
-	- powerdown-gpio: OF device-tree gpio specification
-	- reset-gpio: OF device-tree gpio specification
-	- edid-emulation: The EDID emulation entry to use
-		+-------+------------+------------------+
-		| Value | Resolution | Description      |
-		|   0   |  1024x768  | NXP Generic      |
-		|   1   |  1920x1080 | NXP Generic      |
-		|   2   |  1920x1080 | NXP Generic      |
-		|   3   |  1600x900  | Samsung LTM200KT |
-		|   4   |  1920x1080 | Samsung LTM230HT |
-		|   5   |  1366x768  | NXP Generic      |
-		|   6   |  1600x900  | ChiMei M215HGE   |
-		+-------+------------+------------------+
-
-	- video interfaces: Device node can contain video interface port
-			    nodes for panel according to [1].
-
-[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
-
-Example:
-	lvds-bridge at 20 {
-		compatible = "nxp,ptn3460";
-		reg = <0x20>;
-		powerdown-gpio = <&gpy2 5 1 0 0>;
-		reset-gpio = <&gpx1 5 1 0 0>;
-		edid-emulation = <5>;
-		ports {
-			port at 0 {
-				bridge_out: endpoint {
-					remote-endpoint = <&panel_in>;
-				};
-			};
-		};
-	};
diff --git a/Documentation/devicetree/bindings/video/bridge/ptn3460.txt b/Documentation/devicetree/bindings/video/bridge/ptn3460.txt
new file mode 100644
index 0000000..361971b
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/bridge/ptn3460.txt
@@ -0,0 +1,39 @@
+ptn3460 bridge bindings
+
+Required properties:
+	- compatible: "nxp,ptn3460"
+	- reg: i2c address of the bridge
+	- powerdown-gpio: OF device-tree gpio specification  for PD_N pin.
+	- reset-gpio: OF device-tree gpio specification for RST_N pin.
+	- edid-emulation: The EDID emulation entry to use
+		+-------+------------+------------------+
+		| Value | Resolution | Description      |
+		|   0   |  1024x768  | NXP Generic      |
+		|   1   |  1920x1080 | NXP Generic      |
+		|   2   |  1920x1080 | NXP Generic      |
+		|   3   |  1600x900  | Samsung LTM200KT |
+		|   4   |  1920x1080 | Samsung LTM230HT |
+		|   5   |  1366x768  | NXP Generic      |
+		|   6   |  1600x900  | ChiMei M215HGE   |
+		+-------+------------+------------------+
+
+	- video interfaces: Device node can contain video interface port
+			    nodes for panel according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+	lvds-bridge at 20 {
+		compatible = "nxp,ptn3460";
+		reg = <0x20>;
+		powerdown-gpio = <&gpy2 5 1 0 0>;
+		reset-gpio = <&gpx1 5 1 0 0>;
+		edid-emulation = <5>;
+		ports {
+			port at 0 {
+				bridge_out: endpoint {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+		};
+	};
-- 
1.7.9.5

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

* [PATCH V9 10/14] Documentation: devicetree: Add vendor prefix for parade
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38   ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree
  Cc: kgene.kim, inki.dae, thierry.reding, daniel.vetter, seanpaul,
	ajaynumb, jg1.han, bhushan.r, prashanth.g, Ajay Kumar

ps8622 eDP-LVDS converter bridge chip is from parade technologies

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 .../devicetree/bindings/vendor-prefixes.txt        |    1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 4df1d78..eca48be 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -125,6 +125,7 @@ nxp	NXP Semiconductors
 onnn	ON Semiconductor Corp.
 opencores	OpenCores.org
 panasonic	Panasonic Corporation
+parade	Parade Technologies Inc.
 pericom	Pericom Technology Inc.
 phytec	PHYTEC Messtechnik GmbH
 picochip	Picochip Ltd
-- 
1.7.9.5

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

* [PATCH V9 10/14] Documentation: devicetree: Add vendor prefix for parade
@ 2015-01-20 16:38   ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

ps8622 eDP-LVDS converter bridge chip is from parade technologies

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 .../devicetree/bindings/vendor-prefixes.txt        |    1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 4df1d78..eca48be 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -125,6 +125,7 @@ nxp	NXP Semiconductors
 onnn	ON Semiconductor Corp.
 opencores	OpenCores.org
 panasonic	Panasonic Corporation
+parade	Parade Technologies Inc.
 pericom	Pericom Technology Inc.
 phytec	PHYTEC Messtechnik GmbH
 picochip	Picochip Ltd
-- 
1.7.9.5

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

* [PATCH V9 11/14] Documentation: bridge: Add documentation for ps8622 DT properties
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38     ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: kgene.kim-Sze3O3UU22JBDgjK7y7TUQ,
	inki.dae-Sze3O3UU22JBDgjK7y7TUQ,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, daniel.vetter-/w4YWyX8dFk,
	seanpaul-hpIqsD4AKlfQT0dZR+AlfA, ajaynumb-Re5JQEeQqe8AvxtiuMwx3w,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, bhushan.r-Sze3O3UU22JBDgjK7y7TUQ,
	prashanth.g-Sze3O3UU22JBDgjK7y7TUQ, Ajay Kumar

Add documentation for DT properties supported by ps8622/ps8625
eDP-LVDS converter.

Signed-off-by: Ajay Kumar <ajaykumar.rs-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Acked-by: Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Tested-by: Rahul Sharma <rahul.sharma-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Tested-by: Javier Martinez Canillas <javier.martinez-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
Tested-by: Gustavo Padovan <gustavo.padovan-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
Tested-by: Sjoerd Simons <sjoerd.simons-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
---
 .../devicetree/bindings/video/bridge/ps8622.txt    |   31 ++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/video/bridge/ps8622.txt

diff --git a/Documentation/devicetree/bindings/video/bridge/ps8622.txt b/Documentation/devicetree/bindings/video/bridge/ps8622.txt
new file mode 100644
index 0000000..c989c38
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/bridge/ps8622.txt
@@ -0,0 +1,31 @@
+ps8622-bridge bindings
+
+Required properties:
+	- compatible: "parade,ps8622" or "parade,ps8625"
+	- reg: first i2c address of the bridge
+	- sleep-gpios: OF device-tree gpio specification for PD_ pin.
+	- reset-gpios: OF device-tree gpio specification for RST_ pin.
+
+Optional properties:
+	- lane-count: number of DP lanes to use
+	- use-external-pwm: backlight will be controlled by an external PWM
+	- video interfaces: Device node can contain video interface port
+			    nodes for panel according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+	lvds-bridge@48 {
+		compatible = "parade,ps8622";
+		reg = <0x48>;
+		sleep-gpios = <&gpc3 6 1 0 0>;
+		reset-gpios = <&gpc3 1 1 0 0>;
+		lane-count = <1>;
+		ports {
+			port@0 {
+				bridge_out: endpoint {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+		};
+	};
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH V9 11/14] Documentation: bridge: Add documentation for ps8622 DT properties
@ 2015-01-20 16:38     ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

Add documentation for DT properties supported by ps8622/ps8625
eDP-LVDS converter.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 .../devicetree/bindings/video/bridge/ps8622.txt    |   31 ++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/video/bridge/ps8622.txt

diff --git a/Documentation/devicetree/bindings/video/bridge/ps8622.txt b/Documentation/devicetree/bindings/video/bridge/ps8622.txt
new file mode 100644
index 0000000..c989c38
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/bridge/ps8622.txt
@@ -0,0 +1,31 @@
+ps8622-bridge bindings
+
+Required properties:
+	- compatible: "parade,ps8622" or "parade,ps8625"
+	- reg: first i2c address of the bridge
+	- sleep-gpios: OF device-tree gpio specification for PD_ pin.
+	- reset-gpios: OF device-tree gpio specification for RST_ pin.
+
+Optional properties:
+	- lane-count: number of DP lanes to use
+	- use-external-pwm: backlight will be controlled by an external PWM
+	- video interfaces: Device node can contain video interface port
+			    nodes for panel according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+	lvds-bridge at 48 {
+		compatible = "parade,ps8622";
+		reg = <0x48>;
+		sleep-gpios = <&gpc3 6 1 0 0>;
+		reset-gpios = <&gpc3 1 1 0 0>;
+		lane-count = <1>;
+		ports {
+			port at 0 {
+				bridge_out: endpoint {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+		};
+	};
-- 
1.7.9.5

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

* [PATCH V9 12/14] drm/bridge: Add i2c based driver for ps8622/ps8625 bridge
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38   ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree
  Cc: kgene.kim, inki.dae, thierry.reding, daniel.vetter, seanpaul,
	ajaynumb, jg1.han, bhushan.r, prashanth.g, Vincent Palatin,
	Andrew Bresticker, Sean Paul, Rahul Sharma, Ajay Kumar

From: Vincent Palatin <vpalatin@chromium.org>

This patch adds drm_bridge driver for parade DisplayPort
to LVDS bridge chip.

Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/bridge/Kconfig  |    9 +
 drivers/gpu/drm/bridge/Makefile |    1 +
 drivers/gpu/drm/bridge/ps8622.c |  684 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 694 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/ps8622.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 8b426e2..d06eda3 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -6,3 +6,12 @@ config DRM_PTN3460
 	select DRM_PANEL
 	---help---
 	  ptn3460 eDP-LVDS bridge chip driver.
+
+config DRM_PS8622
+	tristate "Parade eDP/LVDS bridge"
+	depends on OF && I2C
+	select DRM_PANEL
+	select BACKLIGHT_LCD_SUPPORT
+	select BACKLIGHT_CLASS_DEVICE
+	---help---
+	  parade eDP-LVDS bridge chip driver.
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index b4733e1..105da3e 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,3 +1,4 @@
 ccflags-y := -Iinclude/drm
 
+obj-$(CONFIG_DRM_PS8622) += ps8622.o
 obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
diff --git a/drivers/gpu/drm/bridge/ps8622.c b/drivers/gpu/drm/bridge/ps8622.c
new file mode 100644
index 0000000..5474a39
--- /dev/null
+++ b/drivers/gpu/drm/bridge/ps8622.c
@@ -0,0 +1,684 @@
+/*
+ * Parade PS8622 eDP/LVDS bridge driver
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/backlight.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pm.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_panel.h>
+
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+
+/* Brightness scale on the Parade chip */
+#define PS8622_MAX_BRIGHTNESS 0xff
+
+/* Timings taken from the version 1.7 datasheet for the PS8622/PS8625 */
+#define PS8622_POWER_RISE_T1_MIN_US 10
+#define PS8622_POWER_RISE_T1_MAX_US 10000
+#define PS8622_RST_HIGH_T2_MIN_US 3000
+#define PS8622_RST_HIGH_T2_MAX_US 30000
+#define PS8622_PWMO_END_T12_MS 200
+#define PS8622_POWER_FALL_T16_MAX_US 10000
+#define PS8622_POWER_OFF_T17_MS 500
+
+#if ((PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US) > \
+	(PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US))
+#error "T2.min + T1.max must be less than T2.max + T1.min"
+#endif
+
+struct ps8622_bridge {
+	struct drm_connector connector;
+	struct i2c_client *client;
+	struct drm_bridge bridge;
+	struct drm_panel *panel;
+	struct regulator *v12;
+	struct backlight_device *bl;
+
+	struct gpio_desc *gpio_slp;
+	struct gpio_desc *gpio_rst;
+
+	u32 max_lane_count;
+	u32 lane_count;
+
+	bool enabled;
+};
+
+static inline struct ps8622_bridge *
+		bridge_to_ps8622(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct ps8622_bridge, bridge);
+}
+
+static inline struct ps8622_bridge *
+		connector_to_ps8622(struct drm_connector *connector)
+{
+	return container_of(connector, struct ps8622_bridge, connector);
+}
+
+static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val)
+{
+	int ret;
+	struct i2c_adapter *adap = client->adapter;
+	struct i2c_msg msg;
+	u8 data[] = {reg, val};
+
+	msg.addr = client->addr + page;
+	msg.flags = 0;
+	msg.len = sizeof(data);
+	msg.buf = data;
+
+	ret = i2c_transfer(adap, &msg, 1);
+	if (ret != 1)
+		pr_warn("PS8622 I2C write (0x%02x,0x%02x,0x%02x) failed: %d\n",
+			client->addr + page, reg, val, ret);
+	return !(ret == 1);
+}
+
+static int ps8622_send_config(struct ps8622_bridge *ps8622)
+{
+	struct i2c_client *cl = ps8622->client;
+	int err = 0;
+
+	/* HPD low */
+	err = ps8622_set(cl, 0x02, 0xa1, 0x01);
+	if (err)
+		goto error;
+
+	/* SW setting: [1:0] SW output 1.2V voltage is lower to 96% */
+	err = ps8622_set(cl, 0x04, 0x14, 0x01);
+	if (err)
+		goto error;
+
+	/* RCO SS setting: [5:4] = b01 0.5%, b10 1%, b11 1.5% */
+	err = ps8622_set(cl, 0x04, 0xe3, 0x20);
+	if (err)
+		goto error;
+
+	/* [7] RCO SS enable */
+	err = ps8622_set(cl, 0x04, 0xe2, 0x80);
+	if (err)
+		goto error;
+
+	/* RPHY Setting
+	 * [3:2] CDR tune wait cycle before measure for fine tune
+	 * b00: 1us b01: 0.5us b10:2us, b11: 4us
+	 */
+	err = ps8622_set(cl, 0x04, 0x8a, 0x0c);
+	if (err)
+		goto error;
+
+	/* [3] RFD always on */
+	err = ps8622_set(cl, 0x04, 0x89, 0x08);
+	if (err)
+		goto error;
+
+	/* CTN lock in/out: 20000ppm/80000ppm. Lock out 2 times. */
+	err = ps8622_set(cl, 0x04, 0x71, 0x2d);
+	if (err)
+		goto error;
+
+	/* 2.7G CDR settings: NOF=40LSB for HBR CDR  setting */
+	err = ps8622_set(cl, 0x04, 0x7d, 0x07);
+	if (err)
+		goto error;
+
+	/* [1:0] Fmin=+4bands */
+	err = ps8622_set(cl, 0x04, 0x7b, 0x00);
+	if (err)
+		goto error;
+
+	/* [7:5] DCO_FTRNG=+-40% */
+	err = ps8622_set(cl, 0x04, 0x7a, 0xfd);
+	if (err)
+		goto error;
+
+	/* 1.62G CDR settings: [5:2]NOF=64LSB [1:0]DCO scale is 2/5 */
+	err = ps8622_set(cl, 0x04, 0xc0, 0x12);
+	if (err)
+		goto error;
+
+	/* Gitune=-37% */
+	err = ps8622_set(cl, 0x04, 0xc1, 0x92);
+	if (err)
+		goto error;
+
+	/* Fbstep=100% */
+	err = ps8622_set(cl, 0x04, 0xc2, 0x1c);
+	if (err)
+		goto error;
+
+	/* [7] LOS signal disable */
+	err = ps8622_set(cl, 0x04, 0x32, 0x80);
+	if (err)
+		goto error;
+
+	/* RPIO Setting: [7:4] LVDS driver bias current : 75% (250mV swing) */
+	err = ps8622_set(cl, 0x04, 0x00, 0xb0);
+	if (err)
+		goto error;
+
+	/* [7:6] Right-bar GPIO output strength is 8mA */
+	err = ps8622_set(cl, 0x04, 0x15, 0x40);
+	if (err)
+		goto error;
+
+	/* EQ Training State Machine Setting, RCO calibration start */
+	err = ps8622_set(cl, 0x04, 0x54, 0x10);
+	if (err)
+		goto error;
+
+	/* Logic, needs more than 10 I2C command */
+	/* [4:0] MAX_LANE_COUNT set to max supported lanes */
+	err = ps8622_set(cl, 0x01, 0x02, 0x80 | ps8622->max_lane_count);
+	if (err)
+		goto error;
+
+	/* [4:0] LANE_COUNT_SET set to chosen lane count */
+	err = ps8622_set(cl, 0x01, 0x21, 0x80 | ps8622->lane_count);
+	if (err)
+		goto error;
+
+	err = ps8622_set(cl, 0x00, 0x52, 0x20);
+	if (err)
+		goto error;
+
+	/* HPD CP toggle enable */
+	err = ps8622_set(cl, 0x00, 0xf1, 0x03);
+	if (err)
+		goto error;
+
+	err = ps8622_set(cl, 0x00, 0x62, 0x41);
+	if (err)
+		goto error;
+
+	/* Counter number, add 1ms counter delay */
+	err = ps8622_set(cl, 0x00, 0xf6, 0x01);
+	if (err)
+		goto error;
+
+	/* [6]PWM function control by DPCD0040f[7], default is PWM block */
+	err = ps8622_set(cl, 0x00, 0x77, 0x06);
+	if (err)
+		goto error;
+
+	/* 04h Adjust VTotal toleranceto fix the 30Hz no display issue */
+	err = ps8622_set(cl, 0x00, 0x4c, 0x04);
+	if (err)
+		goto error;
+
+	/* DPCD00400='h00, Parade OUI ='h001cf8 */
+	err = ps8622_set(cl, 0x01, 0xc0, 0x00);
+	if (err)
+		goto error;
+
+	/* DPCD00401='h1c */
+	err = ps8622_set(cl, 0x01, 0xc1, 0x1c);
+	if (err)
+		goto error;
+
+	/* DPCD00402='hf8 */
+	err = ps8622_set(cl, 0x01, 0xc2, 0xf8);
+	if (err)
+		goto error;
+
+	/* DPCD403~408 = ASCII code, D2SLV5='h4432534c5635 */
+	err = ps8622_set(cl, 0x01, 0xc3, 0x44);
+	if (err)
+		goto error;
+
+	/* DPCD404 */
+	err = ps8622_set(cl, 0x01, 0xc4, 0x32);
+	if (err)
+		goto error;
+
+	/* DPCD405 */
+	err = ps8622_set(cl, 0x01, 0xc5, 0x53);
+	if (err)
+		goto error;
+
+	/* DPCD406 */
+	err = ps8622_set(cl, 0x01, 0xc6, 0x4c);
+	if (err)
+		goto error;
+
+	/* DPCD407 */
+	err = ps8622_set(cl, 0x01, 0xc7, 0x56);
+	if (err)
+		goto error;
+
+	/* DPCD408 */
+	err = ps8622_set(cl, 0x01, 0xc8, 0x35);
+	if (err)
+		goto error;
+
+	/* DPCD40A, Initial Code major revision '01' */
+	err = ps8622_set(cl, 0x01, 0xca, 0x01);
+	if (err)
+		goto error;
+
+	/* DPCD40B, Initial Code minor revision '05' */
+	err = ps8622_set(cl, 0x01, 0xcb, 0x05);
+	if (err)
+		goto error;
+
+
+	if (ps8622->bl) {
+		/* DPCD720, internal PWM */
+		err = ps8622_set(cl, 0x01, 0xa5, 0xa0);
+		if (err)
+			goto error;
+
+		/* FFh for 100% brightness, 0h for 0% brightness */
+		err = ps8622_set(cl, 0x01, 0xa7,
+				ps8622->bl->props.brightness);
+		if (err)
+			goto error;
+	} else {
+		/* DPCD720, external PWM */
+		err = ps8622_set(cl, 0x01, 0xa5, 0x80);
+		if (err)
+			goto error;
+	}
+
+	/* Set LVDS output as 6bit-VESA mapping, single LVDS channel */
+	err = ps8622_set(cl, 0x01, 0xcc, 0x13);
+	if (err)
+		goto error;
+
+	/* Enable SSC set by register */
+	err = ps8622_set(cl, 0x02, 0xb1, 0x20);
+	if (err)
+		goto error;
+
+	/* Set SSC enabled and +/-1% central spreading */
+	err = ps8622_set(cl, 0x04, 0x10, 0x16);
+	if (err)
+		goto error;
+
+	/* Logic end */
+	/* MPU Clock source: LC => RCO */
+	err = ps8622_set(cl, 0x04, 0x59, 0x60);
+	if (err)
+		goto error;
+
+	/* LC -> RCO */
+	err = ps8622_set(cl, 0x04, 0x54, 0x14);
+	if (err)
+		goto error;
+
+	/* HPD high */
+	err = ps8622_set(cl, 0x02, 0xa1, 0x91);
+
+error:
+	return err ? -EIO : 0;
+}
+
+static int ps8622_backlight_update(struct backlight_device *bl)
+{
+	struct ps8622_bridge *ps8622 = dev_get_drvdata(&bl->dev);
+	int ret, brightness = bl->props.brightness;
+
+	if (bl->props.power != FB_BLANK_UNBLANK ||
+	    bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
+		brightness = 0;
+
+	if (!ps8622->enabled)
+		return -EINVAL;
+
+	ret = ps8622_set(ps8622->client, 0x01, 0xa7, brightness);
+
+	return ret;
+}
+
+static const struct backlight_ops ps8622_backlight_ops = {
+	.update_status	= ps8622_backlight_update,
+};
+
+static void ps8622_pre_enable(struct drm_bridge *bridge)
+{
+	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+	int ret;
+
+	if (ps8622->enabled)
+		return;
+
+	gpiod_set_value(ps8622->gpio_rst, 0);
+
+	if (ps8622->v12) {
+		ret = regulator_enable(ps8622->v12);
+		if (ret)
+			DRM_ERROR("fails to enable ps8622->v12");
+	}
+
+	if (drm_panel_prepare(ps8622->panel)) {
+		DRM_ERROR("failed to prepare panel\n");
+		return;
+	}
+
+	gpiod_set_value(ps8622->gpio_slp, 1);
+
+	/*
+	 * T1 is the range of time that it takes for the power to rise after we
+	 * enable the lcd/ps8622 fet. T2 is the range of time in which the
+	 * data sheet specifies we should deassert the reset pin.
+	 *
+	 * If it takes T1.max for the power to rise, we need to wait atleast
+	 * T2.min before deasserting the reset pin. If it takes T1.min for the
+	 * power to rise, we need to wait at most T2.max before deasserting the
+	 * reset pin.
+	 */
+	usleep_range(PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US,
+		     PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US);
+
+	gpiod_set_value(ps8622->gpio_rst, 1);
+
+	/* wait 20ms after RST high */
+	usleep_range(20000, 30000);
+
+	ret = ps8622_send_config(ps8622);
+	if (ret) {
+		DRM_ERROR("Failed to send config to bridge (%d)\n", ret);
+		return;
+	}
+
+	ps8622->enabled = true;
+}
+
+static void ps8622_enable(struct drm_bridge *bridge)
+{
+	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+
+	if (drm_panel_enable(ps8622->panel)) {
+		DRM_ERROR("failed to enable panel\n");
+		return;
+	}
+}
+
+static void ps8622_disable(struct drm_bridge *bridge)
+{
+	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+
+	if (drm_panel_disable(ps8622->panel)) {
+		DRM_ERROR("failed to disable panel\n");
+		return;
+	}
+	msleep(PS8622_PWMO_END_T12_MS);
+}
+
+static void ps8622_post_disable(struct drm_bridge *bridge)
+{
+	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+
+	if (!ps8622->enabled)
+		return;
+
+	ps8622->enabled = false;
+
+	/*
+	 * This doesn't matter if the regulators are turned off, but something
+	 * else might keep them on. In that case, we want to assert the slp gpio
+	 * to lower power.
+	 */
+	gpiod_set_value(ps8622->gpio_slp, 0);
+
+	if (drm_panel_unprepare(ps8622->panel)) {
+		DRM_ERROR("failed to unprepare panel\n");
+		return;
+	}
+
+	if (ps8622->v12)
+		regulator_disable(ps8622->v12);
+
+	/*
+	 * Sleep for at least the amount of time that it takes the power rail to
+	 * fall to prevent asserting the rst gpio from doing anything.
+	 */
+	usleep_range(PS8622_POWER_FALL_T16_MAX_US,
+		     2 * PS8622_POWER_FALL_T16_MAX_US);
+	gpiod_set_value(ps8622->gpio_rst, 0);
+
+	msleep(PS8622_POWER_OFF_T17_MS);
+}
+
+static int ps8622_get_modes(struct drm_connector *connector)
+{
+	struct ps8622_bridge *ps8622;
+
+	ps8622 = connector_to_ps8622(connector);
+
+	return drm_panel_get_modes(ps8622->panel);
+}
+
+static struct drm_encoder *ps8622_best_encoder(struct drm_connector *connector)
+{
+	struct ps8622_bridge *ps8622;
+
+	ps8622 = connector_to_ps8622(connector);
+
+	return ps8622->bridge.encoder;
+}
+
+static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = {
+	.get_modes = ps8622_get_modes,
+	.best_encoder = ps8622_best_encoder,
+};
+
+static enum drm_connector_status ps8622_detect(struct drm_connector *connector,
+								bool force)
+{
+	return connector_status_connected;
+}
+
+static void ps8622_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs ps8622_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = ps8622_detect,
+	.destroy = ps8622_connector_destroy,
+};
+
+int ps8622_attach(struct drm_bridge *bridge)
+{
+	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+	int ret;
+
+	if (!bridge->encoder) {
+		DRM_ERROR("Parent encoder object not found");
+		return -ENODEV;
+	}
+
+	ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD;
+	ret = drm_connector_init(bridge->dev, &ps8622->connector,
+			&ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+	if (ret) {
+		DRM_ERROR("Failed to initialize connector with drm\n");
+		return ret;
+	}
+	drm_connector_helper_add(&ps8622->connector,
+					&ps8622_connector_helper_funcs);
+	drm_connector_register(&ps8622->connector);
+	drm_mode_connector_attach_encoder(&ps8622->connector,
+							bridge->encoder);
+
+	if (ps8622->panel)
+		drm_panel_attach(ps8622->panel, &ps8622->connector);
+
+	drm_helper_hpd_irq_event(ps8622->connector.dev);
+
+	return ret;
+}
+
+static const struct drm_bridge_funcs ps8622_bridge_funcs = {
+	.pre_enable = ps8622_pre_enable,
+	.enable = ps8622_enable,
+	.disable = ps8622_disable,
+	.post_disable = ps8622_post_disable,
+	.attach = ps8622_attach,
+};
+
+static const struct of_device_id ps8622_devices[] = {
+	{.compatible = "parade,ps8622",},
+	{.compatible = "parade,ps8625",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, ps8622_devices);
+
+static int ps8622_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device_node *endpoint, *panel_node;
+	struct ps8622_bridge *ps8622;
+	int ret;
+
+	ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL);
+	if (!ps8622)
+		return -ENOMEM;
+
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (endpoint) {
+		panel_node = of_graph_get_remote_port_parent(endpoint);
+		if (panel_node) {
+			ps8622->panel = of_drm_find_panel(panel_node);
+			of_node_put(panel_node);
+			if (!ps8622->panel)
+				return -EPROBE_DEFER;
+		}
+	}
+
+	ps8622->client = client;
+
+	ps8622->v12 = devm_regulator_get(dev, "vdd12");
+	if (IS_ERR(ps8622->v12)) {
+		dev_info(dev, "no 1.2v regulator found for PS8622\n");
+		ps8622->v12 = NULL;
+	}
+
+	ps8622->gpio_slp = devm_gpiod_get(dev, "sleep");
+	if (IS_ERR(ps8622->gpio_slp)) {
+		ret = PTR_ERR(ps8622->gpio_slp);
+		dev_err(dev, "cannot get gpio_slp %d\n", ret);
+		return ret;
+	}
+	ret = gpiod_direction_output(ps8622->gpio_slp, 1);
+	if (ret) {
+		dev_err(dev, "cannot configure gpio_slp\n");
+		return ret;
+	}
+
+	ps8622->gpio_rst = devm_gpiod_get(dev, "reset");
+	if (IS_ERR(ps8622->gpio_rst)) {
+		ret = PTR_ERR(ps8622->gpio_rst);
+		dev_err(dev, "cannot get gpio_rst %d\n", ret);
+		return ret;
+	}
+	/*
+	 * Assert the reset pin high to avoid the bridge being
+	 * initialized prematurely
+	 */
+	ret = gpiod_direction_output(ps8622->gpio_rst, 1);
+	if (ret) {
+		dev_err(dev, "cannot configure gpio_rst\n");
+		return ret;
+	}
+
+	ps8622->max_lane_count = id->driver_data;
+
+	if (of_property_read_u32(dev->of_node, "lane-count",
+						&ps8622->lane_count)) {
+		ps8622->lane_count = ps8622->max_lane_count;
+	} else if (ps8622->lane_count > ps8622->max_lane_count) {
+		dev_info(dev, "lane-count property is too high,"
+						"using max_lane_count\n");
+		ps8622->lane_count = ps8622->max_lane_count;
+	}
+
+	if (!of_find_property(dev->of_node, "use-external-pwm", NULL)) {
+		ps8622->bl = backlight_device_register("ps8622-backlight",
+				dev, ps8622, &ps8622_backlight_ops,
+				NULL);
+		if (IS_ERR(ps8622->bl)) {
+			DRM_ERROR("failed to register backlight\n");
+			ret = PTR_ERR(ps8622->bl);
+			ps8622->bl = NULL;
+			return ret;
+		}
+		ps8622->bl->props.max_brightness = PS8622_MAX_BRIGHTNESS;
+		ps8622->bl->props.brightness = PS8622_MAX_BRIGHTNESS;
+	}
+
+	ps8622->bridge.funcs = &ps8622_bridge_funcs;
+	ps8622->bridge.of_node = dev->of_node;
+	ret = drm_bridge_add(&ps8622->bridge);
+	if (ret) {
+		DRM_ERROR("Failed to add bridge\n");
+		return ret;
+	}
+
+	i2c_set_clientdata(client, ps8622);
+
+	return 0;
+}
+
+static int ps8622_remove(struct i2c_client *client)
+{
+	struct ps8622_bridge *ps8622 = i2c_get_clientdata(client);
+
+	if (ps8622->bl)
+		backlight_device_unregister(ps8622->bl);
+
+	drm_bridge_remove(&ps8622->bridge);
+
+	return 0;
+}
+
+static const struct i2c_device_id ps8622_i2c_table[] = {
+	/* Device type, max_lane_count */
+	{"ps8622", 1},
+	{"ps8625", 2},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);
+
+struct i2c_driver ps8622_driver = {
+	.id_table	= ps8622_i2c_table,
+	.probe		= ps8622_probe,
+	.remove		= ps8622_remove,
+	.driver		= {
+		.name	= "ps8622",
+		.owner	= THIS_MODULE,
+		.of_match_table = ps8622_devices,
+	},
+};
+module_i2c_driver(ps8622_driver);
+
+MODULE_AUTHOR("Vincent Palatin <vpalatin@chromium.org>");
+MODULE_DESCRIPTION("Parade ps8622/ps8625 eDP-LVDS converter driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

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

* [PATCH V9 12/14] drm/bridge: Add i2c based driver for ps8622/ps8625 bridge
@ 2015-01-20 16:38   ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vincent Palatin <vpalatin@chromium.org>

This patch adds drm_bridge driver for parade DisplayPort
to LVDS bridge chip.

Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 drivers/gpu/drm/bridge/Kconfig  |    9 +
 drivers/gpu/drm/bridge/Makefile |    1 +
 drivers/gpu/drm/bridge/ps8622.c |  684 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 694 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/ps8622.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 8b426e2..d06eda3 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -6,3 +6,12 @@ config DRM_PTN3460
 	select DRM_PANEL
 	---help---
 	  ptn3460 eDP-LVDS bridge chip driver.
+
+config DRM_PS8622
+	tristate "Parade eDP/LVDS bridge"
+	depends on OF && I2C
+	select DRM_PANEL
+	select BACKLIGHT_LCD_SUPPORT
+	select BACKLIGHT_CLASS_DEVICE
+	---help---
+	  parade eDP-LVDS bridge chip driver.
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index b4733e1..105da3e 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,3 +1,4 @@
 ccflags-y := -Iinclude/drm
 
+obj-$(CONFIG_DRM_PS8622) += ps8622.o
 obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
diff --git a/drivers/gpu/drm/bridge/ps8622.c b/drivers/gpu/drm/bridge/ps8622.c
new file mode 100644
index 0000000..5474a39
--- /dev/null
+++ b/drivers/gpu/drm/bridge/ps8622.c
@@ -0,0 +1,684 @@
+/*
+ * Parade PS8622 eDP/LVDS bridge driver
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/backlight.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pm.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_panel.h>
+
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+
+/* Brightness scale on the Parade chip */
+#define PS8622_MAX_BRIGHTNESS 0xff
+
+/* Timings taken from the version 1.7 datasheet for the PS8622/PS8625 */
+#define PS8622_POWER_RISE_T1_MIN_US 10
+#define PS8622_POWER_RISE_T1_MAX_US 10000
+#define PS8622_RST_HIGH_T2_MIN_US 3000
+#define PS8622_RST_HIGH_T2_MAX_US 30000
+#define PS8622_PWMO_END_T12_MS 200
+#define PS8622_POWER_FALL_T16_MAX_US 10000
+#define PS8622_POWER_OFF_T17_MS 500
+
+#if ((PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US) > \
+	(PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US))
+#error "T2.min + T1.max must be less than T2.max + T1.min"
+#endif
+
+struct ps8622_bridge {
+	struct drm_connector connector;
+	struct i2c_client *client;
+	struct drm_bridge bridge;
+	struct drm_panel *panel;
+	struct regulator *v12;
+	struct backlight_device *bl;
+
+	struct gpio_desc *gpio_slp;
+	struct gpio_desc *gpio_rst;
+
+	u32 max_lane_count;
+	u32 lane_count;
+
+	bool enabled;
+};
+
+static inline struct ps8622_bridge *
+		bridge_to_ps8622(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct ps8622_bridge, bridge);
+}
+
+static inline struct ps8622_bridge *
+		connector_to_ps8622(struct drm_connector *connector)
+{
+	return container_of(connector, struct ps8622_bridge, connector);
+}
+
+static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val)
+{
+	int ret;
+	struct i2c_adapter *adap = client->adapter;
+	struct i2c_msg msg;
+	u8 data[] = {reg, val};
+
+	msg.addr = client->addr + page;
+	msg.flags = 0;
+	msg.len = sizeof(data);
+	msg.buf = data;
+
+	ret = i2c_transfer(adap, &msg, 1);
+	if (ret != 1)
+		pr_warn("PS8622 I2C write (0x%02x,0x%02x,0x%02x) failed: %d\n",
+			client->addr + page, reg, val, ret);
+	return !(ret == 1);
+}
+
+static int ps8622_send_config(struct ps8622_bridge *ps8622)
+{
+	struct i2c_client *cl = ps8622->client;
+	int err = 0;
+
+	/* HPD low */
+	err = ps8622_set(cl, 0x02, 0xa1, 0x01);
+	if (err)
+		goto error;
+
+	/* SW setting: [1:0] SW output 1.2V voltage is lower to 96% */
+	err = ps8622_set(cl, 0x04, 0x14, 0x01);
+	if (err)
+		goto error;
+
+	/* RCO SS setting: [5:4] = b01 0.5%, b10 1%, b11 1.5% */
+	err = ps8622_set(cl, 0x04, 0xe3, 0x20);
+	if (err)
+		goto error;
+
+	/* [7] RCO SS enable */
+	err = ps8622_set(cl, 0x04, 0xe2, 0x80);
+	if (err)
+		goto error;
+
+	/* RPHY Setting
+	 * [3:2] CDR tune wait cycle before measure for fine tune
+	 * b00: 1us b01: 0.5us b10:2us, b11: 4us
+	 */
+	err = ps8622_set(cl, 0x04, 0x8a, 0x0c);
+	if (err)
+		goto error;
+
+	/* [3] RFD always on */
+	err = ps8622_set(cl, 0x04, 0x89, 0x08);
+	if (err)
+		goto error;
+
+	/* CTN lock in/out: 20000ppm/80000ppm. Lock out 2 times. */
+	err = ps8622_set(cl, 0x04, 0x71, 0x2d);
+	if (err)
+		goto error;
+
+	/* 2.7G CDR settings: NOF=40LSB for HBR CDR  setting */
+	err = ps8622_set(cl, 0x04, 0x7d, 0x07);
+	if (err)
+		goto error;
+
+	/* [1:0] Fmin=+4bands */
+	err = ps8622_set(cl, 0x04, 0x7b, 0x00);
+	if (err)
+		goto error;
+
+	/* [7:5] DCO_FTRNG=+-40% */
+	err = ps8622_set(cl, 0x04, 0x7a, 0xfd);
+	if (err)
+		goto error;
+
+	/* 1.62G CDR settings: [5:2]NOF=64LSB [1:0]DCO scale is 2/5 */
+	err = ps8622_set(cl, 0x04, 0xc0, 0x12);
+	if (err)
+		goto error;
+
+	/* Gitune=-37% */
+	err = ps8622_set(cl, 0x04, 0xc1, 0x92);
+	if (err)
+		goto error;
+
+	/* Fbstep=100% */
+	err = ps8622_set(cl, 0x04, 0xc2, 0x1c);
+	if (err)
+		goto error;
+
+	/* [7] LOS signal disable */
+	err = ps8622_set(cl, 0x04, 0x32, 0x80);
+	if (err)
+		goto error;
+
+	/* RPIO Setting: [7:4] LVDS driver bias current : 75% (250mV swing) */
+	err = ps8622_set(cl, 0x04, 0x00, 0xb0);
+	if (err)
+		goto error;
+
+	/* [7:6] Right-bar GPIO output strength is 8mA */
+	err = ps8622_set(cl, 0x04, 0x15, 0x40);
+	if (err)
+		goto error;
+
+	/* EQ Training State Machine Setting, RCO calibration start */
+	err = ps8622_set(cl, 0x04, 0x54, 0x10);
+	if (err)
+		goto error;
+
+	/* Logic, needs more than 10 I2C command */
+	/* [4:0] MAX_LANE_COUNT set to max supported lanes */
+	err = ps8622_set(cl, 0x01, 0x02, 0x80 | ps8622->max_lane_count);
+	if (err)
+		goto error;
+
+	/* [4:0] LANE_COUNT_SET set to chosen lane count */
+	err = ps8622_set(cl, 0x01, 0x21, 0x80 | ps8622->lane_count);
+	if (err)
+		goto error;
+
+	err = ps8622_set(cl, 0x00, 0x52, 0x20);
+	if (err)
+		goto error;
+
+	/* HPD CP toggle enable */
+	err = ps8622_set(cl, 0x00, 0xf1, 0x03);
+	if (err)
+		goto error;
+
+	err = ps8622_set(cl, 0x00, 0x62, 0x41);
+	if (err)
+		goto error;
+
+	/* Counter number, add 1ms counter delay */
+	err = ps8622_set(cl, 0x00, 0xf6, 0x01);
+	if (err)
+		goto error;
+
+	/* [6]PWM function control by DPCD0040f[7], default is PWM block */
+	err = ps8622_set(cl, 0x00, 0x77, 0x06);
+	if (err)
+		goto error;
+
+	/* 04h Adjust VTotal toleranceto fix the 30Hz no display issue */
+	err = ps8622_set(cl, 0x00, 0x4c, 0x04);
+	if (err)
+		goto error;
+
+	/* DPCD00400='h00, Parade OUI ='h001cf8 */
+	err = ps8622_set(cl, 0x01, 0xc0, 0x00);
+	if (err)
+		goto error;
+
+	/* DPCD00401='h1c */
+	err = ps8622_set(cl, 0x01, 0xc1, 0x1c);
+	if (err)
+		goto error;
+
+	/* DPCD00402='hf8 */
+	err = ps8622_set(cl, 0x01, 0xc2, 0xf8);
+	if (err)
+		goto error;
+
+	/* DPCD403~408 = ASCII code, D2SLV5='h4432534c5635 */
+	err = ps8622_set(cl, 0x01, 0xc3, 0x44);
+	if (err)
+		goto error;
+
+	/* DPCD404 */
+	err = ps8622_set(cl, 0x01, 0xc4, 0x32);
+	if (err)
+		goto error;
+
+	/* DPCD405 */
+	err = ps8622_set(cl, 0x01, 0xc5, 0x53);
+	if (err)
+		goto error;
+
+	/* DPCD406 */
+	err = ps8622_set(cl, 0x01, 0xc6, 0x4c);
+	if (err)
+		goto error;
+
+	/* DPCD407 */
+	err = ps8622_set(cl, 0x01, 0xc7, 0x56);
+	if (err)
+		goto error;
+
+	/* DPCD408 */
+	err = ps8622_set(cl, 0x01, 0xc8, 0x35);
+	if (err)
+		goto error;
+
+	/* DPCD40A, Initial Code major revision '01' */
+	err = ps8622_set(cl, 0x01, 0xca, 0x01);
+	if (err)
+		goto error;
+
+	/* DPCD40B, Initial Code minor revision '05' */
+	err = ps8622_set(cl, 0x01, 0xcb, 0x05);
+	if (err)
+		goto error;
+
+
+	if (ps8622->bl) {
+		/* DPCD720, internal PWM */
+		err = ps8622_set(cl, 0x01, 0xa5, 0xa0);
+		if (err)
+			goto error;
+
+		/* FFh for 100% brightness, 0h for 0% brightness */
+		err = ps8622_set(cl, 0x01, 0xa7,
+				ps8622->bl->props.brightness);
+		if (err)
+			goto error;
+	} else {
+		/* DPCD720, external PWM */
+		err = ps8622_set(cl, 0x01, 0xa5, 0x80);
+		if (err)
+			goto error;
+	}
+
+	/* Set LVDS output as 6bit-VESA mapping, single LVDS channel */
+	err = ps8622_set(cl, 0x01, 0xcc, 0x13);
+	if (err)
+		goto error;
+
+	/* Enable SSC set by register */
+	err = ps8622_set(cl, 0x02, 0xb1, 0x20);
+	if (err)
+		goto error;
+
+	/* Set SSC enabled and +/-1% central spreading */
+	err = ps8622_set(cl, 0x04, 0x10, 0x16);
+	if (err)
+		goto error;
+
+	/* Logic end */
+	/* MPU Clock source: LC => RCO */
+	err = ps8622_set(cl, 0x04, 0x59, 0x60);
+	if (err)
+		goto error;
+
+	/* LC -> RCO */
+	err = ps8622_set(cl, 0x04, 0x54, 0x14);
+	if (err)
+		goto error;
+
+	/* HPD high */
+	err = ps8622_set(cl, 0x02, 0xa1, 0x91);
+
+error:
+	return err ? -EIO : 0;
+}
+
+static int ps8622_backlight_update(struct backlight_device *bl)
+{
+	struct ps8622_bridge *ps8622 = dev_get_drvdata(&bl->dev);
+	int ret, brightness = bl->props.brightness;
+
+	if (bl->props.power != FB_BLANK_UNBLANK ||
+	    bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
+		brightness = 0;
+
+	if (!ps8622->enabled)
+		return -EINVAL;
+
+	ret = ps8622_set(ps8622->client, 0x01, 0xa7, brightness);
+
+	return ret;
+}
+
+static const struct backlight_ops ps8622_backlight_ops = {
+	.update_status	= ps8622_backlight_update,
+};
+
+static void ps8622_pre_enable(struct drm_bridge *bridge)
+{
+	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+	int ret;
+
+	if (ps8622->enabled)
+		return;
+
+	gpiod_set_value(ps8622->gpio_rst, 0);
+
+	if (ps8622->v12) {
+		ret = regulator_enable(ps8622->v12);
+		if (ret)
+			DRM_ERROR("fails to enable ps8622->v12");
+	}
+
+	if (drm_panel_prepare(ps8622->panel)) {
+		DRM_ERROR("failed to prepare panel\n");
+		return;
+	}
+
+	gpiod_set_value(ps8622->gpio_slp, 1);
+
+	/*
+	 * T1 is the range of time that it takes for the power to rise after we
+	 * enable the lcd/ps8622 fet. T2 is the range of time in which the
+	 * data sheet specifies we should deassert the reset pin.
+	 *
+	 * If it takes T1.max for the power to rise, we need to wait atleast
+	 * T2.min before deasserting the reset pin. If it takes T1.min for the
+	 * power to rise, we need to wait at most T2.max before deasserting the
+	 * reset pin.
+	 */
+	usleep_range(PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US,
+		     PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US);
+
+	gpiod_set_value(ps8622->gpio_rst, 1);
+
+	/* wait 20ms after RST high */
+	usleep_range(20000, 30000);
+
+	ret = ps8622_send_config(ps8622);
+	if (ret) {
+		DRM_ERROR("Failed to send config to bridge (%d)\n", ret);
+		return;
+	}
+
+	ps8622->enabled = true;
+}
+
+static void ps8622_enable(struct drm_bridge *bridge)
+{
+	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+
+	if (drm_panel_enable(ps8622->panel)) {
+		DRM_ERROR("failed to enable panel\n");
+		return;
+	}
+}
+
+static void ps8622_disable(struct drm_bridge *bridge)
+{
+	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+
+	if (drm_panel_disable(ps8622->panel)) {
+		DRM_ERROR("failed to disable panel\n");
+		return;
+	}
+	msleep(PS8622_PWMO_END_T12_MS);
+}
+
+static void ps8622_post_disable(struct drm_bridge *bridge)
+{
+	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+
+	if (!ps8622->enabled)
+		return;
+
+	ps8622->enabled = false;
+
+	/*
+	 * This doesn't matter if the regulators are turned off, but something
+	 * else might keep them on. In that case, we want to assert the slp gpio
+	 * to lower power.
+	 */
+	gpiod_set_value(ps8622->gpio_slp, 0);
+
+	if (drm_panel_unprepare(ps8622->panel)) {
+		DRM_ERROR("failed to unprepare panel\n");
+		return;
+	}
+
+	if (ps8622->v12)
+		regulator_disable(ps8622->v12);
+
+	/*
+	 * Sleep for at least the amount of time that it takes the power rail to
+	 * fall to prevent asserting the rst gpio from doing anything.
+	 */
+	usleep_range(PS8622_POWER_FALL_T16_MAX_US,
+		     2 * PS8622_POWER_FALL_T16_MAX_US);
+	gpiod_set_value(ps8622->gpio_rst, 0);
+
+	msleep(PS8622_POWER_OFF_T17_MS);
+}
+
+static int ps8622_get_modes(struct drm_connector *connector)
+{
+	struct ps8622_bridge *ps8622;
+
+	ps8622 = connector_to_ps8622(connector);
+
+	return drm_panel_get_modes(ps8622->panel);
+}
+
+static struct drm_encoder *ps8622_best_encoder(struct drm_connector *connector)
+{
+	struct ps8622_bridge *ps8622;
+
+	ps8622 = connector_to_ps8622(connector);
+
+	return ps8622->bridge.encoder;
+}
+
+static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = {
+	.get_modes = ps8622_get_modes,
+	.best_encoder = ps8622_best_encoder,
+};
+
+static enum drm_connector_status ps8622_detect(struct drm_connector *connector,
+								bool force)
+{
+	return connector_status_connected;
+}
+
+static void ps8622_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs ps8622_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = ps8622_detect,
+	.destroy = ps8622_connector_destroy,
+};
+
+int ps8622_attach(struct drm_bridge *bridge)
+{
+	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+	int ret;
+
+	if (!bridge->encoder) {
+		DRM_ERROR("Parent encoder object not found");
+		return -ENODEV;
+	}
+
+	ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD;
+	ret = drm_connector_init(bridge->dev, &ps8622->connector,
+			&ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+	if (ret) {
+		DRM_ERROR("Failed to initialize connector with drm\n");
+		return ret;
+	}
+	drm_connector_helper_add(&ps8622->connector,
+					&ps8622_connector_helper_funcs);
+	drm_connector_register(&ps8622->connector);
+	drm_mode_connector_attach_encoder(&ps8622->connector,
+							bridge->encoder);
+
+	if (ps8622->panel)
+		drm_panel_attach(ps8622->panel, &ps8622->connector);
+
+	drm_helper_hpd_irq_event(ps8622->connector.dev);
+
+	return ret;
+}
+
+static const struct drm_bridge_funcs ps8622_bridge_funcs = {
+	.pre_enable = ps8622_pre_enable,
+	.enable = ps8622_enable,
+	.disable = ps8622_disable,
+	.post_disable = ps8622_post_disable,
+	.attach = ps8622_attach,
+};
+
+static const struct of_device_id ps8622_devices[] = {
+	{.compatible = "parade,ps8622",},
+	{.compatible = "parade,ps8625",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, ps8622_devices);
+
+static int ps8622_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device_node *endpoint, *panel_node;
+	struct ps8622_bridge *ps8622;
+	int ret;
+
+	ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL);
+	if (!ps8622)
+		return -ENOMEM;
+
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (endpoint) {
+		panel_node = of_graph_get_remote_port_parent(endpoint);
+		if (panel_node) {
+			ps8622->panel = of_drm_find_panel(panel_node);
+			of_node_put(panel_node);
+			if (!ps8622->panel)
+				return -EPROBE_DEFER;
+		}
+	}
+
+	ps8622->client = client;
+
+	ps8622->v12 = devm_regulator_get(dev, "vdd12");
+	if (IS_ERR(ps8622->v12)) {
+		dev_info(dev, "no 1.2v regulator found for PS8622\n");
+		ps8622->v12 = NULL;
+	}
+
+	ps8622->gpio_slp = devm_gpiod_get(dev, "sleep");
+	if (IS_ERR(ps8622->gpio_slp)) {
+		ret = PTR_ERR(ps8622->gpio_slp);
+		dev_err(dev, "cannot get gpio_slp %d\n", ret);
+		return ret;
+	}
+	ret = gpiod_direction_output(ps8622->gpio_slp, 1);
+	if (ret) {
+		dev_err(dev, "cannot configure gpio_slp\n");
+		return ret;
+	}
+
+	ps8622->gpio_rst = devm_gpiod_get(dev, "reset");
+	if (IS_ERR(ps8622->gpio_rst)) {
+		ret = PTR_ERR(ps8622->gpio_rst);
+		dev_err(dev, "cannot get gpio_rst %d\n", ret);
+		return ret;
+	}
+	/*
+	 * Assert the reset pin high to avoid the bridge being
+	 * initialized prematurely
+	 */
+	ret = gpiod_direction_output(ps8622->gpio_rst, 1);
+	if (ret) {
+		dev_err(dev, "cannot configure gpio_rst\n");
+		return ret;
+	}
+
+	ps8622->max_lane_count = id->driver_data;
+
+	if (of_property_read_u32(dev->of_node, "lane-count",
+						&ps8622->lane_count)) {
+		ps8622->lane_count = ps8622->max_lane_count;
+	} else if (ps8622->lane_count > ps8622->max_lane_count) {
+		dev_info(dev, "lane-count property is too high,"
+						"using max_lane_count\n");
+		ps8622->lane_count = ps8622->max_lane_count;
+	}
+
+	if (!of_find_property(dev->of_node, "use-external-pwm", NULL)) {
+		ps8622->bl = backlight_device_register("ps8622-backlight",
+				dev, ps8622, &ps8622_backlight_ops,
+				NULL);
+		if (IS_ERR(ps8622->bl)) {
+			DRM_ERROR("failed to register backlight\n");
+			ret = PTR_ERR(ps8622->bl);
+			ps8622->bl = NULL;
+			return ret;
+		}
+		ps8622->bl->props.max_brightness = PS8622_MAX_BRIGHTNESS;
+		ps8622->bl->props.brightness = PS8622_MAX_BRIGHTNESS;
+	}
+
+	ps8622->bridge.funcs = &ps8622_bridge_funcs;
+	ps8622->bridge.of_node = dev->of_node;
+	ret = drm_bridge_add(&ps8622->bridge);
+	if (ret) {
+		DRM_ERROR("Failed to add bridge\n");
+		return ret;
+	}
+
+	i2c_set_clientdata(client, ps8622);
+
+	return 0;
+}
+
+static int ps8622_remove(struct i2c_client *client)
+{
+	struct ps8622_bridge *ps8622 = i2c_get_clientdata(client);
+
+	if (ps8622->bl)
+		backlight_device_unregister(ps8622->bl);
+
+	drm_bridge_remove(&ps8622->bridge);
+
+	return 0;
+}
+
+static const struct i2c_device_id ps8622_i2c_table[] = {
+	/* Device type, max_lane_count */
+	{"ps8622", 1},
+	{"ps8625", 2},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);
+
+struct i2c_driver ps8622_driver = {
+	.id_table	= ps8622_i2c_table,
+	.probe		= ps8622_probe,
+	.remove		= ps8622_remove,
+	.driver		= {
+		.name	= "ps8622",
+		.owner	= THIS_MODULE,
+		.of_match_table = ps8622_devices,
+	},
+};
+module_i2c_driver(ps8622_driver);
+
+MODULE_AUTHOR("Vincent Palatin <vpalatin@chromium.org>");
+MODULE_DESCRIPTION("Parade ps8622/ps8625 eDP-LVDS converter driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

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

* [PATCH V9 13/14] ARM: dts: snow: represent the connection between bridge and panel using videoport and endpoints
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38   ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree
  Cc: kgene.kim, inki.dae, thierry.reding, daniel.vetter, seanpaul,
	ajaynumb, jg1.han, bhushan.r, prashanth.g, Ajay Kumar

Define videoports and use endpoints to describe the connection between
the encoder, bridge and the panel, instead of using phandles.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 arch/arm/boot/dts/exynos5250-snow.dts |   30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
index b9aeec4..1bd5d3a 100644
--- a/arch/arm/boot/dts/exynos5250-snow.dts
+++ b/arch/arm/boot/dts/exynos5250-snow.dts
@@ -183,7 +183,20 @@
 			powerdown-gpios = <&gpy2 5 GPIO_ACTIVE_HIGH>;
 			reset-gpios = <&gpx1 5 GPIO_ACTIVE_HIGH>;
 			edid-emulation = <5>;
-			panel = <&panel>;
+
+			ports {
+				port@0 {
+					bridge_out: endpoint {
+						remote-endpoint = <&panel_in>;
+					};
+				};
+
+				port@1 {
+					bridge_in: endpoint {
+						remote-endpoint = <&dp_out>;
+					};
+				};
+			};
 		};
 	};
 
@@ -228,6 +241,12 @@
 		compatible = "auo,b116xw03";
 		power-supply = <&fet6>;
 		backlight = <&backlight>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&bridge_out>;
+			};
+		};
 	};
 };
 
@@ -242,7 +261,14 @@
 	samsung,link-rate = <0x0a>;
 	samsung,lane-count = <2>;
 	samsung,hpd-gpio = <&gpx0 7 GPIO_ACTIVE_HIGH>;
-	bridge = <&ptn3460>;
+
+	ports {
+		port@0 {
+			dp_out: endpoint {
+				remote-endpoint = <&bridge_in>;
+			};
+		};
+	};
 };
 
 &ehci {
-- 
1.7.9.5

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

* [PATCH V9 13/14] ARM: dts: snow: represent the connection between bridge and panel using videoport and endpoints
@ 2015-01-20 16:38   ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

Define videoports and use endpoints to describe the connection between
the encoder, bridge and the panel, instead of using phandles.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 arch/arm/boot/dts/exynos5250-snow.dts |   30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
index b9aeec4..1bd5d3a 100644
--- a/arch/arm/boot/dts/exynos5250-snow.dts
+++ b/arch/arm/boot/dts/exynos5250-snow.dts
@@ -183,7 +183,20 @@
 			powerdown-gpios = <&gpy2 5 GPIO_ACTIVE_HIGH>;
 			reset-gpios = <&gpx1 5 GPIO_ACTIVE_HIGH>;
 			edid-emulation = <5>;
-			panel = <&panel>;
+
+			ports {
+				port at 0 {
+					bridge_out: endpoint {
+						remote-endpoint = <&panel_in>;
+					};
+				};
+
+				port at 1 {
+					bridge_in: endpoint {
+						remote-endpoint = <&dp_out>;
+					};
+				};
+			};
 		};
 	};
 
@@ -228,6 +241,12 @@
 		compatible = "auo,b116xw03";
 		power-supply = <&fet6>;
 		backlight = <&backlight>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&bridge_out>;
+			};
+		};
 	};
 };
 
@@ -242,7 +261,14 @@
 	samsung,link-rate = <0x0a>;
 	samsung,lane-count = <2>;
 	samsung,hpd-gpio = <&gpx0 7 GPIO_ACTIVE_HIGH>;
-	bridge = <&ptn3460>;
+
+	ports {
+		port at 0 {
+			dp_out: endpoint {
+				remote-endpoint = <&bridge_in>;
+			};
+		};
+	};
 };
 
 &ehci {
-- 
1.7.9.5

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

* [PATCH V9 14/14] ARM: dts: peach-pit: represent the connection between bridge and panel using videoport and endpoints
  2015-01-20 16:38 ` Ajay Kumar
@ 2015-01-20 16:38     ` Ajay Kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: kgene.kim-Sze3O3UU22JBDgjK7y7TUQ,
	inki.dae-Sze3O3UU22JBDgjK7y7TUQ,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, daniel.vetter-/w4YWyX8dFk,
	seanpaul-hpIqsD4AKlfQT0dZR+AlfA, ajaynumb-Re5JQEeQqe8AvxtiuMwx3w,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, bhushan.r-Sze3O3UU22JBDgjK7y7TUQ,
	prashanth.g-Sze3O3UU22JBDgjK7y7TUQ, Ajay Kumar

Define videoports and use endpoints to describe the connection between
the encoder, bridge and the panel, instead of using phandles.

Signed-off-by: Ajay Kumar <ajaykumar.rs-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Acked-by: Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Tested-by: Rahul Sharma <rahul.sharma-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Tested-by: Javier Martinez Canillas <javier.martinez-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
Tested-by: Gustavo Padovan <gustavo.padovan-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
Tested-by: Sjoerd Simons <sjoerd.simons-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
---
 arch/arm/boot/dts/exynos5420-peach-pit.dts |   31 ++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index c47bb70..ec86d95 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -118,6 +118,12 @@
 		compatible = "auo,b116xw03";
 		power-supply = <&tps65090_fet6>;
 		backlight = <&backlight>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&bridge_out>;
+			};
+		};
 	};
 };
 
@@ -137,7 +143,14 @@
 	samsung,link-rate = <0x06>;
 	samsung,lane-count = <2>;
 	samsung,hpd-gpio = <&gpx2 6 0>;
-	bridge = <&ps8625>;
+
+	ports {
+		port@0 {
+			dp_out: endpoint {
+				remote-endpoint = <&bridge_in>;
+			};
+		};
+	};
 };
 
 &fimd {
@@ -595,8 +608,22 @@
 		sleep-gpios = <&gpx3 5 GPIO_ACTIVE_HIGH>;
 		reset-gpios = <&gpy7 7 GPIO_ACTIVE_HIGH>;
 		lane-count = <2>;
-		panel = <&panel>;
 		use-external-pwm;
+
+		ports {
+			port@0 {
+				bridge_out: endpoint {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+
+			port@1 {
+				bridge_in: endpoint {
+					remote-endpoint = <&dp_out>;
+				};
+			};
+		};
+
 	};
 };
 
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH V9 14/14] ARM: dts: peach-pit: represent the connection between bridge and panel using videoport and endpoints
@ 2015-01-20 16:38     ` Ajay Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay Kumar @ 2015-01-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

Define videoports and use endpoints to describe the connection between
the encoder, bridge and the panel, instead of using phandles.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
 arch/arm/boot/dts/exynos5420-peach-pit.dts |   31 ++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index c47bb70..ec86d95 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -118,6 +118,12 @@
 		compatible = "auo,b116xw03";
 		power-supply = <&tps65090_fet6>;
 		backlight = <&backlight>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&bridge_out>;
+			};
+		};
 	};
 };
 
@@ -137,7 +143,14 @@
 	samsung,link-rate = <0x06>;
 	samsung,lane-count = <2>;
 	samsung,hpd-gpio = <&gpx2 6 0>;
-	bridge = <&ps8625>;
+
+	ports {
+		port at 0 {
+			dp_out: endpoint {
+				remote-endpoint = <&bridge_in>;
+			};
+		};
+	};
 };
 
 &fimd {
@@ -595,8 +608,22 @@
 		sleep-gpios = <&gpx3 5 GPIO_ACTIVE_HIGH>;
 		reset-gpios = <&gpy7 7 GPIO_ACTIVE_HIGH>;
 		lane-count = <2>;
-		panel = <&panel>;
 		use-external-pwm;
+
+		ports {
+			port at 0 {
+				bridge_out: endpoint {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+
+			port at 1 {
+				bridge_in: endpoint {
+					remote-endpoint = <&dp_out>;
+				};
+			};
+		};
+
 	};
 };
 
-- 
1.7.9.5

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

* RE: [PATCH V9 13/14] ARM: dts: snow: represent the connection between bridge and panel using videoport and endpoints
  2015-01-20 16:38   ` Ajay Kumar
@ 2015-01-23  7:01       ` Kukjin Kim
  -1 siblings, 0 replies; 58+ messages in thread
From: Kukjin Kim @ 2015-01-23  7:01 UTC (permalink / raw)
  To: 'Ajay Kumar',
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: inki.dae-Sze3O3UU22JBDgjK7y7TUQ,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, daniel.vetter-/w4YWyX8dFk,
	seanpaul-hpIqsD4AKlfQT0dZR+AlfA, ajaynumb-Re5JQEeQqe8AvxtiuMwx3w,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, bhushan.r-Sze3O3UU22JBDgjK7y7TUQ,
	prashanth.g-Sze3O3UU22JBDgjK7y7TUQ

Ajay Kumar wrote:
> 
> Define videoports and use endpoints to describe the connection between
> the encoder, bridge and the panel, instead of using phandles.
> 
> Signed-off-by: Ajay Kumar <ajaykumar.rs-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Tested-by: Rahul Sharma <rahul.sharma-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Tested-by: Javier Martinez Canillas <javier.martinez-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
> Tested-by: Gustavo Padovan <gustavo.padovan-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
> Tested-by: Sjoerd Simons <sjoerd.simons-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
> ---
>  arch/arm/boot/dts/exynos5250-snow.dts |   30 ++++++++++++++++++++++++++++--
>  1 file changed, 28 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
> index b9aeec4..1bd5d3a 100644
> --- a/arch/arm/boot/dts/exynos5250-snow.dts
> +++ b/arch/arm/boot/dts/exynos5250-snow.dts
> @@ -183,7 +183,20 @@
>  			powerdown-gpios = <&gpy2 5 GPIO_ACTIVE_HIGH>;
>  			reset-gpios = <&gpx1 5 GPIO_ACTIVE_HIGH>;
>  			edid-emulation = <5>;
> -			panel = <&panel>;
> +
> +			ports {
> +				port@0 {
> +					bridge_out: endpoint {
> +						remote-endpoint = <&panel_in>;
> +					};
> +				};
> +
> +				port@1 {
> +					bridge_in: endpoint {
> +						remote-endpoint = <&dp_out>;
> +					};
> +				};
> +			};
>  		};
>  	};
> 
> @@ -228,6 +241,12 @@
>  		compatible = "auo,b116xw03";
>  		power-supply = <&fet6>;
>  		backlight = <&backlight>;
> +
> +		port {
> +			panel_in: endpoint {
> +				remote-endpoint = <&bridge_out>;
> +			};
> +		};
>  	};
>  };
> 
> @@ -242,7 +261,14 @@
>  	samsung,link-rate = <0x0a>;
>  	samsung,lane-count = <2>;
>  	samsung,hpd-gpio = <&gpx0 7 GPIO_ACTIVE_HIGH>;
> -	bridge = <&ptn3460>;
> +
> +	ports {
> +		port@0 {
> +			dp_out: endpoint {
> +				remote-endpoint = <&bridge_in>;
> +			};
> +		};
> +	};
>  };
> 
>  &ehci {
> --
> 1.7.9.5

I'm fine on the DT changes in this series, shall I take 13/14 and 14/14 in
Samsung tree?

- Kukjin

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH V9 13/14] ARM: dts: snow: represent the connection between bridge and panel using videoport and endpoints
@ 2015-01-23  7:01       ` Kukjin Kim
  0 siblings, 0 replies; 58+ messages in thread
From: Kukjin Kim @ 2015-01-23  7:01 UTC (permalink / raw)
  To: linux-arm-kernel

Ajay Kumar wrote:
> 
> Define videoports and use endpoints to describe the connection between
> the encoder, bridge and the panel, instead of using phandles.
> 
> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
> Acked-by: Inki Dae <inki.dae@samsung.com>
> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
> ---
>  arch/arm/boot/dts/exynos5250-snow.dts |   30 ++++++++++++++++++++++++++++--
>  1 file changed, 28 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
> index b9aeec4..1bd5d3a 100644
> --- a/arch/arm/boot/dts/exynos5250-snow.dts
> +++ b/arch/arm/boot/dts/exynos5250-snow.dts
> @@ -183,7 +183,20 @@
>  			powerdown-gpios = <&gpy2 5 GPIO_ACTIVE_HIGH>;
>  			reset-gpios = <&gpx1 5 GPIO_ACTIVE_HIGH>;
>  			edid-emulation = <5>;
> -			panel = <&panel>;
> +
> +			ports {
> +				port at 0 {
> +					bridge_out: endpoint {
> +						remote-endpoint = <&panel_in>;
> +					};
> +				};
> +
> +				port at 1 {
> +					bridge_in: endpoint {
> +						remote-endpoint = <&dp_out>;
> +					};
> +				};
> +			};
>  		};
>  	};
> 
> @@ -228,6 +241,12 @@
>  		compatible = "auo,b116xw03";
>  		power-supply = <&fet6>;
>  		backlight = <&backlight>;
> +
> +		port {
> +			panel_in: endpoint {
> +				remote-endpoint = <&bridge_out>;
> +			};
> +		};
>  	};
>  };
> 
> @@ -242,7 +261,14 @@
>  	samsung,link-rate = <0x0a>;
>  	samsung,lane-count = <2>;
>  	samsung,hpd-gpio = <&gpx0 7 GPIO_ACTIVE_HIGH>;
> -	bridge = <&ptn3460>;
> +
> +	ports {
> +		port at 0 {
> +			dp_out: endpoint {
> +				remote-endpoint = <&bridge_in>;
> +			};
> +		};
> +	};
>  };
> 
>  &ehci {
> --
> 1.7.9.5

I'm fine on the DT changes in this series, shall I take 13/14 and 14/14 in
Samsung tree?

- Kukjin

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

* Re: [PATCH V9 13/14] ARM: dts: snow: represent the connection between bridge and panel using videoport and endpoints
  2015-01-23  7:01       ` Kukjin Kim
@ 2015-01-27  4:27         ` Ajay kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay kumar @ 2015-01-27  4:27 UTC (permalink / raw)
  To: Kukjin Kim
  Cc: devicetree, linux-samsung-soc, Sean Paul, Daniel Vetter,
	Jingoo Han, dri-devel, Pannaga Bhushan Reddy Patel, Prashanth G,
	Ajay Kumar, linux-arm-kernel

Hi Kukjin,

On Fri, Jan 23, 2015 at 12:31 PM, Kukjin Kim <kgene@kernel.org> wrote:
> Ajay Kumar wrote:
>>
>> Define videoports and use endpoints to describe the connection between
>> the encoder, bridge and the panel, instead of using phandles.
>>
>> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
>> Acked-by: Inki Dae <inki.dae@samsung.com>
>> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
>> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
>> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
>> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
>> ---
>>  arch/arm/boot/dts/exynos5250-snow.dts |   30 ++++++++++++++++++++++++++++--
>>  1 file changed, 28 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
>> index b9aeec4..1bd5d3a 100644
>> --- a/arch/arm/boot/dts/exynos5250-snow.dts
>> +++ b/arch/arm/boot/dts/exynos5250-snow.dts
>> @@ -183,7 +183,20 @@
>>                       powerdown-gpios = <&gpy2 5 GPIO_ACTIVE_HIGH>;
>>                       reset-gpios = <&gpx1 5 GPIO_ACTIVE_HIGH>;
>>                       edid-emulation = <5>;
>> -                     panel = <&panel>;
>> +
>> +                     ports {
>> +                             port@0 {
>> +                                     bridge_out: endpoint {
>> +                                             remote-endpoint = <&panel_in>;
>> +                                     };
>> +                             };
>> +
>> +                             port@1 {
>> +                                     bridge_in: endpoint {
>> +                                             remote-endpoint = <&dp_out>;
>> +                                     };
>> +                             };
>> +                     };
>>               };
>>       };
>>
>> @@ -228,6 +241,12 @@
>>               compatible = "auo,b116xw03";
>>               power-supply = <&fet6>;
>>               backlight = <&backlight>;
>> +
>> +             port {
>> +                     panel_in: endpoint {
>> +                             remote-endpoint = <&bridge_out>;
>> +                     };
>> +             };
>>       };
>>  };
>>
>> @@ -242,7 +261,14 @@
>>       samsung,link-rate = <0x0a>;
>>       samsung,lane-count = <2>;
>>       samsung,hpd-gpio = <&gpx0 7 GPIO_ACTIVE_HIGH>;
>> -     bridge = <&ptn3460>;
>> +
>> +     ports {
>> +             port@0 {
>> +                     dp_out: endpoint {
>> +                             remote-endpoint = <&bridge_in>;
>> +                     };
>> +             };
>> +     };
>>  };
>>
>>  &ehci {
>> --
>> 1.7.9.5
>
> I'm fine on the DT changes in this series, shall I take 13/14 and 14/14 in
> Samsung tree?
Yes, please take these patches.

Thanks and regards,
Ajay Kumar
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH V9 13/14] ARM: dts: snow: represent the connection between bridge and panel using videoport and endpoints
@ 2015-01-27  4:27         ` Ajay kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay kumar @ 2015-01-27  4:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Kukjin,

On Fri, Jan 23, 2015 at 12:31 PM, Kukjin Kim <kgene@kernel.org> wrote:
> Ajay Kumar wrote:
>>
>> Define videoports and use endpoints to describe the connection between
>> the encoder, bridge and the panel, instead of using phandles.
>>
>> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
>> Acked-by: Inki Dae <inki.dae@samsung.com>
>> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
>> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
>> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
>> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
>> ---
>>  arch/arm/boot/dts/exynos5250-snow.dts |   30 ++++++++++++++++++++++++++++--
>>  1 file changed, 28 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
>> index b9aeec4..1bd5d3a 100644
>> --- a/arch/arm/boot/dts/exynos5250-snow.dts
>> +++ b/arch/arm/boot/dts/exynos5250-snow.dts
>> @@ -183,7 +183,20 @@
>>                       powerdown-gpios = <&gpy2 5 GPIO_ACTIVE_HIGH>;
>>                       reset-gpios = <&gpx1 5 GPIO_ACTIVE_HIGH>;
>>                       edid-emulation = <5>;
>> -                     panel = <&panel>;
>> +
>> +                     ports {
>> +                             port at 0 {
>> +                                     bridge_out: endpoint {
>> +                                             remote-endpoint = <&panel_in>;
>> +                                     };
>> +                             };
>> +
>> +                             port at 1 {
>> +                                     bridge_in: endpoint {
>> +                                             remote-endpoint = <&dp_out>;
>> +                                     };
>> +                             };
>> +                     };
>>               };
>>       };
>>
>> @@ -228,6 +241,12 @@
>>               compatible = "auo,b116xw03";
>>               power-supply = <&fet6>;
>>               backlight = <&backlight>;
>> +
>> +             port {
>> +                     panel_in: endpoint {
>> +                             remote-endpoint = <&bridge_out>;
>> +                     };
>> +             };
>>       };
>>  };
>>
>> @@ -242,7 +261,14 @@
>>       samsung,link-rate = <0x0a>;
>>       samsung,lane-count = <2>;
>>       samsung,hpd-gpio = <&gpx0 7 GPIO_ACTIVE_HIGH>;
>> -     bridge = <&ptn3460>;
>> +
>> +     ports {
>> +             port at 0 {
>> +                     dp_out: endpoint {
>> +                             remote-endpoint = <&bridge_in>;
>> +                     };
>> +             };
>> +     };
>>  };
>>
>>  &ehci {
>> --
>> 1.7.9.5
>
> I'm fine on the DT changes in this series, shall I take 13/14 and 14/14 in
> Samsung tree?
Yes, please take these patches.

Thanks and regards,
Ajay Kumar

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

* Re: [PATCH V9 04/14] drm/bridge: ptn3460: Convert to i2c driver model
  2015-01-20 16:38   ` Ajay Kumar
@ 2015-01-29 14:29     ` Gustavo Padovan
  -1 siblings, 0 replies; 58+ messages in thread
From: Gustavo Padovan @ 2015-01-29 14:29 UTC (permalink / raw)
  To: Ajay Kumar
  Cc: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree,
	kgene.kim, inki.dae, thierry.reding, daniel.vetter, seanpaul,
	ajaynumb, jg1.han, bhushan.r, prashanth.g

Hi Ajay,

2015-01-20 Ajay Kumar <ajaykumar.rs@samsung.com>:

> Use drm_bridge helpers to modify the driver to support
> i2c driver model.
> 
> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
> Acked-by: Inki Dae <inki.dae@samsung.com>
> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
> ---
>  drivers/gpu/drm/bridge/Kconfig          |    2 +
>  drivers/gpu/drm/bridge/ptn3460.c        |  124 +++++++++++++++++++++----------
>  drivers/gpu/drm/exynos/exynos_dp_core.c |   22 ------
>  3 files changed, 86 insertions(+), 62 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 884923f..4254c2b 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -1,5 +1,7 @@
>  config DRM_PTN3460
>  	tristate "PTN3460 DP/LVDS bridge"
>  	depends on DRM
> +	depends on OF && I2C

Adding I2C here is causing this circular dependency:

scripts/kconfig/conf --silentoldconfig Kconfig
drivers/video/fbdev/Kconfig:5:error: recursive dependency detected!
drivers/video/fbdev/Kconfig:5:  symbol FB is selected by DRM_KMS_FB_HELPER
drivers/gpu/drm/Kconfig:34:     symbol DRM_KMS_FB_HELPER depends on
DRM_KMS_HELPER
drivers/gpu/drm/Kconfig:28:     symbol DRM_KMS_HELPER is selected by
DRM_PTN3460
drivers/gpu/drm/bridge/Kconfig:1:       symbol DRM_PTN3460 depends on I2C
drivers/i2c/Kconfig:7:  symbol I2C is selected by FB_DDC
drivers/video/fbdev/Kconfig:59: symbol FB_DDC is selected by FB_CYBER2000_DDC
drivers/video/fbdev/Kconfig:374:        symbol FB_CYBER2000_DDC depends on
FB_CYBER2000
drivers/video/fbdev/Kconfig:362:        symbol FB_CYBER2000 depends on FB

To solve this we just need to remove I2C from depends as DRM already selects
I2C. This was already fixed by:


commit 90bde571ad194adb039cb92a11a5b346f15eb610
Author: Arnd Bergmann <arnd@arndb.de>
Date:   Tue Mar 25 12:06:46 2014 +0100

    drm/bridge: PTN3460 needs DRM_KMS_HELPER

    The recently added PTN3460 device driver uses interfaces that
    are provided by the KMS helper infrastructure, so we should
    explicitly select that to avoid this linker error:

    ERROR: "drm_helper_probe_single_connector_modes" [drivers/gpu/drm/bridge/ptn3460.ko] undefined!
    ERROR: "drm_helper_connector_dpms" [drivers/gpu/drm/bridge/ptn3460.ko] undefined!

    We have to drop the I2C dependency to avoid a circular dependency
    chain, but that's ok because DRM already selects I2C.

    Signed-off-by: Arnd Bergmann <arnd@arndb.de>
    Signed-off-by: Dave Airlie <airlied@redhat.com>


But you may have introduced it again on a rebase. The following patch fixes it:

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 990b4b2..946d1ef 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -1,7 +1,6 @@
 config DRM_PTN3460
        tristate "PTN3460 DP/LVDS bridge"
-       depends on DRM
-       depends on OF && I2C
+       depends on DRM && OF
        select DRM_KMS_HELPER
        select DRM_PANEL
        ---help---


	Gustavo

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

* [PATCH V9 04/14] drm/bridge: ptn3460: Convert to i2c driver model
@ 2015-01-29 14:29     ` Gustavo Padovan
  0 siblings, 0 replies; 58+ messages in thread
From: Gustavo Padovan @ 2015-01-29 14:29 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ajay,

2015-01-20 Ajay Kumar <ajaykumar.rs@samsung.com>:

> Use drm_bridge helpers to modify the driver to support
> i2c driver model.
> 
> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
> Acked-by: Inki Dae <inki.dae@samsung.com>
> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
> ---
>  drivers/gpu/drm/bridge/Kconfig          |    2 +
>  drivers/gpu/drm/bridge/ptn3460.c        |  124 +++++++++++++++++++++----------
>  drivers/gpu/drm/exynos/exynos_dp_core.c |   22 ------
>  3 files changed, 86 insertions(+), 62 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 884923f..4254c2b 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -1,5 +1,7 @@
>  config DRM_PTN3460
>  	tristate "PTN3460 DP/LVDS bridge"
>  	depends on DRM
> +	depends on OF && I2C

Adding I2C here is causing this circular dependency:

scripts/kconfig/conf --silentoldconfig Kconfig
drivers/video/fbdev/Kconfig:5:error: recursive dependency detected!
drivers/video/fbdev/Kconfig:5:  symbol FB is selected by DRM_KMS_FB_HELPER
drivers/gpu/drm/Kconfig:34:     symbol DRM_KMS_FB_HELPER depends on
DRM_KMS_HELPER
drivers/gpu/drm/Kconfig:28:     symbol DRM_KMS_HELPER is selected by
DRM_PTN3460
drivers/gpu/drm/bridge/Kconfig:1:       symbol DRM_PTN3460 depends on I2C
drivers/i2c/Kconfig:7:  symbol I2C is selected by FB_DDC
drivers/video/fbdev/Kconfig:59: symbol FB_DDC is selected by FB_CYBER2000_DDC
drivers/video/fbdev/Kconfig:374:        symbol FB_CYBER2000_DDC depends on
FB_CYBER2000
drivers/video/fbdev/Kconfig:362:        symbol FB_CYBER2000 depends on FB

To solve this we just need to remove I2C from depends as DRM already selects
I2C. This was already fixed by:


commit 90bde571ad194adb039cb92a11a5b346f15eb610
Author: Arnd Bergmann <arnd@arndb.de>
Date:   Tue Mar 25 12:06:46 2014 +0100

    drm/bridge: PTN3460 needs DRM_KMS_HELPER

    The recently added PTN3460 device driver uses interfaces that
    are provided by the KMS helper infrastructure, so we should
    explicitly select that to avoid this linker error:

    ERROR: "drm_helper_probe_single_connector_modes" [drivers/gpu/drm/bridge/ptn3460.ko] undefined!
    ERROR: "drm_helper_connector_dpms" [drivers/gpu/drm/bridge/ptn3460.ko] undefined!

    We have to drop the I2C dependency to avoid a circular dependency
    chain, but that's ok because DRM already selects I2C.

    Signed-off-by: Arnd Bergmann <arnd@arndb.de>
    Signed-off-by: Dave Airlie <airlied@redhat.com>


But you may have introduced it again on a rebase. The following patch fixes it:

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 990b4b2..946d1ef 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -1,7 +1,6 @@
 config DRM_PTN3460
        tristate "PTN3460 DP/LVDS bridge"
-       depends on DRM
-       depends on OF && I2C
+       depends on DRM && OF
        select DRM_KMS_HELPER
        select DRM_PANEL
        ---help---


	Gustavo

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

* Re: [PATCH V9 04/14] drm/bridge: ptn3460: Convert to i2c driver model
  2015-01-29 14:29     ` Gustavo Padovan
@ 2015-01-29 14:39       ` Ajay kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay kumar @ 2015-01-29 14:39 UTC (permalink / raw)
  To: Gustavo Padovan
  Cc: devicetree, linux-samsung-soc, Sean Paul, Daniel Vetter,
	Jingoo Han, dri-devel, Kukjin Kim, Pannaga Bhushan Reddy Patel,
	Prashanth G, Ajay Kumar, linux-arm-kernel

Hi Gustavo,

I think Thierry already fixed it. Check this.
http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/bridge/Kconfig


Regards,
Ajay



On Thu, Jan 29, 2015 at 7:59 PM, Gustavo Padovan <gustavo@padovan.org> wrote:
> Hi Ajay,
>
> 2015-01-20 Ajay Kumar <ajaykumar.rs@samsung.com>:
>
>> Use drm_bridge helpers to modify the driver to support
>> i2c driver model.
>>
>> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
>> Acked-by: Inki Dae <inki.dae@samsung.com>
>> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
>> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
>> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
>> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
>> ---
>>  drivers/gpu/drm/bridge/Kconfig          |    2 +
>>  drivers/gpu/drm/bridge/ptn3460.c        |  124 +++++++++++++++++++++----------
>>  drivers/gpu/drm/exynos/exynos_dp_core.c |   22 ------
>>  3 files changed, 86 insertions(+), 62 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
>> index 884923f..4254c2b 100644
>> --- a/drivers/gpu/drm/bridge/Kconfig
>> +++ b/drivers/gpu/drm/bridge/Kconfig
>> @@ -1,5 +1,7 @@
>>  config DRM_PTN3460
>>       tristate "PTN3460 DP/LVDS bridge"
>>       depends on DRM
>> +     depends on OF && I2C
>
> Adding I2C here is causing this circular dependency:
>
> scripts/kconfig/conf --silentoldconfig Kconfig
> drivers/video/fbdev/Kconfig:5:error: recursive dependency detected!
> drivers/video/fbdev/Kconfig:5:  symbol FB is selected by DRM_KMS_FB_HELPER
> drivers/gpu/drm/Kconfig:34:     symbol DRM_KMS_FB_HELPER depends on
> DRM_KMS_HELPER
> drivers/gpu/drm/Kconfig:28:     symbol DRM_KMS_HELPER is selected by
> DRM_PTN3460
> drivers/gpu/drm/bridge/Kconfig:1:       symbol DRM_PTN3460 depends on I2C
> drivers/i2c/Kconfig:7:  symbol I2C is selected by FB_DDC
> drivers/video/fbdev/Kconfig:59: symbol FB_DDC is selected by FB_CYBER2000_DDC
> drivers/video/fbdev/Kconfig:374:        symbol FB_CYBER2000_DDC depends on
> FB_CYBER2000
> drivers/video/fbdev/Kconfig:362:        symbol FB_CYBER2000 depends on FB
>
> To solve this we just need to remove I2C from depends as DRM already selects
> I2C. This was already fixed by:
>
>
> commit 90bde571ad194adb039cb92a11a5b346f15eb610
> Author: Arnd Bergmann <arnd@arndb.de>
> Date:   Tue Mar 25 12:06:46 2014 +0100
>
>     drm/bridge: PTN3460 needs DRM_KMS_HELPER
>
>     The recently added PTN3460 device driver uses interfaces that
>     are provided by the KMS helper infrastructure, so we should
>     explicitly select that to avoid this linker error:
>
>     ERROR: "drm_helper_probe_single_connector_modes" [drivers/gpu/drm/bridge/ptn3460.ko] undefined!
>     ERROR: "drm_helper_connector_dpms" [drivers/gpu/drm/bridge/ptn3460.ko] undefined!
>
>     We have to drop the I2C dependency to avoid a circular dependency
>     chain, but that's ok because DRM already selects I2C.
>
>     Signed-off-by: Arnd Bergmann <arnd@arndb.de>
>     Signed-off-by: Dave Airlie <airlied@redhat.com>
>
>
> But you may have introduced it again on a rebase. The following patch fixes it:
>
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 990b4b2..946d1ef 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -1,7 +1,6 @@
>  config DRM_PTN3460
>         tristate "PTN3460 DP/LVDS bridge"
> -       depends on DRM
> -       depends on OF && I2C
> +       depends on DRM && OF
>         select DRM_KMS_HELPER
>         select DRM_PANEL
>         ---help---
>
>
>         Gustavo
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH V9 04/14] drm/bridge: ptn3460: Convert to i2c driver model
@ 2015-01-29 14:39       ` Ajay kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay kumar @ 2015-01-29 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Gustavo,

I think Thierry already fixed it. Check this.
http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/bridge/Kconfig


Regards,
Ajay



On Thu, Jan 29, 2015 at 7:59 PM, Gustavo Padovan <gustavo@padovan.org> wrote:
> Hi Ajay,
>
> 2015-01-20 Ajay Kumar <ajaykumar.rs@samsung.com>:
>
>> Use drm_bridge helpers to modify the driver to support
>> i2c driver model.
>>
>> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
>> Acked-by: Inki Dae <inki.dae@samsung.com>
>> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
>> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
>> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
>> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
>> ---
>>  drivers/gpu/drm/bridge/Kconfig          |    2 +
>>  drivers/gpu/drm/bridge/ptn3460.c        |  124 +++++++++++++++++++++----------
>>  drivers/gpu/drm/exynos/exynos_dp_core.c |   22 ------
>>  3 files changed, 86 insertions(+), 62 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
>> index 884923f..4254c2b 100644
>> --- a/drivers/gpu/drm/bridge/Kconfig
>> +++ b/drivers/gpu/drm/bridge/Kconfig
>> @@ -1,5 +1,7 @@
>>  config DRM_PTN3460
>>       tristate "PTN3460 DP/LVDS bridge"
>>       depends on DRM
>> +     depends on OF && I2C
>
> Adding I2C here is causing this circular dependency:
>
> scripts/kconfig/conf --silentoldconfig Kconfig
> drivers/video/fbdev/Kconfig:5:error: recursive dependency detected!
> drivers/video/fbdev/Kconfig:5:  symbol FB is selected by DRM_KMS_FB_HELPER
> drivers/gpu/drm/Kconfig:34:     symbol DRM_KMS_FB_HELPER depends on
> DRM_KMS_HELPER
> drivers/gpu/drm/Kconfig:28:     symbol DRM_KMS_HELPER is selected by
> DRM_PTN3460
> drivers/gpu/drm/bridge/Kconfig:1:       symbol DRM_PTN3460 depends on I2C
> drivers/i2c/Kconfig:7:  symbol I2C is selected by FB_DDC
> drivers/video/fbdev/Kconfig:59: symbol FB_DDC is selected by FB_CYBER2000_DDC
> drivers/video/fbdev/Kconfig:374:        symbol FB_CYBER2000_DDC depends on
> FB_CYBER2000
> drivers/video/fbdev/Kconfig:362:        symbol FB_CYBER2000 depends on FB
>
> To solve this we just need to remove I2C from depends as DRM already selects
> I2C. This was already fixed by:
>
>
> commit 90bde571ad194adb039cb92a11a5b346f15eb610
> Author: Arnd Bergmann <arnd@arndb.de>
> Date:   Tue Mar 25 12:06:46 2014 +0100
>
>     drm/bridge: PTN3460 needs DRM_KMS_HELPER
>
>     The recently added PTN3460 device driver uses interfaces that
>     are provided by the KMS helper infrastructure, so we should
>     explicitly select that to avoid this linker error:
>
>     ERROR: "drm_helper_probe_single_connector_modes" [drivers/gpu/drm/bridge/ptn3460.ko] undefined!
>     ERROR: "drm_helper_connector_dpms" [drivers/gpu/drm/bridge/ptn3460.ko] undefined!
>
>     We have to drop the I2C dependency to avoid a circular dependency
>     chain, but that's ok because DRM already selects I2C.
>
>     Signed-off-by: Arnd Bergmann <arnd@arndb.de>
>     Signed-off-by: Dave Airlie <airlied@redhat.com>
>
>
> But you may have introduced it again on a rebase. The following patch fixes it:
>
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 990b4b2..946d1ef 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -1,7 +1,6 @@
>  config DRM_PTN3460
>         tristate "PTN3460 DP/LVDS bridge"
> -       depends on DRM
> -       depends on OF && I2C
> +       depends on DRM && OF
>         select DRM_KMS_HELPER
>         select DRM_PANEL
>         ---help---
>
>
>         Gustavo

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

* Re: [PATCH V9 12/14] drm/bridge: Add i2c based driver for ps8622/ps8625 bridge
  2015-01-20 16:38   ` Ajay Kumar
@ 2015-01-29 14:42     ` Ajay kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay kumar @ 2015-01-29 14:42 UTC (permalink / raw)
  To: Thierry Reding, Dave Airlie
  Cc: Ajay Kumar, dri-devel, linux-samsung-soc, linux-arm-kernel,
	devicetree, Kukjin Kim, InKi Dae, Daniel Vetter, Sean Paul,
	Jingoo Han, Pannaga Bhushan Reddy Patel, Prashanth G,
	Vincent Palatin, Andrew Bresticker, Sean Paul, Rahul Sharma

Hi Thierry,

I think you forgot to take this patch!
Can you check this?

Regards,
Ajay Kumar


On Tue, Jan 20, 2015 at 10:08 PM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
> From: Vincent Palatin <vpalatin@chromium.org>
>
> This patch adds drm_bridge driver for parade DisplayPort
> to LVDS bridge chip.
>
> Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
> Acked-by: Inki Dae <inki.dae@samsung.com>
> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
> ---
>  drivers/gpu/drm/bridge/Kconfig  |    9 +
>  drivers/gpu/drm/bridge/Makefile |    1 +
>  drivers/gpu/drm/bridge/ps8622.c |  684 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 694 insertions(+)
>  create mode 100644 drivers/gpu/drm/bridge/ps8622.c
>
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 8b426e2..d06eda3 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -6,3 +6,12 @@ config DRM_PTN3460
>         select DRM_PANEL
>         ---help---
>           ptn3460 eDP-LVDS bridge chip driver.
> +
> +config DRM_PS8622
> +       tristate "Parade eDP/LVDS bridge"
> +       depends on OF && I2C
> +       select DRM_PANEL
> +       select BACKLIGHT_LCD_SUPPORT
> +       select BACKLIGHT_CLASS_DEVICE
> +       ---help---
> +         parade eDP-LVDS bridge chip driver.
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> index b4733e1..105da3e 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -1,3 +1,4 @@
>  ccflags-y := -Iinclude/drm
>
> +obj-$(CONFIG_DRM_PS8622) += ps8622.o
>  obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
> diff --git a/drivers/gpu/drm/bridge/ps8622.c b/drivers/gpu/drm/bridge/ps8622.c
> new file mode 100644
> index 0000000..5474a39
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/ps8622.c
> @@ -0,0 +1,684 @@
> +/*
> + * Parade PS8622 eDP/LVDS bridge driver
> + *
> + * Copyright (C) 2014 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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/backlight.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/fb.h>
> +#include <linux/gpio.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/of_graph.h>
> +#include <linux/pm.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_panel.h>
> +
> +#include "drmP.h"
> +#include "drm_crtc.h"
> +#include "drm_crtc_helper.h"
> +
> +/* Brightness scale on the Parade chip */
> +#define PS8622_MAX_BRIGHTNESS 0xff
> +
> +/* Timings taken from the version 1.7 datasheet for the PS8622/PS8625 */
> +#define PS8622_POWER_RISE_T1_MIN_US 10
> +#define PS8622_POWER_RISE_T1_MAX_US 10000
> +#define PS8622_RST_HIGH_T2_MIN_US 3000
> +#define PS8622_RST_HIGH_T2_MAX_US 30000
> +#define PS8622_PWMO_END_T12_MS 200
> +#define PS8622_POWER_FALL_T16_MAX_US 10000
> +#define PS8622_POWER_OFF_T17_MS 500
> +
> +#if ((PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US) > \
> +       (PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US))
> +#error "T2.min + T1.max must be less than T2.max + T1.min"
> +#endif
> +
> +struct ps8622_bridge {
> +       struct drm_connector connector;
> +       struct i2c_client *client;
> +       struct drm_bridge bridge;
> +       struct drm_panel *panel;
> +       struct regulator *v12;
> +       struct backlight_device *bl;
> +
> +       struct gpio_desc *gpio_slp;
> +       struct gpio_desc *gpio_rst;
> +
> +       u32 max_lane_count;
> +       u32 lane_count;
> +
> +       bool enabled;
> +};
> +
> +static inline struct ps8622_bridge *
> +               bridge_to_ps8622(struct drm_bridge *bridge)
> +{
> +       return container_of(bridge, struct ps8622_bridge, bridge);
> +}
> +
> +static inline struct ps8622_bridge *
> +               connector_to_ps8622(struct drm_connector *connector)
> +{
> +       return container_of(connector, struct ps8622_bridge, connector);
> +}
> +
> +static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val)
> +{
> +       int ret;
> +       struct i2c_adapter *adap = client->adapter;
> +       struct i2c_msg msg;
> +       u8 data[] = {reg, val};
> +
> +       msg.addr = client->addr + page;
> +       msg.flags = 0;
> +       msg.len = sizeof(data);
> +       msg.buf = data;
> +
> +       ret = i2c_transfer(adap, &msg, 1);
> +       if (ret != 1)
> +               pr_warn("PS8622 I2C write (0x%02x,0x%02x,0x%02x) failed: %d\n",
> +                       client->addr + page, reg, val, ret);
> +       return !(ret == 1);
> +}
> +
> +static int ps8622_send_config(struct ps8622_bridge *ps8622)
> +{
> +       struct i2c_client *cl = ps8622->client;
> +       int err = 0;
> +
> +       /* HPD low */
> +       err = ps8622_set(cl, 0x02, 0xa1, 0x01);
> +       if (err)
> +               goto error;
> +
> +       /* SW setting: [1:0] SW output 1.2V voltage is lower to 96% */
> +       err = ps8622_set(cl, 0x04, 0x14, 0x01);
> +       if (err)
> +               goto error;
> +
> +       /* RCO SS setting: [5:4] = b01 0.5%, b10 1%, b11 1.5% */
> +       err = ps8622_set(cl, 0x04, 0xe3, 0x20);
> +       if (err)
> +               goto error;
> +
> +       /* [7] RCO SS enable */
> +       err = ps8622_set(cl, 0x04, 0xe2, 0x80);
> +       if (err)
> +               goto error;
> +
> +       /* RPHY Setting
> +        * [3:2] CDR tune wait cycle before measure for fine tune
> +        * b00: 1us b01: 0.5us b10:2us, b11: 4us
> +        */
> +       err = ps8622_set(cl, 0x04, 0x8a, 0x0c);
> +       if (err)
> +               goto error;
> +
> +       /* [3] RFD always on */
> +       err = ps8622_set(cl, 0x04, 0x89, 0x08);
> +       if (err)
> +               goto error;
> +
> +       /* CTN lock in/out: 20000ppm/80000ppm. Lock out 2 times. */
> +       err = ps8622_set(cl, 0x04, 0x71, 0x2d);
> +       if (err)
> +               goto error;
> +
> +       /* 2.7G CDR settings: NOF=40LSB for HBR CDR  setting */
> +       err = ps8622_set(cl, 0x04, 0x7d, 0x07);
> +       if (err)
> +               goto error;
> +
> +       /* [1:0] Fmin=+4bands */
> +       err = ps8622_set(cl, 0x04, 0x7b, 0x00);
> +       if (err)
> +               goto error;
> +
> +       /* [7:5] DCO_FTRNG=+-40% */
> +       err = ps8622_set(cl, 0x04, 0x7a, 0xfd);
> +       if (err)
> +               goto error;
> +
> +       /* 1.62G CDR settings: [5:2]NOF=64LSB [1:0]DCO scale is 2/5 */
> +       err = ps8622_set(cl, 0x04, 0xc0, 0x12);
> +       if (err)
> +               goto error;
> +
> +       /* Gitune=-37% */
> +       err = ps8622_set(cl, 0x04, 0xc1, 0x92);
> +       if (err)
> +               goto error;
> +
> +       /* Fbstep=100% */
> +       err = ps8622_set(cl, 0x04, 0xc2, 0x1c);
> +       if (err)
> +               goto error;
> +
> +       /* [7] LOS signal disable */
> +       err = ps8622_set(cl, 0x04, 0x32, 0x80);
> +       if (err)
> +               goto error;
> +
> +       /* RPIO Setting: [7:4] LVDS driver bias current : 75% (250mV swing) */
> +       err = ps8622_set(cl, 0x04, 0x00, 0xb0);
> +       if (err)
> +               goto error;
> +
> +       /* [7:6] Right-bar GPIO output strength is 8mA */
> +       err = ps8622_set(cl, 0x04, 0x15, 0x40);
> +       if (err)
> +               goto error;
> +
> +       /* EQ Training State Machine Setting, RCO calibration start */
> +       err = ps8622_set(cl, 0x04, 0x54, 0x10);
> +       if (err)
> +               goto error;
> +
> +       /* Logic, needs more than 10 I2C command */
> +       /* [4:0] MAX_LANE_COUNT set to max supported lanes */
> +       err = ps8622_set(cl, 0x01, 0x02, 0x80 | ps8622->max_lane_count);
> +       if (err)
> +               goto error;
> +
> +       /* [4:0] LANE_COUNT_SET set to chosen lane count */
> +       err = ps8622_set(cl, 0x01, 0x21, 0x80 | ps8622->lane_count);
> +       if (err)
> +               goto error;
> +
> +       err = ps8622_set(cl, 0x00, 0x52, 0x20);
> +       if (err)
> +               goto error;
> +
> +       /* HPD CP toggle enable */
> +       err = ps8622_set(cl, 0x00, 0xf1, 0x03);
> +       if (err)
> +               goto error;
> +
> +       err = ps8622_set(cl, 0x00, 0x62, 0x41);
> +       if (err)
> +               goto error;
> +
> +       /* Counter number, add 1ms counter delay */
> +       err = ps8622_set(cl, 0x00, 0xf6, 0x01);
> +       if (err)
> +               goto error;
> +
> +       /* [6]PWM function control by DPCD0040f[7], default is PWM block */
> +       err = ps8622_set(cl, 0x00, 0x77, 0x06);
> +       if (err)
> +               goto error;
> +
> +       /* 04h Adjust VTotal toleranceto fix the 30Hz no display issue */
> +       err = ps8622_set(cl, 0x00, 0x4c, 0x04);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD00400='h00, Parade OUI ='h001cf8 */
> +       err = ps8622_set(cl, 0x01, 0xc0, 0x00);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD00401='h1c */
> +       err = ps8622_set(cl, 0x01, 0xc1, 0x1c);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD00402='hf8 */
> +       err = ps8622_set(cl, 0x01, 0xc2, 0xf8);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD403~408 = ASCII code, D2SLV5='h4432534c5635 */
> +       err = ps8622_set(cl, 0x01, 0xc3, 0x44);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD404 */
> +       err = ps8622_set(cl, 0x01, 0xc4, 0x32);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD405 */
> +       err = ps8622_set(cl, 0x01, 0xc5, 0x53);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD406 */
> +       err = ps8622_set(cl, 0x01, 0xc6, 0x4c);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD407 */
> +       err = ps8622_set(cl, 0x01, 0xc7, 0x56);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD408 */
> +       err = ps8622_set(cl, 0x01, 0xc8, 0x35);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD40A, Initial Code major revision '01' */
> +       err = ps8622_set(cl, 0x01, 0xca, 0x01);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD40B, Initial Code minor revision '05' */
> +       err = ps8622_set(cl, 0x01, 0xcb, 0x05);
> +       if (err)
> +               goto error;
> +
> +
> +       if (ps8622->bl) {
> +               /* DPCD720, internal PWM */
> +               err = ps8622_set(cl, 0x01, 0xa5, 0xa0);
> +               if (err)
> +                       goto error;
> +
> +               /* FFh for 100% brightness, 0h for 0% brightness */
> +               err = ps8622_set(cl, 0x01, 0xa7,
> +                               ps8622->bl->props.brightness);
> +               if (err)
> +                       goto error;
> +       } else {
> +               /* DPCD720, external PWM */
> +               err = ps8622_set(cl, 0x01, 0xa5, 0x80);
> +               if (err)
> +                       goto error;
> +       }
> +
> +       /* Set LVDS output as 6bit-VESA mapping, single LVDS channel */
> +       err = ps8622_set(cl, 0x01, 0xcc, 0x13);
> +       if (err)
> +               goto error;
> +
> +       /* Enable SSC set by register */
> +       err = ps8622_set(cl, 0x02, 0xb1, 0x20);
> +       if (err)
> +               goto error;
> +
> +       /* Set SSC enabled and +/-1% central spreading */
> +       err = ps8622_set(cl, 0x04, 0x10, 0x16);
> +       if (err)
> +               goto error;
> +
> +       /* Logic end */
> +       /* MPU Clock source: LC => RCO */
> +       err = ps8622_set(cl, 0x04, 0x59, 0x60);
> +       if (err)
> +               goto error;
> +
> +       /* LC -> RCO */
> +       err = ps8622_set(cl, 0x04, 0x54, 0x14);
> +       if (err)
> +               goto error;
> +
> +       /* HPD high */
> +       err = ps8622_set(cl, 0x02, 0xa1, 0x91);
> +
> +error:
> +       return err ? -EIO : 0;
> +}
> +
> +static int ps8622_backlight_update(struct backlight_device *bl)
> +{
> +       struct ps8622_bridge *ps8622 = dev_get_drvdata(&bl->dev);
> +       int ret, brightness = bl->props.brightness;
> +
> +       if (bl->props.power != FB_BLANK_UNBLANK ||
> +           bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
> +               brightness = 0;
> +
> +       if (!ps8622->enabled)
> +               return -EINVAL;
> +
> +       ret = ps8622_set(ps8622->client, 0x01, 0xa7, brightness);
> +
> +       return ret;
> +}
> +
> +static const struct backlight_ops ps8622_backlight_ops = {
> +       .update_status  = ps8622_backlight_update,
> +};
> +
> +static void ps8622_pre_enable(struct drm_bridge *bridge)
> +{
> +       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
> +       int ret;
> +
> +       if (ps8622->enabled)
> +               return;
> +
> +       gpiod_set_value(ps8622->gpio_rst, 0);
> +
> +       if (ps8622->v12) {
> +               ret = regulator_enable(ps8622->v12);
> +               if (ret)
> +                       DRM_ERROR("fails to enable ps8622->v12");
> +       }
> +
> +       if (drm_panel_prepare(ps8622->panel)) {
> +               DRM_ERROR("failed to prepare panel\n");
> +               return;
> +       }
> +
> +       gpiod_set_value(ps8622->gpio_slp, 1);
> +
> +       /*
> +        * T1 is the range of time that it takes for the power to rise after we
> +        * enable the lcd/ps8622 fet. T2 is the range of time in which the
> +        * data sheet specifies we should deassert the reset pin.
> +        *
> +        * If it takes T1.max for the power to rise, we need to wait atleast
> +        * T2.min before deasserting the reset pin. If it takes T1.min for the
> +        * power to rise, we need to wait at most T2.max before deasserting the
> +        * reset pin.
> +        */
> +       usleep_range(PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US,
> +                    PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US);
> +
> +       gpiod_set_value(ps8622->gpio_rst, 1);
> +
> +       /* wait 20ms after RST high */
> +       usleep_range(20000, 30000);
> +
> +       ret = ps8622_send_config(ps8622);
> +       if (ret) {
> +               DRM_ERROR("Failed to send config to bridge (%d)\n", ret);
> +               return;
> +       }
> +
> +       ps8622->enabled = true;
> +}
> +
> +static void ps8622_enable(struct drm_bridge *bridge)
> +{
> +       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
> +
> +       if (drm_panel_enable(ps8622->panel)) {
> +               DRM_ERROR("failed to enable panel\n");
> +               return;
> +       }
> +}
> +
> +static void ps8622_disable(struct drm_bridge *bridge)
> +{
> +       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
> +
> +       if (drm_panel_disable(ps8622->panel)) {
> +               DRM_ERROR("failed to disable panel\n");
> +               return;
> +       }
> +       msleep(PS8622_PWMO_END_T12_MS);
> +}
> +
> +static void ps8622_post_disable(struct drm_bridge *bridge)
> +{
> +       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
> +
> +       if (!ps8622->enabled)
> +               return;
> +
> +       ps8622->enabled = false;
> +
> +       /*
> +        * This doesn't matter if the regulators are turned off, but something
> +        * else might keep them on. In that case, we want to assert the slp gpio
> +        * to lower power.
> +        */
> +       gpiod_set_value(ps8622->gpio_slp, 0);
> +
> +       if (drm_panel_unprepare(ps8622->panel)) {
> +               DRM_ERROR("failed to unprepare panel\n");
> +               return;
> +       }
> +
> +       if (ps8622->v12)
> +               regulator_disable(ps8622->v12);
> +
> +       /*
> +        * Sleep for at least the amount of time that it takes the power rail to
> +        * fall to prevent asserting the rst gpio from doing anything.
> +        */
> +       usleep_range(PS8622_POWER_FALL_T16_MAX_US,
> +                    2 * PS8622_POWER_FALL_T16_MAX_US);
> +       gpiod_set_value(ps8622->gpio_rst, 0);
> +
> +       msleep(PS8622_POWER_OFF_T17_MS);
> +}
> +
> +static int ps8622_get_modes(struct drm_connector *connector)
> +{
> +       struct ps8622_bridge *ps8622;
> +
> +       ps8622 = connector_to_ps8622(connector);
> +
> +       return drm_panel_get_modes(ps8622->panel);
> +}
> +
> +static struct drm_encoder *ps8622_best_encoder(struct drm_connector *connector)
> +{
> +       struct ps8622_bridge *ps8622;
> +
> +       ps8622 = connector_to_ps8622(connector);
> +
> +       return ps8622->bridge.encoder;
> +}
> +
> +static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = {
> +       .get_modes = ps8622_get_modes,
> +       .best_encoder = ps8622_best_encoder,
> +};
> +
> +static enum drm_connector_status ps8622_detect(struct drm_connector *connector,
> +                                                               bool force)
> +{
> +       return connector_status_connected;
> +}
> +
> +static void ps8622_connector_destroy(struct drm_connector *connector)
> +{
> +       drm_connector_cleanup(connector);
> +}
> +
> +static const struct drm_connector_funcs ps8622_connector_funcs = {
> +       .dpms = drm_helper_connector_dpms,
> +       .fill_modes = drm_helper_probe_single_connector_modes,
> +       .detect = ps8622_detect,
> +       .destroy = ps8622_connector_destroy,
> +};
> +
> +int ps8622_attach(struct drm_bridge *bridge)
> +{
> +       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
> +       int ret;
> +
> +       if (!bridge->encoder) {
> +               DRM_ERROR("Parent encoder object not found");
> +               return -ENODEV;
> +       }
> +
> +       ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD;
> +       ret = drm_connector_init(bridge->dev, &ps8622->connector,
> +                       &ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
> +       if (ret) {
> +               DRM_ERROR("Failed to initialize connector with drm\n");
> +               return ret;
> +       }
> +       drm_connector_helper_add(&ps8622->connector,
> +                                       &ps8622_connector_helper_funcs);
> +       drm_connector_register(&ps8622->connector);
> +       drm_mode_connector_attach_encoder(&ps8622->connector,
> +                                                       bridge->encoder);
> +
> +       if (ps8622->panel)
> +               drm_panel_attach(ps8622->panel, &ps8622->connector);
> +
> +       drm_helper_hpd_irq_event(ps8622->connector.dev);
> +
> +       return ret;
> +}
> +
> +static const struct drm_bridge_funcs ps8622_bridge_funcs = {
> +       .pre_enable = ps8622_pre_enable,
> +       .enable = ps8622_enable,
> +       .disable = ps8622_disable,
> +       .post_disable = ps8622_post_disable,
> +       .attach = ps8622_attach,
> +};
> +
> +static const struct of_device_id ps8622_devices[] = {
> +       {.compatible = "parade,ps8622",},
> +       {.compatible = "parade,ps8625",},
> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, ps8622_devices);
> +
> +static int ps8622_probe(struct i2c_client *client,
> +                                       const struct i2c_device_id *id)
> +{
> +       struct device *dev = &client->dev;
> +       struct device_node *endpoint, *panel_node;
> +       struct ps8622_bridge *ps8622;
> +       int ret;
> +
> +       ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL);
> +       if (!ps8622)
> +               return -ENOMEM;
> +
> +       endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
> +       if (endpoint) {
> +               panel_node = of_graph_get_remote_port_parent(endpoint);
> +               if (panel_node) {
> +                       ps8622->panel = of_drm_find_panel(panel_node);
> +                       of_node_put(panel_node);
> +                       if (!ps8622->panel)
> +                               return -EPROBE_DEFER;
> +               }
> +       }
> +
> +       ps8622->client = client;
> +
> +       ps8622->v12 = devm_regulator_get(dev, "vdd12");
> +       if (IS_ERR(ps8622->v12)) {
> +               dev_info(dev, "no 1.2v regulator found for PS8622\n");
> +               ps8622->v12 = NULL;
> +       }
> +
> +       ps8622->gpio_slp = devm_gpiod_get(dev, "sleep");
> +       if (IS_ERR(ps8622->gpio_slp)) {
> +               ret = PTR_ERR(ps8622->gpio_slp);
> +               dev_err(dev, "cannot get gpio_slp %d\n", ret);
> +               return ret;
> +       }
> +       ret = gpiod_direction_output(ps8622->gpio_slp, 1);
> +       if (ret) {
> +               dev_err(dev, "cannot configure gpio_slp\n");
> +               return ret;
> +       }
> +
> +       ps8622->gpio_rst = devm_gpiod_get(dev, "reset");
> +       if (IS_ERR(ps8622->gpio_rst)) {
> +               ret = PTR_ERR(ps8622->gpio_rst);
> +               dev_err(dev, "cannot get gpio_rst %d\n", ret);
> +               return ret;
> +       }
> +       /*
> +        * Assert the reset pin high to avoid the bridge being
> +        * initialized prematurely
> +        */
> +       ret = gpiod_direction_output(ps8622->gpio_rst, 1);
> +       if (ret) {
> +               dev_err(dev, "cannot configure gpio_rst\n");
> +               return ret;
> +       }
> +
> +       ps8622->max_lane_count = id->driver_data;
> +
> +       if (of_property_read_u32(dev->of_node, "lane-count",
> +                                               &ps8622->lane_count)) {
> +               ps8622->lane_count = ps8622->max_lane_count;
> +       } else if (ps8622->lane_count > ps8622->max_lane_count) {
> +               dev_info(dev, "lane-count property is too high,"
> +                                               "using max_lane_count\n");
> +               ps8622->lane_count = ps8622->max_lane_count;
> +       }
> +
> +       if (!of_find_property(dev->of_node, "use-external-pwm", NULL)) {
> +               ps8622->bl = backlight_device_register("ps8622-backlight",
> +                               dev, ps8622, &ps8622_backlight_ops,
> +                               NULL);
> +               if (IS_ERR(ps8622->bl)) {
> +                       DRM_ERROR("failed to register backlight\n");
> +                       ret = PTR_ERR(ps8622->bl);
> +                       ps8622->bl = NULL;
> +                       return ret;
> +               }
> +               ps8622->bl->props.max_brightness = PS8622_MAX_BRIGHTNESS;
> +               ps8622->bl->props.brightness = PS8622_MAX_BRIGHTNESS;
> +       }
> +
> +       ps8622->bridge.funcs = &ps8622_bridge_funcs;
> +       ps8622->bridge.of_node = dev->of_node;
> +       ret = drm_bridge_add(&ps8622->bridge);
> +       if (ret) {
> +               DRM_ERROR("Failed to add bridge\n");
> +               return ret;
> +       }
> +
> +       i2c_set_clientdata(client, ps8622);
> +
> +       return 0;
> +}
> +
> +static int ps8622_remove(struct i2c_client *client)
> +{
> +       struct ps8622_bridge *ps8622 = i2c_get_clientdata(client);
> +
> +       if (ps8622->bl)
> +               backlight_device_unregister(ps8622->bl);
> +
> +       drm_bridge_remove(&ps8622->bridge);
> +
> +       return 0;
> +}
> +
> +static const struct i2c_device_id ps8622_i2c_table[] = {
> +       /* Device type, max_lane_count */
> +       {"ps8622", 1},
> +       {"ps8625", 2},
> +       {},
> +};
> +MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);
> +
> +struct i2c_driver ps8622_driver = {
> +       .id_table       = ps8622_i2c_table,
> +       .probe          = ps8622_probe,
> +       .remove         = ps8622_remove,
> +       .driver         = {
> +               .name   = "ps8622",
> +               .owner  = THIS_MODULE,
> +               .of_match_table = ps8622_devices,
> +       },
> +};
> +module_i2c_driver(ps8622_driver);
> +
> +MODULE_AUTHOR("Vincent Palatin <vpalatin@chromium.org>");
> +MODULE_DESCRIPTION("Parade ps8622/ps8625 eDP-LVDS converter driver");
> +MODULE_LICENSE("GPL v2");
> --
> 1.7.9.5
>

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

* [PATCH V9 12/14] drm/bridge: Add i2c based driver for ps8622/ps8625 bridge
@ 2015-01-29 14:42     ` Ajay kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay kumar @ 2015-01-29 14:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thierry,

I think you forgot to take this patch!
Can you check this?

Regards,
Ajay Kumar


On Tue, Jan 20, 2015 at 10:08 PM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
> From: Vincent Palatin <vpalatin@chromium.org>
>
> This patch adds drm_bridge driver for parade DisplayPort
> to LVDS bridge chip.
>
> Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
> Acked-by: Inki Dae <inki.dae@samsung.com>
> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
> ---
>  drivers/gpu/drm/bridge/Kconfig  |    9 +
>  drivers/gpu/drm/bridge/Makefile |    1 +
>  drivers/gpu/drm/bridge/ps8622.c |  684 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 694 insertions(+)
>  create mode 100644 drivers/gpu/drm/bridge/ps8622.c
>
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 8b426e2..d06eda3 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -6,3 +6,12 @@ config DRM_PTN3460
>         select DRM_PANEL
>         ---help---
>           ptn3460 eDP-LVDS bridge chip driver.
> +
> +config DRM_PS8622
> +       tristate "Parade eDP/LVDS bridge"
> +       depends on OF && I2C
> +       select DRM_PANEL
> +       select BACKLIGHT_LCD_SUPPORT
> +       select BACKLIGHT_CLASS_DEVICE
> +       ---help---
> +         parade eDP-LVDS bridge chip driver.
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> index b4733e1..105da3e 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -1,3 +1,4 @@
>  ccflags-y := -Iinclude/drm
>
> +obj-$(CONFIG_DRM_PS8622) += ps8622.o
>  obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
> diff --git a/drivers/gpu/drm/bridge/ps8622.c b/drivers/gpu/drm/bridge/ps8622.c
> new file mode 100644
> index 0000000..5474a39
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/ps8622.c
> @@ -0,0 +1,684 @@
> +/*
> + * Parade PS8622 eDP/LVDS bridge driver
> + *
> + * Copyright (C) 2014 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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/backlight.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/fb.h>
> +#include <linux/gpio.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/of_graph.h>
> +#include <linux/pm.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_panel.h>
> +
> +#include "drmP.h"
> +#include "drm_crtc.h"
> +#include "drm_crtc_helper.h"
> +
> +/* Brightness scale on the Parade chip */
> +#define PS8622_MAX_BRIGHTNESS 0xff
> +
> +/* Timings taken from the version 1.7 datasheet for the PS8622/PS8625 */
> +#define PS8622_POWER_RISE_T1_MIN_US 10
> +#define PS8622_POWER_RISE_T1_MAX_US 10000
> +#define PS8622_RST_HIGH_T2_MIN_US 3000
> +#define PS8622_RST_HIGH_T2_MAX_US 30000
> +#define PS8622_PWMO_END_T12_MS 200
> +#define PS8622_POWER_FALL_T16_MAX_US 10000
> +#define PS8622_POWER_OFF_T17_MS 500
> +
> +#if ((PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US) > \
> +       (PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US))
> +#error "T2.min + T1.max must be less than T2.max + T1.min"
> +#endif
> +
> +struct ps8622_bridge {
> +       struct drm_connector connector;
> +       struct i2c_client *client;
> +       struct drm_bridge bridge;
> +       struct drm_panel *panel;
> +       struct regulator *v12;
> +       struct backlight_device *bl;
> +
> +       struct gpio_desc *gpio_slp;
> +       struct gpio_desc *gpio_rst;
> +
> +       u32 max_lane_count;
> +       u32 lane_count;
> +
> +       bool enabled;
> +};
> +
> +static inline struct ps8622_bridge *
> +               bridge_to_ps8622(struct drm_bridge *bridge)
> +{
> +       return container_of(bridge, struct ps8622_bridge, bridge);
> +}
> +
> +static inline struct ps8622_bridge *
> +               connector_to_ps8622(struct drm_connector *connector)
> +{
> +       return container_of(connector, struct ps8622_bridge, connector);
> +}
> +
> +static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val)
> +{
> +       int ret;
> +       struct i2c_adapter *adap = client->adapter;
> +       struct i2c_msg msg;
> +       u8 data[] = {reg, val};
> +
> +       msg.addr = client->addr + page;
> +       msg.flags = 0;
> +       msg.len = sizeof(data);
> +       msg.buf = data;
> +
> +       ret = i2c_transfer(adap, &msg, 1);
> +       if (ret != 1)
> +               pr_warn("PS8622 I2C write (0x%02x,0x%02x,0x%02x) failed: %d\n",
> +                       client->addr + page, reg, val, ret);
> +       return !(ret == 1);
> +}
> +
> +static int ps8622_send_config(struct ps8622_bridge *ps8622)
> +{
> +       struct i2c_client *cl = ps8622->client;
> +       int err = 0;
> +
> +       /* HPD low */
> +       err = ps8622_set(cl, 0x02, 0xa1, 0x01);
> +       if (err)
> +               goto error;
> +
> +       /* SW setting: [1:0] SW output 1.2V voltage is lower to 96% */
> +       err = ps8622_set(cl, 0x04, 0x14, 0x01);
> +       if (err)
> +               goto error;
> +
> +       /* RCO SS setting: [5:4] = b01 0.5%, b10 1%, b11 1.5% */
> +       err = ps8622_set(cl, 0x04, 0xe3, 0x20);
> +       if (err)
> +               goto error;
> +
> +       /* [7] RCO SS enable */
> +       err = ps8622_set(cl, 0x04, 0xe2, 0x80);
> +       if (err)
> +               goto error;
> +
> +       /* RPHY Setting
> +        * [3:2] CDR tune wait cycle before measure for fine tune
> +        * b00: 1us b01: 0.5us b10:2us, b11: 4us
> +        */
> +       err = ps8622_set(cl, 0x04, 0x8a, 0x0c);
> +       if (err)
> +               goto error;
> +
> +       /* [3] RFD always on */
> +       err = ps8622_set(cl, 0x04, 0x89, 0x08);
> +       if (err)
> +               goto error;
> +
> +       /* CTN lock in/out: 20000ppm/80000ppm. Lock out 2 times. */
> +       err = ps8622_set(cl, 0x04, 0x71, 0x2d);
> +       if (err)
> +               goto error;
> +
> +       /* 2.7G CDR settings: NOF=40LSB for HBR CDR  setting */
> +       err = ps8622_set(cl, 0x04, 0x7d, 0x07);
> +       if (err)
> +               goto error;
> +
> +       /* [1:0] Fmin=+4bands */
> +       err = ps8622_set(cl, 0x04, 0x7b, 0x00);
> +       if (err)
> +               goto error;
> +
> +       /* [7:5] DCO_FTRNG=+-40% */
> +       err = ps8622_set(cl, 0x04, 0x7a, 0xfd);
> +       if (err)
> +               goto error;
> +
> +       /* 1.62G CDR settings: [5:2]NOF=64LSB [1:0]DCO scale is 2/5 */
> +       err = ps8622_set(cl, 0x04, 0xc0, 0x12);
> +       if (err)
> +               goto error;
> +
> +       /* Gitune=-37% */
> +       err = ps8622_set(cl, 0x04, 0xc1, 0x92);
> +       if (err)
> +               goto error;
> +
> +       /* Fbstep=100% */
> +       err = ps8622_set(cl, 0x04, 0xc2, 0x1c);
> +       if (err)
> +               goto error;
> +
> +       /* [7] LOS signal disable */
> +       err = ps8622_set(cl, 0x04, 0x32, 0x80);
> +       if (err)
> +               goto error;
> +
> +       /* RPIO Setting: [7:4] LVDS driver bias current : 75% (250mV swing) */
> +       err = ps8622_set(cl, 0x04, 0x00, 0xb0);
> +       if (err)
> +               goto error;
> +
> +       /* [7:6] Right-bar GPIO output strength is 8mA */
> +       err = ps8622_set(cl, 0x04, 0x15, 0x40);
> +       if (err)
> +               goto error;
> +
> +       /* EQ Training State Machine Setting, RCO calibration start */
> +       err = ps8622_set(cl, 0x04, 0x54, 0x10);
> +       if (err)
> +               goto error;
> +
> +       /* Logic, needs more than 10 I2C command */
> +       /* [4:0] MAX_LANE_COUNT set to max supported lanes */
> +       err = ps8622_set(cl, 0x01, 0x02, 0x80 | ps8622->max_lane_count);
> +       if (err)
> +               goto error;
> +
> +       /* [4:0] LANE_COUNT_SET set to chosen lane count */
> +       err = ps8622_set(cl, 0x01, 0x21, 0x80 | ps8622->lane_count);
> +       if (err)
> +               goto error;
> +
> +       err = ps8622_set(cl, 0x00, 0x52, 0x20);
> +       if (err)
> +               goto error;
> +
> +       /* HPD CP toggle enable */
> +       err = ps8622_set(cl, 0x00, 0xf1, 0x03);
> +       if (err)
> +               goto error;
> +
> +       err = ps8622_set(cl, 0x00, 0x62, 0x41);
> +       if (err)
> +               goto error;
> +
> +       /* Counter number, add 1ms counter delay */
> +       err = ps8622_set(cl, 0x00, 0xf6, 0x01);
> +       if (err)
> +               goto error;
> +
> +       /* [6]PWM function control by DPCD0040f[7], default is PWM block */
> +       err = ps8622_set(cl, 0x00, 0x77, 0x06);
> +       if (err)
> +               goto error;
> +
> +       /* 04h Adjust VTotal toleranceto fix the 30Hz no display issue */
> +       err = ps8622_set(cl, 0x00, 0x4c, 0x04);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD00400='h00, Parade OUI ='h001cf8 */
> +       err = ps8622_set(cl, 0x01, 0xc0, 0x00);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD00401='h1c */
> +       err = ps8622_set(cl, 0x01, 0xc1, 0x1c);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD00402='hf8 */
> +       err = ps8622_set(cl, 0x01, 0xc2, 0xf8);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD403~408 = ASCII code, D2SLV5='h4432534c5635 */
> +       err = ps8622_set(cl, 0x01, 0xc3, 0x44);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD404 */
> +       err = ps8622_set(cl, 0x01, 0xc4, 0x32);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD405 */
> +       err = ps8622_set(cl, 0x01, 0xc5, 0x53);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD406 */
> +       err = ps8622_set(cl, 0x01, 0xc6, 0x4c);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD407 */
> +       err = ps8622_set(cl, 0x01, 0xc7, 0x56);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD408 */
> +       err = ps8622_set(cl, 0x01, 0xc8, 0x35);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD40A, Initial Code major revision '01' */
> +       err = ps8622_set(cl, 0x01, 0xca, 0x01);
> +       if (err)
> +               goto error;
> +
> +       /* DPCD40B, Initial Code minor revision '05' */
> +       err = ps8622_set(cl, 0x01, 0xcb, 0x05);
> +       if (err)
> +               goto error;
> +
> +
> +       if (ps8622->bl) {
> +               /* DPCD720, internal PWM */
> +               err = ps8622_set(cl, 0x01, 0xa5, 0xa0);
> +               if (err)
> +                       goto error;
> +
> +               /* FFh for 100% brightness, 0h for 0% brightness */
> +               err = ps8622_set(cl, 0x01, 0xa7,
> +                               ps8622->bl->props.brightness);
> +               if (err)
> +                       goto error;
> +       } else {
> +               /* DPCD720, external PWM */
> +               err = ps8622_set(cl, 0x01, 0xa5, 0x80);
> +               if (err)
> +                       goto error;
> +       }
> +
> +       /* Set LVDS output as 6bit-VESA mapping, single LVDS channel */
> +       err = ps8622_set(cl, 0x01, 0xcc, 0x13);
> +       if (err)
> +               goto error;
> +
> +       /* Enable SSC set by register */
> +       err = ps8622_set(cl, 0x02, 0xb1, 0x20);
> +       if (err)
> +               goto error;
> +
> +       /* Set SSC enabled and +/-1% central spreading */
> +       err = ps8622_set(cl, 0x04, 0x10, 0x16);
> +       if (err)
> +               goto error;
> +
> +       /* Logic end */
> +       /* MPU Clock source: LC => RCO */
> +       err = ps8622_set(cl, 0x04, 0x59, 0x60);
> +       if (err)
> +               goto error;
> +
> +       /* LC -> RCO */
> +       err = ps8622_set(cl, 0x04, 0x54, 0x14);
> +       if (err)
> +               goto error;
> +
> +       /* HPD high */
> +       err = ps8622_set(cl, 0x02, 0xa1, 0x91);
> +
> +error:
> +       return err ? -EIO : 0;
> +}
> +
> +static int ps8622_backlight_update(struct backlight_device *bl)
> +{
> +       struct ps8622_bridge *ps8622 = dev_get_drvdata(&bl->dev);
> +       int ret, brightness = bl->props.brightness;
> +
> +       if (bl->props.power != FB_BLANK_UNBLANK ||
> +           bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
> +               brightness = 0;
> +
> +       if (!ps8622->enabled)
> +               return -EINVAL;
> +
> +       ret = ps8622_set(ps8622->client, 0x01, 0xa7, brightness);
> +
> +       return ret;
> +}
> +
> +static const struct backlight_ops ps8622_backlight_ops = {
> +       .update_status  = ps8622_backlight_update,
> +};
> +
> +static void ps8622_pre_enable(struct drm_bridge *bridge)
> +{
> +       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
> +       int ret;
> +
> +       if (ps8622->enabled)
> +               return;
> +
> +       gpiod_set_value(ps8622->gpio_rst, 0);
> +
> +       if (ps8622->v12) {
> +               ret = regulator_enable(ps8622->v12);
> +               if (ret)
> +                       DRM_ERROR("fails to enable ps8622->v12");
> +       }
> +
> +       if (drm_panel_prepare(ps8622->panel)) {
> +               DRM_ERROR("failed to prepare panel\n");
> +               return;
> +       }
> +
> +       gpiod_set_value(ps8622->gpio_slp, 1);
> +
> +       /*
> +        * T1 is the range of time that it takes for the power to rise after we
> +        * enable the lcd/ps8622 fet. T2 is the range of time in which the
> +        * data sheet specifies we should deassert the reset pin.
> +        *
> +        * If it takes T1.max for the power to rise, we need to wait atleast
> +        * T2.min before deasserting the reset pin. If it takes T1.min for the
> +        * power to rise, we need to wait at most T2.max before deasserting the
> +        * reset pin.
> +        */
> +       usleep_range(PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US,
> +                    PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US);
> +
> +       gpiod_set_value(ps8622->gpio_rst, 1);
> +
> +       /* wait 20ms after RST high */
> +       usleep_range(20000, 30000);
> +
> +       ret = ps8622_send_config(ps8622);
> +       if (ret) {
> +               DRM_ERROR("Failed to send config to bridge (%d)\n", ret);
> +               return;
> +       }
> +
> +       ps8622->enabled = true;
> +}
> +
> +static void ps8622_enable(struct drm_bridge *bridge)
> +{
> +       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
> +
> +       if (drm_panel_enable(ps8622->panel)) {
> +               DRM_ERROR("failed to enable panel\n");
> +               return;
> +       }
> +}
> +
> +static void ps8622_disable(struct drm_bridge *bridge)
> +{
> +       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
> +
> +       if (drm_panel_disable(ps8622->panel)) {
> +               DRM_ERROR("failed to disable panel\n");
> +               return;
> +       }
> +       msleep(PS8622_PWMO_END_T12_MS);
> +}
> +
> +static void ps8622_post_disable(struct drm_bridge *bridge)
> +{
> +       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
> +
> +       if (!ps8622->enabled)
> +               return;
> +
> +       ps8622->enabled = false;
> +
> +       /*
> +        * This doesn't matter if the regulators are turned off, but something
> +        * else might keep them on. In that case, we want to assert the slp gpio
> +        * to lower power.
> +        */
> +       gpiod_set_value(ps8622->gpio_slp, 0);
> +
> +       if (drm_panel_unprepare(ps8622->panel)) {
> +               DRM_ERROR("failed to unprepare panel\n");
> +               return;
> +       }
> +
> +       if (ps8622->v12)
> +               regulator_disable(ps8622->v12);
> +
> +       /*
> +        * Sleep for at least the amount of time that it takes the power rail to
> +        * fall to prevent asserting the rst gpio from doing anything.
> +        */
> +       usleep_range(PS8622_POWER_FALL_T16_MAX_US,
> +                    2 * PS8622_POWER_FALL_T16_MAX_US);
> +       gpiod_set_value(ps8622->gpio_rst, 0);
> +
> +       msleep(PS8622_POWER_OFF_T17_MS);
> +}
> +
> +static int ps8622_get_modes(struct drm_connector *connector)
> +{
> +       struct ps8622_bridge *ps8622;
> +
> +       ps8622 = connector_to_ps8622(connector);
> +
> +       return drm_panel_get_modes(ps8622->panel);
> +}
> +
> +static struct drm_encoder *ps8622_best_encoder(struct drm_connector *connector)
> +{
> +       struct ps8622_bridge *ps8622;
> +
> +       ps8622 = connector_to_ps8622(connector);
> +
> +       return ps8622->bridge.encoder;
> +}
> +
> +static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = {
> +       .get_modes = ps8622_get_modes,
> +       .best_encoder = ps8622_best_encoder,
> +};
> +
> +static enum drm_connector_status ps8622_detect(struct drm_connector *connector,
> +                                                               bool force)
> +{
> +       return connector_status_connected;
> +}
> +
> +static void ps8622_connector_destroy(struct drm_connector *connector)
> +{
> +       drm_connector_cleanup(connector);
> +}
> +
> +static const struct drm_connector_funcs ps8622_connector_funcs = {
> +       .dpms = drm_helper_connector_dpms,
> +       .fill_modes = drm_helper_probe_single_connector_modes,
> +       .detect = ps8622_detect,
> +       .destroy = ps8622_connector_destroy,
> +};
> +
> +int ps8622_attach(struct drm_bridge *bridge)
> +{
> +       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
> +       int ret;
> +
> +       if (!bridge->encoder) {
> +               DRM_ERROR("Parent encoder object not found");
> +               return -ENODEV;
> +       }
> +
> +       ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD;
> +       ret = drm_connector_init(bridge->dev, &ps8622->connector,
> +                       &ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
> +       if (ret) {
> +               DRM_ERROR("Failed to initialize connector with drm\n");
> +               return ret;
> +       }
> +       drm_connector_helper_add(&ps8622->connector,
> +                                       &ps8622_connector_helper_funcs);
> +       drm_connector_register(&ps8622->connector);
> +       drm_mode_connector_attach_encoder(&ps8622->connector,
> +                                                       bridge->encoder);
> +
> +       if (ps8622->panel)
> +               drm_panel_attach(ps8622->panel, &ps8622->connector);
> +
> +       drm_helper_hpd_irq_event(ps8622->connector.dev);
> +
> +       return ret;
> +}
> +
> +static const struct drm_bridge_funcs ps8622_bridge_funcs = {
> +       .pre_enable = ps8622_pre_enable,
> +       .enable = ps8622_enable,
> +       .disable = ps8622_disable,
> +       .post_disable = ps8622_post_disable,
> +       .attach = ps8622_attach,
> +};
> +
> +static const struct of_device_id ps8622_devices[] = {
> +       {.compatible = "parade,ps8622",},
> +       {.compatible = "parade,ps8625",},
> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, ps8622_devices);
> +
> +static int ps8622_probe(struct i2c_client *client,
> +                                       const struct i2c_device_id *id)
> +{
> +       struct device *dev = &client->dev;
> +       struct device_node *endpoint, *panel_node;
> +       struct ps8622_bridge *ps8622;
> +       int ret;
> +
> +       ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL);
> +       if (!ps8622)
> +               return -ENOMEM;
> +
> +       endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
> +       if (endpoint) {
> +               panel_node = of_graph_get_remote_port_parent(endpoint);
> +               if (panel_node) {
> +                       ps8622->panel = of_drm_find_panel(panel_node);
> +                       of_node_put(panel_node);
> +                       if (!ps8622->panel)
> +                               return -EPROBE_DEFER;
> +               }
> +       }
> +
> +       ps8622->client = client;
> +
> +       ps8622->v12 = devm_regulator_get(dev, "vdd12");
> +       if (IS_ERR(ps8622->v12)) {
> +               dev_info(dev, "no 1.2v regulator found for PS8622\n");
> +               ps8622->v12 = NULL;
> +       }
> +
> +       ps8622->gpio_slp = devm_gpiod_get(dev, "sleep");
> +       if (IS_ERR(ps8622->gpio_slp)) {
> +               ret = PTR_ERR(ps8622->gpio_slp);
> +               dev_err(dev, "cannot get gpio_slp %d\n", ret);
> +               return ret;
> +       }
> +       ret = gpiod_direction_output(ps8622->gpio_slp, 1);
> +       if (ret) {
> +               dev_err(dev, "cannot configure gpio_slp\n");
> +               return ret;
> +       }
> +
> +       ps8622->gpio_rst = devm_gpiod_get(dev, "reset");
> +       if (IS_ERR(ps8622->gpio_rst)) {
> +               ret = PTR_ERR(ps8622->gpio_rst);
> +               dev_err(dev, "cannot get gpio_rst %d\n", ret);
> +               return ret;
> +       }
> +       /*
> +        * Assert the reset pin high to avoid the bridge being
> +        * initialized prematurely
> +        */
> +       ret = gpiod_direction_output(ps8622->gpio_rst, 1);
> +       if (ret) {
> +               dev_err(dev, "cannot configure gpio_rst\n");
> +               return ret;
> +       }
> +
> +       ps8622->max_lane_count = id->driver_data;
> +
> +       if (of_property_read_u32(dev->of_node, "lane-count",
> +                                               &ps8622->lane_count)) {
> +               ps8622->lane_count = ps8622->max_lane_count;
> +       } else if (ps8622->lane_count > ps8622->max_lane_count) {
> +               dev_info(dev, "lane-count property is too high,"
> +                                               "using max_lane_count\n");
> +               ps8622->lane_count = ps8622->max_lane_count;
> +       }
> +
> +       if (!of_find_property(dev->of_node, "use-external-pwm", NULL)) {
> +               ps8622->bl = backlight_device_register("ps8622-backlight",
> +                               dev, ps8622, &ps8622_backlight_ops,
> +                               NULL);
> +               if (IS_ERR(ps8622->bl)) {
> +                       DRM_ERROR("failed to register backlight\n");
> +                       ret = PTR_ERR(ps8622->bl);
> +                       ps8622->bl = NULL;
> +                       return ret;
> +               }
> +               ps8622->bl->props.max_brightness = PS8622_MAX_BRIGHTNESS;
> +               ps8622->bl->props.brightness = PS8622_MAX_BRIGHTNESS;
> +       }
> +
> +       ps8622->bridge.funcs = &ps8622_bridge_funcs;
> +       ps8622->bridge.of_node = dev->of_node;
> +       ret = drm_bridge_add(&ps8622->bridge);
> +       if (ret) {
> +               DRM_ERROR("Failed to add bridge\n");
> +               return ret;
> +       }
> +
> +       i2c_set_clientdata(client, ps8622);
> +
> +       return 0;
> +}
> +
> +static int ps8622_remove(struct i2c_client *client)
> +{
> +       struct ps8622_bridge *ps8622 = i2c_get_clientdata(client);
> +
> +       if (ps8622->bl)
> +               backlight_device_unregister(ps8622->bl);
> +
> +       drm_bridge_remove(&ps8622->bridge);
> +
> +       return 0;
> +}
> +
> +static const struct i2c_device_id ps8622_i2c_table[] = {
> +       /* Device type, max_lane_count */
> +       {"ps8622", 1},
> +       {"ps8625", 2},
> +       {},
> +};
> +MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);
> +
> +struct i2c_driver ps8622_driver = {
> +       .id_table       = ps8622_i2c_table,
> +       .probe          = ps8622_probe,
> +       .remove         = ps8622_remove,
> +       .driver         = {
> +               .name   = "ps8622",
> +               .owner  = THIS_MODULE,
> +               .of_match_table = ps8622_devices,
> +       },
> +};
> +module_i2c_driver(ps8622_driver);
> +
> +MODULE_AUTHOR("Vincent Palatin <vpalatin@chromium.org>");
> +MODULE_DESCRIPTION("Parade ps8622/ps8625 eDP-LVDS converter driver");
> +MODULE_LICENSE("GPL v2");
> --
> 1.7.9.5
>

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

* Re: [PATCH V9 12/14] drm/bridge: Add i2c based driver for ps8622/ps8625 bridge
  2015-01-29 14:42     ` Ajay kumar
@ 2015-01-30 11:43         ` Thierry Reding
  -1 siblings, 0 replies; 58+ messages in thread
From: Thierry Reding @ 2015-01-30 11:43 UTC (permalink / raw)
  To: Ajay kumar
  Cc: Dave Airlie, Ajay Kumar,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Kukjin Kim, InKi Dae,
	Daniel Vetter, Sean Paul, Jingoo Han,
	Pannaga Bhushan Reddy Patel, Prashanth G, Vincent Palatin,
	Andrew Bresticker, Sean Paul, Rahul Sharma

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

On Thu, Jan 29, 2015 at 08:12:20PM +0530, Ajay kumar wrote:
> Hi Thierry,
> 
> I think you forgot to take this patch!
> Can you check this?

Yes, I missed it somehow. It didn't build for me after applying it now,
but I fixed that up (and a few sparse warnings along with it). I'll send
out another pull request shortly.

Thierry

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

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

* [PATCH V9 12/14] drm/bridge: Add i2c based driver for ps8622/ps8625 bridge
@ 2015-01-30 11:43         ` Thierry Reding
  0 siblings, 0 replies; 58+ messages in thread
From: Thierry Reding @ 2015-01-30 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 29, 2015 at 08:12:20PM +0530, Ajay kumar wrote:
> Hi Thierry,
> 
> I think you forgot to take this patch!
> Can you check this?

Yes, I missed it somehow. It didn't build for me after applying it now,
but I fixed that up (and a few sparse warnings along with it). I'll send
out another pull request shortly.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150130/8202edd9/attachment.sig>

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

* Re: [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
  2015-01-20 16:38     ` Ajay Kumar
@ 2015-01-30 15:37       ` Rob Clark
  -1 siblings, 0 replies; 58+ messages in thread
From: Rob Clark @ 2015-01-30 15:37 UTC (permalink / raw)
  To: Ajay Kumar
  Cc: devicetree, Kukjin Kim, Sean Paul, Daniel Vetter, jg1.han,
	dri-devel, moderated list:ARM/S5P EXYNOS AR...,
	Ajay kumar, bhushan.r, Prashanth G, linux-arm-kernel

On Tue, Jan 20, 2015 at 11:38 AM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
> Currently, third party bridge drivers(ptn3460) are dependent
> on the corresponding encoder driver init, since bridge driver
> needs a drm_device pointer to finish drm initializations.
> The encoder driver passes the drm_device pointer to the
> bridge driver. Because of this dependency, third party drivers
> like ptn3460 doesn't adhere to the driver model.
>
> In this patch, we reframe the bridge registration framework
> so that bridge initialization is split into 2 steps, and
> bridge registration happens independent of drm flow:
> --Step 1: gather all the bridge settings independent of drm and
>           add the bridge onto a global list of bridges.
> --Step 2: when the encoder driver is probed, call drm_bridge_attach
>           for the corresponding bridge so that the bridge receives
>           drm_device pointer and continues with connector and other
>           drm initializations.
>
> The old set of bridge helpers are removed, and a set of new helpers
> are added to accomplish the 2 step initialization.
>
> The bridge devices register themselves onto global list of bridges
> when they get probed by calling "drm_bridge_add".
>
> The parent encoder driver waits till the bridge is available
> in the lookup table(by calling "of_drm_find_bridge") and then
> continues with its initialization.
>
> The encoder driver should also call "drm_bridge_attach" to pass
> on the drm_device to the bridge object.
>
> drm_bridge_attach inturn calls "bridge->funcs->attach" so that
> bridge can continue with drm related initializations.

ok, so I probably should have had a closer look at this before it
landed in drm-next, so if it is too late to revert (and deal w/
untangling subsequent patches that depend on this) some of these
issues we'll just have to fix with follow-on patches.

1) needs headerdoc for new fxns in drm_bridge.c, and needs to be added
in drm.tmpl
2) as far as I can tell, the new approach to cleaning up bridge
objects is to just let them leak !?!

I'll also need to update the new bridge in the msm edp code..
although that isn't such a big deal if I knew how this was *supposed*
to work.. since what is there now at least doesn't look right..

BR,
-R



> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
> Acked-by: Inki Dae <inki.dae@samsung.com>
> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
> ---
>  drivers/gpu/drm/Makefile               |    2 +-
>  drivers/gpu/drm/bridge/ptn3460.c       |   27 +++++-----
>  drivers/gpu/drm/drm_bridge.c           |   91 ++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_crtc.c             |   67 -----------------------
>  drivers/gpu/drm/msm/hdmi/hdmi.c        |    4 +-
>  drivers/gpu/drm/msm/hdmi/hdmi.h        |    1 +
>  drivers/gpu/drm/msm/hdmi/hdmi_bridge.c |    6 +--
>  drivers/gpu/drm/sti/sti_hda.c          |   10 +---
>  drivers/gpu/drm/sti/sti_hdmi.c         |   10 +---
>  include/drm/bridge/ptn3460.h           |    8 +++
>  include/drm/drm_crtc.h                 |   26 ++++-----
>  11 files changed, 133 insertions(+), 119 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_bridge.c
>
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index e620807..c83ef2d 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -14,7 +14,7 @@ drm-y       :=        drm_auth.o drm_bufs.o drm_cache.o \
>                 drm_info.o drm_debugfs.o drm_encoder_slave.o \
>                 drm_trace_points.o drm_global.o drm_prime.o \
>                 drm_rect.o drm_vma_manager.o drm_flip_work.o \
> -               drm_modeset_lock.o drm_atomic.o
> +               drm_modeset_lock.o drm_atomic.o drm_bridge.o
>
>  drm-$(CONFIG_COMPAT) += drm_ioc32.o
>  drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
> diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
> index a2ddc8d..4a818c1 100644
> --- a/drivers/gpu/drm/bridge/ptn3460.c
> +++ b/drivers/gpu/drm/bridge/ptn3460.c
> @@ -176,24 +176,11 @@ static void ptn3460_post_disable(struct drm_bridge *bridge)
>  {
>  }
>
> -static void ptn3460_bridge_destroy(struct drm_bridge *bridge)
> -{
> -       struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
> -
> -       drm_bridge_cleanup(bridge);
> -       if (gpio_is_valid(ptn_bridge->gpio_pd_n))
> -               gpio_free(ptn_bridge->gpio_pd_n);
> -       if (gpio_is_valid(ptn_bridge->gpio_rst_n))
> -               gpio_free(ptn_bridge->gpio_rst_n);
> -       /* Nothing else to free, we've got devm allocated memory */
> -}
> -
>  static struct drm_bridge_funcs ptn3460_bridge_funcs = {
>         .pre_enable = ptn3460_pre_enable,
>         .enable = ptn3460_enable,
>         .disable = ptn3460_disable,
>         .post_disable = ptn3460_post_disable,
> -       .destroy = ptn3460_bridge_destroy,
>  };
>
>  static int ptn3460_get_modes(struct drm_connector *connector)
> @@ -314,7 +301,7 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
>         }
>
>         ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
> -       ret = drm_bridge_init(dev, &ptn_bridge->bridge);
> +       ret = drm_bridge_attach(dev, &ptn_bridge->bridge);
>         if (ret) {
>                 DRM_ERROR("Failed to initialize bridge with drm\n");
>                 goto err;
> @@ -343,3 +330,15 @@ err:
>         return ret;
>  }
>  EXPORT_SYMBOL(ptn3460_init);
> +
> +void ptn3460_destroy(struct drm_bridge *bridge)
> +{
> +       struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
> +
> +       if (gpio_is_valid(ptn_bridge->gpio_pd_n))
> +               gpio_free(ptn_bridge->gpio_pd_n);
> +       if (gpio_is_valid(ptn_bridge->gpio_rst_n))
> +               gpio_free(ptn_bridge->gpio_rst_n);
> +       /* Nothing else to free, we've got devm allocated memory */
> +}
> +EXPORT_SYMBOL(ptn3460_destroy);
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> new file mode 100644
> index 0000000..d1187e5
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -0,0 +1,91 @@
> +/*
> + * Copyright (c) 2014 Samsung Electronics Co., Ltd
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sub license,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/module.h>
> +
> +#include <drm/drm_crtc.h>
> +
> +#include "drm/drmP.h"
> +
> +static DEFINE_MUTEX(bridge_lock);
> +static LIST_HEAD(bridge_list);
> +
> +int drm_bridge_add(struct drm_bridge *bridge)
> +{
> +       mutex_lock(&bridge_lock);
> +       list_add_tail(&bridge->list, &bridge_list);
> +       mutex_unlock(&bridge_lock);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(drm_bridge_add);
> +
> +void drm_bridge_remove(struct drm_bridge *bridge)
> +{
> +       mutex_lock(&bridge_lock);
> +       list_del_init(&bridge->list);
> +       mutex_unlock(&bridge_lock);
> +}
> +EXPORT_SYMBOL(drm_bridge_remove);
> +
> +extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> +{
> +       if (!dev || !bridge)
> +               return -EINVAL;
> +
> +       if (bridge->dev)
> +               return -EBUSY;
> +
> +       bridge->dev = dev;
> +
> +       if (bridge->funcs->attach)
> +               return bridge->funcs->attach(bridge);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(drm_bridge_attach);
> +
> +#ifdef CONFIG_OF
> +struct drm_bridge *of_drm_find_bridge(struct device_node *np)
> +{
> +       struct drm_bridge *bridge;
> +
> +       mutex_lock(&bridge_lock);
> +
> +       list_for_each_entry(bridge, &bridge_list, list) {
> +               if (bridge->of_node == np) {
> +                       mutex_unlock(&bridge_lock);
> +                       return bridge;
> +               }
> +       }
> +
> +       mutex_unlock(&bridge_lock);
> +       return NULL;
> +}
> +EXPORT_SYMBOL(of_drm_find_bridge);
> +#endif
> +
> +MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
> +MODULE_DESCRIPTION("DRM bridge infrastructure");
> +MODULE_LICENSE("GPL and additional rights");
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index af57103..bb8e31e 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -1028,58 +1028,6 @@ void drm_connector_unplug_all(struct drm_device *dev)
>  EXPORT_SYMBOL(drm_connector_unplug_all);
>
>  /**
> - * drm_bridge_init - initialize a drm transcoder/bridge
> - * @dev: drm device
> - * @bridge: transcoder/bridge to set up
> - *
> - * Initialises a preallocated bridge. Bridges should be
> - * subclassed as part of driver connector objects.
> - *
> - * Returns:
> - * Zero on success, error code on failure.
> - */
> -int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge)
> -{
> -       int ret;
> -
> -       drm_modeset_lock_all(dev);
> -
> -       ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE);
> -       if (ret)
> -               goto out;
> -
> -       bridge->dev = dev;
> -
> -       list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
> -       dev->mode_config.num_bridge++;
> -
> - out:
> -       drm_modeset_unlock_all(dev);
> -       return ret;
> -}
> -EXPORT_SYMBOL(drm_bridge_init);
> -
> -/**
> - * drm_bridge_cleanup - cleans up an initialised bridge
> - * @bridge: bridge to cleanup
> - *
> - * Cleans up the bridge but doesn't free the object.
> - */
> -void drm_bridge_cleanup(struct drm_bridge *bridge)
> -{
> -       struct drm_device *dev = bridge->dev;
> -
> -       drm_modeset_lock_all(dev);
> -       drm_mode_object_put(dev, &bridge->base);
> -       list_del(&bridge->head);
> -       dev->mode_config.num_bridge--;
> -       drm_modeset_unlock_all(dev);
> -
> -       memset(bridge, 0, sizeof(*bridge));
> -}
> -EXPORT_SYMBOL(drm_bridge_cleanup);
> -
> -/**
>   * drm_encoder_init - Init a preallocated encoder
>   * @dev: drm device
>   * @encoder: the encoder to init
> @@ -1594,7 +1542,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
>         total_objects += dev->mode_config.num_crtc;
>         total_objects += dev->mode_config.num_connector;
>         total_objects += dev->mode_config.num_encoder;
> -       total_objects += dev->mode_config.num_bridge;
>
>         group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
>         if (!group->id_list)
> @@ -1603,7 +1550,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
>         group->num_crtcs = 0;
>         group->num_connectors = 0;
>         group->num_encoders = 0;
> -       group->num_bridges = 0;
>         return 0;
>  }
>
> @@ -1623,7 +1569,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
>         struct drm_crtc *crtc;
>         struct drm_encoder *encoder;
>         struct drm_connector *connector;
> -       struct drm_bridge *bridge;
>         int ret;
>
>         if ((ret = drm_mode_group_init(dev, group)))
> @@ -1640,11 +1585,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
>                 group->id_list[group->num_crtcs + group->num_encoders +
>                                group->num_connectors++] = connector->base.id;
>
> -       list_for_each_entry(bridge, &dev->mode_config.bridge_list, head)
> -               group->id_list[group->num_crtcs + group->num_encoders +
> -                              group->num_connectors + group->num_bridges++] =
> -                                       bridge->base.id;
> -
>         return 0;
>  }
>  EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
> @@ -5208,7 +5148,6 @@ void drm_mode_config_init(struct drm_device *dev)
>         INIT_LIST_HEAD(&dev->mode_config.fb_list);
>         INIT_LIST_HEAD(&dev->mode_config.crtc_list);
>         INIT_LIST_HEAD(&dev->mode_config.connector_list);
> -       INIT_LIST_HEAD(&dev->mode_config.bridge_list);
>         INIT_LIST_HEAD(&dev->mode_config.encoder_list);
>         INIT_LIST_HEAD(&dev->mode_config.property_list);
>         INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
> @@ -5249,7 +5188,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>         struct drm_connector *connector, *ot;
>         struct drm_crtc *crtc, *ct;
>         struct drm_encoder *encoder, *enct;
> -       struct drm_bridge *bridge, *brt;
>         struct drm_framebuffer *fb, *fbt;
>         struct drm_property *property, *pt;
>         struct drm_property_blob *blob, *bt;
> @@ -5260,11 +5198,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>                 encoder->funcs->destroy(encoder);
>         }
>
> -       list_for_each_entry_safe(bridge, brt,
> -                                &dev->mode_config.bridge_list, head) {
> -               bridge->funcs->destroy(bridge);
> -       }
> -
>         list_for_each_entry_safe(connector, ot,
>                                  &dev->mode_config.connector_list, head) {
>                 connector->funcs->destroy(connector);
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
> index 062c687..95f7b8d 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
> @@ -247,9 +247,9 @@ int hdmi_modeset_init(struct hdmi *hdmi,
>         return 0;
>
>  fail:
> -       /* bridge/connector are normally destroyed by drm: */
> +       /* bridge is normally destroyed by drm: */
>         if (hdmi->bridge) {
> -               hdmi->bridge->funcs->destroy(hdmi->bridge);
> +               hdmi_bridge_destroy(hdmi->bridge);
>                 hdmi->bridge = NULL;
>         }
>         if (hdmi->connector) {
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
> index 43e654f..4d4cad4 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi.h
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
> @@ -146,6 +146,7 @@ void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
>   */
>
>  struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
> +void hdmi_bridge_destroy(struct drm_bridge *bridge);
>
>  /*
>   * hdmi connector:
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index 52ed2b5..d6f8d58 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -23,10 +23,9 @@ struct hdmi_bridge {
>  };
>  #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
>
> -static void hdmi_bridge_destroy(struct drm_bridge *bridge)
> +void hdmi_bridge_destroy(struct drm_bridge *bridge)
>  {
>         struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> -       drm_bridge_cleanup(bridge);
>         kfree(hdmi_bridge);
>  }
>
> @@ -200,7 +199,6 @@ static const struct drm_bridge_funcs hdmi_bridge_funcs = {
>                 .disable = hdmi_bridge_disable,
>                 .post_disable = hdmi_bridge_post_disable,
>                 .mode_set = hdmi_bridge_mode_set,
> -               .destroy = hdmi_bridge_destroy,
>  };
>
>
> @@ -222,7 +220,7 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
>         bridge = &hdmi_bridge->base;
>         bridge->funcs = &hdmi_bridge_funcs;
>
> -       drm_bridge_init(hdmi->dev, bridge);
> +       drm_bridge_attach(hdmi->dev, bridge);
>
>         return bridge;
>
> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
> index 6cf145d..a9bbb08 100644
> --- a/drivers/gpu/drm/sti/sti_hda.c
> +++ b/drivers/gpu/drm/sti/sti_hda.c
> @@ -508,19 +508,12 @@ static void sti_hda_bridge_nope(struct drm_bridge *bridge)
>         /* do nothing */
>  }
>
> -static void sti_hda_brigde_destroy(struct drm_bridge *bridge)
> -{
> -       drm_bridge_cleanup(bridge);
> -       kfree(bridge);
> -}
> -
>  static const struct drm_bridge_funcs sti_hda_bridge_funcs = {
>         .pre_enable = sti_hda_pre_enable,
>         .enable = sti_hda_bridge_nope,
>         .disable = sti_hda_disable,
>         .post_disable = sti_hda_bridge_nope,
>         .mode_set = sti_hda_set_mode,
> -       .destroy = sti_hda_brigde_destroy,
>  };
>
>  static int sti_hda_connector_get_modes(struct drm_connector *connector)
> @@ -665,7 +658,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>
>         bridge->driver_private = hda;
>         bridge->funcs = &sti_hda_bridge_funcs;
> -       drm_bridge_init(drm_dev, bridge);
> +       drm_bridge_attach(drm_dev, bridge);
>
>         encoder->bridge = bridge;
>         connector->encoder = encoder;
> @@ -694,7 +687,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>  err_sysfs:
>         drm_connector_unregister(drm_connector);
>  err_connector:
> -       drm_bridge_cleanup(bridge);
>         drm_connector_cleanup(drm_connector);
>         return -EINVAL;
>  }
> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
> index 74e943e..e840ca5d 100644
> --- a/drivers/gpu/drm/sti/sti_hdmi.c
> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
> @@ -463,19 +463,12 @@ static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
>         /* do nothing */
>  }
>
> -static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge)
> -{
> -       drm_bridge_cleanup(bridge);
> -       kfree(bridge);
> -}
> -
>  static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
>         .pre_enable = sti_hdmi_pre_enable,
>         .enable = sti_hdmi_bridge_nope,
>         .disable = sti_hdmi_disable,
>         .post_disable = sti_hdmi_bridge_nope,
>         .mode_set = sti_hdmi_set_mode,
> -       .destroy = sti_hdmi_brigde_destroy,
>  };
>
>  static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
> @@ -636,7 +629,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>
>         bridge->driver_private = hdmi;
>         bridge->funcs = &sti_hdmi_bridge_funcs;
> -       drm_bridge_init(drm_dev, bridge);
> +       drm_bridge_attach(drm_dev, bridge);
>
>         encoder->bridge = bridge;
>         connector->encoder = encoder;
> @@ -668,7 +661,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>  err_sysfs:
>         drm_connector_unregister(drm_connector);
>  err_connector:
> -       drm_bridge_cleanup(bridge);
>         drm_connector_cleanup(drm_connector);
>  err_adapt:
>         put_device(&hdmi->ddc_adapt->dev);
> diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h
> index ff62344..b11f8e1 100644
> --- a/include/drm/bridge/ptn3460.h
> +++ b/include/drm/bridge/ptn3460.h
> @@ -15,6 +15,7 @@
>  #define _DRM_BRIDGE_PTN3460_H_
>
>  struct drm_device;
> +struct drm_bridge;
>  struct drm_encoder;
>  struct i2c_client;
>  struct device_node;
> @@ -23,6 +24,9 @@ struct device_node;
>
>  int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
>                 struct i2c_client *client, struct device_node *node);
> +
> +void ptn3460_destroy(struct drm_bridge *bridge);
> +
>  #else
>
>  static inline int ptn3460_init(struct drm_device *dev,
> @@ -32,6 +36,10 @@ static inline int ptn3460_init(struct drm_device *dev,
>         return 0;
>  }
>
> +static inline void ptn3460_destroy(struct drm_bridge *bridge)
> +{
> +}
> +
>  #endif
>
>  #endif
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 5b8f254..cc369f3 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -813,15 +813,16 @@ struct drm_plane {
>
>  /**
>   * struct drm_bridge_funcs - drm_bridge control functions
> + * @attach: Called during drm_bridge_attach
>   * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
>   * @disable: Called right before encoder prepare, disables the bridge
>   * @post_disable: Called right after encoder prepare, for lockstepped disable
>   * @mode_set: Set this mode to the bridge
>   * @pre_enable: Called right before encoder commit, for lockstepped commit
>   * @enable: Called right after encoder commit, enables the bridge
> - * @destroy: make object go away
>   */
>  struct drm_bridge_funcs {
> +       int (*attach)(struct drm_bridge *bridge);
>         bool (*mode_fixup)(struct drm_bridge *bridge,
>                            const struct drm_display_mode *mode,
>                            struct drm_display_mode *adjusted_mode);
> @@ -832,22 +833,24 @@ struct drm_bridge_funcs {
>                          struct drm_display_mode *adjusted_mode);
>         void (*pre_enable)(struct drm_bridge *bridge);
>         void (*enable)(struct drm_bridge *bridge);
> -       void (*destroy)(struct drm_bridge *bridge);
>  };
>
>  /**
>   * struct drm_bridge - central DRM bridge control structure
>   * @dev: DRM device this bridge belongs to
> - * @head: list management
> + * @of_node: device node pointer to the bridge
> + * @list: to keep track of all added bridges
>   * @base: base mode object
>   * @funcs: control functions
>   * @driver_private: pointer to the bridge driver's internal context
>   */
>  struct drm_bridge {
>         struct drm_device *dev;
> -       struct list_head head;
> -
> -       struct drm_mode_object base;
> +       struct drm_encoder *encoder;
> +#ifdef CONFIG_OF
> +       struct device_node *of_node;
> +#endif
> +       struct list_head list;
>
>         const struct drm_bridge_funcs *funcs;
>         void *driver_private;
> @@ -950,7 +953,6 @@ struct drm_mode_group {
>         uint32_t num_crtcs;
>         uint32_t num_encoders;
>         uint32_t num_connectors;
> -       uint32_t num_bridges;
>
>         /* list of object IDs for this group */
>         uint32_t *id_list;
> @@ -969,8 +971,6 @@ struct drm_mode_group {
>   * @fb_list: list of framebuffers available
>   * @num_connector: number of connectors on this device
>   * @connector_list: list of connector objects
> - * @num_bridge: number of bridges on this device
> - * @bridge_list: list of bridge objects
>   * @num_encoder: number of encoders on this device
>   * @encoder_list: list of encoder objects
>   * @num_overlay_plane: number of overlay planes on this device
> @@ -1015,8 +1015,6 @@ struct drm_mode_config {
>
>         int num_connector;
>         struct list_head connector_list;
> -       int num_bridge;
> -       struct list_head bridge_list;
>         int num_encoder;
>         struct list_head encoder_list;
>
> @@ -1153,8 +1151,10 @@ extern unsigned int drm_connector_index(struct drm_connector *connector);
>  /* helper to unplug all connectors from sysfs for device */
>  extern void drm_connector_unplug_all(struct drm_device *dev);
>
> -extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge);
> -extern void drm_bridge_cleanup(struct drm_bridge *bridge);
> +extern int drm_bridge_add(struct drm_bridge *bridge);
> +extern void drm_bridge_remove(struct drm_bridge *bridge);
> +extern struct drm_bridge *of_drm_find_bridge(struct device_node *np);
> +extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
>
>  extern int drm_encoder_init(struct drm_device *dev,
>                             struct drm_encoder *encoder,
> --
> 1.7.9.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
@ 2015-01-30 15:37       ` Rob Clark
  0 siblings, 0 replies; 58+ messages in thread
From: Rob Clark @ 2015-01-30 15:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 20, 2015 at 11:38 AM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
> Currently, third party bridge drivers(ptn3460) are dependent
> on the corresponding encoder driver init, since bridge driver
> needs a drm_device pointer to finish drm initializations.
> The encoder driver passes the drm_device pointer to the
> bridge driver. Because of this dependency, third party drivers
> like ptn3460 doesn't adhere to the driver model.
>
> In this patch, we reframe the bridge registration framework
> so that bridge initialization is split into 2 steps, and
> bridge registration happens independent of drm flow:
> --Step 1: gather all the bridge settings independent of drm and
>           add the bridge onto a global list of bridges.
> --Step 2: when the encoder driver is probed, call drm_bridge_attach
>           for the corresponding bridge so that the bridge receives
>           drm_device pointer and continues with connector and other
>           drm initializations.
>
> The old set of bridge helpers are removed, and a set of new helpers
> are added to accomplish the 2 step initialization.
>
> The bridge devices register themselves onto global list of bridges
> when they get probed by calling "drm_bridge_add".
>
> The parent encoder driver waits till the bridge is available
> in the lookup table(by calling "of_drm_find_bridge") and then
> continues with its initialization.
>
> The encoder driver should also call "drm_bridge_attach" to pass
> on the drm_device to the bridge object.
>
> drm_bridge_attach inturn calls "bridge->funcs->attach" so that
> bridge can continue with drm related initializations.

ok, so I probably should have had a closer look at this before it
landed in drm-next, so if it is too late to revert (and deal w/
untangling subsequent patches that depend on this) some of these
issues we'll just have to fix with follow-on patches.

1) needs headerdoc for new fxns in drm_bridge.c, and needs to be added
in drm.tmpl
2) as far as I can tell, the new approach to cleaning up bridge
objects is to just let them leak !?!

I'll also need to update the new bridge in the msm edp code..
although that isn't such a big deal if I knew how this was *supposed*
to work.. since what is there now at least doesn't look right..

BR,
-R



> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
> Acked-by: Inki Dae <inki.dae@samsung.com>
> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
> ---
>  drivers/gpu/drm/Makefile               |    2 +-
>  drivers/gpu/drm/bridge/ptn3460.c       |   27 +++++-----
>  drivers/gpu/drm/drm_bridge.c           |   91 ++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_crtc.c             |   67 -----------------------
>  drivers/gpu/drm/msm/hdmi/hdmi.c        |    4 +-
>  drivers/gpu/drm/msm/hdmi/hdmi.h        |    1 +
>  drivers/gpu/drm/msm/hdmi/hdmi_bridge.c |    6 +--
>  drivers/gpu/drm/sti/sti_hda.c          |   10 +---
>  drivers/gpu/drm/sti/sti_hdmi.c         |   10 +---
>  include/drm/bridge/ptn3460.h           |    8 +++
>  include/drm/drm_crtc.h                 |   26 ++++-----
>  11 files changed, 133 insertions(+), 119 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_bridge.c
>
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index e620807..c83ef2d 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -14,7 +14,7 @@ drm-y       :=        drm_auth.o drm_bufs.o drm_cache.o \
>                 drm_info.o drm_debugfs.o drm_encoder_slave.o \
>                 drm_trace_points.o drm_global.o drm_prime.o \
>                 drm_rect.o drm_vma_manager.o drm_flip_work.o \
> -               drm_modeset_lock.o drm_atomic.o
> +               drm_modeset_lock.o drm_atomic.o drm_bridge.o
>
>  drm-$(CONFIG_COMPAT) += drm_ioc32.o
>  drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
> diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
> index a2ddc8d..4a818c1 100644
> --- a/drivers/gpu/drm/bridge/ptn3460.c
> +++ b/drivers/gpu/drm/bridge/ptn3460.c
> @@ -176,24 +176,11 @@ static void ptn3460_post_disable(struct drm_bridge *bridge)
>  {
>  }
>
> -static void ptn3460_bridge_destroy(struct drm_bridge *bridge)
> -{
> -       struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
> -
> -       drm_bridge_cleanup(bridge);
> -       if (gpio_is_valid(ptn_bridge->gpio_pd_n))
> -               gpio_free(ptn_bridge->gpio_pd_n);
> -       if (gpio_is_valid(ptn_bridge->gpio_rst_n))
> -               gpio_free(ptn_bridge->gpio_rst_n);
> -       /* Nothing else to free, we've got devm allocated memory */
> -}
> -
>  static struct drm_bridge_funcs ptn3460_bridge_funcs = {
>         .pre_enable = ptn3460_pre_enable,
>         .enable = ptn3460_enable,
>         .disable = ptn3460_disable,
>         .post_disable = ptn3460_post_disable,
> -       .destroy = ptn3460_bridge_destroy,
>  };
>
>  static int ptn3460_get_modes(struct drm_connector *connector)
> @@ -314,7 +301,7 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
>         }
>
>         ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
> -       ret = drm_bridge_init(dev, &ptn_bridge->bridge);
> +       ret = drm_bridge_attach(dev, &ptn_bridge->bridge);
>         if (ret) {
>                 DRM_ERROR("Failed to initialize bridge with drm\n");
>                 goto err;
> @@ -343,3 +330,15 @@ err:
>         return ret;
>  }
>  EXPORT_SYMBOL(ptn3460_init);
> +
> +void ptn3460_destroy(struct drm_bridge *bridge)
> +{
> +       struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
> +
> +       if (gpio_is_valid(ptn_bridge->gpio_pd_n))
> +               gpio_free(ptn_bridge->gpio_pd_n);
> +       if (gpio_is_valid(ptn_bridge->gpio_rst_n))
> +               gpio_free(ptn_bridge->gpio_rst_n);
> +       /* Nothing else to free, we've got devm allocated memory */
> +}
> +EXPORT_SYMBOL(ptn3460_destroy);
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> new file mode 100644
> index 0000000..d1187e5
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -0,0 +1,91 @@
> +/*
> + * Copyright (c) 2014 Samsung Electronics Co., Ltd
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sub license,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/module.h>
> +
> +#include <drm/drm_crtc.h>
> +
> +#include "drm/drmP.h"
> +
> +static DEFINE_MUTEX(bridge_lock);
> +static LIST_HEAD(bridge_list);
> +
> +int drm_bridge_add(struct drm_bridge *bridge)
> +{
> +       mutex_lock(&bridge_lock);
> +       list_add_tail(&bridge->list, &bridge_list);
> +       mutex_unlock(&bridge_lock);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(drm_bridge_add);
> +
> +void drm_bridge_remove(struct drm_bridge *bridge)
> +{
> +       mutex_lock(&bridge_lock);
> +       list_del_init(&bridge->list);
> +       mutex_unlock(&bridge_lock);
> +}
> +EXPORT_SYMBOL(drm_bridge_remove);
> +
> +extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> +{
> +       if (!dev || !bridge)
> +               return -EINVAL;
> +
> +       if (bridge->dev)
> +               return -EBUSY;
> +
> +       bridge->dev = dev;
> +
> +       if (bridge->funcs->attach)
> +               return bridge->funcs->attach(bridge);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(drm_bridge_attach);
> +
> +#ifdef CONFIG_OF
> +struct drm_bridge *of_drm_find_bridge(struct device_node *np)
> +{
> +       struct drm_bridge *bridge;
> +
> +       mutex_lock(&bridge_lock);
> +
> +       list_for_each_entry(bridge, &bridge_list, list) {
> +               if (bridge->of_node == np) {
> +                       mutex_unlock(&bridge_lock);
> +                       return bridge;
> +               }
> +       }
> +
> +       mutex_unlock(&bridge_lock);
> +       return NULL;
> +}
> +EXPORT_SYMBOL(of_drm_find_bridge);
> +#endif
> +
> +MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
> +MODULE_DESCRIPTION("DRM bridge infrastructure");
> +MODULE_LICENSE("GPL and additional rights");
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index af57103..bb8e31e 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -1028,58 +1028,6 @@ void drm_connector_unplug_all(struct drm_device *dev)
>  EXPORT_SYMBOL(drm_connector_unplug_all);
>
>  /**
> - * drm_bridge_init - initialize a drm transcoder/bridge
> - * @dev: drm device
> - * @bridge: transcoder/bridge to set up
> - *
> - * Initialises a preallocated bridge. Bridges should be
> - * subclassed as part of driver connector objects.
> - *
> - * Returns:
> - * Zero on success, error code on failure.
> - */
> -int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge)
> -{
> -       int ret;
> -
> -       drm_modeset_lock_all(dev);
> -
> -       ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE);
> -       if (ret)
> -               goto out;
> -
> -       bridge->dev = dev;
> -
> -       list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
> -       dev->mode_config.num_bridge++;
> -
> - out:
> -       drm_modeset_unlock_all(dev);
> -       return ret;
> -}
> -EXPORT_SYMBOL(drm_bridge_init);
> -
> -/**
> - * drm_bridge_cleanup - cleans up an initialised bridge
> - * @bridge: bridge to cleanup
> - *
> - * Cleans up the bridge but doesn't free the object.
> - */
> -void drm_bridge_cleanup(struct drm_bridge *bridge)
> -{
> -       struct drm_device *dev = bridge->dev;
> -
> -       drm_modeset_lock_all(dev);
> -       drm_mode_object_put(dev, &bridge->base);
> -       list_del(&bridge->head);
> -       dev->mode_config.num_bridge--;
> -       drm_modeset_unlock_all(dev);
> -
> -       memset(bridge, 0, sizeof(*bridge));
> -}
> -EXPORT_SYMBOL(drm_bridge_cleanup);
> -
> -/**
>   * drm_encoder_init - Init a preallocated encoder
>   * @dev: drm device
>   * @encoder: the encoder to init
> @@ -1594,7 +1542,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
>         total_objects += dev->mode_config.num_crtc;
>         total_objects += dev->mode_config.num_connector;
>         total_objects += dev->mode_config.num_encoder;
> -       total_objects += dev->mode_config.num_bridge;
>
>         group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
>         if (!group->id_list)
> @@ -1603,7 +1550,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
>         group->num_crtcs = 0;
>         group->num_connectors = 0;
>         group->num_encoders = 0;
> -       group->num_bridges = 0;
>         return 0;
>  }
>
> @@ -1623,7 +1569,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
>         struct drm_crtc *crtc;
>         struct drm_encoder *encoder;
>         struct drm_connector *connector;
> -       struct drm_bridge *bridge;
>         int ret;
>
>         if ((ret = drm_mode_group_init(dev, group)))
> @@ -1640,11 +1585,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
>                 group->id_list[group->num_crtcs + group->num_encoders +
>                                group->num_connectors++] = connector->base.id;
>
> -       list_for_each_entry(bridge, &dev->mode_config.bridge_list, head)
> -               group->id_list[group->num_crtcs + group->num_encoders +
> -                              group->num_connectors + group->num_bridges++] =
> -                                       bridge->base.id;
> -
>         return 0;
>  }
>  EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
> @@ -5208,7 +5148,6 @@ void drm_mode_config_init(struct drm_device *dev)
>         INIT_LIST_HEAD(&dev->mode_config.fb_list);
>         INIT_LIST_HEAD(&dev->mode_config.crtc_list);
>         INIT_LIST_HEAD(&dev->mode_config.connector_list);
> -       INIT_LIST_HEAD(&dev->mode_config.bridge_list);
>         INIT_LIST_HEAD(&dev->mode_config.encoder_list);
>         INIT_LIST_HEAD(&dev->mode_config.property_list);
>         INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
> @@ -5249,7 +5188,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>         struct drm_connector *connector, *ot;
>         struct drm_crtc *crtc, *ct;
>         struct drm_encoder *encoder, *enct;
> -       struct drm_bridge *bridge, *brt;
>         struct drm_framebuffer *fb, *fbt;
>         struct drm_property *property, *pt;
>         struct drm_property_blob *blob, *bt;
> @@ -5260,11 +5198,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>                 encoder->funcs->destroy(encoder);
>         }
>
> -       list_for_each_entry_safe(bridge, brt,
> -                                &dev->mode_config.bridge_list, head) {
> -               bridge->funcs->destroy(bridge);
> -       }
> -
>         list_for_each_entry_safe(connector, ot,
>                                  &dev->mode_config.connector_list, head) {
>                 connector->funcs->destroy(connector);
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
> index 062c687..95f7b8d 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
> @@ -247,9 +247,9 @@ int hdmi_modeset_init(struct hdmi *hdmi,
>         return 0;
>
>  fail:
> -       /* bridge/connector are normally destroyed by drm: */
> +       /* bridge is normally destroyed by drm: */
>         if (hdmi->bridge) {
> -               hdmi->bridge->funcs->destroy(hdmi->bridge);
> +               hdmi_bridge_destroy(hdmi->bridge);
>                 hdmi->bridge = NULL;
>         }
>         if (hdmi->connector) {
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
> index 43e654f..4d4cad4 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi.h
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
> @@ -146,6 +146,7 @@ void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
>   */
>
>  struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
> +void hdmi_bridge_destroy(struct drm_bridge *bridge);
>
>  /*
>   * hdmi connector:
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index 52ed2b5..d6f8d58 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -23,10 +23,9 @@ struct hdmi_bridge {
>  };
>  #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
>
> -static void hdmi_bridge_destroy(struct drm_bridge *bridge)
> +void hdmi_bridge_destroy(struct drm_bridge *bridge)
>  {
>         struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> -       drm_bridge_cleanup(bridge);
>         kfree(hdmi_bridge);
>  }
>
> @@ -200,7 +199,6 @@ static const struct drm_bridge_funcs hdmi_bridge_funcs = {
>                 .disable = hdmi_bridge_disable,
>                 .post_disable = hdmi_bridge_post_disable,
>                 .mode_set = hdmi_bridge_mode_set,
> -               .destroy = hdmi_bridge_destroy,
>  };
>
>
> @@ -222,7 +220,7 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
>         bridge = &hdmi_bridge->base;
>         bridge->funcs = &hdmi_bridge_funcs;
>
> -       drm_bridge_init(hdmi->dev, bridge);
> +       drm_bridge_attach(hdmi->dev, bridge);
>
>         return bridge;
>
> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
> index 6cf145d..a9bbb08 100644
> --- a/drivers/gpu/drm/sti/sti_hda.c
> +++ b/drivers/gpu/drm/sti/sti_hda.c
> @@ -508,19 +508,12 @@ static void sti_hda_bridge_nope(struct drm_bridge *bridge)
>         /* do nothing */
>  }
>
> -static void sti_hda_brigde_destroy(struct drm_bridge *bridge)
> -{
> -       drm_bridge_cleanup(bridge);
> -       kfree(bridge);
> -}
> -
>  static const struct drm_bridge_funcs sti_hda_bridge_funcs = {
>         .pre_enable = sti_hda_pre_enable,
>         .enable = sti_hda_bridge_nope,
>         .disable = sti_hda_disable,
>         .post_disable = sti_hda_bridge_nope,
>         .mode_set = sti_hda_set_mode,
> -       .destroy = sti_hda_brigde_destroy,
>  };
>
>  static int sti_hda_connector_get_modes(struct drm_connector *connector)
> @@ -665,7 +658,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>
>         bridge->driver_private = hda;
>         bridge->funcs = &sti_hda_bridge_funcs;
> -       drm_bridge_init(drm_dev, bridge);
> +       drm_bridge_attach(drm_dev, bridge);
>
>         encoder->bridge = bridge;
>         connector->encoder = encoder;
> @@ -694,7 +687,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>  err_sysfs:
>         drm_connector_unregister(drm_connector);
>  err_connector:
> -       drm_bridge_cleanup(bridge);
>         drm_connector_cleanup(drm_connector);
>         return -EINVAL;
>  }
> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
> index 74e943e..e840ca5d 100644
> --- a/drivers/gpu/drm/sti/sti_hdmi.c
> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
> @@ -463,19 +463,12 @@ static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
>         /* do nothing */
>  }
>
> -static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge)
> -{
> -       drm_bridge_cleanup(bridge);
> -       kfree(bridge);
> -}
> -
>  static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
>         .pre_enable = sti_hdmi_pre_enable,
>         .enable = sti_hdmi_bridge_nope,
>         .disable = sti_hdmi_disable,
>         .post_disable = sti_hdmi_bridge_nope,
>         .mode_set = sti_hdmi_set_mode,
> -       .destroy = sti_hdmi_brigde_destroy,
>  };
>
>  static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
> @@ -636,7 +629,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>
>         bridge->driver_private = hdmi;
>         bridge->funcs = &sti_hdmi_bridge_funcs;
> -       drm_bridge_init(drm_dev, bridge);
> +       drm_bridge_attach(drm_dev, bridge);
>
>         encoder->bridge = bridge;
>         connector->encoder = encoder;
> @@ -668,7 +661,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>  err_sysfs:
>         drm_connector_unregister(drm_connector);
>  err_connector:
> -       drm_bridge_cleanup(bridge);
>         drm_connector_cleanup(drm_connector);
>  err_adapt:
>         put_device(&hdmi->ddc_adapt->dev);
> diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h
> index ff62344..b11f8e1 100644
> --- a/include/drm/bridge/ptn3460.h
> +++ b/include/drm/bridge/ptn3460.h
> @@ -15,6 +15,7 @@
>  #define _DRM_BRIDGE_PTN3460_H_
>
>  struct drm_device;
> +struct drm_bridge;
>  struct drm_encoder;
>  struct i2c_client;
>  struct device_node;
> @@ -23,6 +24,9 @@ struct device_node;
>
>  int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
>                 struct i2c_client *client, struct device_node *node);
> +
> +void ptn3460_destroy(struct drm_bridge *bridge);
> +
>  #else
>
>  static inline int ptn3460_init(struct drm_device *dev,
> @@ -32,6 +36,10 @@ static inline int ptn3460_init(struct drm_device *dev,
>         return 0;
>  }
>
> +static inline void ptn3460_destroy(struct drm_bridge *bridge)
> +{
> +}
> +
>  #endif
>
>  #endif
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 5b8f254..cc369f3 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -813,15 +813,16 @@ struct drm_plane {
>
>  /**
>   * struct drm_bridge_funcs - drm_bridge control functions
> + * @attach: Called during drm_bridge_attach
>   * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
>   * @disable: Called right before encoder prepare, disables the bridge
>   * @post_disable: Called right after encoder prepare, for lockstepped disable
>   * @mode_set: Set this mode to the bridge
>   * @pre_enable: Called right before encoder commit, for lockstepped commit
>   * @enable: Called right after encoder commit, enables the bridge
> - * @destroy: make object go away
>   */
>  struct drm_bridge_funcs {
> +       int (*attach)(struct drm_bridge *bridge);
>         bool (*mode_fixup)(struct drm_bridge *bridge,
>                            const struct drm_display_mode *mode,
>                            struct drm_display_mode *adjusted_mode);
> @@ -832,22 +833,24 @@ struct drm_bridge_funcs {
>                          struct drm_display_mode *adjusted_mode);
>         void (*pre_enable)(struct drm_bridge *bridge);
>         void (*enable)(struct drm_bridge *bridge);
> -       void (*destroy)(struct drm_bridge *bridge);
>  };
>
>  /**
>   * struct drm_bridge - central DRM bridge control structure
>   * @dev: DRM device this bridge belongs to
> - * @head: list management
> + * @of_node: device node pointer to the bridge
> + * @list: to keep track of all added bridges
>   * @base: base mode object
>   * @funcs: control functions
>   * @driver_private: pointer to the bridge driver's internal context
>   */
>  struct drm_bridge {
>         struct drm_device *dev;
> -       struct list_head head;
> -
> -       struct drm_mode_object base;
> +       struct drm_encoder *encoder;
> +#ifdef CONFIG_OF
> +       struct device_node *of_node;
> +#endif
> +       struct list_head list;
>
>         const struct drm_bridge_funcs *funcs;
>         void *driver_private;
> @@ -950,7 +953,6 @@ struct drm_mode_group {
>         uint32_t num_crtcs;
>         uint32_t num_encoders;
>         uint32_t num_connectors;
> -       uint32_t num_bridges;
>
>         /* list of object IDs for this group */
>         uint32_t *id_list;
> @@ -969,8 +971,6 @@ struct drm_mode_group {
>   * @fb_list: list of framebuffers available
>   * @num_connector: number of connectors on this device
>   * @connector_list: list of connector objects
> - * @num_bridge: number of bridges on this device
> - * @bridge_list: list of bridge objects
>   * @num_encoder: number of encoders on this device
>   * @encoder_list: list of encoder objects
>   * @num_overlay_plane: number of overlay planes on this device
> @@ -1015,8 +1015,6 @@ struct drm_mode_config {
>
>         int num_connector;
>         struct list_head connector_list;
> -       int num_bridge;
> -       struct list_head bridge_list;
>         int num_encoder;
>         struct list_head encoder_list;
>
> @@ -1153,8 +1151,10 @@ extern unsigned int drm_connector_index(struct drm_connector *connector);
>  /* helper to unplug all connectors from sysfs for device */
>  extern void drm_connector_unplug_all(struct drm_device *dev);
>
> -extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge);
> -extern void drm_bridge_cleanup(struct drm_bridge *bridge);
> +extern int drm_bridge_add(struct drm_bridge *bridge);
> +extern void drm_bridge_remove(struct drm_bridge *bridge);
> +extern struct drm_bridge *of_drm_find_bridge(struct device_node *np);
> +extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
>
>  extern int drm_encoder_init(struct drm_device *dev,
>                             struct drm_encoder *encoder,
> --
> 1.7.9.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
  2015-01-30 15:37       ` Rob Clark
@ 2015-01-30 15:59           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 58+ messages in thread
From: Russell King - ARM Linux @ 2015-01-30 15:59 UTC (permalink / raw)
  To: Rob Clark
  Cc: Ajay Kumar, devicetree-u79uwXL29TY76Z2rM5mHXA, Kukjin Kim,
	Sean Paul, Daniel Vetter, jg1.han-Sze3O3UU22JBDgjK7y7TUQ,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, daeinki,
	moderated list:ARM/S5P EXYNOS AR...,
	Thierry Reding, Ajay kumar, bhushan.r-Sze3O3UU22JBDgjK7y7TUQ,
	Prashanth G, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Fri, Jan 30, 2015 at 10:37:19AM -0500, Rob Clark wrote:
> On Tue, Jan 20, 2015 at 11:38 AM, Ajay Kumar <ajaykumar.rs-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
> I'll also need to update the new bridge in the msm edp code..
> although that isn't such a big deal if I knew how this was *supposed*
> to work.. since what is there now at least doesn't look right..

I wonder whether the new dw-hdmi bridge code get fixed up too...

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
@ 2015-01-30 15:59           ` Russell King - ARM Linux
  0 siblings, 0 replies; 58+ messages in thread
From: Russell King - ARM Linux @ 2015-01-30 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 30, 2015 at 10:37:19AM -0500, Rob Clark wrote:
> On Tue, Jan 20, 2015 at 11:38 AM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
> I'll also need to update the new bridge in the msm edp code..
> although that isn't such a big deal if I knew how this was *supposed*
> to work.. since what is there now at least doesn't look right..

I wonder whether the new dw-hdmi bridge code get fixed up too...

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

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

* Re: [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
  2015-01-30 15:37       ` Rob Clark
@ 2015-01-30 16:08         ` Daniel Stone
  -1 siblings, 0 replies; 58+ messages in thread
From: Daniel Stone @ 2015-01-30 16:08 UTC (permalink / raw)
  To: Rob Clark
  Cc: devicetree, Kukjin Kim, Sean Paul, Daniel Vetter, jg1.han,
	dri-devel, moderated list:ARM/S5P EXYNOS AR...,
	Ajay kumar, Pannaga Bhushan Reddy Patel, Prashanth G, Ajay Kumar,
	linux-arm-kernel

Hi,

On 30 January 2015 at 15:37, Rob Clark <robdclark@gmail.com> wrote:
> ok, so I probably should have had a closer look at this before it
> landed in drm-next, so if it is too late to revert (and deal w/
> untangling subsequent patches that depend on this) some of these
> issues we'll just have to fix with follow-on patches.
>
> 1) needs headerdoc for new fxns in drm_bridge.c, and needs to be added
> in drm.tmpl
> 2) as far as I can tell, the new approach to cleaning up bridge
> objects is to just let them leak !?!
>
> I'll also need to update the new bridge in the msm edp code..
> although that isn't such a big deal if I knew how this was *supposed*
> to work.. since what is there now at least doesn't look right..

Given how long these patches sat around doing being passively NACKed
by discussions going around in circles, and how useful they are, I'd
be much more in favour of fixing them up than reverting and going
through the whole circus again ...

Cheers,
Daniel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
@ 2015-01-30 16:08         ` Daniel Stone
  0 siblings, 0 replies; 58+ messages in thread
From: Daniel Stone @ 2015-01-30 16:08 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 30 January 2015 at 15:37, Rob Clark <robdclark@gmail.com> wrote:
> ok, so I probably should have had a closer look at this before it
> landed in drm-next, so if it is too late to revert (and deal w/
> untangling subsequent patches that depend on this) some of these
> issues we'll just have to fix with follow-on patches.
>
> 1) needs headerdoc for new fxns in drm_bridge.c, and needs to be added
> in drm.tmpl
> 2) as far as I can tell, the new approach to cleaning up bridge
> objects is to just let them leak !?!
>
> I'll also need to update the new bridge in the msm edp code..
> although that isn't such a big deal if I knew how this was *supposed*
> to work.. since what is there now at least doesn't look right..

Given how long these patches sat around doing being passively NACKed
by discussions going around in circles, and how useful they are, I'd
be much more in favour of fixing them up than reverting and going
through the whole circus again ...

Cheers,
Daniel

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

* Re: [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
  2015-01-30 15:37       ` Rob Clark
@ 2015-02-02  9:14         ` Ajay kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay kumar @ 2015-02-02  9:14 UTC (permalink / raw)
  To: Rob Clark
  Cc: Ajay Kumar, dri-devel, moderated list:ARM/S5P EXYNOS AR...,
	linux-arm-kernel, devicetree, Kukjin Kim, Sean Paul,
	Daniel Vetter, Jingoo Han, daeinki, Thierry Reding,
	Pannaga Bhushan Reddy Patel, Prashanth G

Hi Rob,

On Fri, Jan 30, 2015 at 9:07 PM, Rob Clark <robdclark@gmail.com> wrote:
> On Tue, Jan 20, 2015 at 11:38 AM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
>> Currently, third party bridge drivers(ptn3460) are dependent
>> on the corresponding encoder driver init, since bridge driver
>> needs a drm_device pointer to finish drm initializations.
>> The encoder driver passes the drm_device pointer to the
>> bridge driver. Because of this dependency, third party drivers
>> like ptn3460 doesn't adhere to the driver model.
>>
>> In this patch, we reframe the bridge registration framework
>> so that bridge initialization is split into 2 steps, and
>> bridge registration happens independent of drm flow:
>> --Step 1: gather all the bridge settings independent of drm and
>>           add the bridge onto a global list of bridges.
>> --Step 2: when the encoder driver is probed, call drm_bridge_attach
>>           for the corresponding bridge so that the bridge receives
>>           drm_device pointer and continues with connector and other
>>           drm initializations.
>>
>> The old set of bridge helpers are removed, and a set of new helpers
>> are added to accomplish the 2 step initialization.
>>
>> The bridge devices register themselves onto global list of bridges
>> when they get probed by calling "drm_bridge_add".
>>
>> The parent encoder driver waits till the bridge is available
>> in the lookup table(by calling "of_drm_find_bridge") and then
>> continues with its initialization.
>>
>> The encoder driver should also call "drm_bridge_attach" to pass
>> on the drm_device to the bridge object.
>>
>> drm_bridge_attach inturn calls "bridge->funcs->attach" so that
>> bridge can continue with drm related initializations.
>
> ok, so I probably should have had a closer look at this before it
> landed in drm-next, so if it is too late to revert (and deal w/
> untangling subsequent patches that depend on this) some of these
> issues we'll just have to fix with follow-on patches.
>
> 1) needs headerdoc for new fxns in drm_bridge.c, and needs to be added
> in drm.tmpl
Ohh, I totally forgot. I will do this. Just point me to some recent
patch which updates docbook.
> 2) as far as I can tell, the new approach to cleaning up bridge
> objects is to just let them leak !?!
I just checked. Only MSM hdmi_bridge is leaking, and this is because
it doesn't use devm_kzalloc. All other bridges use devm_kzalloc,
and hence that memory is automatically freed.
For MSM HDMI, we need to find a place to call hdmi_bridge_destroy.

> I'll also need to update the new bridge in the msm edp code..
> although that isn't such a big deal if I knew how this was *supposed*
> to work..
You just need to convert drm_bridge_init to drm_bridge_attach, and
remove destroy callback. Refer this:
http://cgit.freedesktop.org/~airlied/linux/commit/?h=drm-next&id=b5217bf4692218d202d3d2cd772864fa1e10be4d

Regards,
Ajay Kumar
> since what is there now at least doesn't look right..
>
> BR,
> -R
>
>
>
>> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
>> Acked-by: Inki Dae <inki.dae@samsung.com>
>> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
>> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
>> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
>> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
>> ---
>>  drivers/gpu/drm/Makefile               |    2 +-
>>  drivers/gpu/drm/bridge/ptn3460.c       |   27 +++++-----
>>  drivers/gpu/drm/drm_bridge.c           |   91 ++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/drm_crtc.c             |   67 -----------------------
>>  drivers/gpu/drm/msm/hdmi/hdmi.c        |    4 +-
>>  drivers/gpu/drm/msm/hdmi/hdmi.h        |    1 +
>>  drivers/gpu/drm/msm/hdmi/hdmi_bridge.c |    6 +--
>>  drivers/gpu/drm/sti/sti_hda.c          |   10 +---
>>  drivers/gpu/drm/sti/sti_hdmi.c         |   10 +---
>>  include/drm/bridge/ptn3460.h           |    8 +++
>>  include/drm/drm_crtc.h                 |   26 ++++-----
>>  11 files changed, 133 insertions(+), 119 deletions(-)
>>  create mode 100644 drivers/gpu/drm/drm_bridge.c
>>
>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> index e620807..c83ef2d 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -14,7 +14,7 @@ drm-y       :=        drm_auth.o drm_bufs.o drm_cache.o \
>>                 drm_info.o drm_debugfs.o drm_encoder_slave.o \
>>                 drm_trace_points.o drm_global.o drm_prime.o \
>>                 drm_rect.o drm_vma_manager.o drm_flip_work.o \
>> -               drm_modeset_lock.o drm_atomic.o
>> +               drm_modeset_lock.o drm_atomic.o drm_bridge.o
>>
>>  drm-$(CONFIG_COMPAT) += drm_ioc32.o
>>  drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
>> diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
>> index a2ddc8d..4a818c1 100644
>> --- a/drivers/gpu/drm/bridge/ptn3460.c
>> +++ b/drivers/gpu/drm/bridge/ptn3460.c
>> @@ -176,24 +176,11 @@ static void ptn3460_post_disable(struct drm_bridge *bridge)
>>  {
>>  }
>>
>> -static void ptn3460_bridge_destroy(struct drm_bridge *bridge)
>> -{
>> -       struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
>> -
>> -       drm_bridge_cleanup(bridge);
>> -       if (gpio_is_valid(ptn_bridge->gpio_pd_n))
>> -               gpio_free(ptn_bridge->gpio_pd_n);
>> -       if (gpio_is_valid(ptn_bridge->gpio_rst_n))
>> -               gpio_free(ptn_bridge->gpio_rst_n);
>> -       /* Nothing else to free, we've got devm allocated memory */
>> -}
>> -
>>  static struct drm_bridge_funcs ptn3460_bridge_funcs = {
>>         .pre_enable = ptn3460_pre_enable,
>>         .enable = ptn3460_enable,
>>         .disable = ptn3460_disable,
>>         .post_disable = ptn3460_post_disable,
>> -       .destroy = ptn3460_bridge_destroy,
>>  };
>>
>>  static int ptn3460_get_modes(struct drm_connector *connector)
>> @@ -314,7 +301,7 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
>>         }
>>
>>         ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
>> -       ret = drm_bridge_init(dev, &ptn_bridge->bridge);
>> +       ret = drm_bridge_attach(dev, &ptn_bridge->bridge);
>>         if (ret) {
>>                 DRM_ERROR("Failed to initialize bridge with drm\n");
>>                 goto err;
>> @@ -343,3 +330,15 @@ err:
>>         return ret;
>>  }
>>  EXPORT_SYMBOL(ptn3460_init);
>> +
>> +void ptn3460_destroy(struct drm_bridge *bridge)
>> +{
>> +       struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
>> +
>> +       if (gpio_is_valid(ptn_bridge->gpio_pd_n))
>> +               gpio_free(ptn_bridge->gpio_pd_n);
>> +       if (gpio_is_valid(ptn_bridge->gpio_rst_n))
>> +               gpio_free(ptn_bridge->gpio_rst_n);
>> +       /* Nothing else to free, we've got devm allocated memory */
>> +}
>> +EXPORT_SYMBOL(ptn3460_destroy);
>> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
>> new file mode 100644
>> index 0000000..d1187e5
>> --- /dev/null
>> +++ b/drivers/gpu/drm/drm_bridge.c
>> @@ -0,0 +1,91 @@
>> +/*
>> + * Copyright (c) 2014 Samsung Electronics Co., Ltd
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sub license,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the
>> + * next paragraph) shall be included in all copies or substantial portions
>> + * of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> + * DEALINGS IN THE SOFTWARE.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/module.h>
>> +
>> +#include <drm/drm_crtc.h>
>> +
>> +#include "drm/drmP.h"
>> +
>> +static DEFINE_MUTEX(bridge_lock);
>> +static LIST_HEAD(bridge_list);
>> +
>> +int drm_bridge_add(struct drm_bridge *bridge)
>> +{
>> +       mutex_lock(&bridge_lock);
>> +       list_add_tail(&bridge->list, &bridge_list);
>> +       mutex_unlock(&bridge_lock);
>> +
>> +       return 0;
>> +}
>> +EXPORT_SYMBOL(drm_bridge_add);
>> +
>> +void drm_bridge_remove(struct drm_bridge *bridge)
>> +{
>> +       mutex_lock(&bridge_lock);
>> +       list_del_init(&bridge->list);
>> +       mutex_unlock(&bridge_lock);
>> +}
>> +EXPORT_SYMBOL(drm_bridge_remove);
>> +
>> +extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
>> +{
>> +       if (!dev || !bridge)
>> +               return -EINVAL;
>> +
>> +       if (bridge->dev)
>> +               return -EBUSY;
>> +
>> +       bridge->dev = dev;
>> +
>> +       if (bridge->funcs->attach)
>> +               return bridge->funcs->attach(bridge);
>> +
>> +       return 0;
>> +}
>> +EXPORT_SYMBOL(drm_bridge_attach);
>> +
>> +#ifdef CONFIG_OF
>> +struct drm_bridge *of_drm_find_bridge(struct device_node *np)
>> +{
>> +       struct drm_bridge *bridge;
>> +
>> +       mutex_lock(&bridge_lock);
>> +
>> +       list_for_each_entry(bridge, &bridge_list, list) {
>> +               if (bridge->of_node == np) {
>> +                       mutex_unlock(&bridge_lock);
>> +                       return bridge;
>> +               }
>> +       }
>> +
>> +       mutex_unlock(&bridge_lock);
>> +       return NULL;
>> +}
>> +EXPORT_SYMBOL(of_drm_find_bridge);
>> +#endif
>> +
>> +MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
>> +MODULE_DESCRIPTION("DRM bridge infrastructure");
>> +MODULE_LICENSE("GPL and additional rights");
>> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
>> index af57103..bb8e31e 100644
>> --- a/drivers/gpu/drm/drm_crtc.c
>> +++ b/drivers/gpu/drm/drm_crtc.c
>> @@ -1028,58 +1028,6 @@ void drm_connector_unplug_all(struct drm_device *dev)
>>  EXPORT_SYMBOL(drm_connector_unplug_all);
>>
>>  /**
>> - * drm_bridge_init - initialize a drm transcoder/bridge
>> - * @dev: drm device
>> - * @bridge: transcoder/bridge to set up
>> - *
>> - * Initialises a preallocated bridge. Bridges should be
>> - * subclassed as part of driver connector objects.
>> - *
>> - * Returns:
>> - * Zero on success, error code on failure.
>> - */
>> -int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge)
>> -{
>> -       int ret;
>> -
>> -       drm_modeset_lock_all(dev);
>> -
>> -       ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE);
>> -       if (ret)
>> -               goto out;
>> -
>> -       bridge->dev = dev;
>> -
>> -       list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
>> -       dev->mode_config.num_bridge++;
>> -
>> - out:
>> -       drm_modeset_unlock_all(dev);
>> -       return ret;
>> -}
>> -EXPORT_SYMBOL(drm_bridge_init);
>> -
>> -/**
>> - * drm_bridge_cleanup - cleans up an initialised bridge
>> - * @bridge: bridge to cleanup
>> - *
>> - * Cleans up the bridge but doesn't free the object.
>> - */
>> -void drm_bridge_cleanup(struct drm_bridge *bridge)
>> -{
>> -       struct drm_device *dev = bridge->dev;
>> -
>> -       drm_modeset_lock_all(dev);
>> -       drm_mode_object_put(dev, &bridge->base);
>> -       list_del(&bridge->head);
>> -       dev->mode_config.num_bridge--;
>> -       drm_modeset_unlock_all(dev);
>> -
>> -       memset(bridge, 0, sizeof(*bridge));
>> -}
>> -EXPORT_SYMBOL(drm_bridge_cleanup);
>> -
>> -/**
>>   * drm_encoder_init - Init a preallocated encoder
>>   * @dev: drm device
>>   * @encoder: the encoder to init
>> @@ -1594,7 +1542,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
>>         total_objects += dev->mode_config.num_crtc;
>>         total_objects += dev->mode_config.num_connector;
>>         total_objects += dev->mode_config.num_encoder;
>> -       total_objects += dev->mode_config.num_bridge;
>>
>>         group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
>>         if (!group->id_list)
>> @@ -1603,7 +1550,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
>>         group->num_crtcs = 0;
>>         group->num_connectors = 0;
>>         group->num_encoders = 0;
>> -       group->num_bridges = 0;
>>         return 0;
>>  }
>>
>> @@ -1623,7 +1569,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
>>         struct drm_crtc *crtc;
>>         struct drm_encoder *encoder;
>>         struct drm_connector *connector;
>> -       struct drm_bridge *bridge;
>>         int ret;
>>
>>         if ((ret = drm_mode_group_init(dev, group)))
>> @@ -1640,11 +1585,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
>>                 group->id_list[group->num_crtcs + group->num_encoders +
>>                                group->num_connectors++] = connector->base.id;
>>
>> -       list_for_each_entry(bridge, &dev->mode_config.bridge_list, head)
>> -               group->id_list[group->num_crtcs + group->num_encoders +
>> -                              group->num_connectors + group->num_bridges++] =
>> -                                       bridge->base.id;
>> -
>>         return 0;
>>  }
>>  EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
>> @@ -5208,7 +5148,6 @@ void drm_mode_config_init(struct drm_device *dev)
>>         INIT_LIST_HEAD(&dev->mode_config.fb_list);
>>         INIT_LIST_HEAD(&dev->mode_config.crtc_list);
>>         INIT_LIST_HEAD(&dev->mode_config.connector_list);
>> -       INIT_LIST_HEAD(&dev->mode_config.bridge_list);
>>         INIT_LIST_HEAD(&dev->mode_config.encoder_list);
>>         INIT_LIST_HEAD(&dev->mode_config.property_list);
>>         INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
>> @@ -5249,7 +5188,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>>         struct drm_connector *connector, *ot;
>>         struct drm_crtc *crtc, *ct;
>>         struct drm_encoder *encoder, *enct;
>> -       struct drm_bridge *bridge, *brt;
>>         struct drm_framebuffer *fb, *fbt;
>>         struct drm_property *property, *pt;
>>         struct drm_property_blob *blob, *bt;
>> @@ -5260,11 +5198,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>>                 encoder->funcs->destroy(encoder);
>>         }
>>
>> -       list_for_each_entry_safe(bridge, brt,
>> -                                &dev->mode_config.bridge_list, head) {
>> -               bridge->funcs->destroy(bridge);
>> -       }
>> -
>>         list_for_each_entry_safe(connector, ot,
>>                                  &dev->mode_config.connector_list, head) {
>>                 connector->funcs->destroy(connector);
>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
>> index 062c687..95f7b8d 100644
>> --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
>> @@ -247,9 +247,9 @@ int hdmi_modeset_init(struct hdmi *hdmi,
>>         return 0;
>>
>>  fail:
>> -       /* bridge/connector are normally destroyed by drm: */
>> +       /* bridge is normally destroyed by drm: */
>>         if (hdmi->bridge) {
>> -               hdmi->bridge->funcs->destroy(hdmi->bridge);
>> +               hdmi_bridge_destroy(hdmi->bridge);
>>                 hdmi->bridge = NULL;
>>         }
>>         if (hdmi->connector) {
>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
>> index 43e654f..4d4cad4 100644
>> --- a/drivers/gpu/drm/msm/hdmi/hdmi.h
>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
>> @@ -146,6 +146,7 @@ void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
>>   */
>>
>>  struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
>> +void hdmi_bridge_destroy(struct drm_bridge *bridge);
>>
>>  /*
>>   * hdmi connector:
>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>> index 52ed2b5..d6f8d58 100644
>> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>> @@ -23,10 +23,9 @@ struct hdmi_bridge {
>>  };
>>  #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
>>
>> -static void hdmi_bridge_destroy(struct drm_bridge *bridge)
>> +void hdmi_bridge_destroy(struct drm_bridge *bridge)
>>  {
>>         struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
>> -       drm_bridge_cleanup(bridge);
>>         kfree(hdmi_bridge);
>>  }
>>
>> @@ -200,7 +199,6 @@ static const struct drm_bridge_funcs hdmi_bridge_funcs = {
>>                 .disable = hdmi_bridge_disable,
>>                 .post_disable = hdmi_bridge_post_disable,
>>                 .mode_set = hdmi_bridge_mode_set,
>> -               .destroy = hdmi_bridge_destroy,
>>  };
>>
>>
>> @@ -222,7 +220,7 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
>>         bridge = &hdmi_bridge->base;
>>         bridge->funcs = &hdmi_bridge_funcs;
>>
>> -       drm_bridge_init(hdmi->dev, bridge);
>> +       drm_bridge_attach(hdmi->dev, bridge);
>>
>>         return bridge;
>>
>> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
>> index 6cf145d..a9bbb08 100644
>> --- a/drivers/gpu/drm/sti/sti_hda.c
>> +++ b/drivers/gpu/drm/sti/sti_hda.c
>> @@ -508,19 +508,12 @@ static void sti_hda_bridge_nope(struct drm_bridge *bridge)
>>         /* do nothing */
>>  }
>>
>> -static void sti_hda_brigde_destroy(struct drm_bridge *bridge)
>> -{
>> -       drm_bridge_cleanup(bridge);
>> -       kfree(bridge);
>> -}
>> -
>>  static const struct drm_bridge_funcs sti_hda_bridge_funcs = {
>>         .pre_enable = sti_hda_pre_enable,
>>         .enable = sti_hda_bridge_nope,
>>         .disable = sti_hda_disable,
>>         .post_disable = sti_hda_bridge_nope,
>>         .mode_set = sti_hda_set_mode,
>> -       .destroy = sti_hda_brigde_destroy,
>>  };
>>
>>  static int sti_hda_connector_get_modes(struct drm_connector *connector)
>> @@ -665,7 +658,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>>
>>         bridge->driver_private = hda;
>>         bridge->funcs = &sti_hda_bridge_funcs;
>> -       drm_bridge_init(drm_dev, bridge);
>> +       drm_bridge_attach(drm_dev, bridge);
>>
>>         encoder->bridge = bridge;
>>         connector->encoder = encoder;
>> @@ -694,7 +687,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>>  err_sysfs:
>>         drm_connector_unregister(drm_connector);
>>  err_connector:
>> -       drm_bridge_cleanup(bridge);
>>         drm_connector_cleanup(drm_connector);
>>         return -EINVAL;
>>  }
>> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
>> index 74e943e..e840ca5d 100644
>> --- a/drivers/gpu/drm/sti/sti_hdmi.c
>> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
>> @@ -463,19 +463,12 @@ static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
>>         /* do nothing */
>>  }
>>
>> -static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge)
>> -{
>> -       drm_bridge_cleanup(bridge);
>> -       kfree(bridge);
>> -}
>> -
>>  static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
>>         .pre_enable = sti_hdmi_pre_enable,
>>         .enable = sti_hdmi_bridge_nope,
>>         .disable = sti_hdmi_disable,
>>         .post_disable = sti_hdmi_bridge_nope,
>>         .mode_set = sti_hdmi_set_mode,
>> -       .destroy = sti_hdmi_brigde_destroy,
>>  };
>>
>>  static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
>> @@ -636,7 +629,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>>
>>         bridge->driver_private = hdmi;
>>         bridge->funcs = &sti_hdmi_bridge_funcs;
>> -       drm_bridge_init(drm_dev, bridge);
>> +       drm_bridge_attach(drm_dev, bridge);
>>
>>         encoder->bridge = bridge;
>>         connector->encoder = encoder;
>> @@ -668,7 +661,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>>  err_sysfs:
>>         drm_connector_unregister(drm_connector);
>>  err_connector:
>> -       drm_bridge_cleanup(bridge);
>>         drm_connector_cleanup(drm_connector);
>>  err_adapt:
>>         put_device(&hdmi->ddc_adapt->dev);
>> diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h
>> index ff62344..b11f8e1 100644
>> --- a/include/drm/bridge/ptn3460.h
>> +++ b/include/drm/bridge/ptn3460.h
>> @@ -15,6 +15,7 @@
>>  #define _DRM_BRIDGE_PTN3460_H_
>>
>>  struct drm_device;
>> +struct drm_bridge;
>>  struct drm_encoder;
>>  struct i2c_client;
>>  struct device_node;
>> @@ -23,6 +24,9 @@ struct device_node;
>>
>>  int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
>>                 struct i2c_client *client, struct device_node *node);
>> +
>> +void ptn3460_destroy(struct drm_bridge *bridge);
>> +
>>  #else
>>
>>  static inline int ptn3460_init(struct drm_device *dev,
>> @@ -32,6 +36,10 @@ static inline int ptn3460_init(struct drm_device *dev,
>>         return 0;
>>  }
>>
>> +static inline void ptn3460_destroy(struct drm_bridge *bridge)
>> +{
>> +}
>> +
>>  #endif
>>
>>  #endif
>> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
>> index 5b8f254..cc369f3 100644
>> --- a/include/drm/drm_crtc.h
>> +++ b/include/drm/drm_crtc.h
>> @@ -813,15 +813,16 @@ struct drm_plane {
>>
>>  /**
>>   * struct drm_bridge_funcs - drm_bridge control functions
>> + * @attach: Called during drm_bridge_attach
>>   * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
>>   * @disable: Called right before encoder prepare, disables the bridge
>>   * @post_disable: Called right after encoder prepare, for lockstepped disable
>>   * @mode_set: Set this mode to the bridge
>>   * @pre_enable: Called right before encoder commit, for lockstepped commit
>>   * @enable: Called right after encoder commit, enables the bridge
>> - * @destroy: make object go away
>>   */
>>  struct drm_bridge_funcs {
>> +       int (*attach)(struct drm_bridge *bridge);
>>         bool (*mode_fixup)(struct drm_bridge *bridge,
>>                            const struct drm_display_mode *mode,
>>                            struct drm_display_mode *adjusted_mode);
>> @@ -832,22 +833,24 @@ struct drm_bridge_funcs {
>>                          struct drm_display_mode *adjusted_mode);
>>         void (*pre_enable)(struct drm_bridge *bridge);
>>         void (*enable)(struct drm_bridge *bridge);
>> -       void (*destroy)(struct drm_bridge *bridge);
>>  };
>>
>>  /**
>>   * struct drm_bridge - central DRM bridge control structure
>>   * @dev: DRM device this bridge belongs to
>> - * @head: list management
>> + * @of_node: device node pointer to the bridge
>> + * @list: to keep track of all added bridges
>>   * @base: base mode object
>>   * @funcs: control functions
>>   * @driver_private: pointer to the bridge driver's internal context
>>   */
>>  struct drm_bridge {
>>         struct drm_device *dev;
>> -       struct list_head head;
>> -
>> -       struct drm_mode_object base;
>> +       struct drm_encoder *encoder;
>> +#ifdef CONFIG_OF
>> +       struct device_node *of_node;
>> +#endif
>> +       struct list_head list;
>>
>>         const struct drm_bridge_funcs *funcs;
>>         void *driver_private;
>> @@ -950,7 +953,6 @@ struct drm_mode_group {
>>         uint32_t num_crtcs;
>>         uint32_t num_encoders;
>>         uint32_t num_connectors;
>> -       uint32_t num_bridges;
>>
>>         /* list of object IDs for this group */
>>         uint32_t *id_list;
>> @@ -969,8 +971,6 @@ struct drm_mode_group {
>>   * @fb_list: list of framebuffers available
>>   * @num_connector: number of connectors on this device
>>   * @connector_list: list of connector objects
>> - * @num_bridge: number of bridges on this device
>> - * @bridge_list: list of bridge objects
>>   * @num_encoder: number of encoders on this device
>>   * @encoder_list: list of encoder objects
>>   * @num_overlay_plane: number of overlay planes on this device
>> @@ -1015,8 +1015,6 @@ struct drm_mode_config {
>>
>>         int num_connector;
>>         struct list_head connector_list;
>> -       int num_bridge;
>> -       struct list_head bridge_list;
>>         int num_encoder;
>>         struct list_head encoder_list;
>>
>> @@ -1153,8 +1151,10 @@ extern unsigned int drm_connector_index(struct drm_connector *connector);
>>  /* helper to unplug all connectors from sysfs for device */
>>  extern void drm_connector_unplug_all(struct drm_device *dev);
>>
>> -extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge);
>> -extern void drm_bridge_cleanup(struct drm_bridge *bridge);
>> +extern int drm_bridge_add(struct drm_bridge *bridge);
>> +extern void drm_bridge_remove(struct drm_bridge *bridge);
>> +extern struct drm_bridge *of_drm_find_bridge(struct device_node *np);
>> +extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
>>
>>  extern int drm_encoder_init(struct drm_device *dev,
>>                             struct drm_encoder *encoder,
>> --
>> 1.7.9.5
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
@ 2015-02-02  9:14         ` Ajay kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay kumar @ 2015-02-02  9:14 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Rob,

On Fri, Jan 30, 2015 at 9:07 PM, Rob Clark <robdclark@gmail.com> wrote:
> On Tue, Jan 20, 2015 at 11:38 AM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
>> Currently, third party bridge drivers(ptn3460) are dependent
>> on the corresponding encoder driver init, since bridge driver
>> needs a drm_device pointer to finish drm initializations.
>> The encoder driver passes the drm_device pointer to the
>> bridge driver. Because of this dependency, third party drivers
>> like ptn3460 doesn't adhere to the driver model.
>>
>> In this patch, we reframe the bridge registration framework
>> so that bridge initialization is split into 2 steps, and
>> bridge registration happens independent of drm flow:
>> --Step 1: gather all the bridge settings independent of drm and
>>           add the bridge onto a global list of bridges.
>> --Step 2: when the encoder driver is probed, call drm_bridge_attach
>>           for the corresponding bridge so that the bridge receives
>>           drm_device pointer and continues with connector and other
>>           drm initializations.
>>
>> The old set of bridge helpers are removed, and a set of new helpers
>> are added to accomplish the 2 step initialization.
>>
>> The bridge devices register themselves onto global list of bridges
>> when they get probed by calling "drm_bridge_add".
>>
>> The parent encoder driver waits till the bridge is available
>> in the lookup table(by calling "of_drm_find_bridge") and then
>> continues with its initialization.
>>
>> The encoder driver should also call "drm_bridge_attach" to pass
>> on the drm_device to the bridge object.
>>
>> drm_bridge_attach inturn calls "bridge->funcs->attach" so that
>> bridge can continue with drm related initializations.
>
> ok, so I probably should have had a closer look at this before it
> landed in drm-next, so if it is too late to revert (and deal w/
> untangling subsequent patches that depend on this) some of these
> issues we'll just have to fix with follow-on patches.
>
> 1) needs headerdoc for new fxns in drm_bridge.c, and needs to be added
> in drm.tmpl
Ohh, I totally forgot. I will do this. Just point me to some recent
patch which updates docbook.
> 2) as far as I can tell, the new approach to cleaning up bridge
> objects is to just let them leak !?!
I just checked. Only MSM hdmi_bridge is leaking, and this is because
it doesn't use devm_kzalloc. All other bridges use devm_kzalloc,
and hence that memory is automatically freed.
For MSM HDMI, we need to find a place to call hdmi_bridge_destroy.

> I'll also need to update the new bridge in the msm edp code..
> although that isn't such a big deal if I knew how this was *supposed*
> to work..
You just need to convert drm_bridge_init to drm_bridge_attach, and
remove destroy callback. Refer this:
http://cgit.freedesktop.org/~airlied/linux/commit/?h=drm-next&id=b5217bf4692218d202d3d2cd772864fa1e10be4d

Regards,
Ajay Kumar
> since what is there now at least doesn't look right..
>
> BR,
> -R
>
>
>
>> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
>> Acked-by: Inki Dae <inki.dae@samsung.com>
>> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
>> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
>> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
>> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
>> ---
>>  drivers/gpu/drm/Makefile               |    2 +-
>>  drivers/gpu/drm/bridge/ptn3460.c       |   27 +++++-----
>>  drivers/gpu/drm/drm_bridge.c           |   91 ++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/drm_crtc.c             |   67 -----------------------
>>  drivers/gpu/drm/msm/hdmi/hdmi.c        |    4 +-
>>  drivers/gpu/drm/msm/hdmi/hdmi.h        |    1 +
>>  drivers/gpu/drm/msm/hdmi/hdmi_bridge.c |    6 +--
>>  drivers/gpu/drm/sti/sti_hda.c          |   10 +---
>>  drivers/gpu/drm/sti/sti_hdmi.c         |   10 +---
>>  include/drm/bridge/ptn3460.h           |    8 +++
>>  include/drm/drm_crtc.h                 |   26 ++++-----
>>  11 files changed, 133 insertions(+), 119 deletions(-)
>>  create mode 100644 drivers/gpu/drm/drm_bridge.c
>>
>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> index e620807..c83ef2d 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -14,7 +14,7 @@ drm-y       :=        drm_auth.o drm_bufs.o drm_cache.o \
>>                 drm_info.o drm_debugfs.o drm_encoder_slave.o \
>>                 drm_trace_points.o drm_global.o drm_prime.o \
>>                 drm_rect.o drm_vma_manager.o drm_flip_work.o \
>> -               drm_modeset_lock.o drm_atomic.o
>> +               drm_modeset_lock.o drm_atomic.o drm_bridge.o
>>
>>  drm-$(CONFIG_COMPAT) += drm_ioc32.o
>>  drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
>> diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
>> index a2ddc8d..4a818c1 100644
>> --- a/drivers/gpu/drm/bridge/ptn3460.c
>> +++ b/drivers/gpu/drm/bridge/ptn3460.c
>> @@ -176,24 +176,11 @@ static void ptn3460_post_disable(struct drm_bridge *bridge)
>>  {
>>  }
>>
>> -static void ptn3460_bridge_destroy(struct drm_bridge *bridge)
>> -{
>> -       struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
>> -
>> -       drm_bridge_cleanup(bridge);
>> -       if (gpio_is_valid(ptn_bridge->gpio_pd_n))
>> -               gpio_free(ptn_bridge->gpio_pd_n);
>> -       if (gpio_is_valid(ptn_bridge->gpio_rst_n))
>> -               gpio_free(ptn_bridge->gpio_rst_n);
>> -       /* Nothing else to free, we've got devm allocated memory */
>> -}
>> -
>>  static struct drm_bridge_funcs ptn3460_bridge_funcs = {
>>         .pre_enable = ptn3460_pre_enable,
>>         .enable = ptn3460_enable,
>>         .disable = ptn3460_disable,
>>         .post_disable = ptn3460_post_disable,
>> -       .destroy = ptn3460_bridge_destroy,
>>  };
>>
>>  static int ptn3460_get_modes(struct drm_connector *connector)
>> @@ -314,7 +301,7 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
>>         }
>>
>>         ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
>> -       ret = drm_bridge_init(dev, &ptn_bridge->bridge);
>> +       ret = drm_bridge_attach(dev, &ptn_bridge->bridge);
>>         if (ret) {
>>                 DRM_ERROR("Failed to initialize bridge with drm\n");
>>                 goto err;
>> @@ -343,3 +330,15 @@ err:
>>         return ret;
>>  }
>>  EXPORT_SYMBOL(ptn3460_init);
>> +
>> +void ptn3460_destroy(struct drm_bridge *bridge)
>> +{
>> +       struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
>> +
>> +       if (gpio_is_valid(ptn_bridge->gpio_pd_n))
>> +               gpio_free(ptn_bridge->gpio_pd_n);
>> +       if (gpio_is_valid(ptn_bridge->gpio_rst_n))
>> +               gpio_free(ptn_bridge->gpio_rst_n);
>> +       /* Nothing else to free, we've got devm allocated memory */
>> +}
>> +EXPORT_SYMBOL(ptn3460_destroy);
>> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
>> new file mode 100644
>> index 0000000..d1187e5
>> --- /dev/null
>> +++ b/drivers/gpu/drm/drm_bridge.c
>> @@ -0,0 +1,91 @@
>> +/*
>> + * Copyright (c) 2014 Samsung Electronics Co., Ltd
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sub license,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the
>> + * next paragraph) shall be included in all copies or substantial portions
>> + * of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> + * DEALINGS IN THE SOFTWARE.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/module.h>
>> +
>> +#include <drm/drm_crtc.h>
>> +
>> +#include "drm/drmP.h"
>> +
>> +static DEFINE_MUTEX(bridge_lock);
>> +static LIST_HEAD(bridge_list);
>> +
>> +int drm_bridge_add(struct drm_bridge *bridge)
>> +{
>> +       mutex_lock(&bridge_lock);
>> +       list_add_tail(&bridge->list, &bridge_list);
>> +       mutex_unlock(&bridge_lock);
>> +
>> +       return 0;
>> +}
>> +EXPORT_SYMBOL(drm_bridge_add);
>> +
>> +void drm_bridge_remove(struct drm_bridge *bridge)
>> +{
>> +       mutex_lock(&bridge_lock);
>> +       list_del_init(&bridge->list);
>> +       mutex_unlock(&bridge_lock);
>> +}
>> +EXPORT_SYMBOL(drm_bridge_remove);
>> +
>> +extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
>> +{
>> +       if (!dev || !bridge)
>> +               return -EINVAL;
>> +
>> +       if (bridge->dev)
>> +               return -EBUSY;
>> +
>> +       bridge->dev = dev;
>> +
>> +       if (bridge->funcs->attach)
>> +               return bridge->funcs->attach(bridge);
>> +
>> +       return 0;
>> +}
>> +EXPORT_SYMBOL(drm_bridge_attach);
>> +
>> +#ifdef CONFIG_OF
>> +struct drm_bridge *of_drm_find_bridge(struct device_node *np)
>> +{
>> +       struct drm_bridge *bridge;
>> +
>> +       mutex_lock(&bridge_lock);
>> +
>> +       list_for_each_entry(bridge, &bridge_list, list) {
>> +               if (bridge->of_node == np) {
>> +                       mutex_unlock(&bridge_lock);
>> +                       return bridge;
>> +               }
>> +       }
>> +
>> +       mutex_unlock(&bridge_lock);
>> +       return NULL;
>> +}
>> +EXPORT_SYMBOL(of_drm_find_bridge);
>> +#endif
>> +
>> +MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
>> +MODULE_DESCRIPTION("DRM bridge infrastructure");
>> +MODULE_LICENSE("GPL and additional rights");
>> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
>> index af57103..bb8e31e 100644
>> --- a/drivers/gpu/drm/drm_crtc.c
>> +++ b/drivers/gpu/drm/drm_crtc.c
>> @@ -1028,58 +1028,6 @@ void drm_connector_unplug_all(struct drm_device *dev)
>>  EXPORT_SYMBOL(drm_connector_unplug_all);
>>
>>  /**
>> - * drm_bridge_init - initialize a drm transcoder/bridge
>> - * @dev: drm device
>> - * @bridge: transcoder/bridge to set up
>> - *
>> - * Initialises a preallocated bridge. Bridges should be
>> - * subclassed as part of driver connector objects.
>> - *
>> - * Returns:
>> - * Zero on success, error code on failure.
>> - */
>> -int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge)
>> -{
>> -       int ret;
>> -
>> -       drm_modeset_lock_all(dev);
>> -
>> -       ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE);
>> -       if (ret)
>> -               goto out;
>> -
>> -       bridge->dev = dev;
>> -
>> -       list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
>> -       dev->mode_config.num_bridge++;
>> -
>> - out:
>> -       drm_modeset_unlock_all(dev);
>> -       return ret;
>> -}
>> -EXPORT_SYMBOL(drm_bridge_init);
>> -
>> -/**
>> - * drm_bridge_cleanup - cleans up an initialised bridge
>> - * @bridge: bridge to cleanup
>> - *
>> - * Cleans up the bridge but doesn't free the object.
>> - */
>> -void drm_bridge_cleanup(struct drm_bridge *bridge)
>> -{
>> -       struct drm_device *dev = bridge->dev;
>> -
>> -       drm_modeset_lock_all(dev);
>> -       drm_mode_object_put(dev, &bridge->base);
>> -       list_del(&bridge->head);
>> -       dev->mode_config.num_bridge--;
>> -       drm_modeset_unlock_all(dev);
>> -
>> -       memset(bridge, 0, sizeof(*bridge));
>> -}
>> -EXPORT_SYMBOL(drm_bridge_cleanup);
>> -
>> -/**
>>   * drm_encoder_init - Init a preallocated encoder
>>   * @dev: drm device
>>   * @encoder: the encoder to init
>> @@ -1594,7 +1542,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
>>         total_objects += dev->mode_config.num_crtc;
>>         total_objects += dev->mode_config.num_connector;
>>         total_objects += dev->mode_config.num_encoder;
>> -       total_objects += dev->mode_config.num_bridge;
>>
>>         group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
>>         if (!group->id_list)
>> @@ -1603,7 +1550,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
>>         group->num_crtcs = 0;
>>         group->num_connectors = 0;
>>         group->num_encoders = 0;
>> -       group->num_bridges = 0;
>>         return 0;
>>  }
>>
>> @@ -1623,7 +1569,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
>>         struct drm_crtc *crtc;
>>         struct drm_encoder *encoder;
>>         struct drm_connector *connector;
>> -       struct drm_bridge *bridge;
>>         int ret;
>>
>>         if ((ret = drm_mode_group_init(dev, group)))
>> @@ -1640,11 +1585,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
>>                 group->id_list[group->num_crtcs + group->num_encoders +
>>                                group->num_connectors++] = connector->base.id;
>>
>> -       list_for_each_entry(bridge, &dev->mode_config.bridge_list, head)
>> -               group->id_list[group->num_crtcs + group->num_encoders +
>> -                              group->num_connectors + group->num_bridges++] =
>> -                                       bridge->base.id;
>> -
>>         return 0;
>>  }
>>  EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
>> @@ -5208,7 +5148,6 @@ void drm_mode_config_init(struct drm_device *dev)
>>         INIT_LIST_HEAD(&dev->mode_config.fb_list);
>>         INIT_LIST_HEAD(&dev->mode_config.crtc_list);
>>         INIT_LIST_HEAD(&dev->mode_config.connector_list);
>> -       INIT_LIST_HEAD(&dev->mode_config.bridge_list);
>>         INIT_LIST_HEAD(&dev->mode_config.encoder_list);
>>         INIT_LIST_HEAD(&dev->mode_config.property_list);
>>         INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
>> @@ -5249,7 +5188,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>>         struct drm_connector *connector, *ot;
>>         struct drm_crtc *crtc, *ct;
>>         struct drm_encoder *encoder, *enct;
>> -       struct drm_bridge *bridge, *brt;
>>         struct drm_framebuffer *fb, *fbt;
>>         struct drm_property *property, *pt;
>>         struct drm_property_blob *blob, *bt;
>> @@ -5260,11 +5198,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>>                 encoder->funcs->destroy(encoder);
>>         }
>>
>> -       list_for_each_entry_safe(bridge, brt,
>> -                                &dev->mode_config.bridge_list, head) {
>> -               bridge->funcs->destroy(bridge);
>> -       }
>> -
>>         list_for_each_entry_safe(connector, ot,
>>                                  &dev->mode_config.connector_list, head) {
>>                 connector->funcs->destroy(connector);
>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
>> index 062c687..95f7b8d 100644
>> --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
>> @@ -247,9 +247,9 @@ int hdmi_modeset_init(struct hdmi *hdmi,
>>         return 0;
>>
>>  fail:
>> -       /* bridge/connector are normally destroyed by drm: */
>> +       /* bridge is normally destroyed by drm: */
>>         if (hdmi->bridge) {
>> -               hdmi->bridge->funcs->destroy(hdmi->bridge);
>> +               hdmi_bridge_destroy(hdmi->bridge);
>>                 hdmi->bridge = NULL;
>>         }
>>         if (hdmi->connector) {
>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
>> index 43e654f..4d4cad4 100644
>> --- a/drivers/gpu/drm/msm/hdmi/hdmi.h
>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
>> @@ -146,6 +146,7 @@ void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
>>   */
>>
>>  struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
>> +void hdmi_bridge_destroy(struct drm_bridge *bridge);
>>
>>  /*
>>   * hdmi connector:
>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>> index 52ed2b5..d6f8d58 100644
>> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>> @@ -23,10 +23,9 @@ struct hdmi_bridge {
>>  };
>>  #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
>>
>> -static void hdmi_bridge_destroy(struct drm_bridge *bridge)
>> +void hdmi_bridge_destroy(struct drm_bridge *bridge)
>>  {
>>         struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
>> -       drm_bridge_cleanup(bridge);
>>         kfree(hdmi_bridge);
>>  }
>>
>> @@ -200,7 +199,6 @@ static const struct drm_bridge_funcs hdmi_bridge_funcs = {
>>                 .disable = hdmi_bridge_disable,
>>                 .post_disable = hdmi_bridge_post_disable,
>>                 .mode_set = hdmi_bridge_mode_set,
>> -               .destroy = hdmi_bridge_destroy,
>>  };
>>
>>
>> @@ -222,7 +220,7 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
>>         bridge = &hdmi_bridge->base;
>>         bridge->funcs = &hdmi_bridge_funcs;
>>
>> -       drm_bridge_init(hdmi->dev, bridge);
>> +       drm_bridge_attach(hdmi->dev, bridge);
>>
>>         return bridge;
>>
>> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
>> index 6cf145d..a9bbb08 100644
>> --- a/drivers/gpu/drm/sti/sti_hda.c
>> +++ b/drivers/gpu/drm/sti/sti_hda.c
>> @@ -508,19 +508,12 @@ static void sti_hda_bridge_nope(struct drm_bridge *bridge)
>>         /* do nothing */
>>  }
>>
>> -static void sti_hda_brigde_destroy(struct drm_bridge *bridge)
>> -{
>> -       drm_bridge_cleanup(bridge);
>> -       kfree(bridge);
>> -}
>> -
>>  static const struct drm_bridge_funcs sti_hda_bridge_funcs = {
>>         .pre_enable = sti_hda_pre_enable,
>>         .enable = sti_hda_bridge_nope,
>>         .disable = sti_hda_disable,
>>         .post_disable = sti_hda_bridge_nope,
>>         .mode_set = sti_hda_set_mode,
>> -       .destroy = sti_hda_brigde_destroy,
>>  };
>>
>>  static int sti_hda_connector_get_modes(struct drm_connector *connector)
>> @@ -665,7 +658,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>>
>>         bridge->driver_private = hda;
>>         bridge->funcs = &sti_hda_bridge_funcs;
>> -       drm_bridge_init(drm_dev, bridge);
>> +       drm_bridge_attach(drm_dev, bridge);
>>
>>         encoder->bridge = bridge;
>>         connector->encoder = encoder;
>> @@ -694,7 +687,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>>  err_sysfs:
>>         drm_connector_unregister(drm_connector);
>>  err_connector:
>> -       drm_bridge_cleanup(bridge);
>>         drm_connector_cleanup(drm_connector);
>>         return -EINVAL;
>>  }
>> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
>> index 74e943e..e840ca5d 100644
>> --- a/drivers/gpu/drm/sti/sti_hdmi.c
>> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
>> @@ -463,19 +463,12 @@ static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
>>         /* do nothing */
>>  }
>>
>> -static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge)
>> -{
>> -       drm_bridge_cleanup(bridge);
>> -       kfree(bridge);
>> -}
>> -
>>  static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
>>         .pre_enable = sti_hdmi_pre_enable,
>>         .enable = sti_hdmi_bridge_nope,
>>         .disable = sti_hdmi_disable,
>>         .post_disable = sti_hdmi_bridge_nope,
>>         .mode_set = sti_hdmi_set_mode,
>> -       .destroy = sti_hdmi_brigde_destroy,
>>  };
>>
>>  static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
>> @@ -636,7 +629,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>>
>>         bridge->driver_private = hdmi;
>>         bridge->funcs = &sti_hdmi_bridge_funcs;
>> -       drm_bridge_init(drm_dev, bridge);
>> +       drm_bridge_attach(drm_dev, bridge);
>>
>>         encoder->bridge = bridge;
>>         connector->encoder = encoder;
>> @@ -668,7 +661,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>>  err_sysfs:
>>         drm_connector_unregister(drm_connector);
>>  err_connector:
>> -       drm_bridge_cleanup(bridge);
>>         drm_connector_cleanup(drm_connector);
>>  err_adapt:
>>         put_device(&hdmi->ddc_adapt->dev);
>> diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h
>> index ff62344..b11f8e1 100644
>> --- a/include/drm/bridge/ptn3460.h
>> +++ b/include/drm/bridge/ptn3460.h
>> @@ -15,6 +15,7 @@
>>  #define _DRM_BRIDGE_PTN3460_H_
>>
>>  struct drm_device;
>> +struct drm_bridge;
>>  struct drm_encoder;
>>  struct i2c_client;
>>  struct device_node;
>> @@ -23,6 +24,9 @@ struct device_node;
>>
>>  int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
>>                 struct i2c_client *client, struct device_node *node);
>> +
>> +void ptn3460_destroy(struct drm_bridge *bridge);
>> +
>>  #else
>>
>>  static inline int ptn3460_init(struct drm_device *dev,
>> @@ -32,6 +36,10 @@ static inline int ptn3460_init(struct drm_device *dev,
>>         return 0;
>>  }
>>
>> +static inline void ptn3460_destroy(struct drm_bridge *bridge)
>> +{
>> +}
>> +
>>  #endif
>>
>>  #endif
>> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
>> index 5b8f254..cc369f3 100644
>> --- a/include/drm/drm_crtc.h
>> +++ b/include/drm/drm_crtc.h
>> @@ -813,15 +813,16 @@ struct drm_plane {
>>
>>  /**
>>   * struct drm_bridge_funcs - drm_bridge control functions
>> + * @attach: Called during drm_bridge_attach
>>   * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
>>   * @disable: Called right before encoder prepare, disables the bridge
>>   * @post_disable: Called right after encoder prepare, for lockstepped disable
>>   * @mode_set: Set this mode to the bridge
>>   * @pre_enable: Called right before encoder commit, for lockstepped commit
>>   * @enable: Called right after encoder commit, enables the bridge
>> - * @destroy: make object go away
>>   */
>>  struct drm_bridge_funcs {
>> +       int (*attach)(struct drm_bridge *bridge);
>>         bool (*mode_fixup)(struct drm_bridge *bridge,
>>                            const struct drm_display_mode *mode,
>>                            struct drm_display_mode *adjusted_mode);
>> @@ -832,22 +833,24 @@ struct drm_bridge_funcs {
>>                          struct drm_display_mode *adjusted_mode);
>>         void (*pre_enable)(struct drm_bridge *bridge);
>>         void (*enable)(struct drm_bridge *bridge);
>> -       void (*destroy)(struct drm_bridge *bridge);
>>  };
>>
>>  /**
>>   * struct drm_bridge - central DRM bridge control structure
>>   * @dev: DRM device this bridge belongs to
>> - * @head: list management
>> + * @of_node: device node pointer to the bridge
>> + * @list: to keep track of all added bridges
>>   * @base: base mode object
>>   * @funcs: control functions
>>   * @driver_private: pointer to the bridge driver's internal context
>>   */
>>  struct drm_bridge {
>>         struct drm_device *dev;
>> -       struct list_head head;
>> -
>> -       struct drm_mode_object base;
>> +       struct drm_encoder *encoder;
>> +#ifdef CONFIG_OF
>> +       struct device_node *of_node;
>> +#endif
>> +       struct list_head list;
>>
>>         const struct drm_bridge_funcs *funcs;
>>         void *driver_private;
>> @@ -950,7 +953,6 @@ struct drm_mode_group {
>>         uint32_t num_crtcs;
>>         uint32_t num_encoders;
>>         uint32_t num_connectors;
>> -       uint32_t num_bridges;
>>
>>         /* list of object IDs for this group */
>>         uint32_t *id_list;
>> @@ -969,8 +971,6 @@ struct drm_mode_group {
>>   * @fb_list: list of framebuffers available
>>   * @num_connector: number of connectors on this device
>>   * @connector_list: list of connector objects
>> - * @num_bridge: number of bridges on this device
>> - * @bridge_list: list of bridge objects
>>   * @num_encoder: number of encoders on this device
>>   * @encoder_list: list of encoder objects
>>   * @num_overlay_plane: number of overlay planes on this device
>> @@ -1015,8 +1015,6 @@ struct drm_mode_config {
>>
>>         int num_connector;
>>         struct list_head connector_list;
>> -       int num_bridge;
>> -       struct list_head bridge_list;
>>         int num_encoder;
>>         struct list_head encoder_list;
>>
>> @@ -1153,8 +1151,10 @@ extern unsigned int drm_connector_index(struct drm_connector *connector);
>>  /* helper to unplug all connectors from sysfs for device */
>>  extern void drm_connector_unplug_all(struct drm_device *dev);
>>
>> -extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge);
>> -extern void drm_bridge_cleanup(struct drm_bridge *bridge);
>> +extern int drm_bridge_add(struct drm_bridge *bridge);
>> +extern void drm_bridge_remove(struct drm_bridge *bridge);
>> +extern struct drm_bridge *of_drm_find_bridge(struct device_node *np);
>> +extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
>>
>>  extern int drm_encoder_init(struct drm_device *dev,
>>                             struct drm_encoder *encoder,
>> --
>> 1.7.9.5
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
  2015-01-30 15:59           ` Russell King - ARM Linux
@ 2015-02-02  9:16             ` Ajay kumar
  -1 siblings, 0 replies; 58+ messages in thread
From: Ajay kumar @ 2015-02-02  9:16 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devicetree, Kukjin Kim, Sean Paul, Daniel Vetter, Jingoo Han,
	dri-devel, moderated list:ARM/S5P EXYNOS AR...,
	Pannaga Bhushan Reddy Patel, Prashanth G, Ajay Kumar,
	linux-arm-kernel

Hi,

On Fri, Jan 30, 2015 at 9:29 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Fri, Jan 30, 2015 at 10:37:19AM -0500, Rob Clark wrote:
>> On Tue, Jan 20, 2015 at 11:38 AM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
>> I'll also need to update the new bridge in the msm edp code..
>> although that isn't such a big deal if I knew how this was *supposed*
>> to work.. since what is there now at least doesn't look right..
>
> I wonder whether the new dw-hdmi bridge code get fixed up too...
I think its already fixed. Check this:
http://cgit.freedesktop.org/~airlied/linux/commit/?h=drm-next&id=b5217bf4692218d202d3d2cd772864fa1e10be4d

Regards,
Ajay Kumar
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
@ 2015-02-02  9:16             ` Ajay kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Ajay kumar @ 2015-02-02  9:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Fri, Jan 30, 2015 at 9:29 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Fri, Jan 30, 2015 at 10:37:19AM -0500, Rob Clark wrote:
>> On Tue, Jan 20, 2015 at 11:38 AM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
>> I'll also need to update the new bridge in the msm edp code..
>> although that isn't such a big deal if I knew how this was *supposed*
>> to work.. since what is there now at least doesn't look right..
>
> I wonder whether the new dw-hdmi bridge code get fixed up too...
I think its already fixed. Check this:
http://cgit.freedesktop.org/~airlied/linux/commit/?h=drm-next&id=b5217bf4692218d202d3d2cd772864fa1e10be4d

Regards,
Ajay Kumar

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

* Re: [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
  2015-01-30 15:37       ` Rob Clark
@ 2015-02-03 12:03         ` Thierry Reding
  -1 siblings, 0 replies; 58+ messages in thread
From: Thierry Reding @ 2015-02-03 12:03 UTC (permalink / raw)
  To: Rob Clark
  Cc: Ajay Kumar, dri-devel, moderated list:ARM/S5P EXYNOS AR...,
	linux-arm-kernel, devicetree, Kukjin Kim, Sean Paul,
	Daniel Vetter, jg1.han, daeinki, Ajay kumar, bhushan.r,
	Prashanth G

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

On Fri, Jan 30, 2015 at 10:37:19AM -0500, Rob Clark wrote:
> On Tue, Jan 20, 2015 at 11:38 AM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
> > Currently, third party bridge drivers(ptn3460) are dependent
> > on the corresponding encoder driver init, since bridge driver
> > needs a drm_device pointer to finish drm initializations.
> > The encoder driver passes the drm_device pointer to the
> > bridge driver. Because of this dependency, third party drivers
> > like ptn3460 doesn't adhere to the driver model.
> >
> > In this patch, we reframe the bridge registration framework
> > so that bridge initialization is split into 2 steps, and
> > bridge registration happens independent of drm flow:
> > --Step 1: gather all the bridge settings independent of drm and
> >           add the bridge onto a global list of bridges.
> > --Step 2: when the encoder driver is probed, call drm_bridge_attach
> >           for the corresponding bridge so that the bridge receives
> >           drm_device pointer and continues with connector and other
> >           drm initializations.
> >
> > The old set of bridge helpers are removed, and a set of new helpers
> > are added to accomplish the 2 step initialization.
> >
> > The bridge devices register themselves onto global list of bridges
> > when they get probed by calling "drm_bridge_add".
> >
> > The parent encoder driver waits till the bridge is available
> > in the lookup table(by calling "of_drm_find_bridge") and then
> > continues with its initialization.
> >
> > The encoder driver should also call "drm_bridge_attach" to pass
> > on the drm_device to the bridge object.
> >
> > drm_bridge_attach inturn calls "bridge->funcs->attach" so that
> > bridge can continue with drm related initializations.
> 
> ok, so I probably should have had a closer look at this before it
> landed in drm-next, so if it is too late to revert (and deal w/
> untangling subsequent patches that depend on this) some of these
> issues we'll just have to fix with follow-on patches.
> 
> 1) needs headerdoc for new fxns in drm_bridge.c, and needs to be added
> in drm.tmpl

drm_panel.c is missing kerneldoc as well, though I have a local patch to
add it. If nobody else steps up I'll take this.

> 2) as far as I can tell, the new approach to cleaning up bridge
> objects is to just let them leak !?!

With this series bridges are no longer part of the DRM device and it's
the driver that provides them that needs to free them (in ->remove()).
It's not a completely perfect solution yet, but with the registry patch
that I proposed a while back all the remaining issues should go away.
Now if I could get anybody to look at that patch...

Thierry

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

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

* [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow
@ 2015-02-03 12:03         ` Thierry Reding
  0 siblings, 0 replies; 58+ messages in thread
From: Thierry Reding @ 2015-02-03 12:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 30, 2015 at 10:37:19AM -0500, Rob Clark wrote:
> On Tue, Jan 20, 2015 at 11:38 AM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
> > Currently, third party bridge drivers(ptn3460) are dependent
> > on the corresponding encoder driver init, since bridge driver
> > needs a drm_device pointer to finish drm initializations.
> > The encoder driver passes the drm_device pointer to the
> > bridge driver. Because of this dependency, third party drivers
> > like ptn3460 doesn't adhere to the driver model.
> >
> > In this patch, we reframe the bridge registration framework
> > so that bridge initialization is split into 2 steps, and
> > bridge registration happens independent of drm flow:
> > --Step 1: gather all the bridge settings independent of drm and
> >           add the bridge onto a global list of bridges.
> > --Step 2: when the encoder driver is probed, call drm_bridge_attach
> >           for the corresponding bridge so that the bridge receives
> >           drm_device pointer and continues with connector and other
> >           drm initializations.
> >
> > The old set of bridge helpers are removed, and a set of new helpers
> > are added to accomplish the 2 step initialization.
> >
> > The bridge devices register themselves onto global list of bridges
> > when they get probed by calling "drm_bridge_add".
> >
> > The parent encoder driver waits till the bridge is available
> > in the lookup table(by calling "of_drm_find_bridge") and then
> > continues with its initialization.
> >
> > The encoder driver should also call "drm_bridge_attach" to pass
> > on the drm_device to the bridge object.
> >
> > drm_bridge_attach inturn calls "bridge->funcs->attach" so that
> > bridge can continue with drm related initializations.
> 
> ok, so I probably should have had a closer look at this before it
> landed in drm-next, so if it is too late to revert (and deal w/
> untangling subsequent patches that depend on this) some of these
> issues we'll just have to fix with follow-on patches.
> 
> 1) needs headerdoc for new fxns in drm_bridge.c, and needs to be added
> in drm.tmpl

drm_panel.c is missing kerneldoc as well, though I have a local patch to
add it. If nobody else steps up I'll take this.

> 2) as far as I can tell, the new approach to cleaning up bridge
> objects is to just let them leak !?!

With this series bridges are no longer part of the DRM device and it's
the driver that provides them that needs to free them (in ->remove()).
It's not a completely perfect solution yet, but with the registry patch
that I proposed a while back all the remaining issues should go away.
Now if I could get anybody to look at that patch...

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150203/443d0324/attachment.sig>

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

* Re: [PATCH V9 10/14] Documentation: devicetree: Add vendor prefix for parade
  2015-01-20 16:38   ` Ajay Kumar
@ 2015-02-04 15:12     ` Rob Herring
  -1 siblings, 0 replies; 58+ messages in thread
From: Rob Herring @ 2015-02-04 15:12 UTC (permalink / raw)
  To: Ajay Kumar
  Cc: dri-devel, linux-samsung-soc, linux-arm-kernel, devicetree,
	Kukjin Kim, seanpaul, daniel.vetter, Jingoo Han, InKi Dae,
	Thierry Reding, ajaynumb, bhushan.r, prashanth.g

On Tue, Jan 20, 2015 at 10:38 AM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
> ps8622 eDP-LVDS converter bridge chip is from parade technologies
>
> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
> Acked-by: Inki Dae <inki.dae@samsung.com>
> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>

Acked-by: Rob Herring <robh@kernel.org>

> ---
>  .../devicetree/bindings/vendor-prefixes.txt        |    1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index 4df1d78..eca48be 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -125,6 +125,7 @@ nxp NXP Semiconductors
>  onnn   ON Semiconductor Corp.
>  opencores      OpenCores.org
>  panasonic      Panasonic Corporation
> +parade Parade Technologies Inc.
>  pericom        Pericom Technology Inc.
>  phytec PHYTEC Messtechnik GmbH
>  picochip       Picochip Ltd
> --
> 1.7.9.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH V9 10/14] Documentation: devicetree: Add vendor prefix for parade
@ 2015-02-04 15:12     ` Rob Herring
  0 siblings, 0 replies; 58+ messages in thread
From: Rob Herring @ 2015-02-04 15:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 20, 2015 at 10:38 AM, Ajay Kumar <ajaykumar.rs@samsung.com> wrote:
> ps8622 eDP-LVDS converter bridge chip is from parade technologies
>
> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
> Acked-by: Inki Dae <inki.dae@samsung.com>
> Tested-by: Rahul Sharma <rahul.sharma@samsung.com>
> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>

Acked-by: Rob Herring <robh@kernel.org>

> ---
>  .../devicetree/bindings/vendor-prefixes.txt        |    1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index 4df1d78..eca48be 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -125,6 +125,7 @@ nxp NXP Semiconductors
>  onnn   ON Semiconductor Corp.
>  opencores      OpenCores.org
>  panasonic      Panasonic Corporation
> +parade Parade Technologies Inc.
>  pericom        Pericom Technology Inc.
>  phytec PHYTEC Messtechnik GmbH
>  picochip       Picochip Ltd
> --
> 1.7.9.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH V9 13/14] ARM: dts: snow: represent the connection between bridge and panel using videoport and endpoints
  2015-01-27  4:27         ` Ajay kumar
@ 2015-02-04 15:30           ` Kukjin Kim
  -1 siblings, 0 replies; 58+ messages in thread
From: Kukjin Kim @ 2015-02-04 15:30 UTC (permalink / raw)
  To: Ajay kumar
  Cc: Kukjin Kim, Ajay Kumar, dri-devel, linux-samsung-soc,
	linux-arm-kernel, devicetree, InKi Dae, Thierry Reding,
	Daniel Vetter, Sean Paul, Jingoo Han,
	Pannaga Bhushan Reddy Patel, Prashanth G

On 01/27/15 13:27, Ajay kumar wrote:
> Hi Kukjin,
> 
Hi,

[...]
>>
>> I'm fine on the DT changes in this series, shall I take 13/14 and 14/14 in
>> Samsung tree?
> Yes, please take these patches.
> 
Done, thanks.

- Kukjin

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

* [PATCH V9 13/14] ARM: dts: snow: represent the connection between bridge and panel using videoport and endpoints
@ 2015-02-04 15:30           ` Kukjin Kim
  0 siblings, 0 replies; 58+ messages in thread
From: Kukjin Kim @ 2015-02-04 15:30 UTC (permalink / raw)
  To: linux-arm-kernel

On 01/27/15 13:27, Ajay kumar wrote:
> Hi Kukjin,
> 
Hi,

[...]
>>
>> I'm fine on the DT changes in this series, shall I take 13/14 and 14/14 in
>> Samsung tree?
> Yes, please take these patches.
> 
Done, thanks.

- Kukjin

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

end of thread, other threads:[~2015-02-04 15:30 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-20 16:38 [PATCH V9 00/14] drm/exynos: few patches to enhance bridge chip support Ajay Kumar
2015-01-20 16:38 ` Ajay Kumar
2015-01-20 16:38 ` [PATCH V9 01/14] drm/bridge: ptn3460: Few trivial cleanups Ajay Kumar
2015-01-20 16:38   ` Ajay Kumar
2015-01-20 16:38 ` [PATCH V9 02/14] drm/bridge: do not pass drm_bridge_funcs to drm_bridge_init Ajay Kumar
2015-01-20 16:38   ` Ajay Kumar
2015-01-20 16:38 ` [PATCH V9 04/14] drm/bridge: ptn3460: Convert to i2c driver model Ajay Kumar
2015-01-20 16:38   ` Ajay Kumar
2015-01-29 14:29   ` Gustavo Padovan
2015-01-29 14:29     ` Gustavo Padovan
2015-01-29 14:39     ` Ajay kumar
2015-01-29 14:39       ` Ajay kumar
2015-01-20 16:38 ` [PATCH V9 06/14] drm/bridge: ptn3460: support drm_panel Ajay Kumar
2015-01-20 16:38   ` Ajay Kumar
2015-01-20 16:38 ` [PATCH V9 07/14] drm/bridge: ptn3460: probe connector at the end of bridge attach Ajay Kumar
2015-01-20 16:38   ` Ajay Kumar
2015-01-20 16:38 ` [PATCH V9 08/14] drm/bridge: ptn3460: use gpiod interface Ajay Kumar
2015-01-20 16:38   ` Ajay Kumar
2015-01-20 16:38 ` [PATCH V9 09/14] Documentation: drm: bridge: move to video/bridge Ajay Kumar
2015-01-20 16:38   ` Ajay Kumar
2015-01-20 16:38 ` [PATCH V9 10/14] Documentation: devicetree: Add vendor prefix for parade Ajay Kumar
2015-01-20 16:38   ` Ajay Kumar
2015-02-04 15:12   ` Rob Herring
2015-02-04 15:12     ` Rob Herring
2015-01-20 16:38 ` [PATCH V9 12/14] drm/bridge: Add i2c based driver for ps8622/ps8625 bridge Ajay Kumar
2015-01-20 16:38   ` Ajay Kumar
2015-01-29 14:42   ` Ajay kumar
2015-01-29 14:42     ` Ajay kumar
     [not found]     ` <CAEC9eQMv_qbQJ=DKz=KznxkGbE2O08DUTwSDtpcfZeHtesEewA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-01-30 11:43       ` Thierry Reding
2015-01-30 11:43         ` Thierry Reding
2015-01-20 16:38 ` [PATCH V9 13/14] ARM: dts: snow: represent the connection between bridge and panel using videoport and endpoints Ajay Kumar
2015-01-20 16:38   ` Ajay Kumar
     [not found]   ` <1421771935-31618-14-git-send-email-ajaykumar.rs-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-01-23  7:01     ` Kukjin Kim
2015-01-23  7:01       ` Kukjin Kim
2015-01-27  4:27       ` Ajay kumar
2015-01-27  4:27         ` Ajay kumar
2015-02-04 15:30         ` Kukjin Kim
2015-02-04 15:30           ` Kukjin Kim
     [not found] ` <1421771935-31618-1-git-send-email-ajaykumar.rs-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-01-20 16:38   ` [PATCH 03/14] drm/bridge: make bridge registration independent of drm flow Ajay Kumar
2015-01-20 16:38     ` Ajay Kumar
2015-01-30 15:37     ` Rob Clark
2015-01-30 15:37       ` Rob Clark
     [not found]       ` <CAF6AEGs8GbgYMLmaPjGnXAv=Gsf6gMhNj+Zt0-2GKHOnHv4d4Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-01-30 15:59         ` Russell King - ARM Linux
2015-01-30 15:59           ` Russell King - ARM Linux
2015-02-02  9:16           ` Ajay kumar
2015-02-02  9:16             ` Ajay kumar
2015-01-30 16:08       ` Daniel Stone
2015-01-30 16:08         ` Daniel Stone
2015-02-02  9:14       ` Ajay kumar
2015-02-02  9:14         ` Ajay kumar
2015-02-03 12:03       ` Thierry Reding
2015-02-03 12:03         ` Thierry Reding
2015-01-20 16:38   ` [PATCH V9 05/14] drm/exynos: dp: support drm_bridge Ajay Kumar
2015-01-20 16:38     ` Ajay Kumar
2015-01-20 16:38   ` [PATCH V9 11/14] Documentation: bridge: Add documentation for ps8622 DT properties Ajay Kumar
2015-01-20 16:38     ` Ajay Kumar
2015-01-20 16:38   ` [PATCH V9 14/14] ARM: dts: peach-pit: represent the connection between bridge and panel using videoport and endpoints Ajay Kumar
2015-01-20 16:38     ` Ajay Kumar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.