* [PATCH 0/5] Add some missing bits for exynos5250-snow @ 2013-10-01 23:40 Sean Paul 2013-10-01 23:40 ` [PATCH 1/5] ARM: dts: Add fimd display-timings " Sean Paul ` (4 more replies) 0 siblings, 5 replies; 51+ messages in thread From: Sean Paul @ 2013-10-01 23:40 UTC (permalink / raw) To: dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied This set adds some missing devicetree nodes to the exynos5250-snow file as well as adds a drm_bridge driver for the ptn3460 DP-LVDS chip. This chip is used in the exynos5250-snow board. Sean Sean Paul (5): ARM: dts: Add fimd display-timings for exynos5250-snow ARM: dts: Add dp-controller node to exynos5250-snow drm/bridge: Add PTN3460 bridge driver drm/exynos: Initialize ptn3460 if present ARM: dts: Add ptn3460 to exynos5250-snow Documentation/devicetree/bindings/drm/bridge/ptn3460.txt | 27 +++++++++++++++++++++++++ arch/arm/boot/dts/exynos5250-snow.dts | 48 ++++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/Kconfig | 2 ++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/bridge/Kconfig | 4 ++++ drivers/gpu/drm/bridge/Makefile | 3 +++ drivers/gpu/drm/bridge/ptn3460.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++++++++++- include/drm/bridge/ptn3460.h | 36 +++++++++++++++++++++++++++++++++ 9 files changed, 513 insertions(+), 1 deletion(-) ^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 1/5] ARM: dts: Add fimd display-timings for exynos5250-snow 2013-10-01 23:40 [PATCH 0/5] Add some missing bits for exynos5250-snow Sean Paul @ 2013-10-01 23:40 ` Sean Paul 2013-10-01 23:40 ` [PATCH 2/5] ARM: dts: Add dp-controller node to exynos5250-snow Sean Paul ` (3 subsequent siblings) 4 siblings, 0 replies; 51+ messages in thread From: Sean Paul @ 2013-10-01 23:40 UTC (permalink / raw) To: dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds the internal panel timings to the exynos5250-snow board dts file. Signed-off-by: Sean Paul <seanpaul@chromium.org> --- arch/arm/boot/dts/exynos5250-snow.dts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index e79331d..e5af3f2 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -190,6 +190,23 @@ samsung,vbus-gpio = <&gpx1 1 0>; }; + fimd: fimd@14400000 { + display-timings { + native-mode = <&lcd_timing>; + lcd_timing: 1366x768 { + clock-frequency = <70589280>; + hactive = <1366>; + vactive = <768>; + hfront-porch = <40>; + hback-porch = <40>; + hsync-len = <32>; + vback-porch = <10>; + vfront-porch = <12>; + vsync-len = <6>; + }; + }; + }; + fixed-rate-clocks { xxti { compatible = "samsung,clock-xxti"; -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH 2/5] ARM: dts: Add dp-controller node to exynos5250-snow 2013-10-01 23:40 [PATCH 0/5] Add some missing bits for exynos5250-snow Sean Paul 2013-10-01 23:40 ` [PATCH 1/5] ARM: dts: Add fimd display-timings " Sean Paul @ 2013-10-01 23:40 ` Sean Paul 2013-10-02 21:10 ` Olof Johansson 2013-10-01 23:40 ` [PATCH 4/5] drm/exynos: Initialize ptn3460 if present Sean Paul ` (2 subsequent siblings) 4 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-01 23:40 UTC (permalink / raw) To: dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds the dp-controller node to the exynos5250-snow board dts file. Signed-off-by: Sean Paul <seanpaul@chromium.org> --- arch/arm/boot/dts/exynos5250-snow.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index e5af3f2..780511a 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -190,6 +190,18 @@ samsung,vbus-gpio = <&gpx1 1 0>; }; + dp-controller { + samsung,color-space = <0>; + samsung,dynamic-range = <0>; + samsung,ycbcr-coeff = <0>; + samsung,color-depth = <1>; + samsung,link-rate = <0x0a>; + samsung,lane-count = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&dp_hpd>; + }; + fimd: fimd@14400000 { display-timings { native-mode = <&lcd_timing>; -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
* Re: [PATCH 2/5] ARM: dts: Add dp-controller node to exynos5250-snow 2013-10-01 23:40 ` [PATCH 2/5] ARM: dts: Add dp-controller node to exynos5250-snow Sean Paul @ 2013-10-02 21:10 ` Olof Johansson 2013-10-03 16:06 ` Sean Paul 0 siblings, 1 reply; 51+ messages in thread From: Olof Johansson @ 2013-10-02 21:10 UTC (permalink / raw) To: Sean Paul Cc: dri-devel, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Inki Dae, airlied On Tue, Oct 1, 2013 at 4:40 PM, Sean Paul <seanpaul@chromium.org> wrote: > This patch adds the dp-controller node to the exynos5250-snow board dts > file. > > Signed-off-by: Sean Paul <seanpaul@chromium.org> > --- > arch/arm/boot/dts/exynos5250-snow.dts | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > > diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts > index e5af3f2..780511a 100644 > --- a/arch/arm/boot/dts/exynos5250-snow.dts > +++ b/arch/arm/boot/dts/exynos5250-snow.dts > @@ -190,6 +190,18 @@ > samsung,vbus-gpio = <&gpx1 1 0>; > }; > > + dp-controller { > + samsung,color-space = <0>; > + samsung,dynamic-range = <0>; > + samsung,ycbcr-coeff = <0>; > + samsung,color-depth = <1>; > + samsung,link-rate = <0x0a>; > + samsung,lane-count = <2>; > + > + pinctrl-names = "default"; > + pinctrl-0 = <&dp_hpd>; > + }; This won't actually do what I think you want. Since the dtsi has the node name "dp-controller@145B0000", you will end up duplicating a new node and not build on top of that one. There's two ways to do it: Always include the unit address, or create a label in the dtsi such that: dp_controller: dp-controller@ {.... } Then in your dts you can, at the root level: &dp_controller { ... new stuff and overrides ... }; -Olof ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH 2/5] ARM: dts: Add dp-controller node to exynos5250-snow 2013-10-02 21:10 ` Olof Johansson @ 2013-10-03 16:06 ` Sean Paul 0 siblings, 0 replies; 51+ messages in thread From: Sean Paul @ 2013-10-03 16:06 UTC (permalink / raw) To: Olof Johansson Cc: dri-devel, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Inki Dae, Dave Airlie On Wed, Oct 2, 2013 at 5:10 PM, Olof Johansson <olof@lixom.net> wrote: > On Tue, Oct 1, 2013 at 4:40 PM, Sean Paul <seanpaul@chromium.org> wrote: >> This patch adds the dp-controller node to the exynos5250-snow board dts >> file. >> >> Signed-off-by: Sean Paul <seanpaul@chromium.org> >> --- >> arch/arm/boot/dts/exynos5250-snow.dts | 12 ++++++++++++ >> 1 file changed, 12 insertions(+) >> >> diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts >> index e5af3f2..780511a 100644 >> --- a/arch/arm/boot/dts/exynos5250-snow.dts >> +++ b/arch/arm/boot/dts/exynos5250-snow.dts >> @@ -190,6 +190,18 @@ >> samsung,vbus-gpio = <&gpx1 1 0>; >> }; >> >> + dp-controller { >> + samsung,color-space = <0>; >> + samsung,dynamic-range = <0>; >> + samsung,ycbcr-coeff = <0>; >> + samsung,color-depth = <1>; >> + samsung,link-rate = <0x0a>; >> + samsung,lane-count = <2>; >> + >> + pinctrl-names = "default"; >> + pinctrl-0 = <&dp_hpd>; >> + }; > > This won't actually do what I think you want. Since the dtsi has the > node name "dp-controller@145B0000", you will end up duplicating a new > node and not build on top of that one. > Thanks, Olof. I based this off Inki's exynos-drm-next tree which does not have the latest from arm-soc, I'll re-upload. Sean > There's two ways to do it: Always include the unit address, or create > a label in the dtsi such that: > > dp_controller: dp-controller@ {.... > } > > Then in your dts you can, at the root level: > > &dp_controller { > ... new stuff and overrides ... > }; > > > > -Olof ^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 4/5] drm/exynos: Initialize ptn3460 if present 2013-10-01 23:40 [PATCH 0/5] Add some missing bits for exynos5250-snow Sean Paul 2013-10-01 23:40 ` [PATCH 1/5] ARM: dts: Add fimd display-timings " Sean Paul 2013-10-01 23:40 ` [PATCH 2/5] ARM: dts: Add dp-controller node to exynos5250-snow Sean Paul @ 2013-10-01 23:40 ` Sean Paul [not found] ` <1380670860-17621-5-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2013-10-01 23:41 ` [PATCH 5/5] ARM: dts: Add ptn3460 to exynos5250-snow Sean Paul [not found] ` <1380670860-17621-1-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 4 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-01 23:40 UTC (permalink / raw) To: dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds code to look for the ptn3460 in the device tree file on exynos initialization. If ptn node is found, the driver will initialize the ptn3460 driver and skip creating a DP connector (since the bridge driver will register its own connector). Signed-off-by: Sean Paul <seanpaul@chromium.org> --- drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 1bef6dc..9cf4476 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -12,7 +12,9 @@ * option) any later version. */ +#include <linux/of_i2c.h> #include <drm/drmP.h> +#include <drm/bridge/ptn3460.h> #include "exynos_drm_drv.h" #include "exynos_drm_encoder.h" #include "exynos_drm_connector.h" @@ -20,6 +22,40 @@ static LIST_HEAD(exynos_drm_subdrv_list); +struct bridge_init { + struct i2c_client *client; + struct device_node *node; +}; + +static bool find_bridge(const char *name, struct bridge_init *bridge) +{ + bridge->client = NULL; + bridge->node = of_find_node_by_name(NULL, name); + 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("ptn3460-bridge", &bridge)) { + ret = ptn3460_init(dev, encoder, bridge.client, bridge.node); + if (!ret) + return 1; + } + return 0; +} + static int exynos_drm_create_enc_conn(struct drm_device *dev, struct exynos_drm_subdrv *subdrv) { @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, DRM_ERROR("failed to create encoder\n"); return -EFAULT; } + subdrv->encoder = encoder; + + if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) { + ret = exynos_drm_attach_lcd_bridge(dev, encoder); + if (ret) + return 0; + } /* * create and initialize a connector for this sub driver and @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, goto err_destroy_encoder; } - subdrv->encoder = encoder; subdrv->connector = connector; return 0; -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
[parent not found: <1380670860-17621-5-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>]
* Re: [PATCH 4/5] drm/exynos: Initialize ptn3460 if present [not found] ` <1380670860-17621-5-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> @ 2013-10-03 14:43 ` Inki Dae 2013-10-03 15:02 ` Sean Paul 0 siblings, 1 reply; 51+ messages in thread From: Inki Dae @ 2013-10-03 14:43 UTC (permalink / raw) To: Sean Paul Cc: DRI mailing list, linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-doc-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Dave Airlie 2013/10/2 Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>: > This patch adds code to look for the ptn3460 in the device tree file on > exynos initialization. If ptn node is found, the driver will initialize > the ptn3460 driver and skip creating a DP connector (since the bridge > driver will register its own connector). > > Signed-off-by: Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> > --- > drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++- > 1 file changed, 43 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c > index 1bef6dc..9cf4476 100644 > --- a/drivers/gpu/drm/exynos/exynos_drm_core.c > +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c > @@ -12,7 +12,9 @@ > * option) any later version. > */ > > +#include <linux/of_i2c.h> > #include <drm/drmP.h> > +#include <drm/bridge/ptn3460.h> > #include "exynos_drm_drv.h" > #include "exynos_drm_encoder.h" > #include "exynos_drm_connector.h" > @@ -20,6 +22,40 @@ > > static LIST_HEAD(exynos_drm_subdrv_list); > > +struct bridge_init { > + struct i2c_client *client; > + struct device_node *node; > +}; > + > +static bool find_bridge(const char *name, struct bridge_init *bridge) > +{ > + bridge->client = NULL; > + bridge->node = of_find_node_by_name(NULL, name); Not clear to me. Why do you try to handle device tree here, not real device driver?. How about adding a output property to board specific fimd dt node: i.e. output = <&ptn3460_bridge>? Actually, the output device of fimd hw could be one of MIPI-DSI, eDP, mDNIe, LVDS bridge, or LCD. And then, let's find ptn3460-bridge node in the fimd driver, and initialize the ptn3460 bridge driver, and get power on or off through exynos_drm_display_ops of the fimd driver. And all these codes could be hided from fimd driver by moving them into exynos_drm_display_ops. Of course, for this, you would need additional works. So let's do it if needed. The below is the outline of device tree I recommend, In board dts, i2c@I2CD000 { ptn3460_bridge: prn3460-bridge@20 { ... } } fimd@11c00000 { ... output_dev = <&ptn3460_bridge>; } With this, I believe that you can do all things you want for controlling the LVDS bridge in fimd driver. Thanks, Inki Dae > + 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("ptn3460-bridge", &bridge)) { > + ret = ptn3460_init(dev, encoder, bridge.client, bridge.node); > + if (!ret) > + return 1; > + } > + return 0; > +} > + > static int exynos_drm_create_enc_conn(struct drm_device *dev, > struct exynos_drm_subdrv *subdrv) > { > @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, > DRM_ERROR("failed to create encoder\n"); > return -EFAULT; > } > + subdrv->encoder = encoder; > + > + if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) { > + ret = exynos_drm_attach_lcd_bridge(dev, encoder); > + if (ret) > + return 0; > + } > > /* > * create and initialize a connector for this sub driver and > @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, > goto err_destroy_encoder; > } > > - subdrv->encoder = encoder; > subdrv->connector = connector; > > return 0; > -- > 1.8.4 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel -- 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] 51+ messages in thread
* Re: [PATCH 4/5] drm/exynos: Initialize ptn3460 if present 2013-10-03 14:43 ` Inki Dae @ 2013-10-03 15:02 ` Sean Paul 2013-10-03 17:18 ` Inki Dae 0 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-03 15:02 UTC (permalink / raw) To: Inki Dae Cc: DRI mailing list, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-doc, devicetree@vger.kernel.org, Dave Airlie On Thu, Oct 3, 2013 at 10:43 AM, Inki Dae <inki.dae@samsung.com> wrote: > 2013/10/2 Sean Paul <seanpaul@chromium.org>: >> This patch adds code to look for the ptn3460 in the device tree file on >> exynos initialization. If ptn node is found, the driver will initialize >> the ptn3460 driver and skip creating a DP connector (since the bridge >> driver will register its own connector). >> >> Signed-off-by: Sean Paul <seanpaul@chromium.org> >> --- >> drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++- >> 1 file changed, 43 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c >> index 1bef6dc..9cf4476 100644 >> --- a/drivers/gpu/drm/exynos/exynos_drm_core.c >> +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c >> @@ -12,7 +12,9 @@ >> * option) any later version. >> */ >> >> +#include <linux/of_i2c.h> >> #include <drm/drmP.h> >> +#include <drm/bridge/ptn3460.h> >> #include "exynos_drm_drv.h" >> #include "exynos_drm_encoder.h" >> #include "exynos_drm_connector.h" >> @@ -20,6 +22,40 @@ >> >> static LIST_HEAD(exynos_drm_subdrv_list); >> >> +struct bridge_init { >> + struct i2c_client *client; >> + struct device_node *node; >> +}; >> + >> +static bool find_bridge(const char *name, struct bridge_init *bridge) >> +{ >> + bridge->client = NULL; >> + bridge->node = of_find_node_by_name(NULL, name); > > Not clear to me. Why do you try to handle device tree here, not real > device driver?. How about adding a output property to board specific > fimd dt node: i.e. output = <&ptn3460_bridge>? The problem doing something like this is that we won't have a handle to drm_device if it's just a standalone driver, and so we won't be able to register the bridge or connector. We need this init call one way or another. > Actually, the output > device of fimd hw could be one of MIPI-DSI, eDP, mDNIe, LVDS bridge, > or LCD. And then, let's find ptn3460-bridge node in the fimd driver, > and initialize the ptn3460 bridge driver, and get power on or off > through exynos_drm_display_ops of the fimd driver. And all these > codes could be hided from fimd driver by moving them into > exynos_drm_display_ops. Of course, for this, you would need additional > works. So let's do it if needed. > > The below is the outline of device tree I recommend, > > In board dts, > i2c@I2CD000 { > ptn3460_bridge: prn3460-bridge@20 { > ... > } > } > > fimd@11c00000 { > ... > output_dev = <&ptn3460_bridge>; > } > > With this, I believe that you can do all things you want for > controlling the LVDS bridge in fimd driver. > No, this isn't what I want to do. The bridge should not hang off fimd since it's a crtc. The bridge should only be initialized by the DP driver (it doesn't make sense to initialize ptn when you're using MIPI/LVDS/whatever). Since the actual crtc/encoder drivers are abstracted through exynos_drm_core/crtc/encoder, we need to initialize the ptn driver in the abstraction layers in order to hook it directly into drm. Sean > Thanks, > Inki Dae > >> + 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("ptn3460-bridge", &bridge)) { >> + ret = ptn3460_init(dev, encoder, bridge.client, bridge.node); >> + if (!ret) >> + return 1; >> + } >> + return 0; >> +} >> + >> static int exynos_drm_create_enc_conn(struct drm_device *dev, >> struct exynos_drm_subdrv *subdrv) >> { >> @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >> DRM_ERROR("failed to create encoder\n"); >> return -EFAULT; >> } >> + subdrv->encoder = encoder; >> + >> + if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) { >> + ret = exynos_drm_attach_lcd_bridge(dev, encoder); >> + if (ret) >> + return 0; >> + } >> >> /* >> * create and initialize a connector for this sub driver and >> @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >> goto err_destroy_encoder; >> } >> >> - subdrv->encoder = encoder; >> subdrv->connector = connector; >> >> return 0; >> -- >> 1.8.4 >> >> >> _______________________________________________ >> 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] 51+ messages in thread
* Re: [PATCH 4/5] drm/exynos: Initialize ptn3460 if present 2013-10-03 15:02 ` Sean Paul @ 2013-10-03 17:18 ` Inki Dae 2013-10-03 17:27 ` Sean Paul 0 siblings, 1 reply; 51+ messages in thread From: Inki Dae @ 2013-10-03 17:18 UTC (permalink / raw) To: Sean Paul Cc: devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-doc, linux-kernel@vger.kernel.org, DRI mailing list, linux-arm-kernel@lists.infradead.org 2013/10/4 Sean Paul <seanpaul@chromium.org>: > On Thu, Oct 3, 2013 at 10:43 AM, Inki Dae <inki.dae@samsung.com> wrote: >> 2013/10/2 Sean Paul <seanpaul@chromium.org>: >>> This patch adds code to look for the ptn3460 in the device tree file on >>> exynos initialization. If ptn node is found, the driver will initialize >>> the ptn3460 driver and skip creating a DP connector (since the bridge >>> driver will register its own connector). >>> >>> Signed-off-by: Sean Paul <seanpaul@chromium.org> >>> --- >>> drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++- >>> 1 file changed, 43 insertions(+), 1 deletion(-) >>> >>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c >>> index 1bef6dc..9cf4476 100644 >>> --- a/drivers/gpu/drm/exynos/exynos_drm_core.c >>> +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c >>> @@ -12,7 +12,9 @@ >>> * option) any later version. >>> */ >>> >>> +#include <linux/of_i2c.h> >>> #include <drm/drmP.h> >>> +#include <drm/bridge/ptn3460.h> >>> #include "exynos_drm_drv.h" >>> #include "exynos_drm_encoder.h" >>> #include "exynos_drm_connector.h" >>> @@ -20,6 +22,40 @@ >>> >>> static LIST_HEAD(exynos_drm_subdrv_list); >>> >>> +struct bridge_init { >>> + struct i2c_client *client; >>> + struct device_node *node; >>> +}; >>> + >>> +static bool find_bridge(const char *name, struct bridge_init *bridge) >>> +{ >>> + bridge->client = NULL; >>> + bridge->node = of_find_node_by_name(NULL, name); >> >> Not clear to me. Why do you try to handle device tree here, not real >> device driver?. How about adding a output property to board specific >> fimd dt node: i.e. output = <&ptn3460_bridge>? > > The problem doing something like this is that we won't have a handle > to drm_device if it's just a standalone driver, and so we won't be > able to register the bridge or connector. We need this init call one > way or another. > At least, dt binding shoul be done in real device driver so this way is not good. Let's find a better way. > >> Actually, the output >> device of fimd hw could be one of MIPI-DSI, eDP, mDNIe, LVDS bridge, >> or LCD. And then, let's find ptn3460-bridge node in the fimd driver, >> and initialize the ptn3460 bridge driver, and get power on or off >> through exynos_drm_display_ops of the fimd driver. And all these >> codes could be hided from fimd driver by moving them into >> exynos_drm_display_ops. Of course, for this, you would need additional >> works. So let's do it if needed. >> >> The below is the outline of device tree I recommend, >> >> In board dts, >> i2c@I2CD000 { >> ptn3460_bridge: prn3460-bridge@20 { >> ... >> } >> } >> >> fimd@11c00000 { >> ... >> output_dev = <&ptn3460_bridge>; >> } >> >> With this, I believe that you can do all things you want for >> controlling the LVDS bridge in fimd driver. >> > > No, this isn't what I want to do. The bridge should not hang off fimd > since it's a crtc. The bridge should only be initialized by the DP > driver (it doesn't make sense to initialize ptn when you're using > MIPI/LVDS/whatever). I don't mean that the bridge device should be initialized by fimd directly but the fimd driver provides just interfaces abstracted to control the bridge device. And basically, the exynos_drm_display_ops shouldn't be in fimd driver but in real connector driver; i.e. lcd panel or LVDS driver. The reason I placed the exynos_drm_display_ops in fimd driver is that lcd panel driver is controlled by lcd class depended on Linux framebuffer, and I thought the panel driver should be shared with drm driver in case of ARM SoC. The exynos_drm_display_ops should be moved into right place if something better exists some time or other. So how can the DP driver control the bridge device as of now? the DP you mentioned would be eDP, and the eDP driver is placed in drivers/video/exynos/, and also MIPI-DSI driver. > > Since the actual crtc/encoder drivers are abstracted through > exynos_drm_core/crtc/encoder, we need to initialize the ptn driver in > the abstraction layers in order to hook it directly into drm. > > Sean > > >> Thanks, >> Inki Dae >> >>> + 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("ptn3460-bridge", &bridge)) { >>> + ret = ptn3460_init(dev, encoder, bridge.client, bridge.node); >>> + if (!ret) >>> + return 1; >>> + } >>> + return 0; >>> +} >>> + >>> static int exynos_drm_create_enc_conn(struct drm_device *dev, >>> struct exynos_drm_subdrv *subdrv) >>> { >>> @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >>> DRM_ERROR("failed to create encoder\n"); >>> return -EFAULT; >>> } >>> + subdrv->encoder = encoder; >>> + >>> + if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) { >>> + ret = exynos_drm_attach_lcd_bridge(dev, encoder); >>> + if (ret) >>> + return 0; >>> + } >>> >>> /* >>> * create and initialize a connector for this sub driver and >>> @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >>> goto err_destroy_encoder; >>> } >>> >>> - subdrv->encoder = encoder; >>> subdrv->connector = connector; >>> >>> return 0; >>> -- >>> 1.8.4 >>> >>> >>> _______________________________________________ >>> 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] 51+ messages in thread
* Re: [PATCH 4/5] drm/exynos: Initialize ptn3460 if present 2013-10-03 17:18 ` Inki Dae @ 2013-10-03 17:27 ` Sean Paul 2013-10-03 18:10 ` Inki Dae 0 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-03 17:27 UTC (permalink / raw) To: Inki Dae Cc: devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, DRI mailing list, linux-arm-kernel@lists.infradead.org On Thu, Oct 3, 2013 at 1:18 PM, Inki Dae <inki.dae@samsung.com> wrote: > 2013/10/4 Sean Paul <seanpaul@chromium.org>: >> On Thu, Oct 3, 2013 at 10:43 AM, Inki Dae <inki.dae@samsung.com> wrote: >>> 2013/10/2 Sean Paul <seanpaul@chromium.org>: >>>> This patch adds code to look for the ptn3460 in the device tree file on >>>> exynos initialization. If ptn node is found, the driver will initialize >>>> the ptn3460 driver and skip creating a DP connector (since the bridge >>>> driver will register its own connector). >>>> >>>> Signed-off-by: Sean Paul <seanpaul@chromium.org> >>>> --- >>>> drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++- >>>> 1 file changed, 43 insertions(+), 1 deletion(-) >>>> >>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c >>>> index 1bef6dc..9cf4476 100644 >>>> --- a/drivers/gpu/drm/exynos/exynos_drm_core.c >>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c >>>> @@ -12,7 +12,9 @@ >>>> * option) any later version. >>>> */ >>>> >>>> +#include <linux/of_i2c.h> >>>> #include <drm/drmP.h> >>>> +#include <drm/bridge/ptn3460.h> >>>> #include "exynos_drm_drv.h" >>>> #include "exynos_drm_encoder.h" >>>> #include "exynos_drm_connector.h" >>>> @@ -20,6 +22,40 @@ >>>> >>>> static LIST_HEAD(exynos_drm_subdrv_list); >>>> >>>> +struct bridge_init { >>>> + struct i2c_client *client; >>>> + struct device_node *node; >>>> +}; >>>> + >>>> +static bool find_bridge(const char *name, struct bridge_init *bridge) >>>> +{ >>>> + bridge->client = NULL; >>>> + bridge->node = of_find_node_by_name(NULL, name); >>> >>> Not clear to me. Why do you try to handle device tree here, not real >>> device driver?. How about adding a output property to board specific >>> fimd dt node: i.e. output = <&ptn3460_bridge>? >> >> The problem doing something like this is that we won't have a handle >> to drm_device if it's just a standalone driver, and so we won't be >> able to register the bridge or connector. We need this init call one >> way or another. >> > > At least, dt binding shoul be done in real device driver so this way > is not good. Let's find a better way. > Right, so this is kind of tricky. If you do it in a "real" device driver, you end up parsing the dt stuff in the probe, and then racing the init callback. I figured it would be best just to do everything in one place without races. Hopefully I'm just missing a good way to solve this problem, any concrete ideas? >> >>> Actually, the output >>> device of fimd hw could be one of MIPI-DSI, eDP, mDNIe, LVDS bridge, >>> or LCD. And then, let's find ptn3460-bridge node in the fimd driver, >>> and initialize the ptn3460 bridge driver, and get power on or off >>> through exynos_drm_display_ops of the fimd driver. And all these >>> codes could be hided from fimd driver by moving them into >>> exynos_drm_display_ops. Of course, for this, you would need additional >>> works. So let's do it if needed. >>> >>> The below is the outline of device tree I recommend, >>> >>> In board dts, >>> i2c@I2CD000 { >>> ptn3460_bridge: prn3460-bridge@20 { >>> ... >>> } >>> } >>> >>> fimd@11c00000 { >>> ... >>> output_dev = <&ptn3460_bridge>; >>> } >>> >>> With this, I believe that you can do all things you want for >>> controlling the LVDS bridge in fimd driver. >>> >> >> No, this isn't what I want to do. The bridge should not hang off fimd >> since it's a crtc. The bridge should only be initialized by the DP >> driver (it doesn't make sense to initialize ptn when you're using >> MIPI/LVDS/whatever). > > I don't mean that the bridge device should be initialized by fimd > directly but the fimd driver provides just interfaces abstracted to > control the bridge device. And basically, the exynos_drm_display_ops > shouldn't be in fimd driver but in real connector driver; i.e. lcd > panel or LVDS driver. The reason I placed the exynos_drm_display_ops > in fimd driver is that lcd panel driver is controlled by lcd class > depended on Linux framebuffer, and I thought the panel driver should > be shared with drm driver in case of ARM SoC. The > exynos_drm_display_ops should be moved into right place if something > better exists some time or other. > > So how can the DP driver control the bridge device as of now? the DP > you mentioned would be eDP, and the eDP driver is placed in > drivers/video/exynos/, and also MIPI-DSI driver. > It can't. The DP driver just operates on its own and display either comes up or it doesn't depending on whether fimd happens to be initialized first. As I mentioned earlier, I have a patch set which moves DP driver into drm/exynos and removes the display_ops from fimd. That will fix this issue. Sean >> >> Since the actual crtc/encoder drivers are abstracted through >> exynos_drm_core/crtc/encoder, we need to initialize the ptn driver in >> the abstraction layers in order to hook it directly into drm. >> >> Sean >> >> >>> Thanks, >>> Inki Dae >>> >>>> + 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("ptn3460-bridge", &bridge)) { >>>> + ret = ptn3460_init(dev, encoder, bridge.client, bridge.node); >>>> + if (!ret) >>>> + return 1; >>>> + } >>>> + return 0; >>>> +} >>>> + >>>> static int exynos_drm_create_enc_conn(struct drm_device *dev, >>>> struct exynos_drm_subdrv *subdrv) >>>> { >>>> @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >>>> DRM_ERROR("failed to create encoder\n"); >>>> return -EFAULT; >>>> } >>>> + subdrv->encoder = encoder; >>>> + >>>> + if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) { >>>> + ret = exynos_drm_attach_lcd_bridge(dev, encoder); >>>> + if (ret) >>>> + return 0; >>>> + } >>>> >>>> /* >>>> * create and initialize a connector for this sub driver and >>>> @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >>>> goto err_destroy_encoder; >>>> } >>>> >>>> - subdrv->encoder = encoder; >>>> subdrv->connector = connector; >>>> >>>> return 0; >>>> -- >>>> 1.8.4 >>>> >>>> >>>> _______________________________________________ >>>> 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] 51+ messages in thread
* Re: [PATCH 4/5] drm/exynos: Initialize ptn3460 if present 2013-10-03 17:27 ` Sean Paul @ 2013-10-03 18:10 ` Inki Dae 0 siblings, 0 replies; 51+ messages in thread From: Inki Dae @ 2013-10-03 18:10 UTC (permalink / raw) To: Sean Paul Cc: devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, DRI mailing list, linux-arm-kernel@lists.infradead.org 2013/10/4 Sean Paul <seanpaul@chromium.org>: > On Thu, Oct 3, 2013 at 1:18 PM, Inki Dae <inki.dae@samsung.com> wrote: >> 2013/10/4 Sean Paul <seanpaul@chromium.org>: >>> On Thu, Oct 3, 2013 at 10:43 AM, Inki Dae <inki.dae@samsung.com> wrote: >>>> 2013/10/2 Sean Paul <seanpaul@chromium.org>: >>>>> This patch adds code to look for the ptn3460 in the device tree file on >>>>> exynos initialization. If ptn node is found, the driver will initialize >>>>> the ptn3460 driver and skip creating a DP connector (since the bridge >>>>> driver will register its own connector). >>>>> >>>>> Signed-off-by: Sean Paul <seanpaul@chromium.org> >>>>> --- >>>>> drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++- >>>>> 1 file changed, 43 insertions(+), 1 deletion(-) >>>>> >>>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c >>>>> index 1bef6dc..9cf4476 100644 >>>>> --- a/drivers/gpu/drm/exynos/exynos_drm_core.c >>>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c >>>>> @@ -12,7 +12,9 @@ >>>>> * option) any later version. >>>>> */ >>>>> >>>>> +#include <linux/of_i2c.h> >>>>> #include <drm/drmP.h> >>>>> +#include <drm/bridge/ptn3460.h> >>>>> #include "exynos_drm_drv.h" >>>>> #include "exynos_drm_encoder.h" >>>>> #include "exynos_drm_connector.h" >>>>> @@ -20,6 +22,40 @@ >>>>> >>>>> static LIST_HEAD(exynos_drm_subdrv_list); >>>>> >>>>> +struct bridge_init { >>>>> + struct i2c_client *client; >>>>> + struct device_node *node; >>>>> +}; >>>>> + >>>>> +static bool find_bridge(const char *name, struct bridge_init *bridge) >>>>> +{ >>>>> + bridge->client = NULL; >>>>> + bridge->node = of_find_node_by_name(NULL, name); >>>> >>>> Not clear to me. Why do you try to handle device tree here, not real >>>> device driver?. How about adding a output property to board specific >>>> fimd dt node: i.e. output = <&ptn3460_bridge>? >>> >>> The problem doing something like this is that we won't have a handle >>> to drm_device if it's just a standalone driver, and so we won't be >>> able to register the bridge or connector. We need this init call one >>> way or another. >>> >> >> At least, dt binding shoul be done in real device driver so this way >> is not good. Let's find a better way. >> > > Right, so this is kind of tricky. If you do it in a "real" device > driver, you end up parsing the dt stuff in the probe, and then racing > the init callback. I figured it would be best just to do everything in > one place without races. > > Hopefully I'm just missing a good way to solve this problem, any concrete ideas? > >>> >>>> Actually, the output >>>> device of fimd hw could be one of MIPI-DSI, eDP, mDNIe, LVDS bridge, >>>> or LCD. And then, let's find ptn3460-bridge node in the fimd driver, >>>> and initialize the ptn3460 bridge driver, and get power on or off >>>> through exynos_drm_display_ops of the fimd driver. And all these >>>> codes could be hided from fimd driver by moving them into >>>> exynos_drm_display_ops. Of course, for this, you would need additional >>>> works. So let's do it if needed. >>>> >>>> The below is the outline of device tree I recommend, >>>> >>>> In board dts, >>>> i2c@I2CD000 { >>>> ptn3460_bridge: prn3460-bridge@20 { >>>> ... >>>> } >>>> } >>>> >>>> fimd@11c00000 { >>>> ... >>>> output_dev = <&ptn3460_bridge>; >>>> } >>>> >>>> With this, I believe that you can do all things you want for >>>> controlling the LVDS bridge in fimd driver. >>>> >>> >>> No, this isn't what I want to do. The bridge should not hang off fimd >>> since it's a crtc. The bridge should only be initialized by the DP >>> driver (it doesn't make sense to initialize ptn when you're using >>> MIPI/LVDS/whatever). >> >> I don't mean that the bridge device should be initialized by fimd >> directly but the fimd driver provides just interfaces abstracted to >> control the bridge device. And basically, the exynos_drm_display_ops >> shouldn't be in fimd driver but in real connector driver; i.e. lcd >> panel or LVDS driver. The reason I placed the exynos_drm_display_ops >> in fimd driver is that lcd panel driver is controlled by lcd class >> depended on Linux framebuffer, and I thought the panel driver should >> be shared with drm driver in case of ARM SoC. The >> exynos_drm_display_ops should be moved into right place if something >> better exists some time or other. >> >> So how can the DP driver control the bridge device as of now? the DP >> you mentioned would be eDP, and the eDP driver is placed in >> drivers/video/exynos/, and also MIPI-DSI driver. >> > > It can't. The DP driver just operates on its own and display either > comes up or it doesn't depending on whether fimd happens to be > initialized first. Ok, I don't know the DP hardware well. But, MIPI-DSI driver is depending on fimd on/off ordering. ie. to enable display hw pipe, the ordering should be FIMD----MIPI-DSI-----LCD because initial commands _cannot be set_ to lcd panel if fimd is off. And to disable that, the ordering should be LCD-------MIPI-DSI-------FIMD in same reason: to get lcd panel off, off commands should be set to lcd panel. In similar reason, I had posted FB_EARLY_EVENT_BLANK feature to mainline and that have been merged. > As I mentioned earlier, I have a patch set which > moves DP driver into drm/exynos and removes the display_ops from fimd. > That will fix this issue. Ah... as you may know I mentioned about this issue some time ago; moving eDP driver(maybe??) into drm/exynos. At that time, I had rejected it because I thought we should share these bus drivers with Linux framebuffer driver: actually, I planned to use CDF for this. But.... I'm not sure even CDF as of now. So let's have a discussion about this issue with other people: it doesn't mean I oppose your patch set. > > Sean > > >>> >>> Since the actual crtc/encoder drivers are abstracted through >>> exynos_drm_core/crtc/encoder, we need to initialize the ptn driver in >>> the abstraction layers in order to hook it directly into drm. >>> >>> Sean >>> >>> >>>> Thanks, >>>> Inki Dae >>>> >>>>> + 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("ptn3460-bridge", &bridge)) { >>>>> + ret = ptn3460_init(dev, encoder, bridge.client, bridge.node); >>>>> + if (!ret) >>>>> + return 1; >>>>> + } >>>>> + return 0; >>>>> +} >>>>> + >>>>> static int exynos_drm_create_enc_conn(struct drm_device *dev, >>>>> struct exynos_drm_subdrv *subdrv) >>>>> { >>>>> @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >>>>> DRM_ERROR("failed to create encoder\n"); >>>>> return -EFAULT; >>>>> } >>>>> + subdrv->encoder = encoder; >>>>> + >>>>> + if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) { >>>>> + ret = exynos_drm_attach_lcd_bridge(dev, encoder); >>>>> + if (ret) >>>>> + return 0; >>>>> + } >>>>> >>>>> /* >>>>> * create and initialize a connector for this sub driver and >>>>> @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >>>>> goto err_destroy_encoder; >>>>> } >>>>> >>>>> - subdrv->encoder = encoder; >>>>> subdrv->connector = connector; >>>>> >>>>> return 0; >>>>> -- >>>>> 1.8.4 >>>>> >>>>> >>>>> _______________________________________________ >>>>> 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 > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH 5/5] ARM: dts: Add ptn3460 to exynos5250-snow 2013-10-01 23:40 [PATCH 0/5] Add some missing bits for exynos5250-snow Sean Paul ` (2 preceding siblings ...) 2013-10-01 23:40 ` [PATCH 4/5] drm/exynos: Initialize ptn3460 if present Sean Paul @ 2013-10-01 23:41 ` Sean Paul [not found] ` <1380670860-17621-1-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 4 siblings, 0 replies; 51+ messages in thread From: Sean Paul @ 2013-10-01 23:41 UTC (permalink / raw) To: dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds a node for the ptn3460 DP-LVDS chip in the exynos5250-snow board dts file. Signed-off-by: Sean Paul <seanpaul@chromium.org> --- arch/arm/boot/dts/exynos5250-snow.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index 780511a..122fc1f 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -33,6 +33,13 @@ sd3_bus4: sd3-bus-width4 { samsung,pin-drv = <0>; }; + + ptn3460_gpios: ptn3460-gpios { + samsung,pins = "gpy2-5", "gpx1-5"; + samsung,pin-function = <1>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; }; gpio-keys { @@ -190,6 +197,18 @@ samsung,vbus-gpio = <&gpx1 1 0>; }; + i2c@12CD0000 { + ptn3460-bridge@20 { + compatible = "nxp,ptn3460"; + reg = <0x20>; + powerdown-gpio = <&gpy2 5 0>; + reset-gpio = <&gpx1 5 0>; + edid-emulation = <5>; + pinctrl-names = "default"; + pinctrl-0 = <&ptn3460_gpios>; + }; + }; + dp-controller { samsung,color-space = <0>; samsung,dynamic-range = <0>; -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
[parent not found: <1380670860-17621-1-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>]
* [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver [not found] ` <1380670860-17621-1-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> @ 2013-10-01 23:40 ` Sean Paul 2013-10-02 21:20 ` Olof Johansson 2013-10-03 13:55 ` Inki Dae 2013-10-02 21:07 ` [PATCH 0/5] Add some missing bits for exynos5250-snow Olof Johansson 2013-10-03 22:28 ` [PATCH v2 " Sean Paul 2 siblings, 2 replies; 51+ messages in thread From: Sean Paul @ 2013-10-01 23:40 UTC (permalink / raw) To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-doc-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, inki.dae-Sze3O3UU22JBDgjK7y7TUQ Cc: airlied-cv59FeDIM0c, Sean Paul This patch adds a drm_bridge driver for the PTN3460 DisplayPort to LVDS bridge chip. Signed-off-by: Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> --- .../devicetree/bindings/drm/bridge/ptn3460.txt | 27 ++ drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/bridge/Kconfig | 4 + drivers/gpu/drm/bridge/Makefile | 3 + drivers/gpu/drm/bridge/ptn3460.c | 349 +++++++++++++++++++++ include/drm/bridge/ptn3460.h | 36 +++ 7 files changed, 422 insertions(+) create mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt create mode 100644 drivers/gpu/drm/bridge/Kconfig create mode 100644 drivers/gpu/drm/bridge/Makefile create mode 100644 drivers/gpu/drm/bridge/ptn3460.c create mode 100644 include/drm/bridge/ptn3460.h diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt new file mode 100644 index 0000000..c1cd329 --- /dev/null +++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt @@ -0,0 +1,27 @@ +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 | + +-------+------------+------------------+ + +Example: + ptn3460-bridge@20 { + compatible = "nxp,ptn3460"; + reg = <0x20>; + powerdown-gpio = <&gpy2 5 1 0 0>; + reset-gpio = <&gpx1 5 1 0 0>; + edid-emulation = <5>; + }; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 955555d..cd7bfb3 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -236,3 +236,5 @@ source "drivers/gpu/drm/tilcdc/Kconfig" source "drivers/gpu/drm/qxl/Kconfig" source "drivers/gpu/drm/msm/Kconfig" + +source "drivers/gpu/drm/bridge/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index f089adf..9234253 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -56,3 +56,4 @@ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ obj-$(CONFIG_DRM_QXL) += qxl/ obj-$(CONFIG_DRM_MSM) += msm/ obj-y += i2c/ +obj-y += bridge/ diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig new file mode 100644 index 0000000..f8db069 --- /dev/null +++ b/drivers/gpu/drm/bridge/Kconfig @@ -0,0 +1,4 @@ +config DRM_PTN3460 + tristate "PTN3460 DP/LVDS bridge" + depends on DRM && I2C + ---help--- diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile new file mode 100644 index 0000000..b4733e1 --- /dev/null +++ b/drivers/gpu/drm/bridge/Makefile @@ -0,0 +1,3 @@ +ccflags-y := -Iinclude/drm + +obj-$(CONFIG_DRM_PTN3460) += ptn3460.o diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c new file mode 100644 index 0000000..a9e5c1a --- /dev/null +++ b/drivers/gpu/drm/bridge/ptn3460.c @@ -0,0 +1,349 @@ +/* + * NXP PTN3460 DP/LVDS bridge driver + * + * Copyright (C) 2013 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/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 "drm_crtc.h" +#include "drm_crtc_helper.h" + +#include "bridge/ptn3460.h" + +#define PTN3460_EDID_ADDR 0x0 +#define PTN3460_EDID_EMULATION_ADDR 0x84 +#define PTN3460_EDID_ENABLE_EMULATION 0 +#define PTN3460_EDID_EMULATION_SELECTION 1 +#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85 + +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; + int gpio_rst_n; + u32 edid_emulation; + bool enabled; +}; + +static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, + u8 *buf, int len) +{ + int ret; + + ret = i2c_master_send(ptn_bridge->client, &addr, 1); + if (ret <= 0) { + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); + return ret; + } + + ret = i2c_master_recv(ptn_bridge->client, buf, len); + if (ret <= 0) { + DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, + char val) +{ + int ret; + char buf[2]; + + buf[0] = addr; + buf[1] = val; + + ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); + if (ret <= 0) { + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) +{ + int ret; + char val; + + /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */ + 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); + return ret; + } + + /* Enable EDID emulation and select the desired EDID */ + val = 1 << PTN3460_EDID_ENABLE_EMULATION | + ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION; + + ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); + if (ret) { + DRM_ERROR("Failed to write edid value, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static void ptn3460_pre_enable(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + int ret; + + if (ptn_bridge->enabled) + return; + + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) + gpio_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); + udelay(10); + gpio_set_value(ptn_bridge->gpio_rst_n, 1); + } + + /* + * 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 + * time specified in the chip's datasheet to make sure we're really up. + */ + msleep(90); + + ret = ptn3460_select_edid(ptn_bridge); + if (ret) + DRM_ERROR("Select edid failed ret=%d\n", ret); + + ptn_bridge->enabled = true; +} + +static void ptn3460_enable(struct drm_bridge *bridge) +{ +} + +static void ptn3460_disable(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + + if (!ptn_bridge->enabled) + return; + + ptn_bridge->enabled = false; + + 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); +} + +static void ptn3460_post_disable(struct drm_bridge *bridge) +{ +} + +void ptn3460_bridge_destroy(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + + 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 */ +} + +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, +}; + +int ptn3460_get_modes(struct drm_connector *connector) +{ + struct ptn3460_bridge *ptn_bridge; + u8 *edid; + int ret, num_modes; + bool power_off; + + ptn_bridge = container_of(connector, struct ptn3460_bridge, 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); + + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!edid) { + DRM_ERROR("Failed to allocate edid\n"); + return 0; + } + + ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, + EDID_LENGTH); + if (ret) { + kfree(edid); + num_modes = 0; + goto out; + } + + ptn_bridge->edid = (struct edid *)edid; + drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); + + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); + +out: + if (power_off) + ptn3460_disable(ptn_bridge->bridge); + + return num_modes; +} + +static int ptn3460_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) +{ + struct ptn3460_bridge *ptn_bridge; + + ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); + + return ptn_bridge->encoder; +} + +struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { + .get_modes = ptn3460_get_modes, + .mode_valid = ptn3460_mode_valid, + .best_encoder = ptn3460_best_encoder, +}; + +enum drm_connector_status ptn3460_detect(struct drm_connector *connector, + bool force) +{ + return connector_status_connected; +} + +void ptn3460_connector_destroy(struct drm_connector *connector) +{ + drm_connector_cleanup(connector); +} + +struct drm_connector_funcs ptn3460_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = ptn3460_detect, + .destroy = ptn3460_connector_destroy, +}; + +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); + return ret; + } + } + + ptn_bridge->gpio_rst_n = of_get_named_gpio(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) { + DRM_ERROR("Request reset-gpio failed (%d)\n", ret); + gpio_free(ptn_bridge->gpio_pd_n); + return ret; + } + } + + ret = of_property_read_u32(node, "edid-emulation", + &ptn_bridge->edid_emulation); + if (ret) { + DRM_ERROR("Can't read edid emulation value\n"); + goto err; + } + + ret = drm_bridge_init(dev, 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; + + 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_sysfs_connector_add(&ptn_bridge->connector); + drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); + + 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; +} diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h new file mode 100644 index 0000000..157ffa1 --- /dev/null +++ b/include/drm/bridge/ptn3460.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef _DRM_BRIDGE_PTN3460_H_ +#define _DRM_BRIDGE_PTN3460_H_ + +struct drm_device; +struct drm_encoder; +struct i2c_client; +struct device_node; + +#ifdef CONFIG_DRM_PTN3460 + +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, + struct i2c_client *client, struct device_node *node); +#else + +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, + struct i2c_client *client, struct device_node *node) +{ + return 0; +} + +#endif + +#endif -- 1.8.4 -- 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] 51+ messages in thread
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-01 23:40 ` [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver Sean Paul @ 2013-10-02 21:20 ` Olof Johansson 2013-10-03 13:55 ` Inki Dae 1 sibling, 0 replies; 51+ messages in thread From: Olof Johansson @ 2013-10-02 21:20 UTC (permalink / raw) To: Sean Paul Cc: dri-devel, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Inki Dae, airlied Hi, On Tue, Oct 1, 2013 at 4:40 PM, Sean Paul <seanpaul@chromium.org> wrote: > This patch adds a drm_bridge driver for the PTN3460 DisplayPort to LVDS > bridge chip. > > Signed-off-by: Sean Paul <seanpaul@chromium.org> > --- [...] > +Example: > + ptn3460-bridge@20 { Nit: Name is usually generic device name, i.e. "lvds-bridge" or something like that. > + compatible = "nxp,ptn3460"; > + reg = <0x20>; > + powerdown-gpio = <&gpy2 5 1 0 0>; > + reset-gpio = <&gpx1 5 1 0 0>; > + edid-emulation = <5>; > + }; [...] > diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h > new file mode 100644 > index 0000000..157ffa1 > --- /dev/null > +++ b/include/drm/bridge/ptn3460.h > @@ -0,0 +1,36 @@ > +/* > + * Copyright (C) 2013 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. > + */ > + > +#ifndef _DRM_BRIDGE_PTN3460_H_ > +#define _DRM_BRIDGE_PTN3460_H_ > + > +struct drm_device; > +struct drm_encoder; > +struct i2c_client; > +struct device_node; > + > +#ifdef CONFIG_DRM_PTN3460 > + > +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, > + struct i2c_client *client, struct device_node *node); > +#else > + > +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, > + struct i2c_client *client, struct device_node *node) This should be static inline int ptn3460_init(...) > +{ > + return 0; > +} -0Olof ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-01 23:40 ` [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver Sean Paul 2013-10-02 21:20 ` Olof Johansson @ 2013-10-03 13:55 ` Inki Dae [not found] ` <CAAQKjZN_r-=-sj=Vb-o-KUS4ab5=cjCq1ni3VZeMeVc3NL=MMg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 1 sibling, 1 reply; 51+ messages in thread From: Inki Dae @ 2013-10-03 13:55 UTC (permalink / raw) To: Sean Paul Cc: DRI mailing list, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-doc, devicetree@vger.kernel.org, Dave Airlie Hi, thank you for your contribution and the below is my short comments, 2013/10/2 Sean Paul <seanpaul@chromium.org>: > This patch adds a drm_bridge driver for the PTN3460 DisplayPort to LVDS > bridge chip. > > Signed-off-by: Sean Paul <seanpaul@chromium.org> > --- > .../devicetree/bindings/drm/bridge/ptn3460.txt | 27 ++ > drivers/gpu/drm/Kconfig | 2 + > drivers/gpu/drm/Makefile | 1 + > drivers/gpu/drm/bridge/Kconfig | 4 + > drivers/gpu/drm/bridge/Makefile | 3 + > drivers/gpu/drm/bridge/ptn3460.c | 349 +++++++++++++++++++++ > include/drm/bridge/ptn3460.h | 36 +++ > 7 files changed, 422 insertions(+) > create mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt > create mode 100644 drivers/gpu/drm/bridge/Kconfig > create mode 100644 drivers/gpu/drm/bridge/Makefile > create mode 100644 drivers/gpu/drm/bridge/ptn3460.c > create mode 100644 include/drm/bridge/ptn3460.h > > diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt > new file mode 100644 > index 0000000..c1cd329 > --- /dev/null > +++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt > @@ -0,0 +1,27 @@ > +ptn3460-bridge bindings > + > +Required properties: > + - compatible: "nxp,ptn3460" > + - reg: i2c address of the bridge > + - powerdown-gpio: OF device-tree gpio specification Can a regulator be used instead of gpio in other board case? > + - 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 | > + +-------+------------+------------------+ > + > +Example: > + ptn3460-bridge@20 { > + compatible = "nxp,ptn3460"; > + reg = <0x20>; > + powerdown-gpio = <&gpy2 5 1 0 0>; > + reset-gpio = <&gpx1 5 1 0 0>; > + edid-emulation = <5>; > + }; > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig > index 955555d..cd7bfb3 100644 > --- a/drivers/gpu/drm/Kconfig > +++ b/drivers/gpu/drm/Kconfig > @@ -236,3 +236,5 @@ source "drivers/gpu/drm/tilcdc/Kconfig" > source "drivers/gpu/drm/qxl/Kconfig" > > source "drivers/gpu/drm/msm/Kconfig" > + > +source "drivers/gpu/drm/bridge/Kconfig" > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile > index f089adf..9234253 100644 > --- a/drivers/gpu/drm/Makefile > +++ b/drivers/gpu/drm/Makefile > @@ -56,3 +56,4 @@ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ > obj-$(CONFIG_DRM_QXL) += qxl/ > obj-$(CONFIG_DRM_MSM) += msm/ > obj-y += i2c/ > +obj-y += bridge/ > diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig > new file mode 100644 > index 0000000..f8db069 > --- /dev/null > +++ b/drivers/gpu/drm/bridge/Kconfig > @@ -0,0 +1,4 @@ > +config DRM_PTN3460 > + tristate "PTN3460 DP/LVDS bridge" > + depends on DRM && I2C > + ---help--- > diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile > new file mode 100644 > index 0000000..b4733e1 > --- /dev/null > +++ b/drivers/gpu/drm/bridge/Makefile > @@ -0,0 +1,3 @@ > +ccflags-y := -Iinclude/drm > + > +obj-$(CONFIG_DRM_PTN3460) += ptn3460.o > diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c > new file mode 100644 > index 0000000..a9e5c1a > --- /dev/null > +++ b/drivers/gpu/drm/bridge/ptn3460.c > @@ -0,0 +1,349 @@ > +/* > + * NXP PTN3460 DP/LVDS bridge driver > + * > + * Copyright (C) 2013 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/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 "drm_crtc.h" > +#include "drm_crtc_helper.h" > + > +#include "bridge/ptn3460.h" > + > +#define PTN3460_EDID_ADDR 0x0 > +#define PTN3460_EDID_EMULATION_ADDR 0x84 > +#define PTN3460_EDID_ENABLE_EMULATION 0 > +#define PTN3460_EDID_EMULATION_SELECTION 1 > +#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85 > + > +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; > + int gpio_rst_n; > + u32 edid_emulation; > + bool enabled; > +}; > + > +static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, > + u8 *buf, int len) > +{ > + int ret; > + > + ret = i2c_master_send(ptn_bridge->client, &addr, 1); > + if (ret <= 0) { > + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); > + return ret; > + } > + > + ret = i2c_master_recv(ptn_bridge->client, buf, len); > + if (ret <= 0) { > + DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, > + char val) > +{ > + int ret; > + char buf[2]; > + > + buf[0] = addr; > + buf[1] = val; > + > + ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); > + if (ret <= 0) { > + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) > +{ > + int ret; > + char val; > + > + /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */ > + 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); > + return ret; > + } > + > + /* Enable EDID emulation and select the desired EDID */ > + val = 1 << PTN3460_EDID_ENABLE_EMULATION | > + ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION; > + > + ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); > + if (ret) { > + DRM_ERROR("Failed to write edid value, ret=%d\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +static void ptn3460_pre_enable(struct drm_bridge *bridge) > +{ > + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; > + int ret; > + > + if (ptn_bridge->enabled) > + return; > + > + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) > + gpio_set_value(ptn_bridge->gpio_pd_n, 1); Ditto. > + > + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { > + gpio_set_value(ptn_bridge->gpio_rst_n, 0); > + udelay(10); > + gpio_set_value(ptn_bridge->gpio_rst_n, 1); > + } > + > + /* > + * 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 > + * time specified in the chip's datasheet to make sure we're really up. > + */ > + msleep(90); > + > + ret = ptn3460_select_edid(ptn_bridge); > + if (ret) > + DRM_ERROR("Select edid failed ret=%d\n", ret); > + > + ptn_bridge->enabled = true; > +} > + > +static void ptn3460_enable(struct drm_bridge *bridge) > +{ > +} > + > +static void ptn3460_disable(struct drm_bridge *bridge) > +{ > + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; > + > + if (!ptn_bridge->enabled) > + return; > + > + ptn_bridge->enabled = false; > + > + 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); Ditto. > +} > + > +static void ptn3460_post_disable(struct drm_bridge *bridge) > +{ > +} > + > +void ptn3460_bridge_destroy(struct drm_bridge *bridge) > +{ > + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; > + > + drm_bridge_cleanup(bridge); > + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) > + gpio_free(ptn_bridge->gpio_pd_n); Ditto. > + 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 */ > +} > + > +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, > +}; > + > +int ptn3460_get_modes(struct drm_connector *connector) > +{ > + struct ptn3460_bridge *ptn_bridge; > + u8 *edid; > + int ret, num_modes; > + bool power_off; > + > + ptn_bridge = container_of(connector, struct ptn3460_bridge, 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); > + > + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); > + if (!edid) { > + DRM_ERROR("Failed to allocate edid\n"); > + return 0; > + } > + > + ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, > + EDID_LENGTH); > + if (ret) { > + kfree(edid); > + num_modes = 0; > + goto out; > + } > + > + ptn_bridge->edid = (struct edid *)edid; > + drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); > + > + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); > + > +out: > + if (power_off) > + ptn3460_disable(ptn_bridge->bridge); > + > + return num_modes; > +} > + > +static int ptn3460_mode_valid(struct drm_connector *connector, > + struct drm_display_mode *mode) > +{ > + return MODE_OK; > +} > + > +struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) > +{ > + struct ptn3460_bridge *ptn_bridge; > + > + ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); > + > + return ptn_bridge->encoder; > +} > + > +struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { > + .get_modes = ptn3460_get_modes, > + .mode_valid = ptn3460_mode_valid, > + .best_encoder = ptn3460_best_encoder, > +}; > + > +enum drm_connector_status ptn3460_detect(struct drm_connector *connector, > + bool force) > +{ > + return connector_status_connected; > +} > + > +void ptn3460_connector_destroy(struct drm_connector *connector) > +{ > + drm_connector_cleanup(connector); > +} > + > +struct drm_connector_funcs ptn3460_connector_funcs = { > + .dpms = drm_helper_connector_dpms, > + .fill_modes = drm_helper_probe_single_connector_modes, > + .detect = ptn3460_detect, > + .destroy = ptn3460_connector_destroy, > +}; Why do you try to add a new connector here? We already have the connector for LCD, and also provides some callbacks for it. For this, please see exynos_drm_display_ops of exynos_drm_fimd driver, and you can add new callbacks to there such as init callback for bridge device initialization if needed. > + > +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); Also, if a regulator is used instead? > + 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); > + return ret; > + } > + } > + > + ptn_bridge->gpio_rst_n = of_get_named_gpio(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) { > + DRM_ERROR("Request reset-gpio failed (%d)\n", ret); > + gpio_free(ptn_bridge->gpio_pd_n); > + return ret; > + } > + } > + > + ret = of_property_read_u32(node, "edid-emulation", > + &ptn_bridge->edid_emulation); > + if (ret) { > + DRM_ERROR("Can't read edid emulation value\n"); > + goto err; > + } > + > + ret = drm_bridge_init(dev, 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; > + > + ret = drm_connector_init(dev, &ptn_bridge->connector, > + &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); So it seems that here's not right place to call drm_connector_init function. Display pipeline path could be one of, Display Controller Display bus --------------------------------------------------------------------------- FIMD---------------------LVDS--------------------LCD, or FIMD----------------------eDP---------------------LCD, or FIMD------------------MIPI-DSI------------------LCD, or FIMD-------------------------------------------------LCD And also in case using image enhancement chip, mDNIe-------------FIMD-LITE between Display Controller and Display bus. So, wouldn't the right place below FIMD driver? :) > + 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_sysfs_connector_add(&ptn_bridge->connector); > + drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); > + > + 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; > +} > diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h > new file mode 100644 > index 0000000..157ffa1 > --- /dev/null > +++ b/include/drm/bridge/ptn3460.h > @@ -0,0 +1,36 @@ > +/* > + * Copyright (C) 2013 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. > + */ > + > +#ifndef _DRM_BRIDGE_PTN3460_H_ > +#define _DRM_BRIDGE_PTN3460_H_ > + > +struct drm_device; > +struct drm_encoder; > +struct i2c_client; > +struct device_node; > + > +#ifdef CONFIG_DRM_PTN3460 > + > +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, > + struct i2c_client *client, struct device_node *node); > +#else > + > +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, > + struct i2c_client *client, struct device_node *node) > +{ > + return 0; > +} > + > +#endif > + > +#endif > -- > 1.8.4 > > > _______________________________________________ > 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] 51+ messages in thread
[parent not found: <CAAQKjZN_r-=-sj=Vb-o-KUS4ab5=cjCq1ni3VZeMeVc3NL=MMg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver [not found] ` <CAAQKjZN_r-=-sj=Vb-o-KUS4ab5=cjCq1ni3VZeMeVc3NL=MMg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2013-10-03 14:57 ` Sean Paul 2013-10-03 17:39 ` Inki Dae 0 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-03 14:57 UTC (permalink / raw) To: Inki Dae Cc: DRI mailing list, linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-doc-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Dave Airlie On Thu, Oct 3, 2013 at 9:55 AM, Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote: > Hi, thank you for your contribution and the below is my short comments, > > 2013/10/2 Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>: >> This patch adds a drm_bridge driver for the PTN3460 DisplayPort to LVDS >> bridge chip. >> >> Signed-off-by: Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> >> --- >> .../devicetree/bindings/drm/bridge/ptn3460.txt | 27 ++ >> drivers/gpu/drm/Kconfig | 2 + >> drivers/gpu/drm/Makefile | 1 + >> drivers/gpu/drm/bridge/Kconfig | 4 + >> drivers/gpu/drm/bridge/Makefile | 3 + >> drivers/gpu/drm/bridge/ptn3460.c | 349 +++++++++++++++++++++ >> include/drm/bridge/ptn3460.h | 36 +++ >> 7 files changed, 422 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >> create mode 100644 drivers/gpu/drm/bridge/Kconfig >> create mode 100644 drivers/gpu/drm/bridge/Makefile >> create mode 100644 drivers/gpu/drm/bridge/ptn3460.c >> create mode 100644 include/drm/bridge/ptn3460.h >> >> diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >> new file mode 100644 >> index 0000000..c1cd329 >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >> @@ -0,0 +1,27 @@ >> +ptn3460-bridge bindings >> + >> +Required properties: >> + - compatible: "nxp,ptn3460" >> + - reg: i2c address of the bridge >> + - powerdown-gpio: OF device-tree gpio specification > > Can a regulator be used instead of gpio in other board case? > No, not to my knowledge. >> + - 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 | >> + +-------+------------+------------------+ >> + >> +Example: >> + ptn3460-bridge@20 { >> + compatible = "nxp,ptn3460"; >> + reg = <0x20>; >> + powerdown-gpio = <&gpy2 5 1 0 0>; >> + reset-gpio = <&gpx1 5 1 0 0>; >> + edid-emulation = <5>; >> + }; >> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig >> index 955555d..cd7bfb3 100644 >> --- a/drivers/gpu/drm/Kconfig >> +++ b/drivers/gpu/drm/Kconfig >> @@ -236,3 +236,5 @@ source "drivers/gpu/drm/tilcdc/Kconfig" >> source "drivers/gpu/drm/qxl/Kconfig" >> >> source "drivers/gpu/drm/msm/Kconfig" >> + >> +source "drivers/gpu/drm/bridge/Kconfig" >> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile >> index f089adf..9234253 100644 >> --- a/drivers/gpu/drm/Makefile >> +++ b/drivers/gpu/drm/Makefile >> @@ -56,3 +56,4 @@ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ >> obj-$(CONFIG_DRM_QXL) += qxl/ >> obj-$(CONFIG_DRM_MSM) += msm/ >> obj-y += i2c/ >> +obj-y += bridge/ >> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig >> new file mode 100644 >> index 0000000..f8db069 >> --- /dev/null >> +++ b/drivers/gpu/drm/bridge/Kconfig >> @@ -0,0 +1,4 @@ >> +config DRM_PTN3460 >> + tristate "PTN3460 DP/LVDS bridge" >> + depends on DRM && I2C >> + ---help--- >> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile >> new file mode 100644 >> index 0000000..b4733e1 >> --- /dev/null >> +++ b/drivers/gpu/drm/bridge/Makefile >> @@ -0,0 +1,3 @@ >> +ccflags-y := -Iinclude/drm >> + >> +obj-$(CONFIG_DRM_PTN3460) += ptn3460.o >> diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c >> new file mode 100644 >> index 0000000..a9e5c1a >> --- /dev/null >> +++ b/drivers/gpu/drm/bridge/ptn3460.c >> @@ -0,0 +1,349 @@ >> +/* >> + * NXP PTN3460 DP/LVDS bridge driver >> + * >> + * Copyright (C) 2013 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/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 "drm_crtc.h" >> +#include "drm_crtc_helper.h" >> + >> +#include "bridge/ptn3460.h" >> + >> +#define PTN3460_EDID_ADDR 0x0 >> +#define PTN3460_EDID_EMULATION_ADDR 0x84 >> +#define PTN3460_EDID_ENABLE_EMULATION 0 >> +#define PTN3460_EDID_EMULATION_SELECTION 1 >> +#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85 >> + >> +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; >> + int gpio_rst_n; >> + u32 edid_emulation; >> + bool enabled; >> +}; >> + >> +static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, >> + u8 *buf, int len) >> +{ >> + int ret; >> + >> + ret = i2c_master_send(ptn_bridge->client, &addr, 1); >> + if (ret <= 0) { >> + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); >> + return ret; >> + } >> + >> + ret = i2c_master_recv(ptn_bridge->client, buf, len); >> + if (ret <= 0) { >> + DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); >> + return ret; >> + } >> + >> + return 0; >> +} >> + >> +static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, >> + char val) >> +{ >> + int ret; >> + char buf[2]; >> + >> + buf[0] = addr; >> + buf[1] = val; >> + >> + ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); >> + if (ret <= 0) { >> + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); >> + return ret; >> + } >> + >> + return 0; >> +} >> + >> +static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) >> +{ >> + int ret; >> + char val; >> + >> + /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */ >> + 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); >> + return ret; >> + } >> + >> + /* Enable EDID emulation and select the desired EDID */ >> + val = 1 << PTN3460_EDID_ENABLE_EMULATION | >> + ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION; >> + >> + ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); >> + if (ret) { >> + DRM_ERROR("Failed to write edid value, ret=%d\n", ret); >> + return ret; >> + } >> + >> + return 0; >> +} >> + >> +static void ptn3460_pre_enable(struct drm_bridge *bridge) >> +{ >> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >> + int ret; >> + >> + if (ptn_bridge->enabled) >> + return; >> + >> + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) >> + gpio_set_value(ptn_bridge->gpio_pd_n, 1); > > Ditto. > >> + >> + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { >> + gpio_set_value(ptn_bridge->gpio_rst_n, 0); >> + udelay(10); >> + gpio_set_value(ptn_bridge->gpio_rst_n, 1); >> + } >> + >> + /* >> + * 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 >> + * time specified in the chip's datasheet to make sure we're really up. >> + */ >> + msleep(90); >> + >> + ret = ptn3460_select_edid(ptn_bridge); >> + if (ret) >> + DRM_ERROR("Select edid failed ret=%d\n", ret); >> + >> + ptn_bridge->enabled = true; >> +} >> + >> +static void ptn3460_enable(struct drm_bridge *bridge) >> +{ >> +} >> + >> +static void ptn3460_disable(struct drm_bridge *bridge) >> +{ >> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >> + >> + if (!ptn_bridge->enabled) >> + return; >> + >> + ptn_bridge->enabled = false; >> + >> + 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); > > Ditto. > >> +} >> + >> +static void ptn3460_post_disable(struct drm_bridge *bridge) >> +{ >> +} >> + >> +void ptn3460_bridge_destroy(struct drm_bridge *bridge) >> +{ >> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >> + >> + drm_bridge_cleanup(bridge); >> + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) >> + gpio_free(ptn_bridge->gpio_pd_n); > > Ditto. > >> + 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 */ >> +} >> + >> +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, >> +}; >> + >> +int ptn3460_get_modes(struct drm_connector *connector) >> +{ >> + struct ptn3460_bridge *ptn_bridge; >> + u8 *edid; >> + int ret, num_modes; >> + bool power_off; >> + >> + ptn_bridge = container_of(connector, struct ptn3460_bridge, 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); >> + >> + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); >> + if (!edid) { >> + DRM_ERROR("Failed to allocate edid\n"); >> + return 0; >> + } >> + >> + ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, >> + EDID_LENGTH); >> + if (ret) { >> + kfree(edid); >> + num_modes = 0; >> + goto out; >> + } >> + >> + ptn_bridge->edid = (struct edid *)edid; >> + drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); >> + >> + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); >> + >> +out: >> + if (power_off) >> + ptn3460_disable(ptn_bridge->bridge); >> + >> + return num_modes; >> +} >> + >> +static int ptn3460_mode_valid(struct drm_connector *connector, >> + struct drm_display_mode *mode) >> +{ >> + return MODE_OK; >> +} >> + >> +struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) >> +{ >> + struct ptn3460_bridge *ptn_bridge; >> + >> + ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); >> + >> + return ptn_bridge->encoder; >> +} >> + >> +struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { >> + .get_modes = ptn3460_get_modes, >> + .mode_valid = ptn3460_mode_valid, >> + .best_encoder = ptn3460_best_encoder, >> +}; >> + >> +enum drm_connector_status ptn3460_detect(struct drm_connector *connector, >> + bool force) >> +{ >> + return connector_status_connected; >> +} >> + >> +void ptn3460_connector_destroy(struct drm_connector *connector) >> +{ >> + drm_connector_cleanup(connector); >> +} >> + >> +struct drm_connector_funcs ptn3460_connector_funcs = { >> + .dpms = drm_helper_connector_dpms, >> + .fill_modes = drm_helper_probe_single_connector_modes, >> + .detect = ptn3460_detect, >> + .destroy = ptn3460_connector_destroy, >> +}; > > Why do you try to add a new connector here? We already have the > connector for LCD, and also provides some callbacks for it. For this, > please see exynos_drm_display_ops of exynos_drm_fimd driver, and you > can add new callbacks to there such as init callback for bridge device > initialization if needed. > We add a new connector for 2 reasons: 1) We need to override the drm detect() callback to always return true since the DP driver will presumably return its hotplug status which will always be low when the ptn chip is turned off. 2) We want the ability to control the result of get_modes(). I've got a patch set almost ready to tear the display ops out of fimd and put them in the DP driver. The display ops are better suited there, since it's the actual encoder/connector. I hope to get that posted this week. >> + >> +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); > > Also, if a regulator is used instead? > >> + 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); >> + return ret; >> + } >> + } >> + >> + ptn_bridge->gpio_rst_n = of_get_named_gpio(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) { >> + DRM_ERROR("Request reset-gpio failed (%d)\n", ret); >> + gpio_free(ptn_bridge->gpio_pd_n); >> + return ret; >> + } >> + } >> + >> + ret = of_property_read_u32(node, "edid-emulation", >> + &ptn_bridge->edid_emulation); >> + if (ret) { >> + DRM_ERROR("Can't read edid emulation value\n"); >> + goto err; >> + } >> + >> + ret = drm_bridge_init(dev, 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; >> + >> + ret = drm_connector_init(dev, &ptn_bridge->connector, >> + &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); > > So it seems that here's not right place to call drm_connector_init function. > > Display pipeline path could be one of, > Display Controller Display bus > --------------------------------------------------------------------------- > FIMD---------------------LVDS--------------------LCD, > or > FIMD----------------------eDP---------------------LCD, > or > FIMD------------------MIPI-DSI------------------LCD, > or > FIMD-------------------------------------------------LCD > > And also in case using image enhancement chip, > mDNIe-------------FIMD-LITE between Display Controller and Display > bus. > > So, wouldn't the right place below FIMD driver? :) > Well, this driver should be considered outside of exynos context since it could be used by any drm driver. In the exynos context, the right place to implement it would be in the dp driver, actually. However, the exynos driver has a level of abstraction on top of the crtcs/encoders such that we need to initialize it in the exynos_drm_core. The patchset I mentioned above should help move things in a direction where fimd/mixer implement drm_crtc directly and hdmi/dp implement drm_encoder/drm_connector directly. In that world, DP would initialize the ptn driver. > >> + 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_sysfs_connector_add(&ptn_bridge->connector); >> + drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); >> + >> + 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; >> +} >> diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h >> new file mode 100644 >> index 0000000..157ffa1 >> --- /dev/null >> +++ b/include/drm/bridge/ptn3460.h >> @@ -0,0 +1,36 @@ >> +/* >> + * Copyright (C) 2013 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. >> + */ >> + >> +#ifndef _DRM_BRIDGE_PTN3460_H_ >> +#define _DRM_BRIDGE_PTN3460_H_ >> + >> +struct drm_device; >> +struct drm_encoder; >> +struct i2c_client; >> +struct device_node; >> + >> +#ifdef CONFIG_DRM_PTN3460 >> + >> +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, >> + struct i2c_client *client, struct device_node *node); >> +#else >> + >> +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, >> + struct i2c_client *client, struct device_node *node) >> +{ >> + return 0; >> +} >> + >> +#endif >> + >> +#endif >> -- >> 1.8.4 >> >> >> _______________________________________________ >> linux-arm-kernel mailing list >> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org >> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel -- 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] 51+ messages in thread
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-03 14:57 ` Sean Paul @ 2013-10-03 17:39 ` Inki Dae 2013-10-03 18:01 ` Olof Johansson [not found] ` <CAAQKjZPwyKCpju4Ndd+MB_aN24-zA5xTHFsFsun2617h7YT6dw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 2 replies; 51+ messages in thread From: Inki Dae @ 2013-10-03 17:39 UTC (permalink / raw) To: Sean Paul Cc: devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-doc, linux-kernel@vger.kernel.org, DRI mailing list, linux-arm-kernel@lists.infradead.org 2013/10/3 Sean Paul <seanpaul@chromium.org>: > On Thu, Oct 3, 2013 at 9:55 AM, Inki Dae <inki.dae@samsung.com> wrote: >> Hi, thank you for your contribution and the below is my short comments, >> >> 2013/10/2 Sean Paul <seanpaul@chromium.org>: >>> This patch adds a drm_bridge driver for the PTN3460 DisplayPort to LVDS >>> bridge chip. >>> >>> Signed-off-by: Sean Paul <seanpaul@chromium.org> >>> --- >>> .../devicetree/bindings/drm/bridge/ptn3460.txt | 27 ++ >>> drivers/gpu/drm/Kconfig | 2 + >>> drivers/gpu/drm/Makefile | 1 + >>> drivers/gpu/drm/bridge/Kconfig | 4 + >>> drivers/gpu/drm/bridge/Makefile | 3 + >>> drivers/gpu/drm/bridge/ptn3460.c | 349 +++++++++++++++++++++ >>> include/drm/bridge/ptn3460.h | 36 +++ >>> 7 files changed, 422 insertions(+) >>> create mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>> create mode 100644 drivers/gpu/drm/bridge/Kconfig >>> create mode 100644 drivers/gpu/drm/bridge/Makefile >>> create mode 100644 drivers/gpu/drm/bridge/ptn3460.c >>> create mode 100644 include/drm/bridge/ptn3460.h >>> >>> diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>> new file mode 100644 >>> index 0000000..c1cd329 >>> --- /dev/null >>> +++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>> @@ -0,0 +1,27 @@ >>> +ptn3460-bridge bindings >>> + >>> +Required properties: >>> + - compatible: "nxp,ptn3460" >>> + - reg: i2c address of the bridge >>> + - powerdown-gpio: OF device-tree gpio specification >> >> Can a regulator be used instead of gpio in other board case? >> > > No, not to my knowledge. > Hm.. plz check it out again. the gpio pin is specific to board, and the the gpio be used as power source trigger could be replaced with a regulator according to board design. So you should consider all possibilities even though there are no other cases yet: other board could use a regulator instead. > >>> + - 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 | >>> + +-------+------------+------------------+ >>> + >>> +Example: >>> + ptn3460-bridge@20 { >>> + compatible = "nxp,ptn3460"; >>> + reg = <0x20>; >>> + powerdown-gpio = <&gpy2 5 1 0 0>; >>> + reset-gpio = <&gpx1 5 1 0 0>; >>> + edid-emulation = <5>; >>> + }; >>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig >>> index 955555d..cd7bfb3 100644 >>> --- a/drivers/gpu/drm/Kconfig >>> +++ b/drivers/gpu/drm/Kconfig >>> @@ -236,3 +236,5 @@ source "drivers/gpu/drm/tilcdc/Kconfig" >>> source "drivers/gpu/drm/qxl/Kconfig" >>> >>> source "drivers/gpu/drm/msm/Kconfig" >>> + >>> +source "drivers/gpu/drm/bridge/Kconfig" >>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile >>> index f089adf..9234253 100644 >>> --- a/drivers/gpu/drm/Makefile >>> +++ b/drivers/gpu/drm/Makefile >>> @@ -56,3 +56,4 @@ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ >>> obj-$(CONFIG_DRM_QXL) += qxl/ >>> obj-$(CONFIG_DRM_MSM) += msm/ >>> obj-y += i2c/ >>> +obj-y += bridge/ >>> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig >>> new file mode 100644 >>> index 0000000..f8db069 >>> --- /dev/null >>> +++ b/drivers/gpu/drm/bridge/Kconfig >>> @@ -0,0 +1,4 @@ >>> +config DRM_PTN3460 >>> + tristate "PTN3460 DP/LVDS bridge" >>> + depends on DRM && I2C >>> + ---help--- >>> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile >>> new file mode 100644 >>> index 0000000..b4733e1 >>> --- /dev/null >>> +++ b/drivers/gpu/drm/bridge/Makefile >>> @@ -0,0 +1,3 @@ >>> +ccflags-y := -Iinclude/drm >>> + >>> +obj-$(CONFIG_DRM_PTN3460) += ptn3460.o >>> diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c >>> new file mode 100644 >>> index 0000000..a9e5c1a >>> --- /dev/null >>> +++ b/drivers/gpu/drm/bridge/ptn3460.c >>> @@ -0,0 +1,349 @@ >>> +/* >>> + * NXP PTN3460 DP/LVDS bridge driver >>> + * >>> + * Copyright (C) 2013 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/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 "drm_crtc.h" >>> +#include "drm_crtc_helper.h" >>> + >>> +#include "bridge/ptn3460.h" >>> + >>> +#define PTN3460_EDID_ADDR 0x0 >>> +#define PTN3460_EDID_EMULATION_ADDR 0x84 >>> +#define PTN3460_EDID_ENABLE_EMULATION 0 >>> +#define PTN3460_EDID_EMULATION_SELECTION 1 >>> +#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85 >>> + >>> +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; >>> + int gpio_rst_n; >>> + u32 edid_emulation; >>> + bool enabled; >>> +}; >>> + >>> +static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, >>> + u8 *buf, int len) >>> +{ >>> + int ret; >>> + >>> + ret = i2c_master_send(ptn_bridge->client, &addr, 1); >>> + if (ret <= 0) { >>> + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); >>> + return ret; >>> + } >>> + >>> + ret = i2c_master_recv(ptn_bridge->client, buf, len); >>> + if (ret <= 0) { >>> + DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); >>> + return ret; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, >>> + char val) >>> +{ >>> + int ret; >>> + char buf[2]; >>> + >>> + buf[0] = addr; >>> + buf[1] = val; >>> + >>> + ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); >>> + if (ret <= 0) { >>> + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); >>> + return ret; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) >>> +{ >>> + int ret; >>> + char val; >>> + >>> + /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */ >>> + 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); >>> + return ret; >>> + } >>> + >>> + /* Enable EDID emulation and select the desired EDID */ >>> + val = 1 << PTN3460_EDID_ENABLE_EMULATION | >>> + ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION; >>> + >>> + ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); >>> + if (ret) { >>> + DRM_ERROR("Failed to write edid value, ret=%d\n", ret); >>> + return ret; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static void ptn3460_pre_enable(struct drm_bridge *bridge) >>> +{ >>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>> + int ret; >>> + >>> + if (ptn_bridge->enabled) >>> + return; >>> + >>> + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) >>> + gpio_set_value(ptn_bridge->gpio_pd_n, 1); >> >> Ditto. >> >>> + >>> + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { >>> + gpio_set_value(ptn_bridge->gpio_rst_n, 0); >>> + udelay(10); >>> + gpio_set_value(ptn_bridge->gpio_rst_n, 1); >>> + } >>> + >>> + /* >>> + * 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 >>> + * time specified in the chip's datasheet to make sure we're really up. >>> + */ >>> + msleep(90); >>> + >>> + ret = ptn3460_select_edid(ptn_bridge); >>> + if (ret) >>> + DRM_ERROR("Select edid failed ret=%d\n", ret); >>> + >>> + ptn_bridge->enabled = true; >>> +} >>> + >>> +static void ptn3460_enable(struct drm_bridge *bridge) >>> +{ >>> +} >>> + >>> +static void ptn3460_disable(struct drm_bridge *bridge) >>> +{ >>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>> + >>> + if (!ptn_bridge->enabled) >>> + return; >>> + >>> + ptn_bridge->enabled = false; >>> + >>> + 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); >> >> Ditto. >> >>> +} >>> + >>> +static void ptn3460_post_disable(struct drm_bridge *bridge) >>> +{ >>> +} >>> + >>> +void ptn3460_bridge_destroy(struct drm_bridge *bridge) >>> +{ >>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>> + >>> + drm_bridge_cleanup(bridge); >>> + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) >>> + gpio_free(ptn_bridge->gpio_pd_n); >> >> Ditto. >> >>> + 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 */ >>> +} >>> + >>> +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, >>> +}; >>> + >>> +int ptn3460_get_modes(struct drm_connector *connector) >>> +{ >>> + struct ptn3460_bridge *ptn_bridge; >>> + u8 *edid; >>> + int ret, num_modes; >>> + bool power_off; >>> + >>> + ptn_bridge = container_of(connector, struct ptn3460_bridge, 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); >>> + >>> + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); >>> + if (!edid) { >>> + DRM_ERROR("Failed to allocate edid\n"); >>> + return 0; >>> + } >>> + >>> + ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, >>> + EDID_LENGTH); >>> + if (ret) { >>> + kfree(edid); >>> + num_modes = 0; >>> + goto out; >>> + } >>> + >>> + ptn_bridge->edid = (struct edid *)edid; >>> + drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); >>> + >>> + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); >>> + >>> +out: >>> + if (power_off) >>> + ptn3460_disable(ptn_bridge->bridge); >>> + >>> + return num_modes; >>> +} >>> + >>> +static int ptn3460_mode_valid(struct drm_connector *connector, >>> + struct drm_display_mode *mode) >>> +{ >>> + return MODE_OK; >>> +} >>> + >>> +struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) >>> +{ >>> + struct ptn3460_bridge *ptn_bridge; >>> + >>> + ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); >>> + >>> + return ptn_bridge->encoder; >>> +} >>> + >>> +struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { >>> + .get_modes = ptn3460_get_modes, >>> + .mode_valid = ptn3460_mode_valid, >>> + .best_encoder = ptn3460_best_encoder, >>> +}; >>> + >>> +enum drm_connector_status ptn3460_detect(struct drm_connector *connector, >>> + bool force) >>> +{ >>> + return connector_status_connected; >>> +} >>> + >>> +void ptn3460_connector_destroy(struct drm_connector *connector) >>> +{ >>> + drm_connector_cleanup(connector); >>> +} >>> + >>> +struct drm_connector_funcs ptn3460_connector_funcs = { >>> + .dpms = drm_helper_connector_dpms, >>> + .fill_modes = drm_helper_probe_single_connector_modes, >>> + .detect = ptn3460_detect, >>> + .destroy = ptn3460_connector_destroy, >>> +}; >> >> Why do you try to add a new connector here? We already have the >> connector for LCD, and also provides some callbacks for it. For this, >> please see exynos_drm_display_ops of exynos_drm_fimd driver, and you >> can add new callbacks to there such as init callback for bridge device >> initialization if needed. >> > > We add a new connector for 2 reasons: > > 1) We need to override the drm detect() callback to always return true > since the DP driver will presumably return its hotplug status which > will always be low when the ptn chip is turned off. > 2) We want the ability to control the result of get_modes(). > > I've got a patch set almost ready to tear the display ops out of fimd > and put them in the DP driver. Really? if so, that is ideal something we want and we should go. But isn't the DP driver placed in drivers/video/exynos? How did you take care of that? Actually, for this, we planned to use CDF(Common Display Framework) if the framework is merged to mainline somehow. > The display ops are better suited > there, since it's the actual encoder/connector. I hope to get that > posted this week. > I will look forward to that posting. :) > >>> + >>> +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); >> >> Also, if a regulator is used instead? >> >>> + 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); >>> + return ret; >>> + } >>> + } >>> + >>> + ptn_bridge->gpio_rst_n = of_get_named_gpio(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) { >>> + DRM_ERROR("Request reset-gpio failed (%d)\n", ret); >>> + gpio_free(ptn_bridge->gpio_pd_n); >>> + return ret; >>> + } >>> + } >>> + >>> + ret = of_property_read_u32(node, "edid-emulation", >>> + &ptn_bridge->edid_emulation); >>> + if (ret) { >>> + DRM_ERROR("Can't read edid emulation value\n"); >>> + goto err; >>> + } >>> + >>> + ret = drm_bridge_init(dev, 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; >>> + >>> + ret = drm_connector_init(dev, &ptn_bridge->connector, >>> + &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); >> >> So it seems that here's not right place to call drm_connector_init function. >> >> Display pipeline path could be one of, >> Display Controller Display bus >> --------------------------------------------------------------------------- >> FIMD---------------------LVDS--------------------LCD, >> or >> FIMD----------------------eDP---------------------LCD, >> or >> FIMD------------------MIPI-DSI------------------LCD, >> or >> FIMD-------------------------------------------------LCD >> >> And also in case using image enhancement chip, >> mDNIe-------------FIMD-LITE between Display Controller and Display >> bus. >> >> So, wouldn't the right place below FIMD driver? :) >> > > Well, this driver should be considered outside of exynos context since > it could be used by any drm driver. > > In the exynos context, the right place to implement it would be in the > dp driver, actually. However, the exynos driver has a level of > abstraction on top of the crtcs/encoders such that we need to > initialize it in the exynos_drm_core. The patchset I mentioned above > should help move things in a direction where fimd/mixer implement > drm_crtc directly and hdmi/dp implement drm_encoder/drm_connector > directly. In that world, DP would initialize the ptn driver. > >> >>> + 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_sysfs_connector_add(&ptn_bridge->connector); >>> + drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); >>> + >>> + 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; >>> +} >>> diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h >>> new file mode 100644 >>> index 0000000..157ffa1 >>> --- /dev/null >>> +++ b/include/drm/bridge/ptn3460.h >>> @@ -0,0 +1,36 @@ >>> +/* >>> + * Copyright (C) 2013 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. >>> + */ >>> + >>> +#ifndef _DRM_BRIDGE_PTN3460_H_ >>> +#define _DRM_BRIDGE_PTN3460_H_ >>> + >>> +struct drm_device; >>> +struct drm_encoder; >>> +struct i2c_client; >>> +struct device_node; >>> + >>> +#ifdef CONFIG_DRM_PTN3460 >>> + >>> +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, >>> + struct i2c_client *client, struct device_node *node); >>> +#else >>> + >>> +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, >>> + struct i2c_client *client, struct device_node *node) >>> +{ >>> + return 0; >>> +} >>> + >>> +#endif >>> + >>> +#endif >>> -- >>> 1.8.4 >>> >>> >>> _______________________________________________ >>> 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] 51+ messages in thread
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-03 17:39 ` Inki Dae @ 2013-10-03 18:01 ` Olof Johansson 2013-10-04 2:05 ` Inki Dae [not found] ` <CAAQKjZPwyKCpju4Ndd+MB_aN24-zA5xTHFsFsun2617h7YT6dw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 1 sibling, 1 reply; 51+ messages in thread From: Olof Johansson @ 2013-10-03 18:01 UTC (permalink / raw) To: Inki Dae Cc: Sean Paul, devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, DRI mailing list, linux-arm-kernel@lists.infradead.org On Thu, Oct 3, 2013 at 10:39 AM, Inki Dae <inki.dae@samsung.com> wrote: > 2013/10/3 Sean Paul <seanpaul@chromium.org>: >> On Thu, Oct 3, 2013 at 9:55 AM, Inki Dae <inki.dae@samsung.com> wrote: >>> Can a regulator be used instead of gpio in other board case? >>> >> >> No, not to my knowledge. >> > > Hm.. plz check it out again. the gpio pin is specific to board, and > the the gpio be used as power source trigger could be replaced with a > regulator according to board design. So you should consider all > possibilities even though there are no other cases yet: other board > could use a regulator instead. Take a look at the data sheet, it is publicly available. PD_N is not a power supply input, so modelling it as a regulator makes no sense: "If PD_N is LOW, then the device is in Deep power-down completely, even if supply rail is ON; for the device to be able to operate, the PD_N pin must be HIGH." -Olof ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-03 18:01 ` Olof Johansson @ 2013-10-04 2:05 ` Inki Dae 2013-10-09 18:29 ` Mark Brown 0 siblings, 1 reply; 51+ messages in thread From: Inki Dae @ 2013-10-04 2:05 UTC (permalink / raw) To: Olof Johansson Cc: Sean Paul, devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, DRI mailing list, linux-arm-kernel@lists.infradead.org 2013/10/4 Olof Johansson <olof@lixom.net>: > On Thu, Oct 3, 2013 at 10:39 AM, Inki Dae <inki.dae@samsung.com> wrote: >> 2013/10/3 Sean Paul <seanpaul@chromium.org>: >>> On Thu, Oct 3, 2013 at 9:55 AM, Inki Dae <inki.dae@samsung.com> wrote: >>>> Can a regulator be used instead of gpio in other board case? >>>> >>> >>> No, not to my knowledge. >>> >> >> Hm.. plz check it out again. the gpio pin is specific to board, and >> the the gpio be used as power source trigger could be replaced with a >> regulator according to board design. So you should consider all >> possibilities even though there are no other cases yet: other board >> could use a regulator instead. > > Take a look at the data sheet, it is publicly available. > > PD_N is not a power supply input, so modelling it as a regulator makes no sense: > > "If PD_N is LOW, then the device is in Deep power-down completely, > even if supply rail is ON; for the device to be able to operate, the > PD_N pin must be HIGH." > I still think the pin could be replaced with a regulator. But lvds-bridge node has "powerdown-gpio" property - it say this board will use gpio pin - specific to board. So it seems no problem. > > > -Olof > -- > To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-04 2:05 ` Inki Dae @ 2013-10-09 18:29 ` Mark Brown 2013-10-10 4:18 ` Inki Dae 0 siblings, 1 reply; 51+ messages in thread From: Mark Brown @ 2013-10-09 18:29 UTC (permalink / raw) To: Inki Dae Cc: Olof Johansson, Sean Paul, devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, DRI mailing list, linux-arm-kernel@lists.infradead.org [-- Attachment #1: Type: text/plain, Size: 651 bytes --] On Fri, Oct 04, 2013 at 11:05:48AM +0900, Inki Dae wrote: > 2013/10/4 Olof Johansson <olof@lixom.net>: > > "If PD_N is LOW, then the device is in Deep power-down completely, > > even if supply rail is ON; for the device to be able to operate, the > > PD_N pin must be HIGH." > I still think the pin could be replaced with a regulator. But > lvds-bridge node has "powerdown-gpio" property - it say this board > will use gpio pin - specific to board. So it seems no problem. No, don't model things that aren't regulators as regulators - it's just confusing from a usability standpoint and causes breakage when the pins don't behave like regulators. [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 836 bytes --] ^ permalink raw reply [flat|nested] 51+ messages in thread
* RE: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-09 18:29 ` Mark Brown @ 2013-10-10 4:18 ` Inki Dae 2013-10-10 9:37 ` Mark Brown 0 siblings, 1 reply; 51+ messages in thread From: Inki Dae @ 2013-10-10 4:18 UTC (permalink / raw) To: 'Mark Brown' Cc: 'Olof Johansson', 'Sean Paul', devicetree, linux-samsung-soc, linux-doc, linux-kernel, 'DRI mailing list', linux-arm-kernel > -----Original Message----- > From: Mark Brown [mailto:broonie@kernel.org] > Sent: Thursday, October 10, 2013 3:29 AM > To: Inki Dae > Cc: Olof Johansson; Sean Paul; devicetree@vger.kernel.org; linux-samsung- > soc@vger.kernel.org; linux-doc@vger.kernel.org; linux- > kernel@vger.kernel.org; DRI mailing list; linux-arm- > kernel@lists.infradead.org > Subject: Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver > > On Fri, Oct 04, 2013 at 11:05:48AM +0900, Inki Dae wrote: > > 2013/10/4 Olof Johansson <olof@lixom.net>: > > > > "If PD_N is LOW, then the device is in Deep power-down completely, > > > even if supply rail is ON; for the device to be able to operate, the > > > PD_N pin must be HIGH." > > > I still think the pin could be replaced with a regulator. But > > lvds-bridge node has "powerdown-gpio" property - it say this board > > will use gpio pin - specific to board. So it seems no problem. > > No, don't model things that aren't regulators as regulators - it's just > confusing from a usability standpoint and causes breakage when the pins > don't behave like regulators. It seems that there was your missing point. That _is not_ what I mentioned. I mean that other boards can use a regulator instead of gpio pin. ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-10 4:18 ` Inki Dae @ 2013-10-10 9:37 ` Mark Brown 2013-10-10 11:40 ` Inki Dae 0 siblings, 1 reply; 51+ messages in thread From: Mark Brown @ 2013-10-10 9:37 UTC (permalink / raw) To: Inki Dae Cc: 'Olof Johansson', 'Sean Paul', devicetree, linux-samsung-soc, linux-doc, linux-kernel, 'DRI mailing list', linux-arm-kernel [-- Attachment #1: Type: text/plain, Size: 918 bytes --] On Thu, Oct 10, 2013 at 01:18:05PM +0900, Inki Dae wrote: > > > I still think the pin could be replaced with a regulator. But > > > lvds-bridge node has "powerdown-gpio" property - it say this board > > > will use gpio pin - specific to board. So it seems no problem. > > No, don't model things that aren't regulators as regulators - it's just > > confusing from a usability standpoint and causes breakage when the pins > > don't behave like regulators. > It seems that there was your missing point. That _is not_ what I mentioned. > I mean that other boards can use a regulator instead of gpio pin. What I'm saying is no boards should use a regulator to control that GPIO pin, obviously if they're controlling the actual regulators that's fine but the reset signal should not be controlled via the regulator API (there are some unfortunate cases where people have done that already but let's not have any more). [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 836 bytes --] ^ permalink raw reply [flat|nested] 51+ messages in thread
* RE: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-10 9:37 ` Mark Brown @ 2013-10-10 11:40 ` Inki Dae 2013-10-10 12:23 ` Mark Brown 0 siblings, 1 reply; 51+ messages in thread From: Inki Dae @ 2013-10-10 11:40 UTC (permalink / raw) To: 'Mark Brown' Cc: 'Olof Johansson', 'Sean Paul', devicetree, linux-samsung-soc, linux-doc, linux-kernel, 'DRI mailing list', linux-arm-kernel > -----Original Message----- > From: Mark Brown [mailto:broonie@kernel.org] > Sent: Thursday, October 10, 2013 6:37 PM > To: Inki Dae > Cc: 'Olof Johansson'; 'Sean Paul'; devicetree@vger.kernel.org; linux- > samsung-soc@vger.kernel.org; linux-doc@vger.kernel.org; linux- > kernel@vger.kernel.org; 'DRI mailing list'; linux-arm- > kernel@lists.infradead.org > Subject: Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver > > On Thu, Oct 10, 2013 at 01:18:05PM +0900, Inki Dae wrote: > > > > > I still think the pin could be replaced with a regulator. But > > > > lvds-bridge node has "powerdown-gpio" property - it say this board > > > > will use gpio pin - specific to board. So it seems no problem. > > > > No, don't model things that aren't regulators as regulators - it's > > > just confusing from a usability standpoint and causes breakage when > > > the pins don't behave like regulators. > > > It seems that there was your missing point. That _is not_ what I > mentioned. > > I mean that other boards can use a regulator instead of gpio pin. > > What I'm saying is no boards should use a regulator to control that GPIO > pin, obviously if they're controlling the actual regulators that's fine That is what I mentioned. Some boards _could control_ the actual regulator for lvds-bridge, and that would be depended on how HW engineer designs the board. > but the reset signal should not be controlled via the regulator API (there > are some unfortunate cases where people have done that already but let's > not have any more). ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-10 11:40 ` Inki Dae @ 2013-10-10 12:23 ` Mark Brown 0 siblings, 0 replies; 51+ messages in thread From: Mark Brown @ 2013-10-10 12:23 UTC (permalink / raw) To: Inki Dae Cc: 'Olof Johansson', 'Sean Paul', devicetree, linux-samsung-soc, linux-doc, linux-kernel, 'DRI mailing list', linux-arm-kernel [-- Attachment #1: Type: text/plain, Size: 430 bytes --] On Thu, Oct 10, 2013 at 08:40:38PM +0900, Inki Dae wrote: > That is what I mentioned. Some boards _could control_ the actual regulator > for lvds-bridge, and that would be depended on how HW engineer designs the > board. For the driver this should be totally transparent - it should just control the regulator all the time, the regulator API will just not do anything if the regulator state can't actually be changed. [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 836 bytes --] ^ permalink raw reply [flat|nested] 51+ messages in thread
[parent not found: <CAAQKjZPwyKCpju4Ndd+MB_aN24-zA5xTHFsFsun2617h7YT6dw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver [not found] ` <CAAQKjZPwyKCpju4Ndd+MB_aN24-zA5xTHFsFsun2617h7YT6dw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2013-10-03 18:09 ` Sean Paul 2013-10-03 18:23 ` Inki Dae 0 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-03 18:09 UTC (permalink / raw) To: Inki Dae Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, DRI mailing list, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org On Thu, Oct 3, 2013 at 1:39 PM, Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote: > 2013/10/3 Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>: >> On Thu, Oct 3, 2013 at 9:55 AM, Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote: >>> Hi, thank you for your contribution and the below is my short comments, >>> >>> 2013/10/2 Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>: >>>> This patch adds a drm_bridge driver for the PTN3460 DisplayPort to LVDS >>>> bridge chip. >>>> >>>> Signed-off-by: Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> >>>> --- >>>> .../devicetree/bindings/drm/bridge/ptn3460.txt | 27 ++ >>>> drivers/gpu/drm/Kconfig | 2 + >>>> drivers/gpu/drm/Makefile | 1 + >>>> drivers/gpu/drm/bridge/Kconfig | 4 + >>>> drivers/gpu/drm/bridge/Makefile | 3 + >>>> drivers/gpu/drm/bridge/ptn3460.c | 349 +++++++++++++++++++++ >>>> include/drm/bridge/ptn3460.h | 36 +++ >>>> 7 files changed, 422 insertions(+) >>>> create mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>>> create mode 100644 drivers/gpu/drm/bridge/Kconfig >>>> create mode 100644 drivers/gpu/drm/bridge/Makefile >>>> create mode 100644 drivers/gpu/drm/bridge/ptn3460.c >>>> create mode 100644 include/drm/bridge/ptn3460.h >>>> >>>> diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>>> new file mode 100644 >>>> index 0000000..c1cd329 >>>> --- /dev/null >>>> +++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>>> @@ -0,0 +1,27 @@ >>>> +ptn3460-bridge bindings >>>> + >>>> +Required properties: >>>> + - compatible: "nxp,ptn3460" >>>> + - reg: i2c address of the bridge >>>> + - powerdown-gpio: OF device-tree gpio specification >>> >>> Can a regulator be used instead of gpio in other board case? >>> >> >> No, not to my knowledge. >> > > Hm.. plz check it out again. the gpio pin is specific to board, and > the the gpio be used as power source trigger could be replaced with a > regulator according to board design. So you should consider all > possibilities even though there are no other cases yet: other board > could use a regulator instead. > >> >>>> + - 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 | >>>> + +-------+------------+------------------+ >>>> + >>>> +Example: >>>> + ptn3460-bridge@20 { >>>> + compatible = "nxp,ptn3460"; >>>> + reg = <0x20>; >>>> + powerdown-gpio = <&gpy2 5 1 0 0>; >>>> + reset-gpio = <&gpx1 5 1 0 0>; >>>> + edid-emulation = <5>; >>>> + }; >>>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig >>>> index 955555d..cd7bfb3 100644 >>>> --- a/drivers/gpu/drm/Kconfig >>>> +++ b/drivers/gpu/drm/Kconfig >>>> @@ -236,3 +236,5 @@ source "drivers/gpu/drm/tilcdc/Kconfig" >>>> source "drivers/gpu/drm/qxl/Kconfig" >>>> >>>> source "drivers/gpu/drm/msm/Kconfig" >>>> + >>>> +source "drivers/gpu/drm/bridge/Kconfig" >>>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile >>>> index f089adf..9234253 100644 >>>> --- a/drivers/gpu/drm/Makefile >>>> +++ b/drivers/gpu/drm/Makefile >>>> @@ -56,3 +56,4 @@ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ >>>> obj-$(CONFIG_DRM_QXL) += qxl/ >>>> obj-$(CONFIG_DRM_MSM) += msm/ >>>> obj-y += i2c/ >>>> +obj-y += bridge/ >>>> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig >>>> new file mode 100644 >>>> index 0000000..f8db069 >>>> --- /dev/null >>>> +++ b/drivers/gpu/drm/bridge/Kconfig >>>> @@ -0,0 +1,4 @@ >>>> +config DRM_PTN3460 >>>> + tristate "PTN3460 DP/LVDS bridge" >>>> + depends on DRM && I2C >>>> + ---help--- >>>> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile >>>> new file mode 100644 >>>> index 0000000..b4733e1 >>>> --- /dev/null >>>> +++ b/drivers/gpu/drm/bridge/Makefile >>>> @@ -0,0 +1,3 @@ >>>> +ccflags-y := -Iinclude/drm >>>> + >>>> +obj-$(CONFIG_DRM_PTN3460) += ptn3460.o >>>> diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c >>>> new file mode 100644 >>>> index 0000000..a9e5c1a >>>> --- /dev/null >>>> +++ b/drivers/gpu/drm/bridge/ptn3460.c >>>> @@ -0,0 +1,349 @@ >>>> +/* >>>> + * NXP PTN3460 DP/LVDS bridge driver >>>> + * >>>> + * Copyright (C) 2013 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/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 "drm_crtc.h" >>>> +#include "drm_crtc_helper.h" >>>> + >>>> +#include "bridge/ptn3460.h" >>>> + >>>> +#define PTN3460_EDID_ADDR 0x0 >>>> +#define PTN3460_EDID_EMULATION_ADDR 0x84 >>>> +#define PTN3460_EDID_ENABLE_EMULATION 0 >>>> +#define PTN3460_EDID_EMULATION_SELECTION 1 >>>> +#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85 >>>> + >>>> +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; >>>> + int gpio_rst_n; >>>> + u32 edid_emulation; >>>> + bool enabled; >>>> +}; >>>> + >>>> +static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, >>>> + u8 *buf, int len) >>>> +{ >>>> + int ret; >>>> + >>>> + ret = i2c_master_send(ptn_bridge->client, &addr, 1); >>>> + if (ret <= 0) { >>>> + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); >>>> + return ret; >>>> + } >>>> + >>>> + ret = i2c_master_recv(ptn_bridge->client, buf, len); >>>> + if (ret <= 0) { >>>> + DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); >>>> + return ret; >>>> + } >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, >>>> + char val) >>>> +{ >>>> + int ret; >>>> + char buf[2]; >>>> + >>>> + buf[0] = addr; >>>> + buf[1] = val; >>>> + >>>> + ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); >>>> + if (ret <= 0) { >>>> + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); >>>> + return ret; >>>> + } >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) >>>> +{ >>>> + int ret; >>>> + char val; >>>> + >>>> + /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */ >>>> + 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); >>>> + return ret; >>>> + } >>>> + >>>> + /* Enable EDID emulation and select the desired EDID */ >>>> + val = 1 << PTN3460_EDID_ENABLE_EMULATION | >>>> + ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION; >>>> + >>>> + ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); >>>> + if (ret) { >>>> + DRM_ERROR("Failed to write edid value, ret=%d\n", ret); >>>> + return ret; >>>> + } >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static void ptn3460_pre_enable(struct drm_bridge *bridge) >>>> +{ >>>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>>> + int ret; >>>> + >>>> + if (ptn_bridge->enabled) >>>> + return; >>>> + >>>> + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) >>>> + gpio_set_value(ptn_bridge->gpio_pd_n, 1); >>> >>> Ditto. >>> >>>> + >>>> + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { >>>> + gpio_set_value(ptn_bridge->gpio_rst_n, 0); >>>> + udelay(10); >>>> + gpio_set_value(ptn_bridge->gpio_rst_n, 1); >>>> + } >>>> + >>>> + /* >>>> + * 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 >>>> + * time specified in the chip's datasheet to make sure we're really up. >>>> + */ >>>> + msleep(90); >>>> + >>>> + ret = ptn3460_select_edid(ptn_bridge); >>>> + if (ret) >>>> + DRM_ERROR("Select edid failed ret=%d\n", ret); >>>> + >>>> + ptn_bridge->enabled = true; >>>> +} >>>> + >>>> +static void ptn3460_enable(struct drm_bridge *bridge) >>>> +{ >>>> +} >>>> + >>>> +static void ptn3460_disable(struct drm_bridge *bridge) >>>> +{ >>>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>>> + >>>> + if (!ptn_bridge->enabled) >>>> + return; >>>> + >>>> + ptn_bridge->enabled = false; >>>> + >>>> + 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); >>> >>> Ditto. >>> >>>> +} >>>> + >>>> +static void ptn3460_post_disable(struct drm_bridge *bridge) >>>> +{ >>>> +} >>>> + >>>> +void ptn3460_bridge_destroy(struct drm_bridge *bridge) >>>> +{ >>>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>>> + >>>> + drm_bridge_cleanup(bridge); >>>> + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) >>>> + gpio_free(ptn_bridge->gpio_pd_n); >>> >>> Ditto. >>> >>>> + 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 */ >>>> +} >>>> + >>>> +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, >>>> +}; >>>> + >>>> +int ptn3460_get_modes(struct drm_connector *connector) >>>> +{ >>>> + struct ptn3460_bridge *ptn_bridge; >>>> + u8 *edid; >>>> + int ret, num_modes; >>>> + bool power_off; >>>> + >>>> + ptn_bridge = container_of(connector, struct ptn3460_bridge, 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); >>>> + >>>> + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); >>>> + if (!edid) { >>>> + DRM_ERROR("Failed to allocate edid\n"); >>>> + return 0; >>>> + } >>>> + >>>> + ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, >>>> + EDID_LENGTH); >>>> + if (ret) { >>>> + kfree(edid); >>>> + num_modes = 0; >>>> + goto out; >>>> + } >>>> + >>>> + ptn_bridge->edid = (struct edid *)edid; >>>> + drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); >>>> + >>>> + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); >>>> + >>>> +out: >>>> + if (power_off) >>>> + ptn3460_disable(ptn_bridge->bridge); >>>> + >>>> + return num_modes; >>>> +} >>>> + >>>> +static int ptn3460_mode_valid(struct drm_connector *connector, >>>> + struct drm_display_mode *mode) >>>> +{ >>>> + return MODE_OK; >>>> +} >>>> + >>>> +struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) >>>> +{ >>>> + struct ptn3460_bridge *ptn_bridge; >>>> + >>>> + ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); >>>> + >>>> + return ptn_bridge->encoder; >>>> +} >>>> + >>>> +struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { >>>> + .get_modes = ptn3460_get_modes, >>>> + .mode_valid = ptn3460_mode_valid, >>>> + .best_encoder = ptn3460_best_encoder, >>>> +}; >>>> + >>>> +enum drm_connector_status ptn3460_detect(struct drm_connector *connector, >>>> + bool force) >>>> +{ >>>> + return connector_status_connected; >>>> +} >>>> + >>>> +void ptn3460_connector_destroy(struct drm_connector *connector) >>>> +{ >>>> + drm_connector_cleanup(connector); >>>> +} >>>> + >>>> +struct drm_connector_funcs ptn3460_connector_funcs = { >>>> + .dpms = drm_helper_connector_dpms, >>>> + .fill_modes = drm_helper_probe_single_connector_modes, >>>> + .detect = ptn3460_detect, >>>> + .destroy = ptn3460_connector_destroy, >>>> +}; >>> >>> Why do you try to add a new connector here? We already have the >>> connector for LCD, and also provides some callbacks for it. For this, >>> please see exynos_drm_display_ops of exynos_drm_fimd driver, and you >>> can add new callbacks to there such as init callback for bridge device >>> initialization if needed. >>> >> >> We add a new connector for 2 reasons: >> >> 1) We need to override the drm detect() callback to always return true >> since the DP driver will presumably return its hotplug status which >> will always be low when the ptn chip is turned off. >> 2) We want the ability to control the result of get_modes(). >> >> I've got a patch set almost ready to tear the display ops out of fimd >> and put them in the DP driver. > > Really? if so, that is ideal something we want and we should go. But > isn't the DP driver placed in drivers/video/exynos? How did you take > care of that? git mv :) > Actually, for this, we planned to use CDF(Common Display > Framework) if the framework is merged to mainline somehow. > Right. I think CDF will end up being a series of improvements to drm, as opposed to its own framework (at least this was the conclusion I came to after speaking with Laurent at the plumbers conference). I don't think it makes sense to have the DP driver outside of drm. The HDMI driver is already inside drm, the DP driver should be too. Regardless, this conversation is only tangentially related to this patch and can probably be deferred. Sean >> The display ops are better suited >> there, since it's the actual encoder/connector. I hope to get that >> posted this week. >> > > I will look forward to that posting. :) > >> >>>> + >>>> +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); >>> >>> Also, if a regulator is used instead? >>> >>>> + 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); >>>> + return ret; >>>> + } >>>> + } >>>> + >>>> + ptn_bridge->gpio_rst_n = of_get_named_gpio(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) { >>>> + DRM_ERROR("Request reset-gpio failed (%d)\n", ret); >>>> + gpio_free(ptn_bridge->gpio_pd_n); >>>> + return ret; >>>> + } >>>> + } >>>> + >>>> + ret = of_property_read_u32(node, "edid-emulation", >>>> + &ptn_bridge->edid_emulation); >>>> + if (ret) { >>>> + DRM_ERROR("Can't read edid emulation value\n"); >>>> + goto err; >>>> + } >>>> + >>>> + ret = drm_bridge_init(dev, 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; >>>> + >>>> + ret = drm_connector_init(dev, &ptn_bridge->connector, >>>> + &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); >>> >>> So it seems that here's not right place to call drm_connector_init function. >>> >>> Display pipeline path could be one of, >>> Display Controller Display bus >>> --------------------------------------------------------------------------- >>> FIMD---------------------LVDS--------------------LCD, >>> or >>> FIMD----------------------eDP---------------------LCD, >>> or >>> FIMD------------------MIPI-DSI------------------LCD, >>> or >>> FIMD-------------------------------------------------LCD >>> >>> And also in case using image enhancement chip, >>> mDNIe-------------FIMD-LITE between Display Controller and Display >>> bus. >>> >>> So, wouldn't the right place below FIMD driver? :) >>> >> >> Well, this driver should be considered outside of exynos context since >> it could be used by any drm driver. >> >> In the exynos context, the right place to implement it would be in the >> dp driver, actually. However, the exynos driver has a level of >> abstraction on top of the crtcs/encoders such that we need to >> initialize it in the exynos_drm_core. The patchset I mentioned above >> should help move things in a direction where fimd/mixer implement >> drm_crtc directly and hdmi/dp implement drm_encoder/drm_connector >> directly. In that world, DP would initialize the ptn driver. >> >>> >>>> + 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_sysfs_connector_add(&ptn_bridge->connector); >>>> + drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); >>>> + >>>> + 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; >>>> +} >>>> diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h >>>> new file mode 100644 >>>> index 0000000..157ffa1 >>>> --- /dev/null >>>> +++ b/include/drm/bridge/ptn3460.h >>>> @@ -0,0 +1,36 @@ >>>> +/* >>>> + * Copyright (C) 2013 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. >>>> + */ >>>> + >>>> +#ifndef _DRM_BRIDGE_PTN3460_H_ >>>> +#define _DRM_BRIDGE_PTN3460_H_ >>>> + >>>> +struct drm_device; >>>> +struct drm_encoder; >>>> +struct i2c_client; >>>> +struct device_node; >>>> + >>>> +#ifdef CONFIG_DRM_PTN3460 >>>> + >>>> +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, >>>> + struct i2c_client *client, struct device_node *node); >>>> +#else >>>> + >>>> +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, >>>> + struct i2c_client *client, struct device_node *node) >>>> +{ >>>> + return 0; >>>> +} >>>> + >>>> +#endif >>>> + >>>> +#endif >>>> -- >>>> 1.8.4 >>>> >>>> >>>> _______________________________________________ >>>> linux-arm-kernel mailing list >>>> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org >>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel >> _______________________________________________ >> dri-devel mailing list >> dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org >> http://lists.freedesktop.org/mailman/listinfo/dri-devel -- 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] 51+ messages in thread
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-03 18:09 ` Sean Paul @ 2013-10-03 18:23 ` Inki Dae 2013-10-03 18:32 ` Sean Paul 0 siblings, 1 reply; 51+ messages in thread From: Inki Dae @ 2013-10-03 18:23 UTC (permalink / raw) To: Sean Paul Cc: devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, DRI mailing list, linux-arm-kernel@lists.infradead.org 2013/10/4 Sean Paul <seanpaul@chromium.org>: > On Thu, Oct 3, 2013 at 1:39 PM, Inki Dae <inki.dae@samsung.com> wrote: >> 2013/10/3 Sean Paul <seanpaul@chromium.org>: >>> On Thu, Oct 3, 2013 at 9:55 AM, Inki Dae <inki.dae@samsung.com> wrote: >>>> Hi, thank you for your contribution and the below is my short comments, >>>> >>>> 2013/10/2 Sean Paul <seanpaul@chromium.org>: >>>>> This patch adds a drm_bridge driver for the PTN3460 DisplayPort to LVDS >>>>> bridge chip. >>>>> >>>>> Signed-off-by: Sean Paul <seanpaul@chromium.org> >>>>> --- >>>>> .../devicetree/bindings/drm/bridge/ptn3460.txt | 27 ++ >>>>> drivers/gpu/drm/Kconfig | 2 + >>>>> drivers/gpu/drm/Makefile | 1 + >>>>> drivers/gpu/drm/bridge/Kconfig | 4 + >>>>> drivers/gpu/drm/bridge/Makefile | 3 + >>>>> drivers/gpu/drm/bridge/ptn3460.c | 349 +++++++++++++++++++++ >>>>> include/drm/bridge/ptn3460.h | 36 +++ >>>>> 7 files changed, 422 insertions(+) >>>>> create mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>>>> create mode 100644 drivers/gpu/drm/bridge/Kconfig >>>>> create mode 100644 drivers/gpu/drm/bridge/Makefile >>>>> create mode 100644 drivers/gpu/drm/bridge/ptn3460.c >>>>> create mode 100644 include/drm/bridge/ptn3460.h >>>>> >>>>> diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>>>> new file mode 100644 >>>>> index 0000000..c1cd329 >>>>> --- /dev/null >>>>> +++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>>>> @@ -0,0 +1,27 @@ >>>>> +ptn3460-bridge bindings >>>>> + >>>>> +Required properties: >>>>> + - compatible: "nxp,ptn3460" >>>>> + - reg: i2c address of the bridge >>>>> + - powerdown-gpio: OF device-tree gpio specification >>>> >>>> Can a regulator be used instead of gpio in other board case? >>>> >>> >>> No, not to my knowledge. >>> >> >> Hm.. plz check it out again. the gpio pin is specific to board, and >> the the gpio be used as power source trigger could be replaced with a >> regulator according to board design. So you should consider all >> possibilities even though there are no other cases yet: other board >> could use a regulator instead. >> >>> >>>>> + - 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 | >>>>> + +-------+------------+------------------+ >>>>> + >>>>> +Example: >>>>> + ptn3460-bridge@20 { >>>>> + compatible = "nxp,ptn3460"; >>>>> + reg = <0x20>; >>>>> + powerdown-gpio = <&gpy2 5 1 0 0>; >>>>> + reset-gpio = <&gpx1 5 1 0 0>; >>>>> + edid-emulation = <5>; >>>>> + }; >>>>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig >>>>> index 955555d..cd7bfb3 100644 >>>>> --- a/drivers/gpu/drm/Kconfig >>>>> +++ b/drivers/gpu/drm/Kconfig >>>>> @@ -236,3 +236,5 @@ source "drivers/gpu/drm/tilcdc/Kconfig" >>>>> source "drivers/gpu/drm/qxl/Kconfig" >>>>> >>>>> source "drivers/gpu/drm/msm/Kconfig" >>>>> + >>>>> +source "drivers/gpu/drm/bridge/Kconfig" >>>>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile >>>>> index f089adf..9234253 100644 >>>>> --- a/drivers/gpu/drm/Makefile >>>>> +++ b/drivers/gpu/drm/Makefile >>>>> @@ -56,3 +56,4 @@ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ >>>>> obj-$(CONFIG_DRM_QXL) += qxl/ >>>>> obj-$(CONFIG_DRM_MSM) += msm/ >>>>> obj-y += i2c/ >>>>> +obj-y += bridge/ >>>>> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig >>>>> new file mode 100644 >>>>> index 0000000..f8db069 >>>>> --- /dev/null >>>>> +++ b/drivers/gpu/drm/bridge/Kconfig >>>>> @@ -0,0 +1,4 @@ >>>>> +config DRM_PTN3460 >>>>> + tristate "PTN3460 DP/LVDS bridge" >>>>> + depends on DRM && I2C >>>>> + ---help--- >>>>> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile >>>>> new file mode 100644 >>>>> index 0000000..b4733e1 >>>>> --- /dev/null >>>>> +++ b/drivers/gpu/drm/bridge/Makefile >>>>> @@ -0,0 +1,3 @@ >>>>> +ccflags-y := -Iinclude/drm >>>>> + >>>>> +obj-$(CONFIG_DRM_PTN3460) += ptn3460.o >>>>> diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c >>>>> new file mode 100644 >>>>> index 0000000..a9e5c1a >>>>> --- /dev/null >>>>> +++ b/drivers/gpu/drm/bridge/ptn3460.c >>>>> @@ -0,0 +1,349 @@ >>>>> +/* >>>>> + * NXP PTN3460 DP/LVDS bridge driver >>>>> + * >>>>> + * Copyright (C) 2013 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/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 "drm_crtc.h" >>>>> +#include "drm_crtc_helper.h" >>>>> + >>>>> +#include "bridge/ptn3460.h" >>>>> + >>>>> +#define PTN3460_EDID_ADDR 0x0 >>>>> +#define PTN3460_EDID_EMULATION_ADDR 0x84 >>>>> +#define PTN3460_EDID_ENABLE_EMULATION 0 >>>>> +#define PTN3460_EDID_EMULATION_SELECTION 1 >>>>> +#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85 >>>>> + >>>>> +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; >>>>> + int gpio_rst_n; >>>>> + u32 edid_emulation; >>>>> + bool enabled; >>>>> +}; >>>>> + >>>>> +static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, >>>>> + u8 *buf, int len) >>>>> +{ >>>>> + int ret; >>>>> + >>>>> + ret = i2c_master_send(ptn_bridge->client, &addr, 1); >>>>> + if (ret <= 0) { >>>>> + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); >>>>> + return ret; >>>>> + } >>>>> + >>>>> + ret = i2c_master_recv(ptn_bridge->client, buf, len); >>>>> + if (ret <= 0) { >>>>> + DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); >>>>> + return ret; >>>>> + } >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, >>>>> + char val) >>>>> +{ >>>>> + int ret; >>>>> + char buf[2]; >>>>> + >>>>> + buf[0] = addr; >>>>> + buf[1] = val; >>>>> + >>>>> + ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); >>>>> + if (ret <= 0) { >>>>> + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); >>>>> + return ret; >>>>> + } >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) >>>>> +{ >>>>> + int ret; >>>>> + char val; >>>>> + >>>>> + /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */ >>>>> + 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); >>>>> + return ret; >>>>> + } >>>>> + >>>>> + /* Enable EDID emulation and select the desired EDID */ >>>>> + val = 1 << PTN3460_EDID_ENABLE_EMULATION | >>>>> + ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION; >>>>> + >>>>> + ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); >>>>> + if (ret) { >>>>> + DRM_ERROR("Failed to write edid value, ret=%d\n", ret); >>>>> + return ret; >>>>> + } >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +static void ptn3460_pre_enable(struct drm_bridge *bridge) >>>>> +{ >>>>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>>>> + int ret; >>>>> + >>>>> + if (ptn_bridge->enabled) >>>>> + return; >>>>> + >>>>> + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) >>>>> + gpio_set_value(ptn_bridge->gpio_pd_n, 1); >>>> >>>> Ditto. >>>> >>>>> + >>>>> + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { >>>>> + gpio_set_value(ptn_bridge->gpio_rst_n, 0); >>>>> + udelay(10); >>>>> + gpio_set_value(ptn_bridge->gpio_rst_n, 1); >>>>> + } >>>>> + >>>>> + /* >>>>> + * 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 >>>>> + * time specified in the chip's datasheet to make sure we're really up. >>>>> + */ >>>>> + msleep(90); >>>>> + >>>>> + ret = ptn3460_select_edid(ptn_bridge); >>>>> + if (ret) >>>>> + DRM_ERROR("Select edid failed ret=%d\n", ret); >>>>> + >>>>> + ptn_bridge->enabled = true; >>>>> +} >>>>> + >>>>> +static void ptn3460_enable(struct drm_bridge *bridge) >>>>> +{ >>>>> +} >>>>> + >>>>> +static void ptn3460_disable(struct drm_bridge *bridge) >>>>> +{ >>>>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>>>> + >>>>> + if (!ptn_bridge->enabled) >>>>> + return; >>>>> + >>>>> + ptn_bridge->enabled = false; >>>>> + >>>>> + 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); >>>> >>>> Ditto. >>>> >>>>> +} >>>>> + >>>>> +static void ptn3460_post_disable(struct drm_bridge *bridge) >>>>> +{ >>>>> +} >>>>> + >>>>> +void ptn3460_bridge_destroy(struct drm_bridge *bridge) >>>>> +{ >>>>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>>>> + >>>>> + drm_bridge_cleanup(bridge); >>>>> + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) >>>>> + gpio_free(ptn_bridge->gpio_pd_n); >>>> >>>> Ditto. >>>> >>>>> + 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 */ >>>>> +} >>>>> + >>>>> +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, >>>>> +}; >>>>> + >>>>> +int ptn3460_get_modes(struct drm_connector *connector) >>>>> +{ >>>>> + struct ptn3460_bridge *ptn_bridge; >>>>> + u8 *edid; >>>>> + int ret, num_modes; >>>>> + bool power_off; >>>>> + >>>>> + ptn_bridge = container_of(connector, struct ptn3460_bridge, 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); >>>>> + >>>>> + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); >>>>> + if (!edid) { >>>>> + DRM_ERROR("Failed to allocate edid\n"); >>>>> + return 0; >>>>> + } >>>>> + >>>>> + ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, >>>>> + EDID_LENGTH); >>>>> + if (ret) { >>>>> + kfree(edid); >>>>> + num_modes = 0; >>>>> + goto out; >>>>> + } >>>>> + >>>>> + ptn_bridge->edid = (struct edid *)edid; >>>>> + drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); >>>>> + >>>>> + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); >>>>> + >>>>> +out: >>>>> + if (power_off) >>>>> + ptn3460_disable(ptn_bridge->bridge); >>>>> + >>>>> + return num_modes; >>>>> +} >>>>> + >>>>> +static int ptn3460_mode_valid(struct drm_connector *connector, >>>>> + struct drm_display_mode *mode) >>>>> +{ >>>>> + return MODE_OK; >>>>> +} >>>>> + >>>>> +struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) >>>>> +{ >>>>> + struct ptn3460_bridge *ptn_bridge; >>>>> + >>>>> + ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); >>>>> + >>>>> + return ptn_bridge->encoder; >>>>> +} >>>>> + >>>>> +struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { >>>>> + .get_modes = ptn3460_get_modes, >>>>> + .mode_valid = ptn3460_mode_valid, >>>>> + .best_encoder = ptn3460_best_encoder, >>>>> +}; >>>>> + >>>>> +enum drm_connector_status ptn3460_detect(struct drm_connector *connector, >>>>> + bool force) >>>>> +{ >>>>> + return connector_status_connected; >>>>> +} >>>>> + >>>>> +void ptn3460_connector_destroy(struct drm_connector *connector) >>>>> +{ >>>>> + drm_connector_cleanup(connector); >>>>> +} >>>>> + >>>>> +struct drm_connector_funcs ptn3460_connector_funcs = { >>>>> + .dpms = drm_helper_connector_dpms, >>>>> + .fill_modes = drm_helper_probe_single_connector_modes, >>>>> + .detect = ptn3460_detect, >>>>> + .destroy = ptn3460_connector_destroy, >>>>> +}; >>>> >>>> Why do you try to add a new connector here? We already have the >>>> connector for LCD, and also provides some callbacks for it. For this, >>>> please see exynos_drm_display_ops of exynos_drm_fimd driver, and you >>>> can add new callbacks to there such as init callback for bridge device >>>> initialization if needed. >>>> >>> >>> We add a new connector for 2 reasons: >>> >>> 1) We need to override the drm detect() callback to always return true >>> since the DP driver will presumably return its hotplug status which >>> will always be low when the ptn chip is turned off. >>> 2) We want the ability to control the result of get_modes(). >>> >>> I've got a patch set almost ready to tear the display ops out of fimd >>> and put them in the DP driver. >> >> Really? if so, that is ideal something we want and we should go. But >> isn't the DP driver placed in drivers/video/exynos? How did you take >> care of that? > > git mv :) > :) >> Actually, for this, we planned to use CDF(Common Display >> Framework) if the framework is merged to mainline somehow. >> > > Right. I think CDF will end up being a series of improvements to drm, > as opposed to its own framework (at least this was the conclusion I > came to after speaking with Laurent at the plumbers conference). I > don't think it makes sense to have the DP driver outside of drm. The > HDMI driver is already inside drm, the DP driver should be too. See the below, Application -------------------------------------------------------------- v4l2 drm kms hdmi driver hdmi driver ------------------------------------------------------------- hdmi hw HDMI is a controller can be controlled by user application, and for this some frameworks such as v4l2 and drm kms interfaces are used. But DP, MIPI-DSI, LVDS, and so on aren't controlled by user application. These are just display bus between scanout devices(hdmi, fimd) and lcd panel. So the above your example doesn't make sense. > Regardless, this conversation is only tangentially related to this > patch and can probably be deferred. > > Sean > >>> The display ops are better suited >>> there, since it's the actual encoder/connector. I hope to get that >>> posted this week. >>> >> >> I will look forward to that posting. :) >> >>> >>>>> + >>>>> +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); >>>> >>>> Also, if a regulator is used instead? >>>> >>>>> + 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); >>>>> + return ret; >>>>> + } >>>>> + } >>>>> + >>>>> + ptn_bridge->gpio_rst_n = of_get_named_gpio(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) { >>>>> + DRM_ERROR("Request reset-gpio failed (%d)\n", ret); >>>>> + gpio_free(ptn_bridge->gpio_pd_n); >>>>> + return ret; >>>>> + } >>>>> + } >>>>> + >>>>> + ret = of_property_read_u32(node, "edid-emulation", >>>>> + &ptn_bridge->edid_emulation); >>>>> + if (ret) { >>>>> + DRM_ERROR("Can't read edid emulation value\n"); >>>>> + goto err; >>>>> + } >>>>> + >>>>> + ret = drm_bridge_init(dev, 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; >>>>> + >>>>> + ret = drm_connector_init(dev, &ptn_bridge->connector, >>>>> + &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); >>>> >>>> So it seems that here's not right place to call drm_connector_init function. >>>> >>>> Display pipeline path could be one of, >>>> Display Controller Display bus >>>> --------------------------------------------------------------------------- >>>> FIMD---------------------LVDS--------------------LCD, >>>> or >>>> FIMD----------------------eDP---------------------LCD, >>>> or >>>> FIMD------------------MIPI-DSI------------------LCD, >>>> or >>>> FIMD-------------------------------------------------LCD >>>> >>>> And also in case using image enhancement chip, >>>> mDNIe-------------FIMD-LITE between Display Controller and Display >>>> bus. >>>> >>>> So, wouldn't the right place below FIMD driver? :) >>>> >>> >>> Well, this driver should be considered outside of exynos context since >>> it could be used by any drm driver. >>> >>> In the exynos context, the right place to implement it would be in the >>> dp driver, actually. However, the exynos driver has a level of >>> abstraction on top of the crtcs/encoders such that we need to >>> initialize it in the exynos_drm_core. The patchset I mentioned above >>> should help move things in a direction where fimd/mixer implement >>> drm_crtc directly and hdmi/dp implement drm_encoder/drm_connector >>> directly. In that world, DP would initialize the ptn driver. >>> >>>> >>>>> + 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_sysfs_connector_add(&ptn_bridge->connector); >>>>> + drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); >>>>> + >>>>> + 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; >>>>> +} >>>>> diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h >>>>> new file mode 100644 >>>>> index 0000000..157ffa1 >>>>> --- /dev/null >>>>> +++ b/include/drm/bridge/ptn3460.h >>>>> @@ -0,0 +1,36 @@ >>>>> +/* >>>>> + * Copyright (C) 2013 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. >>>>> + */ >>>>> + >>>>> +#ifndef _DRM_BRIDGE_PTN3460_H_ >>>>> +#define _DRM_BRIDGE_PTN3460_H_ >>>>> + >>>>> +struct drm_device; >>>>> +struct drm_encoder; >>>>> +struct i2c_client; >>>>> +struct device_node; >>>>> + >>>>> +#ifdef CONFIG_DRM_PTN3460 >>>>> + >>>>> +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, >>>>> + struct i2c_client *client, struct device_node *node); >>>>> +#else >>>>> + >>>>> +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, >>>>> + struct i2c_client *client, struct device_node *node) >>>>> +{ >>>>> + return 0; >>>>> +} >>>>> + >>>>> +#endif >>>>> + >>>>> +#endif >>>>> -- >>>>> 1.8.4 >>>>> >>>>> >>>>> _______________________________________________ >>>>> 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 > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-03 18:23 ` Inki Dae @ 2013-10-03 18:32 ` Sean Paul 2013-10-04 1:59 ` Inki Dae 0 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-03 18:32 UTC (permalink / raw) To: Inki Dae Cc: devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, DRI mailing list, linux-arm-kernel@lists.infradead.org On Thu, Oct 3, 2013 at 2:23 PM, Inki Dae <inki.dae@samsung.com> wrote: > 2013/10/4 Sean Paul <seanpaul@chromium.org>: >> On Thu, Oct 3, 2013 at 1:39 PM, Inki Dae <inki.dae@samsung.com> wrote: >>> 2013/10/3 Sean Paul <seanpaul@chromium.org>: >>>> On Thu, Oct 3, 2013 at 9:55 AM, Inki Dae <inki.dae@samsung.com> wrote: >>>>> Hi, thank you for your contribution and the below is my short comments, >>>>> >>>>> 2013/10/2 Sean Paul <seanpaul@chromium.org>: >>>>>> This patch adds a drm_bridge driver for the PTN3460 DisplayPort to LVDS >>>>>> bridge chip. >>>>>> >>>>>> Signed-off-by: Sean Paul <seanpaul@chromium.org> >>>>>> --- >>>>>> .../devicetree/bindings/drm/bridge/ptn3460.txt | 27 ++ >>>>>> drivers/gpu/drm/Kconfig | 2 + >>>>>> drivers/gpu/drm/Makefile | 1 + >>>>>> drivers/gpu/drm/bridge/Kconfig | 4 + >>>>>> drivers/gpu/drm/bridge/Makefile | 3 + >>>>>> drivers/gpu/drm/bridge/ptn3460.c | 349 +++++++++++++++++++++ >>>>>> include/drm/bridge/ptn3460.h | 36 +++ >>>>>> 7 files changed, 422 insertions(+) >>>>>> create mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>>>>> create mode 100644 drivers/gpu/drm/bridge/Kconfig >>>>>> create mode 100644 drivers/gpu/drm/bridge/Makefile >>>>>> create mode 100644 drivers/gpu/drm/bridge/ptn3460.c >>>>>> create mode 100644 include/drm/bridge/ptn3460.h >>>>>> >>>>>> diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>>>>> new file mode 100644 >>>>>> index 0000000..c1cd329 >>>>>> --- /dev/null >>>>>> +++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>>>>> @@ -0,0 +1,27 @@ >>>>>> +ptn3460-bridge bindings >>>>>> + >>>>>> +Required properties: >>>>>> + - compatible: "nxp,ptn3460" >>>>>> + - reg: i2c address of the bridge >>>>>> + - powerdown-gpio: OF device-tree gpio specification >>>>> >>>>> Can a regulator be used instead of gpio in other board case? >>>>> >>>> >>>> No, not to my knowledge. >>>> >>> >>> Hm.. plz check it out again. the gpio pin is specific to board, and >>> the the gpio be used as power source trigger could be replaced with a >>> regulator according to board design. So you should consider all >>> possibilities even though there are no other cases yet: other board >>> could use a regulator instead. >>> >>>> >>>>>> + - 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 | >>>>>> + +-------+------------+------------------+ >>>>>> + >>>>>> +Example: >>>>>> + ptn3460-bridge@20 { >>>>>> + compatible = "nxp,ptn3460"; >>>>>> + reg = <0x20>; >>>>>> + powerdown-gpio = <&gpy2 5 1 0 0>; >>>>>> + reset-gpio = <&gpx1 5 1 0 0>; >>>>>> + edid-emulation = <5>; >>>>>> + }; >>>>>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig >>>>>> index 955555d..cd7bfb3 100644 >>>>>> --- a/drivers/gpu/drm/Kconfig >>>>>> +++ b/drivers/gpu/drm/Kconfig >>>>>> @@ -236,3 +236,5 @@ source "drivers/gpu/drm/tilcdc/Kconfig" >>>>>> source "drivers/gpu/drm/qxl/Kconfig" >>>>>> >>>>>> source "drivers/gpu/drm/msm/Kconfig" >>>>>> + >>>>>> +source "drivers/gpu/drm/bridge/Kconfig" >>>>>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile >>>>>> index f089adf..9234253 100644 >>>>>> --- a/drivers/gpu/drm/Makefile >>>>>> +++ b/drivers/gpu/drm/Makefile >>>>>> @@ -56,3 +56,4 @@ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ >>>>>> obj-$(CONFIG_DRM_QXL) += qxl/ >>>>>> obj-$(CONFIG_DRM_MSM) += msm/ >>>>>> obj-y += i2c/ >>>>>> +obj-y += bridge/ >>>>>> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig >>>>>> new file mode 100644 >>>>>> index 0000000..f8db069 >>>>>> --- /dev/null >>>>>> +++ b/drivers/gpu/drm/bridge/Kconfig >>>>>> @@ -0,0 +1,4 @@ >>>>>> +config DRM_PTN3460 >>>>>> + tristate "PTN3460 DP/LVDS bridge" >>>>>> + depends on DRM && I2C >>>>>> + ---help--- >>>>>> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile >>>>>> new file mode 100644 >>>>>> index 0000000..b4733e1 >>>>>> --- /dev/null >>>>>> +++ b/drivers/gpu/drm/bridge/Makefile >>>>>> @@ -0,0 +1,3 @@ >>>>>> +ccflags-y := -Iinclude/drm >>>>>> + >>>>>> +obj-$(CONFIG_DRM_PTN3460) += ptn3460.o >>>>>> diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c >>>>>> new file mode 100644 >>>>>> index 0000000..a9e5c1a >>>>>> --- /dev/null >>>>>> +++ b/drivers/gpu/drm/bridge/ptn3460.c >>>>>> @@ -0,0 +1,349 @@ >>>>>> +/* >>>>>> + * NXP PTN3460 DP/LVDS bridge driver >>>>>> + * >>>>>> + * Copyright (C) 2013 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/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 "drm_crtc.h" >>>>>> +#include "drm_crtc_helper.h" >>>>>> + >>>>>> +#include "bridge/ptn3460.h" >>>>>> + >>>>>> +#define PTN3460_EDID_ADDR 0x0 >>>>>> +#define PTN3460_EDID_EMULATION_ADDR 0x84 >>>>>> +#define PTN3460_EDID_ENABLE_EMULATION 0 >>>>>> +#define PTN3460_EDID_EMULATION_SELECTION 1 >>>>>> +#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85 >>>>>> + >>>>>> +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; >>>>>> + int gpio_rst_n; >>>>>> + u32 edid_emulation; >>>>>> + bool enabled; >>>>>> +}; >>>>>> + >>>>>> +static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, >>>>>> + u8 *buf, int len) >>>>>> +{ >>>>>> + int ret; >>>>>> + >>>>>> + ret = i2c_master_send(ptn_bridge->client, &addr, 1); >>>>>> + if (ret <= 0) { >>>>>> + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); >>>>>> + return ret; >>>>>> + } >>>>>> + >>>>>> + ret = i2c_master_recv(ptn_bridge->client, buf, len); >>>>>> + if (ret <= 0) { >>>>>> + DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); >>>>>> + return ret; >>>>>> + } >>>>>> + >>>>>> + return 0; >>>>>> +} >>>>>> + >>>>>> +static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, >>>>>> + char val) >>>>>> +{ >>>>>> + int ret; >>>>>> + char buf[2]; >>>>>> + >>>>>> + buf[0] = addr; >>>>>> + buf[1] = val; >>>>>> + >>>>>> + ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); >>>>>> + if (ret <= 0) { >>>>>> + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); >>>>>> + return ret; >>>>>> + } >>>>>> + >>>>>> + return 0; >>>>>> +} >>>>>> + >>>>>> +static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) >>>>>> +{ >>>>>> + int ret; >>>>>> + char val; >>>>>> + >>>>>> + /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */ >>>>>> + 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); >>>>>> + return ret; >>>>>> + } >>>>>> + >>>>>> + /* Enable EDID emulation and select the desired EDID */ >>>>>> + val = 1 << PTN3460_EDID_ENABLE_EMULATION | >>>>>> + ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION; >>>>>> + >>>>>> + ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); >>>>>> + if (ret) { >>>>>> + DRM_ERROR("Failed to write edid value, ret=%d\n", ret); >>>>>> + return ret; >>>>>> + } >>>>>> + >>>>>> + return 0; >>>>>> +} >>>>>> + >>>>>> +static void ptn3460_pre_enable(struct drm_bridge *bridge) >>>>>> +{ >>>>>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>>>>> + int ret; >>>>>> + >>>>>> + if (ptn_bridge->enabled) >>>>>> + return; >>>>>> + >>>>>> + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) >>>>>> + gpio_set_value(ptn_bridge->gpio_pd_n, 1); >>>>> >>>>> Ditto. >>>>> >>>>>> + >>>>>> + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { >>>>>> + gpio_set_value(ptn_bridge->gpio_rst_n, 0); >>>>>> + udelay(10); >>>>>> + gpio_set_value(ptn_bridge->gpio_rst_n, 1); >>>>>> + } >>>>>> + >>>>>> + /* >>>>>> + * 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 >>>>>> + * time specified in the chip's datasheet to make sure we're really up. >>>>>> + */ >>>>>> + msleep(90); >>>>>> + >>>>>> + ret = ptn3460_select_edid(ptn_bridge); >>>>>> + if (ret) >>>>>> + DRM_ERROR("Select edid failed ret=%d\n", ret); >>>>>> + >>>>>> + ptn_bridge->enabled = true; >>>>>> +} >>>>>> + >>>>>> +static void ptn3460_enable(struct drm_bridge *bridge) >>>>>> +{ >>>>>> +} >>>>>> + >>>>>> +static void ptn3460_disable(struct drm_bridge *bridge) >>>>>> +{ >>>>>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>>>>> + >>>>>> + if (!ptn_bridge->enabled) >>>>>> + return; >>>>>> + >>>>>> + ptn_bridge->enabled = false; >>>>>> + >>>>>> + 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); >>>>> >>>>> Ditto. >>>>> >>>>>> +} >>>>>> + >>>>>> +static void ptn3460_post_disable(struct drm_bridge *bridge) >>>>>> +{ >>>>>> +} >>>>>> + >>>>>> +void ptn3460_bridge_destroy(struct drm_bridge *bridge) >>>>>> +{ >>>>>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>>>>> + >>>>>> + drm_bridge_cleanup(bridge); >>>>>> + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) >>>>>> + gpio_free(ptn_bridge->gpio_pd_n); >>>>> >>>>> Ditto. >>>>> >>>>>> + 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 */ >>>>>> +} >>>>>> + >>>>>> +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, >>>>>> +}; >>>>>> + >>>>>> +int ptn3460_get_modes(struct drm_connector *connector) >>>>>> +{ >>>>>> + struct ptn3460_bridge *ptn_bridge; >>>>>> + u8 *edid; >>>>>> + int ret, num_modes; >>>>>> + bool power_off; >>>>>> + >>>>>> + ptn_bridge = container_of(connector, struct ptn3460_bridge, 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); >>>>>> + >>>>>> + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); >>>>>> + if (!edid) { >>>>>> + DRM_ERROR("Failed to allocate edid\n"); >>>>>> + return 0; >>>>>> + } >>>>>> + >>>>>> + ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, >>>>>> + EDID_LENGTH); >>>>>> + if (ret) { >>>>>> + kfree(edid); >>>>>> + num_modes = 0; >>>>>> + goto out; >>>>>> + } >>>>>> + >>>>>> + ptn_bridge->edid = (struct edid *)edid; >>>>>> + drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); >>>>>> + >>>>>> + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); >>>>>> + >>>>>> +out: >>>>>> + if (power_off) >>>>>> + ptn3460_disable(ptn_bridge->bridge); >>>>>> + >>>>>> + return num_modes; >>>>>> +} >>>>>> + >>>>>> +static int ptn3460_mode_valid(struct drm_connector *connector, >>>>>> + struct drm_display_mode *mode) >>>>>> +{ >>>>>> + return MODE_OK; >>>>>> +} >>>>>> + >>>>>> +struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) >>>>>> +{ >>>>>> + struct ptn3460_bridge *ptn_bridge; >>>>>> + >>>>>> + ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); >>>>>> + >>>>>> + return ptn_bridge->encoder; >>>>>> +} >>>>>> + >>>>>> +struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { >>>>>> + .get_modes = ptn3460_get_modes, >>>>>> + .mode_valid = ptn3460_mode_valid, >>>>>> + .best_encoder = ptn3460_best_encoder, >>>>>> +}; >>>>>> + >>>>>> +enum drm_connector_status ptn3460_detect(struct drm_connector *connector, >>>>>> + bool force) >>>>>> +{ >>>>>> + return connector_status_connected; >>>>>> +} >>>>>> + >>>>>> +void ptn3460_connector_destroy(struct drm_connector *connector) >>>>>> +{ >>>>>> + drm_connector_cleanup(connector); >>>>>> +} >>>>>> + >>>>>> +struct drm_connector_funcs ptn3460_connector_funcs = { >>>>>> + .dpms = drm_helper_connector_dpms, >>>>>> + .fill_modes = drm_helper_probe_single_connector_modes, >>>>>> + .detect = ptn3460_detect, >>>>>> + .destroy = ptn3460_connector_destroy, >>>>>> +}; >>>>> >>>>> Why do you try to add a new connector here? We already have the >>>>> connector for LCD, and also provides some callbacks for it. For this, >>>>> please see exynos_drm_display_ops of exynos_drm_fimd driver, and you >>>>> can add new callbacks to there such as init callback for bridge device >>>>> initialization if needed. >>>>> >>>> >>>> We add a new connector for 2 reasons: >>>> >>>> 1) We need to override the drm detect() callback to always return true >>>> since the DP driver will presumably return its hotplug status which >>>> will always be low when the ptn chip is turned off. >>>> 2) We want the ability to control the result of get_modes(). >>>> >>>> I've got a patch set almost ready to tear the display ops out of fimd >>>> and put them in the DP driver. >>> >>> Really? if so, that is ideal something we want and we should go. But >>> isn't the DP driver placed in drivers/video/exynos? How did you take >>> care of that? >> >> git mv :) >> > > :) > > >>> Actually, for this, we planned to use CDF(Common Display >>> Framework) if the framework is merged to mainline somehow. >>> >> >> Right. I think CDF will end up being a series of improvements to drm, >> as opposed to its own framework (at least this was the conclusion I >> came to after speaking with Laurent at the plumbers conference). I >> don't think it makes sense to have the DP driver outside of drm. The >> HDMI driver is already inside drm, the DP driver should be too. > > See the below, > > Application > -------------------------------------------------------------- > v4l2 drm kms > hdmi driver hdmi driver > ------------------------------------------------------------- > hdmi hw > > HDMI is a controller can be controlled by user application, and for > this some frameworks such as v4l2 and drm kms interfaces are used. But > DP, MIPI-DSI, LVDS, and so on aren't controlled by user application. > These are just display bus between scanout devices(hdmi, fimd) and lcd > panel. So the above your example doesn't make sense. > I think we've probably gone far enough off-topic. Let's discuss this when you've had an opportunity to see the patchset. I hope the code will speak for itself. Aside from Olof's suggestion about changing the dts binding to lvds-bridge (which I'll upload a new patch for), do you have any suggestions for this patch? Sean >> Regardless, this conversation is only tangentially related to this >> patch and can probably be deferred. >> >> Sean >> >>>> The display ops are better suited >>>> there, since it's the actual encoder/connector. I hope to get that >>>> posted this week. >>>> >>> >>> I will look forward to that posting. :) >>> >>>> >>>>>> + >>>>>> +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); >>>>> >>>>> Also, if a regulator is used instead? >>>>> >>>>>> + 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); >>>>>> + return ret; >>>>>> + } >>>>>> + } >>>>>> + >>>>>> + ptn_bridge->gpio_rst_n = of_get_named_gpio(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) { >>>>>> + DRM_ERROR("Request reset-gpio failed (%d)\n", ret); >>>>>> + gpio_free(ptn_bridge->gpio_pd_n); >>>>>> + return ret; >>>>>> + } >>>>>> + } >>>>>> + >>>>>> + ret = of_property_read_u32(node, "edid-emulation", >>>>>> + &ptn_bridge->edid_emulation); >>>>>> + if (ret) { >>>>>> + DRM_ERROR("Can't read edid emulation value\n"); >>>>>> + goto err; >>>>>> + } >>>>>> + >>>>>> + ret = drm_bridge_init(dev, 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; >>>>>> + >>>>>> + ret = drm_connector_init(dev, &ptn_bridge->connector, >>>>>> + &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); >>>>> >>>>> So it seems that here's not right place to call drm_connector_init function. >>>>> >>>>> Display pipeline path could be one of, >>>>> Display Controller Display bus >>>>> --------------------------------------------------------------------------- >>>>> FIMD---------------------LVDS--------------------LCD, >>>>> or >>>>> FIMD----------------------eDP---------------------LCD, >>>>> or >>>>> FIMD------------------MIPI-DSI------------------LCD, >>>>> or >>>>> FIMD-------------------------------------------------LCD >>>>> >>>>> And also in case using image enhancement chip, >>>>> mDNIe-------------FIMD-LITE between Display Controller and Display >>>>> bus. >>>>> >>>>> So, wouldn't the right place below FIMD driver? :) >>>>> >>>> >>>> Well, this driver should be considered outside of exynos context since >>>> it could be used by any drm driver. >>>> >>>> In the exynos context, the right place to implement it would be in the >>>> dp driver, actually. However, the exynos driver has a level of >>>> abstraction on top of the crtcs/encoders such that we need to >>>> initialize it in the exynos_drm_core. The patchset I mentioned above >>>> should help move things in a direction where fimd/mixer implement >>>> drm_crtc directly and hdmi/dp implement drm_encoder/drm_connector >>>> directly. In that world, DP would initialize the ptn driver. >>>> >>>>> >>>>>> + 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_sysfs_connector_add(&ptn_bridge->connector); >>>>>> + drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); >>>>>> + >>>>>> + 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; >>>>>> +} >>>>>> diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h >>>>>> new file mode 100644 >>>>>> index 0000000..157ffa1 >>>>>> --- /dev/null >>>>>> +++ b/include/drm/bridge/ptn3460.h >>>>>> @@ -0,0 +1,36 @@ >>>>>> +/* >>>>>> + * Copyright (C) 2013 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. >>>>>> + */ >>>>>> + >>>>>> +#ifndef _DRM_BRIDGE_PTN3460_H_ >>>>>> +#define _DRM_BRIDGE_PTN3460_H_ >>>>>> + >>>>>> +struct drm_device; >>>>>> +struct drm_encoder; >>>>>> +struct i2c_client; >>>>>> +struct device_node; >>>>>> + >>>>>> +#ifdef CONFIG_DRM_PTN3460 >>>>>> + >>>>>> +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, >>>>>> + struct i2c_client *client, struct device_node *node); >>>>>> +#else >>>>>> + >>>>>> +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, >>>>>> + struct i2c_client *client, struct device_node *node) >>>>>> +{ >>>>>> + return 0; >>>>>> +} >>>>>> + >>>>>> +#endif >>>>>> + >>>>>> +#endif >>>>>> -- >>>>>> 1.8.4 >>>>>> >>>>>> >>>>>> _______________________________________________ >>>>>> 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 >> _______________________________________________ >> dri-devel mailing list >> dri-devel@lists.freedesktop.org >> http://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-03 18:32 ` Sean Paul @ 2013-10-04 1:59 ` Inki Dae 0 siblings, 0 replies; 51+ messages in thread From: Inki Dae @ 2013-10-04 1:59 UTC (permalink / raw) To: Sean Paul Cc: devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, DRI mailing list, linux-arm-kernel@lists.infradead.org 2013/10/4 Sean Paul <seanpaul@chromium.org>: > On Thu, Oct 3, 2013 at 2:23 PM, Inki Dae <inki.dae@samsung.com> wrote: >> 2013/10/4 Sean Paul <seanpaul@chromium.org>: >>> On Thu, Oct 3, 2013 at 1:39 PM, Inki Dae <inki.dae@samsung.com> wrote: >>>> 2013/10/3 Sean Paul <seanpaul@chromium.org>: >>>>> On Thu, Oct 3, 2013 at 9:55 AM, Inki Dae <inki.dae@samsung.com> wrote: >>>>>> Hi, thank you for your contribution and the below is my short comments, >>>>>> >>>>>> 2013/10/2 Sean Paul <seanpaul@chromium.org>: >>>>>>> This patch adds a drm_bridge driver for the PTN3460 DisplayPort to LVDS >>>>>>> bridge chip. >>>>>>> >>>>>>> Signed-off-by: Sean Paul <seanpaul@chromium.org> >>>>>>> --- >>>>>>> .../devicetree/bindings/drm/bridge/ptn3460.txt | 27 ++ >>>>>>> drivers/gpu/drm/Kconfig | 2 + >>>>>>> drivers/gpu/drm/Makefile | 1 + >>>>>>> drivers/gpu/drm/bridge/Kconfig | 4 + >>>>>>> drivers/gpu/drm/bridge/Makefile | 3 + >>>>>>> drivers/gpu/drm/bridge/ptn3460.c | 349 +++++++++++++++++++++ >>>>>>> include/drm/bridge/ptn3460.h | 36 +++ >>>>>>> 7 files changed, 422 insertions(+) >>>>>>> create mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>>>>>> create mode 100644 drivers/gpu/drm/bridge/Kconfig >>>>>>> create mode 100644 drivers/gpu/drm/bridge/Makefile >>>>>>> create mode 100644 drivers/gpu/drm/bridge/ptn3460.c >>>>>>> create mode 100644 include/drm/bridge/ptn3460.h >>>>>>> >>>>>>> diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>>>>>> new file mode 100644 >>>>>>> index 0000000..c1cd329 >>>>>>> --- /dev/null >>>>>>> +++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt >>>>>>> @@ -0,0 +1,27 @@ >>>>>>> +ptn3460-bridge bindings >>>>>>> + >>>>>>> +Required properties: >>>>>>> + - compatible: "nxp,ptn3460" >>>>>>> + - reg: i2c address of the bridge >>>>>>> + - powerdown-gpio: OF device-tree gpio specification >>>>>> >>>>>> Can a regulator be used instead of gpio in other board case? >>>>>> >>>>> >>>>> No, not to my knowledge. >>>>> >>>> >>>> Hm.. plz check it out again. the gpio pin is specific to board, and >>>> the the gpio be used as power source trigger could be replaced with a >>>> regulator according to board design. So you should consider all >>>> possibilities even though there are no other cases yet: other board >>>> could use a regulator instead. >>>> >>>>> >>>>>>> + - 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 | >>>>>>> + +-------+------------+------------------+ >>>>>>> + >>>>>>> +Example: >>>>>>> + ptn3460-bridge@20 { >>>>>>> + compatible = "nxp,ptn3460"; >>>>>>> + reg = <0x20>; >>>>>>> + powerdown-gpio = <&gpy2 5 1 0 0>; >>>>>>> + reset-gpio = <&gpx1 5 1 0 0>; >>>>>>> + edid-emulation = <5>; >>>>>>> + }; >>>>>>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig >>>>>>> index 955555d..cd7bfb3 100644 >>>>>>> --- a/drivers/gpu/drm/Kconfig >>>>>>> +++ b/drivers/gpu/drm/Kconfig >>>>>>> @@ -236,3 +236,5 @@ source "drivers/gpu/drm/tilcdc/Kconfig" >>>>>>> source "drivers/gpu/drm/qxl/Kconfig" >>>>>>> >>>>>>> source "drivers/gpu/drm/msm/Kconfig" >>>>>>> + >>>>>>> +source "drivers/gpu/drm/bridge/Kconfig" >>>>>>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile >>>>>>> index f089adf..9234253 100644 >>>>>>> --- a/drivers/gpu/drm/Makefile >>>>>>> +++ b/drivers/gpu/drm/Makefile >>>>>>> @@ -56,3 +56,4 @@ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ >>>>>>> obj-$(CONFIG_DRM_QXL) += qxl/ >>>>>>> obj-$(CONFIG_DRM_MSM) += msm/ >>>>>>> obj-y += i2c/ >>>>>>> +obj-y += bridge/ >>>>>>> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig >>>>>>> new file mode 100644 >>>>>>> index 0000000..f8db069 >>>>>>> --- /dev/null >>>>>>> +++ b/drivers/gpu/drm/bridge/Kconfig >>>>>>> @@ -0,0 +1,4 @@ >>>>>>> +config DRM_PTN3460 >>>>>>> + tristate "PTN3460 DP/LVDS bridge" >>>>>>> + depends on DRM && I2C >>>>>>> + ---help--- >>>>>>> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile >>>>>>> new file mode 100644 >>>>>>> index 0000000..b4733e1 >>>>>>> --- /dev/null >>>>>>> +++ b/drivers/gpu/drm/bridge/Makefile >>>>>>> @@ -0,0 +1,3 @@ >>>>>>> +ccflags-y := -Iinclude/drm >>>>>>> + >>>>>>> +obj-$(CONFIG_DRM_PTN3460) += ptn3460.o >>>>>>> diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c >>>>>>> new file mode 100644 >>>>>>> index 0000000..a9e5c1a >>>>>>> --- /dev/null >>>>>>> +++ b/drivers/gpu/drm/bridge/ptn3460.c >>>>>>> @@ -0,0 +1,349 @@ >>>>>>> +/* >>>>>>> + * NXP PTN3460 DP/LVDS bridge driver >>>>>>> + * >>>>>>> + * Copyright (C) 2013 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/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 "drm_crtc.h" >>>>>>> +#include "drm_crtc_helper.h" >>>>>>> + >>>>>>> +#include "bridge/ptn3460.h" >>>>>>> + >>>>>>> +#define PTN3460_EDID_ADDR 0x0 >>>>>>> +#define PTN3460_EDID_EMULATION_ADDR 0x84 >>>>>>> +#define PTN3460_EDID_ENABLE_EMULATION 0 >>>>>>> +#define PTN3460_EDID_EMULATION_SELECTION 1 >>>>>>> +#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85 >>>>>>> + >>>>>>> +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; >>>>>>> + int gpio_rst_n; >>>>>>> + u32 edid_emulation; >>>>>>> + bool enabled; >>>>>>> +}; >>>>>>> + >>>>>>> +static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, >>>>>>> + u8 *buf, int len) >>>>>>> +{ >>>>>>> + int ret; >>>>>>> + >>>>>>> + ret = i2c_master_send(ptn_bridge->client, &addr, 1); >>>>>>> + if (ret <= 0) { >>>>>>> + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); >>>>>>> + return ret; >>>>>>> + } >>>>>>> + >>>>>>> + ret = i2c_master_recv(ptn_bridge->client, buf, len); >>>>>>> + if (ret <= 0) { >>>>>>> + DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); >>>>>>> + return ret; >>>>>>> + } >>>>>>> + >>>>>>> + return 0; >>>>>>> +} >>>>>>> + >>>>>>> +static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, >>>>>>> + char val) >>>>>>> +{ >>>>>>> + int ret; >>>>>>> + char buf[2]; >>>>>>> + >>>>>>> + buf[0] = addr; >>>>>>> + buf[1] = val; >>>>>>> + >>>>>>> + ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); >>>>>>> + if (ret <= 0) { >>>>>>> + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); >>>>>>> + return ret; >>>>>>> + } >>>>>>> + >>>>>>> + return 0; >>>>>>> +} >>>>>>> + >>>>>>> +static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) >>>>>>> +{ >>>>>>> + int ret; >>>>>>> + char val; >>>>>>> + >>>>>>> + /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */ >>>>>>> + 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); >>>>>>> + return ret; >>>>>>> + } >>>>>>> + >>>>>>> + /* Enable EDID emulation and select the desired EDID */ >>>>>>> + val = 1 << PTN3460_EDID_ENABLE_EMULATION | >>>>>>> + ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION; >>>>>>> + >>>>>>> + ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); >>>>>>> + if (ret) { >>>>>>> + DRM_ERROR("Failed to write edid value, ret=%d\n", ret); >>>>>>> + return ret; >>>>>>> + } >>>>>>> + >>>>>>> + return 0; >>>>>>> +} >>>>>>> + >>>>>>> +static void ptn3460_pre_enable(struct drm_bridge *bridge) >>>>>>> +{ >>>>>>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>>>>>> + int ret; >>>>>>> + >>>>>>> + if (ptn_bridge->enabled) >>>>>>> + return; >>>>>>> + >>>>>>> + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) >>>>>>> + gpio_set_value(ptn_bridge->gpio_pd_n, 1); >>>>>> >>>>>> Ditto. >>>>>> >>>>>>> + >>>>>>> + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { >>>>>>> + gpio_set_value(ptn_bridge->gpio_rst_n, 0); >>>>>>> + udelay(10); >>>>>>> + gpio_set_value(ptn_bridge->gpio_rst_n, 1); >>>>>>> + } >>>>>>> + >>>>>>> + /* >>>>>>> + * 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 >>>>>>> + * time specified in the chip's datasheet to make sure we're really up. >>>>>>> + */ >>>>>>> + msleep(90); >>>>>>> + >>>>>>> + ret = ptn3460_select_edid(ptn_bridge); >>>>>>> + if (ret) >>>>>>> + DRM_ERROR("Select edid failed ret=%d\n", ret); >>>>>>> + >>>>>>> + ptn_bridge->enabled = true; >>>>>>> +} >>>>>>> + >>>>>>> +static void ptn3460_enable(struct drm_bridge *bridge) >>>>>>> +{ >>>>>>> +} >>>>>>> + >>>>>>> +static void ptn3460_disable(struct drm_bridge *bridge) >>>>>>> +{ >>>>>>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>>>>>> + >>>>>>> + if (!ptn_bridge->enabled) >>>>>>> + return; >>>>>>> + >>>>>>> + ptn_bridge->enabled = false; >>>>>>> + >>>>>>> + 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); >>>>>> >>>>>> Ditto. >>>>>> >>>>>>> +} >>>>>>> + >>>>>>> +static void ptn3460_post_disable(struct drm_bridge *bridge) >>>>>>> +{ >>>>>>> +} >>>>>>> + >>>>>>> +void ptn3460_bridge_destroy(struct drm_bridge *bridge) >>>>>>> +{ >>>>>>> + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; >>>>>>> + >>>>>>> + drm_bridge_cleanup(bridge); >>>>>>> + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) >>>>>>> + gpio_free(ptn_bridge->gpio_pd_n); >>>>>> >>>>>> Ditto. >>>>>> >>>>>>> + 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 */ >>>>>>> +} >>>>>>> + >>>>>>> +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, >>>>>>> +}; >>>>>>> + >>>>>>> +int ptn3460_get_modes(struct drm_connector *connector) >>>>>>> +{ >>>>>>> + struct ptn3460_bridge *ptn_bridge; >>>>>>> + u8 *edid; >>>>>>> + int ret, num_modes; >>>>>>> + bool power_off; >>>>>>> + >>>>>>> + ptn_bridge = container_of(connector, struct ptn3460_bridge, 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); >>>>>>> + >>>>>>> + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); >>>>>>> + if (!edid) { >>>>>>> + DRM_ERROR("Failed to allocate edid\n"); >>>>>>> + return 0; >>>>>>> + } >>>>>>> + >>>>>>> + ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, >>>>>>> + EDID_LENGTH); >>>>>>> + if (ret) { >>>>>>> + kfree(edid); >>>>>>> + num_modes = 0; >>>>>>> + goto out; >>>>>>> + } >>>>>>> + >>>>>>> + ptn_bridge->edid = (struct edid *)edid; >>>>>>> + drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); >>>>>>> + >>>>>>> + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); >>>>>>> + >>>>>>> +out: >>>>>>> + if (power_off) >>>>>>> + ptn3460_disable(ptn_bridge->bridge); >>>>>>> + >>>>>>> + return num_modes; >>>>>>> +} >>>>>>> + >>>>>>> +static int ptn3460_mode_valid(struct drm_connector *connector, >>>>>>> + struct drm_display_mode *mode) >>>>>>> +{ >>>>>>> + return MODE_OK; >>>>>>> +} >>>>>>> + >>>>>>> +struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) >>>>>>> +{ >>>>>>> + struct ptn3460_bridge *ptn_bridge; >>>>>>> + >>>>>>> + ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); >>>>>>> + >>>>>>> + return ptn_bridge->encoder; >>>>>>> +} >>>>>>> + >>>>>>> +struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { >>>>>>> + .get_modes = ptn3460_get_modes, >>>>>>> + .mode_valid = ptn3460_mode_valid, >>>>>>> + .best_encoder = ptn3460_best_encoder, >>>>>>> +}; >>>>>>> + >>>>>>> +enum drm_connector_status ptn3460_detect(struct drm_connector *connector, >>>>>>> + bool force) >>>>>>> +{ >>>>>>> + return connector_status_connected; >>>>>>> +} >>>>>>> + >>>>>>> +void ptn3460_connector_destroy(struct drm_connector *connector) >>>>>>> +{ >>>>>>> + drm_connector_cleanup(connector); >>>>>>> +} >>>>>>> + >>>>>>> +struct drm_connector_funcs ptn3460_connector_funcs = { >>>>>>> + .dpms = drm_helper_connector_dpms, >>>>>>> + .fill_modes = drm_helper_probe_single_connector_modes, >>>>>>> + .detect = ptn3460_detect, >>>>>>> + .destroy = ptn3460_connector_destroy, >>>>>>> +}; >>>>>> >>>>>> Why do you try to add a new connector here? We already have the >>>>>> connector for LCD, and also provides some callbacks for it. For this, >>>>>> please see exynos_drm_display_ops of exynos_drm_fimd driver, and you >>>>>> can add new callbacks to there such as init callback for bridge device >>>>>> initialization if needed. >>>>>> >>>>> >>>>> We add a new connector for 2 reasons: >>>>> >>>>> 1) We need to override the drm detect() callback to always return true >>>>> since the DP driver will presumably return its hotplug status which >>>>> will always be low when the ptn chip is turned off. >>>>> 2) We want the ability to control the result of get_modes(). >>>>> >>>>> I've got a patch set almost ready to tear the display ops out of fimd >>>>> and put them in the DP driver. >>>> >>>> Really? if so, that is ideal something we want and we should go. But >>>> isn't the DP driver placed in drivers/video/exynos? How did you take >>>> care of that? >>> >>> git mv :) >>> >> >> :) >> >> >>>> Actually, for this, we planned to use CDF(Common Display >>>> Framework) if the framework is merged to mainline somehow. >>>> >>> >>> Right. I think CDF will end up being a series of improvements to drm, >>> as opposed to its own framework (at least this was the conclusion I >>> came to after speaking with Laurent at the plumbers conference). I >>> don't think it makes sense to have the DP driver outside of drm. The >>> HDMI driver is already inside drm, the DP driver should be too. >> >> See the below, >> >> Application >> -------------------------------------------------------------- >> v4l2 drm kms >> hdmi driver hdmi driver >> ------------------------------------------------------------- >> hdmi hw >> >> HDMI is a controller can be controlled by user application, and for >> this some frameworks such as v4l2 and drm kms interfaces are used. But >> DP, MIPI-DSI, LVDS, and so on aren't controlled by user application. >> These are just display bus between scanout devices(hdmi, fimd) and lcd >> panel. So the above your example doesn't make sense. >> > > I think we've probably gone far enough off-topic. Let's discuss this > when you've had an opportunity to see the patchset. I hope the code > will speak for itself. > Ok, let's have a discussion after looking into the codes. > Aside from Olof's suggestion about changing the dts binding to > lvds-bridge (which I'll upload a new patch for), do you have any > suggestions for this patch? > lvds-bridge is better. It seems reasonable to me. > Sean > > >>> Regardless, this conversation is only tangentially related to this >>> patch and can probably be deferred. >>> >>> Sean >>> >>>>> The display ops are better suited >>>>> there, since it's the actual encoder/connector. I hope to get that >>>>> posted this week. >>>>> >>>> >>>> I will look forward to that posting. :) >>>> >>>>> >>>>>>> + >>>>>>> +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); >>>>>> >>>>>> Also, if a regulator is used instead? >>>>>> >>>>>>> + 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); >>>>>>> + return ret; >>>>>>> + } >>>>>>> + } >>>>>>> + >>>>>>> + ptn_bridge->gpio_rst_n = of_get_named_gpio(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) { >>>>>>> + DRM_ERROR("Request reset-gpio failed (%d)\n", ret); >>>>>>> + gpio_free(ptn_bridge->gpio_pd_n); >>>>>>> + return ret; >>>>>>> + } >>>>>>> + } >>>>>>> + >>>>>>> + ret = of_property_read_u32(node, "edid-emulation", >>>>>>> + &ptn_bridge->edid_emulation); >>>>>>> + if (ret) { >>>>>>> + DRM_ERROR("Can't read edid emulation value\n"); >>>>>>> + goto err; >>>>>>> + } >>>>>>> + >>>>>>> + ret = drm_bridge_init(dev, 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; >>>>>>> + >>>>>>> + ret = drm_connector_init(dev, &ptn_bridge->connector, >>>>>>> + &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); >>>>>> >>>>>> So it seems that here's not right place to call drm_connector_init function. >>>>>> >>>>>> Display pipeline path could be one of, >>>>>> Display Controller Display bus >>>>>> --------------------------------------------------------------------------- >>>>>> FIMD---------------------LVDS--------------------LCD, >>>>>> or >>>>>> FIMD----------------------eDP---------------------LCD, >>>>>> or >>>>>> FIMD------------------MIPI-DSI------------------LCD, >>>>>> or >>>>>> FIMD-------------------------------------------------LCD >>>>>> >>>>>> And also in case using image enhancement chip, >>>>>> mDNIe-------------FIMD-LITE between Display Controller and Display >>>>>> bus. >>>>>> >>>>>> So, wouldn't the right place below FIMD driver? :) >>>>>> >>>>> >>>>> Well, this driver should be considered outside of exynos context since >>>>> it could be used by any drm driver. >>>>> >>>>> In the exynos context, the right place to implement it would be in the >>>>> dp driver, actually. However, the exynos driver has a level of >>>>> abstraction on top of the crtcs/encoders such that we need to >>>>> initialize it in the exynos_drm_core. The patchset I mentioned above >>>>> should help move things in a direction where fimd/mixer implement >>>>> drm_crtc directly and hdmi/dp implement drm_encoder/drm_connector >>>>> directly. In that world, DP would initialize the ptn driver. >>>>> >>>>>> >>>>>>> + 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_sysfs_connector_add(&ptn_bridge->connector); >>>>>>> + drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); >>>>>>> + >>>>>>> + 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; >>>>>>> +} >>>>>>> diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h >>>>>>> new file mode 100644 >>>>>>> index 0000000..157ffa1 >>>>>>> --- /dev/null >>>>>>> +++ b/include/drm/bridge/ptn3460.h >>>>>>> @@ -0,0 +1,36 @@ >>>>>>> +/* >>>>>>> + * Copyright (C) 2013 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. >>>>>>> + */ >>>>>>> + >>>>>>> +#ifndef _DRM_BRIDGE_PTN3460_H_ >>>>>>> +#define _DRM_BRIDGE_PTN3460_H_ >>>>>>> + >>>>>>> +struct drm_device; >>>>>>> +struct drm_encoder; >>>>>>> +struct i2c_client; >>>>>>> +struct device_node; >>>>>>> + >>>>>>> +#ifdef CONFIG_DRM_PTN3460 >>>>>>> + >>>>>>> +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, >>>>>>> + struct i2c_client *client, struct device_node *node); >>>>>>> +#else >>>>>>> + >>>>>>> +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, >>>>>>> + struct i2c_client *client, struct device_node *node) >>>>>>> +{ >>>>>>> + return 0; >>>>>>> +} >>>>>>> + >>>>>>> +#endif >>>>>>> + >>>>>>> +#endif >>>>>>> -- >>>>>>> 1.8.4 >>>>>>> >>>>>>> >>>>>>> _______________________________________________ >>>>>>> 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 >>> _______________________________________________ >>> dri-devel mailing list >>> dri-devel@lists.freedesktop.org >>> http://lists.freedesktop.org/mailman/listinfo/dri-devel > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH 0/5] Add some missing bits for exynos5250-snow [not found] ` <1380670860-17621-1-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2013-10-01 23:40 ` [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver Sean Paul @ 2013-10-02 21:07 ` Olof Johansson 2013-10-03 22:28 ` [PATCH v2 " Sean Paul 2 siblings, 0 replies; 51+ messages in thread From: Olof Johansson @ 2013-10-02 21:07 UTC (permalink / raw) To: Sean Paul Cc: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Inki Dae, airlied-cv59FeDIM0c Hi, On Tue, Oct 1, 2013 at 4:40 PM, Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> wrote: > This set adds some missing devicetree nodes to the exynos5250-snow file as well > as adds a drm_bridge driver for the ptn3460 DP-LVDS chip. This chip is used in > the exynos5250-snow board. > > Sean > > > Sean Paul (5): > ARM: dts: Add fimd display-timings for exynos5250-snow > ARM: dts: Add dp-controller node to exynos5250-snow > drm/bridge: Add PTN3460 bridge driver > drm/exynos: Initialize ptn3460 if present > ARM: dts: Add ptn3460 to exynos5250-snow > > Documentation/devicetree/bindings/drm/bridge/ptn3460.txt | 27 +++++++++++++++++++++++++ > arch/arm/boot/dts/exynos5250-snow.dts | 48 ++++++++++++++++++++++++++++++++++++++++++++ This should go in through Kukjin and the arm-soc tree, not through DRM (Looking at the actual patch shortly). > drivers/gpu/drm/Kconfig | 2 ++ > drivers/gpu/drm/Makefile | 1 + > drivers/gpu/drm/bridge/Kconfig | 4 ++++ > drivers/gpu/drm/bridge/Makefile | 3 +++ > drivers/gpu/drm/bridge/ptn3460.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Tip: When you generate the diffstat, redirect to a file or size your window to something less than, oh, 300 characters wide or so. Maybe even down to 80. :) -Olof -- 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] 51+ messages in thread
* [PATCH v2 0/5] Add some missing bits for exynos5250-snow [not found] ` <1380670860-17621-1-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2013-10-01 23:40 ` [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver Sean Paul 2013-10-02 21:07 ` [PATCH 0/5] Add some missing bits for exynos5250-snow Olof Johansson @ 2013-10-03 22:28 ` Sean Paul 2013-10-03 22:28 ` [PATCH v2 1/5] ARM: dts: Add fimd display-timings " Sean Paul ` (6 more replies) 2 siblings, 7 replies; 51+ messages in thread From: Sean Paul @ 2013-10-03 22:28 UTC (permalink / raw) To: kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-doc-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, inki.dae-Sze3O3UU22JBDgjK7y7TUQ Cc: airlied-cv59FeDIM0c This set adds some missing devicetree nodes to the exynos5250-snow file as well as adds a drm_bridge driver for the ptn3460 DP-LVDS chip. This chip is used in the exynos5250-snow board. Sean Sean Paul (5): ARM: dts: Add fimd display-timings for exynos5250-snow ARM: dts: Add dp-controller node to exynos5250-snow drm/bridge: Add PTN3460 bridge driver drm/exynos: Initialize ptn3460 if present ARM: dts: Add ptn3460 to exynos5250-snow Documentation/devicetree/bindings/drm/bridge/ptn3460.txt | 27 +++ arch/arm/boot/dts/exynos5250-snow.dts | 48 +++++ drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/bridge/Kconfig | 4 + drivers/gpu/drm/bridge/Makefile | 3 + drivers/gpu/drm/bridge/ptn3460.c | 349 ++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_core.c | 44 ++++- include/drm/bridge/ptn3460.h | 37 ++++ 9 files changed, 514 insertions(+), 1 deletion(-) -- 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] 51+ messages in thread
* [PATCH v2 1/5] ARM: dts: Add fimd display-timings for exynos5250-snow 2013-10-03 22:28 ` [PATCH v2 " Sean Paul @ 2013-10-03 22:28 ` Sean Paul [not found] ` <1380839303-4834-2-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2013-10-03 22:28 ` [PATCH v2 2/5] ARM: dts: Add dp-controller node to exynos5250-snow Sean Paul ` (5 subsequent siblings) 6 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-03 22:28 UTC (permalink / raw) To: kgene.kim, dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds the internal panel timings to the exynos5250-snow board dts file. Signed-off-by: Sean Paul <seanpaul@chromium.org> --- v2: No difference arch/arm/boot/dts/exynos5250-snow.dts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index fd711e2..2a0f0de 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -186,6 +186,23 @@ samsung,vbus-gpio = <&gpx1 1 0>; }; + fimd: fimd@14400000 { + display-timings { + native-mode = <&lcd_timing>; + lcd_timing: 1366x768 { + clock-frequency = <70589280>; + hactive = <1366>; + vactive = <768>; + hfront-porch = <40>; + hback-porch = <40>; + hsync-len = <32>; + vback-porch = <10>; + vfront-porch = <12>; + vsync-len = <6>; + }; + }; + }; + fixed-rate-clocks { xxti { compatible = "samsung,clock-xxti"; -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
[parent not found: <1380839303-4834-2-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>]
* Re: [PATCH v2 1/5] ARM: dts: Add fimd display-timings for exynos5250-snow [not found] ` <1380839303-4834-2-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> @ 2013-10-04 2:20 ` Jingoo Han 0 siblings, 0 replies; 51+ messages in thread From: Jingoo Han @ 2013-10-04 2:20 UTC (permalink / raw) To: 'Sean Paul' Cc: kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-doc-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, inki.dae-Sze3O3UU22JBDgjK7y7TUQ, airlied-cv59FeDIM0c, 'Jingoo Han' On Friday, October 04, 2013 7:28 AM, Sean Paul wrote: > > This patch adds the internal panel timings to the exynos5250-snow board > dts file. > > Signed-off-by: Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> > --- > > v2: No difference > > arch/arm/boot/dts/exynos5250-snow.dts | 17 +++++++++++++++++ > 1 file changed, 17 insertions(+) > > diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts > index fd711e2..2a0f0de 100644 > --- a/arch/arm/boot/dts/exynos5250-snow.dts > +++ b/arch/arm/boot/dts/exynos5250-snow.dts > @@ -186,6 +186,23 @@ > samsung,vbus-gpio = <&gpx1 1 0>; > }; > > + fimd: fimd@14400000 { > + display-timings { How about adding 'status = "okay"' as below? fimd: fimd@14400000 { status = "okay"; display-timings { status of fimd node was disabled by exynos5.dtsi ./arch/arm/boot/dts/exynos5.dtsi fimd@14400000 { status = "disabled"; Best regards, Jingoo Han -- 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] 51+ messages in thread
* [PATCH v2 2/5] ARM: dts: Add dp-controller node to exynos5250-snow 2013-10-03 22:28 ` [PATCH v2 " Sean Paul 2013-10-03 22:28 ` [PATCH v2 1/5] ARM: dts: Add fimd display-timings " Sean Paul @ 2013-10-03 22:28 ` Sean Paul 2013-10-04 2:24 ` Jingoo Han 2013-10-03 22:28 ` [PATCH v2 3/5] drm/bridge: Add PTN3460 bridge driver Sean Paul ` (4 subsequent siblings) 6 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-03 22:28 UTC (permalink / raw) To: kgene.kim, dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds the dp-controller node to the exynos5250-snow board dts file. Signed-off-by: Sean Paul <seanpaul@chromium.org> --- v2: Added dp-controller address to node (rebased on linux-next) arch/arm/boot/dts/exynos5250-snow.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index 2a0f0de..f1cf68e 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -186,6 +186,18 @@ samsung,vbus-gpio = <&gpx1 1 0>; }; + dp-controller@145B0000 { + samsung,color-space = <0>; + samsung,dynamic-range = <0>; + samsung,ycbcr-coeff = <0>; + samsung,color-depth = <1>; + samsung,link-rate = <0x0a>; + samsung,lane-count = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&dp_hpd>; + }; + fimd: fimd@14400000 { display-timings { native-mode = <&lcd_timing>; -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
* Re: [PATCH v2 2/5] ARM: dts: Add dp-controller node to exynos5250-snow 2013-10-03 22:28 ` [PATCH v2 2/5] ARM: dts: Add dp-controller node to exynos5250-snow Sean Paul @ 2013-10-04 2:24 ` Jingoo Han 0 siblings, 0 replies; 51+ messages in thread From: Jingoo Han @ 2013-10-04 2:24 UTC (permalink / raw) To: 'Sean Paul' Cc: airlied, kgene.kim, dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae, 'Jingoo Han' On Friday, October 04, 2013 7:28 AM, Sean Paul wrote: > > This patch adds the dp-controller node to the exynos5250-snow board dts > file. > > Signed-off-by: Sean Paul <seanpaul@chromium.org> > --- > > v2: Added dp-controller address to node (rebased on linux-next) > > arch/arm/boot/dts/exynos5250-snow.dts | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > > diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts > index 2a0f0de..f1cf68e 100644 > --- a/arch/arm/boot/dts/exynos5250-snow.dts > +++ b/arch/arm/boot/dts/exynos5250-snow.dts > @@ -186,6 +186,18 @@ > samsung,vbus-gpio = <&gpx1 1 0>; > }; > > + dp-controller@145B0000 { > + samsung,color-space = <0>; > + samsung,dynamic-range = <0>; > + samsung,ycbcr-coeff = <0>; > + samsung,color-depth = <1>; > + samsung,link-rate = <0x0a>; > + samsung,lane-count = <2>; > + > + pinctrl-names = "default"; > + pinctrl-0 = <&dp_hpd>; How about adding 'status = "okay" as below? pinctrl-names = "default"; pinctrl-0 = <&dp_hpd>; status = "okay"; status of dp node was disabled by exynos5.dtsi. ./arch/arm/boot/dts/exynos5.dtsi dp-controller@145B0000 { status = "disabled"; Best regards, Jingoo Han ^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH v2 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-03 22:28 ` [PATCH v2 " Sean Paul 2013-10-03 22:28 ` [PATCH v2 1/5] ARM: dts: Add fimd display-timings " Sean Paul 2013-10-03 22:28 ` [PATCH v2 2/5] ARM: dts: Add dp-controller node to exynos5250-snow Sean Paul @ 2013-10-03 22:28 ` Sean Paul 2013-10-03 22:28 ` [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present Sean Paul ` (3 subsequent siblings) 6 siblings, 0 replies; 51+ messages in thread From: Sean Paul @ 2013-10-03 22:28 UTC (permalink / raw) To: kgene.kim, dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds a drm_bridge driver for the PTN3460 DisplayPort to LVDS bridge chip. Signed-off-by: Sean Paul <seanpaul@chromium.org> --- v2: - Changed header definition to static inline - Changed dt node name to lvds-bridge .../devicetree/bindings/drm/bridge/ptn3460.txt | 27 ++ drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/bridge/Kconfig | 4 + drivers/gpu/drm/bridge/Makefile | 3 + drivers/gpu/drm/bridge/ptn3460.c | 349 +++++++++++++++++++++ include/drm/bridge/ptn3460.h | 37 +++ 7 files changed, 423 insertions(+) create mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt create mode 100644 drivers/gpu/drm/bridge/Kconfig create mode 100644 drivers/gpu/drm/bridge/Makefile create mode 100644 drivers/gpu/drm/bridge/ptn3460.c create mode 100644 include/drm/bridge/ptn3460.h diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt new file mode 100644 index 0000000..52b93b2 --- /dev/null +++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt @@ -0,0 +1,27 @@ +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 | + +-------+------------+------------------+ + +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>; + }; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 955555d..cd7bfb3 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -236,3 +236,5 @@ source "drivers/gpu/drm/tilcdc/Kconfig" source "drivers/gpu/drm/qxl/Kconfig" source "drivers/gpu/drm/msm/Kconfig" + +source "drivers/gpu/drm/bridge/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index f089adf..9234253 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -56,3 +56,4 @@ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ obj-$(CONFIG_DRM_QXL) += qxl/ obj-$(CONFIG_DRM_MSM) += msm/ obj-y += i2c/ +obj-y += bridge/ diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig new file mode 100644 index 0000000..f8db069 --- /dev/null +++ b/drivers/gpu/drm/bridge/Kconfig @@ -0,0 +1,4 @@ +config DRM_PTN3460 + tristate "PTN3460 DP/LVDS bridge" + depends on DRM && I2C + ---help--- diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile new file mode 100644 index 0000000..b4733e1 --- /dev/null +++ b/drivers/gpu/drm/bridge/Makefile @@ -0,0 +1,3 @@ +ccflags-y := -Iinclude/drm + +obj-$(CONFIG_DRM_PTN3460) += ptn3460.o diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c new file mode 100644 index 0000000..a9e5c1a --- /dev/null +++ b/drivers/gpu/drm/bridge/ptn3460.c @@ -0,0 +1,349 @@ +/* + * NXP PTN3460 DP/LVDS bridge driver + * + * Copyright (C) 2013 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/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 "drm_crtc.h" +#include "drm_crtc_helper.h" + +#include "bridge/ptn3460.h" + +#define PTN3460_EDID_ADDR 0x0 +#define PTN3460_EDID_EMULATION_ADDR 0x84 +#define PTN3460_EDID_ENABLE_EMULATION 0 +#define PTN3460_EDID_EMULATION_SELECTION 1 +#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85 + +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; + int gpio_rst_n; + u32 edid_emulation; + bool enabled; +}; + +static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, + u8 *buf, int len) +{ + int ret; + + ret = i2c_master_send(ptn_bridge->client, &addr, 1); + if (ret <= 0) { + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); + return ret; + } + + ret = i2c_master_recv(ptn_bridge->client, buf, len); + if (ret <= 0) { + DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, + char val) +{ + int ret; + char buf[2]; + + buf[0] = addr; + buf[1] = val; + + ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); + if (ret <= 0) { + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) +{ + int ret; + char val; + + /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */ + 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); + return ret; + } + + /* Enable EDID emulation and select the desired EDID */ + val = 1 << PTN3460_EDID_ENABLE_EMULATION | + ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION; + + ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); + if (ret) { + DRM_ERROR("Failed to write edid value, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static void ptn3460_pre_enable(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + int ret; + + if (ptn_bridge->enabled) + return; + + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) + gpio_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); + udelay(10); + gpio_set_value(ptn_bridge->gpio_rst_n, 1); + } + + /* + * 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 + * time specified in the chip's datasheet to make sure we're really up. + */ + msleep(90); + + ret = ptn3460_select_edid(ptn_bridge); + if (ret) + DRM_ERROR("Select edid failed ret=%d\n", ret); + + ptn_bridge->enabled = true; +} + +static void ptn3460_enable(struct drm_bridge *bridge) +{ +} + +static void ptn3460_disable(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + + if (!ptn_bridge->enabled) + return; + + ptn_bridge->enabled = false; + + 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); +} + +static void ptn3460_post_disable(struct drm_bridge *bridge) +{ +} + +void ptn3460_bridge_destroy(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + + 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 */ +} + +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, +}; + +int ptn3460_get_modes(struct drm_connector *connector) +{ + struct ptn3460_bridge *ptn_bridge; + u8 *edid; + int ret, num_modes; + bool power_off; + + ptn_bridge = container_of(connector, struct ptn3460_bridge, 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); + + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!edid) { + DRM_ERROR("Failed to allocate edid\n"); + return 0; + } + + ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, + EDID_LENGTH); + if (ret) { + kfree(edid); + num_modes = 0; + goto out; + } + + ptn_bridge->edid = (struct edid *)edid; + drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); + + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); + +out: + if (power_off) + ptn3460_disable(ptn_bridge->bridge); + + return num_modes; +} + +static int ptn3460_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) +{ + struct ptn3460_bridge *ptn_bridge; + + ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); + + return ptn_bridge->encoder; +} + +struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { + .get_modes = ptn3460_get_modes, + .mode_valid = ptn3460_mode_valid, + .best_encoder = ptn3460_best_encoder, +}; + +enum drm_connector_status ptn3460_detect(struct drm_connector *connector, + bool force) +{ + return connector_status_connected; +} + +void ptn3460_connector_destroy(struct drm_connector *connector) +{ + drm_connector_cleanup(connector); +} + +struct drm_connector_funcs ptn3460_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = ptn3460_detect, + .destroy = ptn3460_connector_destroy, +}; + +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); + return ret; + } + } + + ptn_bridge->gpio_rst_n = of_get_named_gpio(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) { + DRM_ERROR("Request reset-gpio failed (%d)\n", ret); + gpio_free(ptn_bridge->gpio_pd_n); + return ret; + } + } + + ret = of_property_read_u32(node, "edid-emulation", + &ptn_bridge->edid_emulation); + if (ret) { + DRM_ERROR("Can't read edid emulation value\n"); + goto err; + } + + ret = drm_bridge_init(dev, 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; + + 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_sysfs_connector_add(&ptn_bridge->connector); + drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); + + 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; +} diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h new file mode 100644 index 0000000..8481816 --- /dev/null +++ b/include/drm/bridge/ptn3460.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef _DRM_BRIDGE_PTN3460_H_ +#define _DRM_BRIDGE_PTN3460_H_ + +struct drm_device; +struct drm_encoder; +struct i2c_client; +struct device_node; + +#ifdef CONFIG_DRM_PTN3460 + +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, + struct i2c_client *client, struct device_node *node); +#else + +static inline int ptn3460_init(struct drm_device *dev, + struct drm_encoder *encoder, struct i2c_client *client, + struct device_node *node) +{ + return 0; +} + +#endif + +#endif -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present 2013-10-03 22:28 ` [PATCH v2 " Sean Paul ` (2 preceding siblings ...) 2013-10-03 22:28 ` [PATCH v2 3/5] drm/bridge: Add PTN3460 bridge driver Sean Paul @ 2013-10-03 22:28 ` Sean Paul 2013-10-04 2:29 ` Inki Dae 2013-10-03 22:28 ` [PATCH v2 5/5] ARM: dts: Add ptn3460 to exynos5250-snow Sean Paul ` (2 subsequent siblings) 6 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-03 22:28 UTC (permalink / raw) To: kgene.kim, dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds code to look for the ptn3460 in the device tree file on exynos initialization. If ptn node is found, the driver will initialize the ptn3460 driver and skip creating a DP connector (since the bridge driver will register its own connector). Signed-off-by: Sean Paul <seanpaul@chromium.org> --- v2: - Changed include from of_i2c.h to i2c.h - Changed of_find_by_name to of_find_compatible drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 1bef6dc..08ca4f9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -12,7 +12,9 @@ * option) any later version. */ +#include <linux/i2c.h> #include <drm/drmP.h> +#include <drm/bridge/ptn3460.h> #include "exynos_drm_drv.h" #include "exynos_drm_encoder.h" #include "exynos_drm_connector.h" @@ -20,6 +22,40 @@ static LIST_HEAD(exynos_drm_subdrv_list); +struct bridge_init { + struct i2c_client *client; + struct device_node *node; +}; + +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; +} + static int exynos_drm_create_enc_conn(struct drm_device *dev, struct exynos_drm_subdrv *subdrv) { @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, DRM_ERROR("failed to create encoder\n"); return -EFAULT; } + subdrv->encoder = encoder; + + if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) { + ret = exynos_drm_attach_lcd_bridge(dev, encoder); + if (ret) + return 0; + } /* * create and initialize a connector for this sub driver and @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, goto err_destroy_encoder; } - subdrv->encoder = encoder; subdrv->connector = connector; return 0; -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
* Re: [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present 2013-10-03 22:28 ` [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present Sean Paul @ 2013-10-04 2:29 ` Inki Dae 2013-10-04 2:41 ` Sean Paul 0 siblings, 1 reply; 51+ messages in thread From: Inki Dae @ 2013-10-04 2:29 UTC (permalink / raw) To: Sean Paul Cc: Kukjin Kim, DRI mailing list, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Dave Airlie 2013/10/4 Sean Paul <seanpaul@chromium.org>: > This patch adds code to look for the ptn3460 in the device tree file on > exynos initialization. If ptn node is found, the driver will initialize > the ptn3460 driver and skip creating a DP connector (since the bridge > driver will register its own connector). > > Signed-off-by: Sean Paul <seanpaul@chromium.org> > --- > > v2: > - Changed include from of_i2c.h to i2c.h > - Changed of_find_by_name to of_find_compatible > > drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++- > 1 file changed, 43 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c > index 1bef6dc..08ca4f9 100644 > --- a/drivers/gpu/drm/exynos/exynos_drm_core.c > +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c > @@ -12,7 +12,9 @@ > * option) any later version. > */ > > +#include <linux/i2c.h> > #include <drm/drmP.h> > +#include <drm/bridge/ptn3460.h> > #include "exynos_drm_drv.h" > #include "exynos_drm_encoder.h" > #include "exynos_drm_connector.h" > @@ -20,6 +22,40 @@ > > static LIST_HEAD(exynos_drm_subdrv_list); > > +struct bridge_init { > + struct i2c_client *client; > + struct device_node *node; > +}; > + > +static bool find_bridge(const char *compat, struct bridge_init *bridge) > +{ > + bridge->client = NULL; > + bridge->node = of_find_compatible_node(NULL, NULL, compat); Then, shouldn't the lvds-bridge driver be implemented as i2c driver so that such tricky isn't needed? Is there any reason you use such tricky codes? I think you need to implement the lvds-bridge driver as i2c driver, and then consider how to take care of this. I mean let's find a better way how we could take care of the i2c based driver in exynos drm framework or driver. In all cases, such tricky codes are not good. > + 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; > +} > + > static int exynos_drm_create_enc_conn(struct drm_device *dev, > struct exynos_drm_subdrv *subdrv) > { > @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, > DRM_ERROR("failed to create encoder\n"); > return -EFAULT; > } > + subdrv->encoder = encoder; > + > + if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) { > + ret = exynos_drm_attach_lcd_bridge(dev, encoder); > + if (ret) > + return 0; > + } > > /* > * create and initialize a connector for this sub driver and > @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, > goto err_destroy_encoder; > } > > - subdrv->encoder = encoder; > subdrv->connector = connector; > > return 0; > -- > 1.8.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present 2013-10-04 2:29 ` Inki Dae @ 2013-10-04 2:41 ` Sean Paul 2013-10-04 4:18 ` Inki Dae 0 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-04 2:41 UTC (permalink / raw) To: Inki Dae Cc: Kukjin Kim, DRI mailing list, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Dave Airlie On Thu, Oct 3, 2013 at 10:29 PM, Inki Dae <inki.dae@samsung.com> wrote: > 2013/10/4 Sean Paul <seanpaul@chromium.org>: >> This patch adds code to look for the ptn3460 in the device tree file on >> exynos initialization. If ptn node is found, the driver will initialize >> the ptn3460 driver and skip creating a DP connector (since the bridge >> driver will register its own connector). >> >> Signed-off-by: Sean Paul <seanpaul@chromium.org> >> --- >> >> v2: >> - Changed include from of_i2c.h to i2c.h >> - Changed of_find_by_name to of_find_compatible >> >> drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++- >> 1 file changed, 43 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c >> index 1bef6dc..08ca4f9 100644 >> --- a/drivers/gpu/drm/exynos/exynos_drm_core.c >> +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c >> @@ -12,7 +12,9 @@ >> * option) any later version. >> */ >> >> +#include <linux/i2c.h> >> #include <drm/drmP.h> >> +#include <drm/bridge/ptn3460.h> >> #include "exynos_drm_drv.h" >> #include "exynos_drm_encoder.h" >> #include "exynos_drm_connector.h" >> @@ -20,6 +22,40 @@ >> >> static LIST_HEAD(exynos_drm_subdrv_list); >> >> +struct bridge_init { >> + struct i2c_client *client; >> + struct device_node *node; >> +}; >> + >> +static bool find_bridge(const char *compat, struct bridge_init *bridge) >> +{ >> + bridge->client = NULL; >> + bridge->node = of_find_compatible_node(NULL, NULL, compat); > > Then, shouldn't the lvds-bridge driver be implemented as i2c driver so > that such tricky isn't needed? Is there any reason you use such tricky > codes? > This is what I was explaining earlier today. If the bridge driver is just an i2c driver, it won't get a pointer to drm_device, and can't register itself as a drm_bridge or drm_connector. To solve this, you need the ptn3460_init callback. If it's an i2c driver with the ptn3460_init callback, where it parses the dt in probe, then you have a race between the ptn probe and the ptn init/drm hooks. ie: it's possible drm will initialize and call disable/post_disable/pre_enable/enable before things have been probed. To solve this, you need to use some global state and/or locking. So, to summarize. We can have this of_find_compatible with a init callback, or we can have an i2c driver + global state/locking + init callback. I chose the former, since it seemed easier. If you have a better way to achieve this, I'm definitely interested, but I saw this as the lesser of two evils. Sean > I think you need to implement the lvds-bridge driver as i2c driver, > and then consider how to take care of this. I mean let's find a better > way how we could take care of the i2c based driver in exynos drm > framework or driver. In all cases, such tricky codes are not good. > >> + 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; >> +} >> + >> static int exynos_drm_create_enc_conn(struct drm_device *dev, >> struct exynos_drm_subdrv *subdrv) >> { >> @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >> DRM_ERROR("failed to create encoder\n"); >> return -EFAULT; >> } >> + subdrv->encoder = encoder; >> + >> + if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) { >> + ret = exynos_drm_attach_lcd_bridge(dev, encoder); >> + if (ret) >> + return 0; >> + } >> >> /* >> * create and initialize a connector for this sub driver and >> @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >> goto err_destroy_encoder; >> } >> >> - subdrv->encoder = encoder; >> subdrv->connector = connector; >> >> return 0; >> -- >> 1.8.4 >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present 2013-10-04 2:41 ` Sean Paul @ 2013-10-04 4:18 ` Inki Dae [not found] ` <CAAQKjZMfP_Cgo5hPPTiwKa_+Ph+GUt2Fbdtipd5V=CQEDy3eSQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 51+ messages in thread From: Inki Dae @ 2013-10-04 4:18 UTC (permalink / raw) To: Sean Paul Cc: Kukjin Kim, DRI mailing list, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Dave Airlie 2013/10/4 Sean Paul <seanpaul@chromium.org>: > On Thu, Oct 3, 2013 at 10:29 PM, Inki Dae <inki.dae@samsung.com> wrote: >> 2013/10/4 Sean Paul <seanpaul@chromium.org>: >>> This patch adds code to look for the ptn3460 in the device tree file on >>> exynos initialization. If ptn node is found, the driver will initialize >>> the ptn3460 driver and skip creating a DP connector (since the bridge >>> driver will register its own connector). >>> >>> Signed-off-by: Sean Paul <seanpaul@chromium.org> >>> --- >>> >>> v2: >>> - Changed include from of_i2c.h to i2c.h >>> - Changed of_find_by_name to of_find_compatible >>> >>> drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++- >>> 1 file changed, 43 insertions(+), 1 deletion(-) >>> >>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c >>> index 1bef6dc..08ca4f9 100644 >>> --- a/drivers/gpu/drm/exynos/exynos_drm_core.c >>> +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c >>> @@ -12,7 +12,9 @@ >>> * option) any later version. >>> */ >>> >>> +#include <linux/i2c.h> >>> #include <drm/drmP.h> >>> +#include <drm/bridge/ptn3460.h> >>> #include "exynos_drm_drv.h" >>> #include "exynos_drm_encoder.h" >>> #include "exynos_drm_connector.h" >>> @@ -20,6 +22,40 @@ >>> >>> static LIST_HEAD(exynos_drm_subdrv_list); >>> >>> +struct bridge_init { >>> + struct i2c_client *client; >>> + struct device_node *node; >>> +}; >>> + >>> +static bool find_bridge(const char *compat, struct bridge_init *bridge) >>> +{ >>> + bridge->client = NULL; >>> + bridge->node = of_find_compatible_node(NULL, NULL, compat); >> >> Then, shouldn't the lvds-bridge driver be implemented as i2c driver so >> that such tricky isn't needed? Is there any reason you use such tricky >> codes? >> > > This is what I was explaining earlier today. If the bridge driver is > just an i2c driver, it won't get a pointer to drm_device, and can't > register itself as a drm_bridge or drm_connector. To solve this, you > need the ptn3460_init callback. > No, I think you can use sub driver. how about registering to exynos drm core that driver using exynos_drm_subdrv_register function after probed? Is there something I am missing? > If it's an i2c driver with the ptn3460_init callback, where it parses > the dt in probe, then you have a race between the ptn probe and the > ptn init/drm hooks. ie: it's possible drm will initialize and call > disable/post_disable/pre_enable/enable before things have been probed. And also, exynos drm core will call a probe callback of the sub driver after _drm is initialized_. Is there something I am missing? > To solve this, you need to use some global state and/or locking. > > So, to summarize. We can have this of_find_compatible with a init > callback, or we can have an i2c driver + global state/locking + init > callback. I chose the former, since it seemed easier. > > If you have a better way to achieve this, I'm definitely interested, > but I saw this as the lesser of two evils. > > Sean > >> I think you need to implement the lvds-bridge driver as i2c driver, >> and then consider how to take care of this. I mean let's find a better >> way how we could take care of the i2c based driver in exynos drm >> framework or driver. In all cases, such tricky codes are not good. >> >>> + 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; >>> +} >>> + >>> static int exynos_drm_create_enc_conn(struct drm_device *dev, >>> struct exynos_drm_subdrv *subdrv) >>> { >>> @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >>> DRM_ERROR("failed to create encoder\n"); >>> return -EFAULT; >>> } >>> + subdrv->encoder = encoder; >>> + >>> + if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) { >>> + ret = exynos_drm_attach_lcd_bridge(dev, encoder); >>> + if (ret) >>> + return 0; >>> + } >>> >>> /* >>> * create and initialize a connector for this sub driver and >>> @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >>> goto err_destroy_encoder; >>> } >>> >>> - subdrv->encoder = encoder; >>> subdrv->connector = connector; >>> >>> return 0; >>> -- >>> 1.8.4 >>> >>> -- >>> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in >>> the body of a message to majordomo@vger.kernel.org >>> More majordomo info at http://vger.kernel.org/majordomo-info.html > -- > To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 51+ messages in thread
[parent not found: <CAAQKjZMfP_Cgo5hPPTiwKa_+Ph+GUt2Fbdtipd5V=CQEDy3eSQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present [not found] ` <CAAQKjZMfP_Cgo5hPPTiwKa_+Ph+GUt2Fbdtipd5V=CQEDy3eSQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2013-10-04 14:17 ` Sean Paul [not found] ` <CAOw6vbL_W-8S+htX9KB2ABbtr9+JhfxHuL2ikJG7CrqEkeo9NA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-04 14:17 UTC (permalink / raw) To: Inki Dae Cc: Kukjin Kim, DRI mailing list, linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Dave Airlie On Fri, Oct 4, 2013 at 12:18 AM, Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote: > 2013/10/4 Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>: >> On Thu, Oct 3, 2013 at 10:29 PM, Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote: >>> 2013/10/4 Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>: >>>> This patch adds code to look for the ptn3460 in the device tree file on >>>> exynos initialization. If ptn node is found, the driver will initialize >>>> the ptn3460 driver and skip creating a DP connector (since the bridge >>>> driver will register its own connector). >>>> >>>> Signed-off-by: Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> >>>> --- >>>> >>>> v2: >>>> - Changed include from of_i2c.h to i2c.h >>>> - Changed of_find_by_name to of_find_compatible >>>> >>>> drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++- >>>> 1 file changed, 43 insertions(+), 1 deletion(-) >>>> >>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c >>>> index 1bef6dc..08ca4f9 100644 >>>> --- a/drivers/gpu/drm/exynos/exynos_drm_core.c >>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c >>>> @@ -12,7 +12,9 @@ >>>> * option) any later version. >>>> */ >>>> >>>> +#include <linux/i2c.h> >>>> #include <drm/drmP.h> >>>> +#include <drm/bridge/ptn3460.h> >>>> #include "exynos_drm_drv.h" >>>> #include "exynos_drm_encoder.h" >>>> #include "exynos_drm_connector.h" >>>> @@ -20,6 +22,40 @@ >>>> >>>> static LIST_HEAD(exynos_drm_subdrv_list); >>>> >>>> +struct bridge_init { >>>> + struct i2c_client *client; >>>> + struct device_node *node; >>>> +}; >>>> + >>>> +static bool find_bridge(const char *compat, struct bridge_init *bridge) >>>> +{ >>>> + bridge->client = NULL; >>>> + bridge->node = of_find_compatible_node(NULL, NULL, compat); >>> >>> Then, shouldn't the lvds-bridge driver be implemented as i2c driver so >>> that such tricky isn't needed? Is there any reason you use such tricky >>> codes? >>> >> >> This is what I was explaining earlier today. If the bridge driver is >> just an i2c driver, it won't get a pointer to drm_device, and can't >> register itself as a drm_bridge or drm_connector. To solve this, you >> need the ptn3460_init callback. >> > > No, I think you can use sub driver. how about registering to exynos > drm core that driver using exynos_drm_subdrv_register function after > probed? Is there something I am missing? > The ptn driver isn't exynos-specific, so I don't think making it an exynos_drm_subdrv is appropriate. Sean > >> If it's an i2c driver with the ptn3460_init callback, where it parses >> the dt in probe, then you have a race between the ptn probe and the >> ptn init/drm hooks. ie: it's possible drm will initialize and call >> disable/post_disable/pre_enable/enable before things have been probed. > > And also, exynos drm core will call a probe callback of the sub driver > after _drm is initialized_. Is there something I am missing? > >> To solve this, you need to use some global state and/or locking. >> >> So, to summarize. We can have this of_find_compatible with a init >> callback, or we can have an i2c driver + global state/locking + init >> callback. I chose the former, since it seemed easier. >> >> If you have a better way to achieve this, I'm definitely interested, >> but I saw this as the lesser of two evils. >> >> Sean >> >>> I think you need to implement the lvds-bridge driver as i2c driver, >>> and then consider how to take care of this. I mean let's find a better >>> way how we could take care of the i2c based driver in exynos drm >>> framework or driver. In all cases, such tricky codes are not good. >>> >>>> + 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; >>>> +} >>>> + >>>> static int exynos_drm_create_enc_conn(struct drm_device *dev, >>>> struct exynos_drm_subdrv *subdrv) >>>> { >>>> @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >>>> DRM_ERROR("failed to create encoder\n"); >>>> return -EFAULT; >>>> } >>>> + subdrv->encoder = encoder; >>>> + >>>> + if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) { >>>> + ret = exynos_drm_attach_lcd_bridge(dev, encoder); >>>> + if (ret) >>>> + return 0; >>>> + } >>>> >>>> /* >>>> * create and initialize a connector for this sub driver and >>>> @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, >>>> goto err_destroy_encoder; >>>> } >>>> >>>> - subdrv->encoder = encoder; >>>> subdrv->connector = connector; >>>> >>>> return 0; >>>> -- >>>> 1.8.4 >>>> >>>> -- >>>> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in >>>> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org >>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in >> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html -- 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] 51+ messages in thread
[parent not found: <CAOw6vbL_W-8S+htX9KB2ABbtr9+JhfxHuL2ikJG7CrqEkeo9NA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* RE: [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present [not found] ` <CAOw6vbL_W-8S+htX9KB2ABbtr9+JhfxHuL2ikJG7CrqEkeo9NA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2013-10-04 15:01 ` Inki Dae 2013-10-04 15:04 ` Sean Paul 0 siblings, 1 reply; 51+ messages in thread From: Inki Dae @ 2013-10-04 15:01 UTC (permalink / raw) To: 'Sean Paul' Cc: 'Kukjin Kim', 'DRI mailing list', linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-doc-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, 'Dave Airlie' > -----Original Message----- > From: Sean Paul [mailto:seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org] > Sent: Friday, October 04, 2013 11:17 PM > To: Inki Dae > Cc: Kukjin Kim; DRI mailing list; linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; > linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org; linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; linux- > doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Dave Airlie > Subject: Re: [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present > > On Fri, Oct 4, 2013 at 12:18 AM, Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote: > > 2013/10/4 Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>: > >> On Thu, Oct 3, 2013 at 10:29 PM, Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote: > >>> 2013/10/4 Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>: > >>>> This patch adds code to look for the ptn3460 in the device tree file > on > >>>> exynos initialization. If ptn node is found, the driver will > initialize > >>>> the ptn3460 driver and skip creating a DP connector (since the bridge > >>>> driver will register its own connector). > >>>> > >>>> Signed-off-by: Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> > >>>> --- > >>>> > >>>> v2: > >>>> - Changed include from of_i2c.h to i2c.h > >>>> - Changed of_find_by_name to of_find_compatible > >>>> > >>>> drivers/gpu/drm/exynos/exynos_drm_core.c | 44 > +++++++++++++++++++++++++++++++- > >>>> 1 file changed, 43 insertions(+), 1 deletion(-) > >>>> > >>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c > b/drivers/gpu/drm/exynos/exynos_drm_core.c > >>>> index 1bef6dc..08ca4f9 100644 > >>>> --- a/drivers/gpu/drm/exynos/exynos_drm_core.c > >>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c > >>>> @@ -12,7 +12,9 @@ > >>>> * option) any later version. > >>>> */ > >>>> > >>>> +#include <linux/i2c.h> > >>>> #include <drm/drmP.h> > >>>> +#include <drm/bridge/ptn3460.h> > >>>> #include "exynos_drm_drv.h" > >>>> #include "exynos_drm_encoder.h" > >>>> #include "exynos_drm_connector.h" > >>>> @@ -20,6 +22,40 @@ > >>>> > >>>> static LIST_HEAD(exynos_drm_subdrv_list); > >>>> > >>>> +struct bridge_init { > >>>> + struct i2c_client *client; > >>>> + struct device_node *node; > >>>> +}; > >>>> + > >>>> +static bool find_bridge(const char *compat, struct bridge_init > *bridge) > >>>> +{ > >>>> + bridge->client = NULL; > >>>> + bridge->node = of_find_compatible_node(NULL, NULL, compat); > >>> > >>> Then, shouldn't the lvds-bridge driver be implemented as i2c driver so > >>> that such tricky isn't needed? Is there any reason you use such tricky > >>> codes? > >>> > >> > >> This is what I was explaining earlier today. If the bridge driver is > >> just an i2c driver, it won't get a pointer to drm_device, and can't > >> register itself as a drm_bridge or drm_connector. To solve this, you > >> need the ptn3460_init callback. > >> > > > > No, I think you can use sub driver. how about registering to exynos > > drm core that driver using exynos_drm_subdrv_register function after > > probed? Is there something I am missing? > > > > The ptn driver isn't exynos-specific, so I don't think making it an > exynos_drm_subdrv is appropriate. > I _really know_ that the ptn driver isn't exynos-specific. I mean that you can use exynos_drm_subdrv somehow. ie. you can add a new bridge module specific to exynos, and this module can register its own sub driver at end of probe. Why do you try to use such tricky codes? Thanks, Inki Dae > Sean > > > > >> If it's an i2c driver with the ptn3460_init callback, where it parses > >> the dt in probe, then you have a race between the ptn probe and the > >> ptn init/drm hooks. ie: it's possible drm will initialize and call > >> disable/post_disable/pre_enable/enable before things have been probed. > > > > And also, exynos drm core will call a probe callback of the sub driver > > after _drm is initialized_. Is there something I am missing? > > > >> To solve this, you need to use some global state and/or locking. > >> > >> So, to summarize. We can have this of_find_compatible with a init > >> callback, or we can have an i2c driver + global state/locking + init > >> callback. I chose the former, since it seemed easier. > >> > >> If you have a better way to achieve this, I'm definitely interested, > >> but I saw this as the lesser of two evils. > >> > >> Sean > >> > >>> I think you need to implement the lvds-bridge driver as i2c driver, > >>> and then consider how to take care of this. I mean let's find a better > >>> way how we could take care of the i2c based driver in exynos drm > >>> framework or driver. In all cases, such tricky codes are not good. > >>> > >>>> + 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; > >>>> +} > >>>> + > >>>> static int exynos_drm_create_enc_conn(struct drm_device *dev, > >>>> struct exynos_drm_subdrv *subdrv) > >>>> { > >>>> @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct > drm_device *dev, > >>>> DRM_ERROR("failed to create encoder\n"); > >>>> return -EFAULT; > >>>> } > >>>> + subdrv->encoder = encoder; > >>>> + > >>>> + if (subdrv->manager->display_ops->type == > EXYNOS_DISPLAY_TYPE_LCD) { > >>>> + ret = exynos_drm_attach_lcd_bridge(dev, encoder); > >>>> + if (ret) > >>>> + return 0; > >>>> + } > >>>> > >>>> /* > >>>> * create and initialize a connector for this sub driver and > >>>> @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct > drm_device *dev, > >>>> goto err_destroy_encoder; > >>>> } > >>>> > >>>> - subdrv->encoder = encoder; > >>>> subdrv->connector = connector; > >>>> > >>>> return 0; > >>>> -- > >>>> 1.8.4 > >>>> > >>>> -- > >>>> To unsubscribe from this list: send the line "unsubscribe linux- > samsung-soc" in > >>>> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > >>>> More majordomo info at http://vger.kernel.org/majordomo-info.html > >> -- > >> To unsubscribe from this list: send the line "unsubscribe linux- > samsung-soc" in > >> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > >> More majordomo info at http://vger.kernel.org/majordomo-info.html -- 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] 51+ messages in thread
* Re: [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present 2013-10-04 15:01 ` Inki Dae @ 2013-10-04 15:04 ` Sean Paul [not found] ` <CAOw6vbKm+N8ZNyL8HQNhm2TnQOD8---1DkxE-n1LxWz-Y2=MNw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 51+ messages in thread From: Sean Paul @ 2013-10-04 15:04 UTC (permalink / raw) To: Inki Dae Cc: Kukjin Kim, DRI mailing list, linux-samsung-soc, Linux ARM Kernel, Linux Kernel Mailing List, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Dave Airlie On Fri, Oct 4, 2013 at 11:01 AM, Inki Dae <inki.dae@samsung.com> wrote: > > >> -----Original Message----- >> From: Sean Paul [mailto:seanpaul@chromium.org] >> Sent: Friday, October 04, 2013 11:17 PM >> To: Inki Dae >> Cc: Kukjin Kim; DRI mailing list; linux-samsung-soc@vger.kernel.org; >> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; linux- >> doc@vger.kernel.org; devicetree@vger.kernel.org; Dave Airlie >> Subject: Re: [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present >> >> On Fri, Oct 4, 2013 at 12:18 AM, Inki Dae <inki.dae@samsung.com> wrote: >> > 2013/10/4 Sean Paul <seanpaul@chromium.org>: >> >> On Thu, Oct 3, 2013 at 10:29 PM, Inki Dae <inki.dae@samsung.com> wrote: >> >>> 2013/10/4 Sean Paul <seanpaul@chromium.org>: >> >>>> This patch adds code to look for the ptn3460 in the device tree file >> on >> >>>> exynos initialization. If ptn node is found, the driver will >> initialize >> >>>> the ptn3460 driver and skip creating a DP connector (since the bridge >> >>>> driver will register its own connector). >> >>>> >> >>>> Signed-off-by: Sean Paul <seanpaul@chromium.org> >> >>>> --- >> >>>> >> >>>> v2: >> >>>> - Changed include from of_i2c.h to i2c.h >> >>>> - Changed of_find_by_name to of_find_compatible >> >>>> >> >>>> drivers/gpu/drm/exynos/exynos_drm_core.c | 44 >> +++++++++++++++++++++++++++++++- >> >>>> 1 file changed, 43 insertions(+), 1 deletion(-) >> >>>> >> >>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c >> b/drivers/gpu/drm/exynos/exynos_drm_core.c >> >>>> index 1bef6dc..08ca4f9 100644 >> >>>> --- a/drivers/gpu/drm/exynos/exynos_drm_core.c >> >>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c >> >>>> @@ -12,7 +12,9 @@ >> >>>> * option) any later version. >> >>>> */ >> >>>> >> >>>> +#include <linux/i2c.h> >> >>>> #include <drm/drmP.h> >> >>>> +#include <drm/bridge/ptn3460.h> >> >>>> #include "exynos_drm_drv.h" >> >>>> #include "exynos_drm_encoder.h" >> >>>> #include "exynos_drm_connector.h" >> >>>> @@ -20,6 +22,40 @@ >> >>>> >> >>>> static LIST_HEAD(exynos_drm_subdrv_list); >> >>>> >> >>>> +struct bridge_init { >> >>>> + struct i2c_client *client; >> >>>> + struct device_node *node; >> >>>> +}; >> >>>> + >> >>>> +static bool find_bridge(const char *compat, struct bridge_init >> *bridge) >> >>>> +{ >> >>>> + bridge->client = NULL; >> >>>> + bridge->node = of_find_compatible_node(NULL, NULL, compat); >> >>> >> >>> Then, shouldn't the lvds-bridge driver be implemented as i2c driver so >> >>> that such tricky isn't needed? Is there any reason you use such tricky >> >>> codes? >> >>> >> >> >> >> This is what I was explaining earlier today. If the bridge driver is >> >> just an i2c driver, it won't get a pointer to drm_device, and can't >> >> register itself as a drm_bridge or drm_connector. To solve this, you >> >> need the ptn3460_init callback. >> >> >> > >> > No, I think you can use sub driver. how about registering to exynos >> > drm core that driver using exynos_drm_subdrv_register function after >> > probed? Is there something I am missing? >> > >> >> The ptn driver isn't exynos-specific, so I don't think making it an >> exynos_drm_subdrv is appropriate. >> > > I _really know_ that the ptn driver isn't exynos-specific. I mean that you > can use exynos_drm_subdrv somehow. ie. you can add a new bridge module > specific to exynos, and this module can register its own sub driver at end > of probe. Why do you try to use such tricky codes? > So I create a new exynos_lvds_driver which is an i2c driver. When that probes, all it does is register that driver as an exynos_drm_subdrv. Then in the subdrv probe I call into ptn3460_init? That seems a lot more tricky than just calling ptn3460_init directly... Sean > Thanks, > Inki Dae > >> Sean >> >> > >> >> If it's an i2c driver with the ptn3460_init callback, where it parses >> >> the dt in probe, then you have a race between the ptn probe and the >> >> ptn init/drm hooks. ie: it's possible drm will initialize and call >> >> disable/post_disable/pre_enable/enable before things have been probed. >> > >> > And also, exynos drm core will call a probe callback of the sub driver >> > after _drm is initialized_. Is there something I am missing? >> > >> >> To solve this, you need to use some global state and/or locking. >> >> >> >> So, to summarize. We can have this of_find_compatible with a init >> >> callback, or we can have an i2c driver + global state/locking + init >> >> callback. I chose the former, since it seemed easier. >> >> >> >> If you have a better way to achieve this, I'm definitely interested, >> >> but I saw this as the lesser of two evils. >> >> >> >> Sean >> >> >> >>> I think you need to implement the lvds-bridge driver as i2c driver, >> >>> and then consider how to take care of this. I mean let's find a better >> >>> way how we could take care of the i2c based driver in exynos drm >> >>> framework or driver. In all cases, such tricky codes are not good. >> >>> >> >>>> + 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; >> >>>> +} >> >>>> + >> >>>> static int exynos_drm_create_enc_conn(struct drm_device *dev, >> >>>> struct exynos_drm_subdrv > *subdrv) >> >>>> { >> >>>> @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct >> drm_device *dev, >> >>>> DRM_ERROR("failed to create encoder\n"); >> >>>> return -EFAULT; >> >>>> } >> >>>> + subdrv->encoder = encoder; >> >>>> + >> >>>> + if (subdrv->manager->display_ops->type == >> EXYNOS_DISPLAY_TYPE_LCD) { >> >>>> + ret = exynos_drm_attach_lcd_bridge(dev, encoder); >> >>>> + if (ret) >> >>>> + return 0; >> >>>> + } >> >>>> >> >>>> /* >> >>>> * create and initialize a connector for this sub driver and >> >>>> @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct >> drm_device *dev, >> >>>> goto err_destroy_encoder; >> >>>> } >> >>>> >> >>>> - subdrv->encoder = encoder; >> >>>> subdrv->connector = connector; >> >>>> >> >>>> return 0; >> >>>> -- >> >>>> 1.8.4 >> >>>> >> >>>> -- >> >>>> To unsubscribe from this list: send the line "unsubscribe linux- >> samsung-soc" in >> >>>> the body of a message to majordomo@vger.kernel.org >> >>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >> >> -- >> >> To unsubscribe from this list: send the line "unsubscribe linux- >> samsung-soc" in >> >> the body of a message to majordomo@vger.kernel.org >> >> More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 51+ messages in thread
[parent not found: <CAOw6vbKm+N8ZNyL8HQNhm2TnQOD8---1DkxE-n1LxWz-Y2=MNw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* RE: [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present [not found] ` <CAOw6vbKm+N8ZNyL8HQNhm2TnQOD8---1DkxE-n1LxWz-Y2=MNw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2013-10-04 16:01 ` Inki Dae 0 siblings, 0 replies; 51+ messages in thread From: Inki Dae @ 2013-10-04 16:01 UTC (permalink / raw) To: 'Sean Paul' Cc: 'Kukjin Kim', 'DRI mailing list', 'linux-samsung-soc', 'Linux ARM Kernel', 'Linux Kernel Mailing List', linux-doc-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, 'Dave Airlie' > -----Original Message----- > From: Sean Paul [mailto:seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org] > Sent: Saturday, October 05, 2013 12:05 AM > To: Inki Dae > Cc: Kukjin Kim; DRI mailing list; linux-samsung-soc; Linux ARM Kernel; > Linux Kernel Mailing List; linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; > devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Dave Airlie > Subject: Re: [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present > > On Fri, Oct 4, 2013 at 11:01 AM, Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote: > > > > > >> -----Original Message----- > >> From: Sean Paul [mailto:seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org] > >> Sent: Friday, October 04, 2013 11:17 PM > >> To: Inki Dae > >> Cc: Kukjin Kim; DRI mailing list; linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; > >> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org; linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; > linux- > >> doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Dave Airlie > >> Subject: Re: [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present > >> > >> On Fri, Oct 4, 2013 at 12:18 AM, Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote: > >> > 2013/10/4 Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>: > >> >> On Thu, Oct 3, 2013 at 10:29 PM, Inki Dae <inki.dae-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> > wrote: > >> >>> 2013/10/4 Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>: > >> >>>> This patch adds code to look for the ptn3460 in the device tree > file > >> on > >> >>>> exynos initialization. If ptn node is found, the driver will > >> initialize > >> >>>> the ptn3460 driver and skip creating a DP connector (since the > bridge > >> >>>> driver will register its own connector). > >> >>>> > >> >>>> Signed-off-by: Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> > >> >>>> --- > >> >>>> > >> >>>> v2: > >> >>>> - Changed include from of_i2c.h to i2c.h > >> >>>> - Changed of_find_by_name to of_find_compatible > >> >>>> > >> >>>> drivers/gpu/drm/exynos/exynos_drm_core.c | 44 > >> +++++++++++++++++++++++++++++++- > >> >>>> 1 file changed, 43 insertions(+), 1 deletion(-) > >> >>>> > >> >>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c > >> b/drivers/gpu/drm/exynos/exynos_drm_core.c > >> >>>> index 1bef6dc..08ca4f9 100644 > >> >>>> --- a/drivers/gpu/drm/exynos/exynos_drm_core.c > >> >>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c > >> >>>> @@ -12,7 +12,9 @@ > >> >>>> * option) any later version. > >> >>>> */ > >> >>>> > >> >>>> +#include <linux/i2c.h> > >> >>>> #include <drm/drmP.h> > >> >>>> +#include <drm/bridge/ptn3460.h> > >> >>>> #include "exynos_drm_drv.h" > >> >>>> #include "exynos_drm_encoder.h" > >> >>>> #include "exynos_drm_connector.h" > >> >>>> @@ -20,6 +22,40 @@ > >> >>>> > >> >>>> static LIST_HEAD(exynos_drm_subdrv_list); > >> >>>> > >> >>>> +struct bridge_init { > >> >>>> + struct i2c_client *client; > >> >>>> + struct device_node *node; > >> >>>> +}; > >> >>>> + > >> >>>> +static bool find_bridge(const char *compat, struct bridge_init > >> *bridge) > >> >>>> +{ > >> >>>> + bridge->client = NULL; > >> >>>> + bridge->node = of_find_compatible_node(NULL, NULL, compat); > >> >>> > >> >>> Then, shouldn't the lvds-bridge driver be implemented as i2c driver > so > >> >>> that such tricky isn't needed? Is there any reason you use such > tricky > >> >>> codes? > >> >>> > >> >> > >> >> This is what I was explaining earlier today. If the bridge driver is > >> >> just an i2c driver, it won't get a pointer to drm_device, and can't > >> >> register itself as a drm_bridge or drm_connector. To solve this, you > >> >> need the ptn3460_init callback. > >> >> > >> > > >> > No, I think you can use sub driver. how about registering to exynos > >> > drm core that driver using exynos_drm_subdrv_register function after > >> > probed? Is there something I am missing? > >> > > >> > >> The ptn driver isn't exynos-specific, so I don't think making it an > >> exynos_drm_subdrv is appropriate. > >> > > > > I _really know_ that the ptn driver isn't exynos-specific. I mean that > you > > can use exynos_drm_subdrv somehow. ie. you can add a new bridge module > > specific to exynos, and this module can register its own sub driver at > end > > of probe. Why do you try to use such tricky codes? > > > > So I create a new exynos_lvds_driver which is an i2c driver. When that > probes, all it does is register that driver as an exynos_drm_subdrv. > Then in the subdrv probe I call into ptn3460_init? > > That seems a lot more tricky than just calling ptn3460_init directly... > Why more tricky? At least the dt binding will be done in device driver. Anyway, this also is reasonable to me. It seems that we need a bit different design for such bridge driver. Basically, exysnos drm fimd driver has one encoder and one connector, and these are connected each other, and this connector means lcd panel without any display bus. So if we want to use display bus, it might need to create a new encoder and connector for the display bus device. It seems that this way is more reasonable to me. ie. if we want for image data goes from fimd to lcd panel, we can connect a existing connector and crtc of fimd, and if fimd to display bus, we can connect the new connector and the crtc of fimd through setcrtc or setplane. Of course, for this we would need more works and efforts. Such tricky codes definitely are not good. Thanks, Inki Dae > Sean > > > > Thanks, > > Inki Dae > > > >> Sean > >> > >> > > >> >> If it's an i2c driver with the ptn3460_init callback, where it > parses > >> >> the dt in probe, then you have a race between the ptn probe and the > >> >> ptn init/drm hooks. ie: it's possible drm will initialize and call > >> >> disable/post_disable/pre_enable/enable before things have been > probed. > >> > > >> > And also, exynos drm core will call a probe callback of the sub > driver > >> > after _drm is initialized_. Is there something I am missing? > >> > > >> >> To solve this, you need to use some global state and/or locking. > >> >> > >> >> So, to summarize. We can have this of_find_compatible with a init > >> >> callback, or we can have an i2c driver + global state/locking + init > >> >> callback. I chose the former, since it seemed easier. > >> >> > >> >> If you have a better way to achieve this, I'm definitely interested, > >> >> but I saw this as the lesser of two evils. > >> >> > >> >> Sean > >> >> > >> >>> I think you need to implement the lvds-bridge driver as i2c driver, > >> >>> and then consider how to take care of this. I mean let's find a > better > >> >>> way how we could take care of the i2c based driver in exynos drm > >> >>> framework or driver. In all cases, such tricky codes are not good. > >> >>> > >> >>>> + 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; > >> >>>> +} > >> >>>> + > >> >>>> static int exynos_drm_create_enc_conn(struct drm_device *dev, > >> >>>> struct exynos_drm_subdrv > > *subdrv) > >> >>>> { > >> >>>> @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct > >> drm_device *dev, > >> >>>> DRM_ERROR("failed to create encoder\n"); > >> >>>> return -EFAULT; > >> >>>> } > >> >>>> + subdrv->encoder = encoder; > >> >>>> + > >> >>>> + if (subdrv->manager->display_ops->type == > >> EXYNOS_DISPLAY_TYPE_LCD) { > >> >>>> + ret = exynos_drm_attach_lcd_bridge(dev, encoder); > >> >>>> + if (ret) > >> >>>> + return 0; > >> >>>> + } > >> >>>> > >> >>>> /* > >> >>>> * create and initialize a connector for this sub driver and > >> >>>> @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct > >> drm_device *dev, > >> >>>> goto err_destroy_encoder; > >> >>>> } > >> >>>> > >> >>>> - subdrv->encoder = encoder; > >> >>>> subdrv->connector = connector; > >> >>>> > >> >>>> return 0; > >> >>>> -- > >> >>>> 1.8.4 > >> >>>> > >> >>>> -- > >> >>>> To unsubscribe from this list: send the line "unsubscribe linux- > >> samsung-soc" in > >> >>>> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > >> >>>> More majordomo info at http://vger.kernel.org/majordomo-info.html > >> >> -- > >> >> To unsubscribe from this list: send the line "unsubscribe linux- > >> samsung-soc" in > >> >> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > >> >> More majordomo info at http://vger.kernel.org/majordomo-info.html > > -- 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] 51+ messages in thread
* [PATCH v2 5/5] ARM: dts: Add ptn3460 to exynos5250-snow 2013-10-03 22:28 ` [PATCH v2 " Sean Paul ` (3 preceding siblings ...) 2013-10-03 22:28 ` [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present Sean Paul @ 2013-10-03 22:28 ` Sean Paul 2013-10-03 22:35 ` [PATCH v2 0/5] Add some missing bits for exynos5250-snow Olof Johansson 2013-10-10 22:26 ` [PATCH v3 " Sean Paul 6 siblings, 0 replies; 51+ messages in thread From: Sean Paul @ 2013-10-03 22:28 UTC (permalink / raw) To: kgene.kim, dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds a node for the ptn3460 DP-LVDS chip in the exynos5250-snow board dts file. Signed-off-by: Sean Paul <seanpaul@chromium.org> --- v2: Changed node name to lvds-bridge arch/arm/boot/dts/exynos5250-snow.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index f1cf68e..2870205 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -33,6 +33,13 @@ sd3_bus4: sd3-bus-width4 { samsung,pin-drv = <0>; }; + + ptn3460_gpios: ptn3460-gpios { + samsung,pins = "gpy2-5", "gpx1-5"; + samsung,pin-function = <1>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; }; gpio-keys { @@ -186,6 +193,18 @@ samsung,vbus-gpio = <&gpx1 1 0>; }; + i2c@12CD0000 { + lvds-bridge@20 { + compatible = "nxp,ptn3460"; + reg = <0x20>; + powerdown-gpio = <&gpy2 5 0>; + reset-gpio = <&gpx1 5 0>; + edid-emulation = <5>; + pinctrl-names = "default"; + pinctrl-0 = <&ptn3460_gpios>; + }; + }; + dp-controller@145B0000 { samsung,color-space = <0>; samsung,dynamic-range = <0>; -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
* Re: [PATCH v2 0/5] Add some missing bits for exynos5250-snow 2013-10-03 22:28 ` [PATCH v2 " Sean Paul ` (4 preceding siblings ...) 2013-10-03 22:28 ` [PATCH v2 5/5] ARM: dts: Add ptn3460 to exynos5250-snow Sean Paul @ 2013-10-03 22:35 ` Olof Johansson 2013-10-10 22:26 ` [PATCH v3 " Sean Paul 6 siblings, 0 replies; 51+ messages in thread From: Olof Johansson @ 2013-10-03 22:35 UTC (permalink / raw) To: Sean Paul Cc: Kukjin Kim, DRI mailing list, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Inki Dae, airlied On Thu, Oct 3, 2013 at 3:28 PM, Sean Paul <seanpaul@chromium.org> wrote: > This set adds some missing devicetree nodes to the exynos5250-snow file as well > as adds a drm_bridge driver for the ptn3460 DP-LVDS chip. This chip is used in > the exynos5250-snow board. > > Sean Series: Acked-by: Olof Johansson <olof@lixom.net> -Olof ^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH v3 0/5] Add some missing bits for exynos5250-snow 2013-10-03 22:28 ` [PATCH v2 " Sean Paul ` (5 preceding siblings ...) 2013-10-03 22:35 ` [PATCH v2 0/5] Add some missing bits for exynos5250-snow Olof Johansson @ 2013-10-10 22:26 ` Sean Paul 2013-10-10 22:26 ` [PATCH v3 1/5] ARM: dts: Add fimd display-timings " Sean Paul ` (4 more replies) 6 siblings, 5 replies; 51+ messages in thread From: Sean Paul @ 2013-10-10 22:26 UTC (permalink / raw) To: kgene.kim, dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied This set adds some missing devicetree nodes to the exynos5250-snow file as well as adds a drm_bridge driver for the ptn3460 DP-LVDS chip. This chip is used in the exynos5250-snow board. Sean Sean Paul (5): ARM: dts: Add fimd display-timings for exynos5250-snow ARM: dts: Add dp-controller node to exynos5250-snow drm/bridge: Add PTN3460 bridge driver drm/exynos: Initialize ptn3460 if present ARM: dts: Add ptn3460 to exynos5250-snow Documentation/devicetree/bindings/drm/bridge/ptn3460.txt | 27 ++++++++++++++++ arch/arm/boot/dts/exynos5250-snow.dts | 50 ++++++++++++++++ drivers/gpu/drm/Kconfig | 2 ++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/bridge/Kconfig | 4 +++ drivers/gpu/drm/bridge/Makefile | 3 ++ drivers/gpu/drm/bridge/ptn3460.c | 349 ++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_core.c | 44 ++++++++++++++++ include/drm/bridge/ptn3460.h | 37 ++++++++++++++++ ^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH v3 1/5] ARM: dts: Add fimd display-timings for exynos5250-snow 2013-10-10 22:26 ` [PATCH v3 " Sean Paul @ 2013-10-10 22:26 ` Sean Paul 2013-10-10 22:26 ` [PATCH v3 2/5] ARM: dts: Add dp-controller node to exynos5250-snow Sean Paul ` (3 subsequent siblings) 4 siblings, 0 replies; 51+ messages in thread From: Sean Paul @ 2013-10-10 22:26 UTC (permalink / raw) To: kgene.kim, dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds the internal panel timings to the exynos5250-snow board dts file. Signed-off-by: Sean Paul <seanpaul@chromium.org> --- v2: No difference v3: Added status = "okay" arch/arm/boot/dts/exynos5250-snow.dts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index fd711e2..28eea9b 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -186,6 +186,24 @@ samsung,vbus-gpio = <&gpx1 1 0>; }; + fimd: fimd@14400000 { + status = "okay"; + display-timings { + native-mode = <&lcd_timing>; + lcd_timing: 1366x768 { + clock-frequency = <70589280>; + hactive = <1366>; + vactive = <768>; + hfront-porch = <40>; + hback-porch = <40>; + hsync-len = <32>; + vback-porch = <10>; + vfront-porch = <12>; + vsync-len = <6>; + }; + }; + }; + fixed-rate-clocks { xxti { compatible = "samsung,clock-xxti"; -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH v3 2/5] ARM: dts: Add dp-controller node to exynos5250-snow 2013-10-10 22:26 ` [PATCH v3 " Sean Paul 2013-10-10 22:26 ` [PATCH v3 1/5] ARM: dts: Add fimd display-timings " Sean Paul @ 2013-10-10 22:26 ` Sean Paul 2013-10-10 22:26 ` [PATCH v3 3/5] drm/bridge: Add PTN3460 bridge driver Sean Paul ` (2 subsequent siblings) 4 siblings, 0 replies; 51+ messages in thread From: Sean Paul @ 2013-10-10 22:26 UTC (permalink / raw) To: kgene.kim, dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds the dp-controller node to the exynos5250-snow board dts file. Signed-off-by: Sean Paul <seanpaul@chromium.org> --- v2: Added dp-controller address to node (rebased on linux-next) v3: Added status = "okay" arch/arm/boot/dts/exynos5250-snow.dts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index 28eea9b..f813644 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -186,6 +186,19 @@ samsung,vbus-gpio = <&gpx1 1 0>; }; + dp-controller@145B0000 { + samsung,color-space = <0>; + samsung,dynamic-range = <0>; + samsung,ycbcr-coeff = <0>; + samsung,color-depth = <1>; + samsung,link-rate = <0x0a>; + samsung,lane-count = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&dp_hpd>; + status = "okay"; + }; + fimd: fimd@14400000 { status = "okay"; display-timings { -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH v3 3/5] drm/bridge: Add PTN3460 bridge driver 2013-10-10 22:26 ` [PATCH v3 " Sean Paul 2013-10-10 22:26 ` [PATCH v3 1/5] ARM: dts: Add fimd display-timings " Sean Paul 2013-10-10 22:26 ` [PATCH v3 2/5] ARM: dts: Add dp-controller node to exynos5250-snow Sean Paul @ 2013-10-10 22:26 ` Sean Paul 2013-10-10 22:26 ` [PATCH v3 4/5] drm/exynos: Initialize ptn3460 if present Sean Paul 2013-10-10 22:26 ` [PATCH v3 5/5] ARM: dts: Add ptn3460 to exynos5250-snow Sean Paul 4 siblings, 0 replies; 51+ messages in thread From: Sean Paul @ 2013-10-10 22:26 UTC (permalink / raw) To: kgene.kim, dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds a drm_bridge driver for the PTN3460 DisplayPort to LVDS bridge chip. Signed-off-by: Sean Paul <seanpaul@chromium.org> --- v2: - Changed header definition to static inline - Changed dt node name to lvds-bridge v3: No changes .../devicetree/bindings/drm/bridge/ptn3460.txt | 27 ++ drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/bridge/Kconfig | 4 + drivers/gpu/drm/bridge/Makefile | 3 + drivers/gpu/drm/bridge/ptn3460.c | 349 +++++++++++++++++++++ include/drm/bridge/ptn3460.h | 37 +++ 7 files changed, 423 insertions(+) create mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt create mode 100644 drivers/gpu/drm/bridge/Kconfig create mode 100644 drivers/gpu/drm/bridge/Makefile create mode 100644 drivers/gpu/drm/bridge/ptn3460.c create mode 100644 include/drm/bridge/ptn3460.h diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt new file mode 100644 index 0000000..52b93b2 --- /dev/null +++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt @@ -0,0 +1,27 @@ +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 | + +-------+------------+------------------+ + +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>; + }; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 955555d..cd7bfb3 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -236,3 +236,5 @@ source "drivers/gpu/drm/tilcdc/Kconfig" source "drivers/gpu/drm/qxl/Kconfig" source "drivers/gpu/drm/msm/Kconfig" + +source "drivers/gpu/drm/bridge/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index f089adf..9234253 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -56,3 +56,4 @@ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ obj-$(CONFIG_DRM_QXL) += qxl/ obj-$(CONFIG_DRM_MSM) += msm/ obj-y += i2c/ +obj-y += bridge/ diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig new file mode 100644 index 0000000..f8db069 --- /dev/null +++ b/drivers/gpu/drm/bridge/Kconfig @@ -0,0 +1,4 @@ +config DRM_PTN3460 + tristate "PTN3460 DP/LVDS bridge" + depends on DRM && I2C + ---help--- diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile new file mode 100644 index 0000000..b4733e1 --- /dev/null +++ b/drivers/gpu/drm/bridge/Makefile @@ -0,0 +1,3 @@ +ccflags-y := -Iinclude/drm + +obj-$(CONFIG_DRM_PTN3460) += ptn3460.o diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c new file mode 100644 index 0000000..a9e5c1a --- /dev/null +++ b/drivers/gpu/drm/bridge/ptn3460.c @@ -0,0 +1,349 @@ +/* + * NXP PTN3460 DP/LVDS bridge driver + * + * Copyright (C) 2013 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/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 "drm_crtc.h" +#include "drm_crtc_helper.h" + +#include "bridge/ptn3460.h" + +#define PTN3460_EDID_ADDR 0x0 +#define PTN3460_EDID_EMULATION_ADDR 0x84 +#define PTN3460_EDID_ENABLE_EMULATION 0 +#define PTN3460_EDID_EMULATION_SELECTION 1 +#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85 + +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; + int gpio_rst_n; + u32 edid_emulation; + bool enabled; +}; + +static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, + u8 *buf, int len) +{ + int ret; + + ret = i2c_master_send(ptn_bridge->client, &addr, 1); + if (ret <= 0) { + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); + return ret; + } + + ret = i2c_master_recv(ptn_bridge->client, buf, len); + if (ret <= 0) { + DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, + char val) +{ + int ret; + char buf[2]; + + buf[0] = addr; + buf[1] = val; + + ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); + if (ret <= 0) { + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) +{ + int ret; + char val; + + /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */ + 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); + return ret; + } + + /* Enable EDID emulation and select the desired EDID */ + val = 1 << PTN3460_EDID_ENABLE_EMULATION | + ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION; + + ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); + if (ret) { + DRM_ERROR("Failed to write edid value, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static void ptn3460_pre_enable(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + int ret; + + if (ptn_bridge->enabled) + return; + + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) + gpio_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); + udelay(10); + gpio_set_value(ptn_bridge->gpio_rst_n, 1); + } + + /* + * 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 + * time specified in the chip's datasheet to make sure we're really up. + */ + msleep(90); + + ret = ptn3460_select_edid(ptn_bridge); + if (ret) + DRM_ERROR("Select edid failed ret=%d\n", ret); + + ptn_bridge->enabled = true; +} + +static void ptn3460_enable(struct drm_bridge *bridge) +{ +} + +static void ptn3460_disable(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + + if (!ptn_bridge->enabled) + return; + + ptn_bridge->enabled = false; + + 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); +} + +static void ptn3460_post_disable(struct drm_bridge *bridge) +{ +} + +void ptn3460_bridge_destroy(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + + 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 */ +} + +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, +}; + +int ptn3460_get_modes(struct drm_connector *connector) +{ + struct ptn3460_bridge *ptn_bridge; + u8 *edid; + int ret, num_modes; + bool power_off; + + ptn_bridge = container_of(connector, struct ptn3460_bridge, 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); + + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!edid) { + DRM_ERROR("Failed to allocate edid\n"); + return 0; + } + + ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, + EDID_LENGTH); + if (ret) { + kfree(edid); + num_modes = 0; + goto out; + } + + ptn_bridge->edid = (struct edid *)edid; + drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); + + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); + +out: + if (power_off) + ptn3460_disable(ptn_bridge->bridge); + + return num_modes; +} + +static int ptn3460_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) +{ + struct ptn3460_bridge *ptn_bridge; + + ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); + + return ptn_bridge->encoder; +} + +struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { + .get_modes = ptn3460_get_modes, + .mode_valid = ptn3460_mode_valid, + .best_encoder = ptn3460_best_encoder, +}; + +enum drm_connector_status ptn3460_detect(struct drm_connector *connector, + bool force) +{ + return connector_status_connected; +} + +void ptn3460_connector_destroy(struct drm_connector *connector) +{ + drm_connector_cleanup(connector); +} + +struct drm_connector_funcs ptn3460_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = ptn3460_detect, + .destroy = ptn3460_connector_destroy, +}; + +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); + return ret; + } + } + + ptn_bridge->gpio_rst_n = of_get_named_gpio(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) { + DRM_ERROR("Request reset-gpio failed (%d)\n", ret); + gpio_free(ptn_bridge->gpio_pd_n); + return ret; + } + } + + ret = of_property_read_u32(node, "edid-emulation", + &ptn_bridge->edid_emulation); + if (ret) { + DRM_ERROR("Can't read edid emulation value\n"); + goto err; + } + + ret = drm_bridge_init(dev, 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; + + 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_sysfs_connector_add(&ptn_bridge->connector); + drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); + + 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; +} diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h new file mode 100644 index 0000000..8481816 --- /dev/null +++ b/include/drm/bridge/ptn3460.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef _DRM_BRIDGE_PTN3460_H_ +#define _DRM_BRIDGE_PTN3460_H_ + +struct drm_device; +struct drm_encoder; +struct i2c_client; +struct device_node; + +#ifdef CONFIG_DRM_PTN3460 + +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, + struct i2c_client *client, struct device_node *node); +#else + +static inline int ptn3460_init(struct drm_device *dev, + struct drm_encoder *encoder, struct i2c_client *client, + struct device_node *node) +{ + return 0; +} + +#endif + +#endif -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH v3 4/5] drm/exynos: Initialize ptn3460 if present 2013-10-10 22:26 ` [PATCH v3 " Sean Paul ` (2 preceding siblings ...) 2013-10-10 22:26 ` [PATCH v3 3/5] drm/bridge: Add PTN3460 bridge driver Sean Paul @ 2013-10-10 22:26 ` Sean Paul 2013-10-10 22:26 ` [PATCH v3 5/5] ARM: dts: Add ptn3460 to exynos5250-snow Sean Paul 4 siblings, 0 replies; 51+ messages in thread From: Sean Paul @ 2013-10-10 22:26 UTC (permalink / raw) To: kgene.kim, dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds code to look for the ptn3460 in the device tree file on exynos initialization. If ptn node is found, the driver will initialize the ptn3460 driver and skip creating a DP connector (since the bridge driver will register its own connector). Signed-off-by: Sean Paul <seanpaul@chromium.org> --- v2: - Changed include from of_i2c.h to i2c.h - Changed of_find_by_name to of_find_compatible v3: No changes drivers/gpu/drm/exynos/exynos_drm_core.c | 44 +++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 1bef6dc..08ca4f9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -12,7 +12,9 @@ * option) any later version. */ +#include <linux/i2c.h> #include <drm/drmP.h> +#include <drm/bridge/ptn3460.h> #include "exynos_drm_drv.h" #include "exynos_drm_encoder.h" #include "exynos_drm_connector.h" @@ -20,6 +22,40 @@ static LIST_HEAD(exynos_drm_subdrv_list); +struct bridge_init { + struct i2c_client *client; + struct device_node *node; +}; + +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; +} + static int exynos_drm_create_enc_conn(struct drm_device *dev, struct exynos_drm_subdrv *subdrv) { @@ -36,6 +72,13 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, DRM_ERROR("failed to create encoder\n"); return -EFAULT; } + subdrv->encoder = encoder; + + if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) { + ret = exynos_drm_attach_lcd_bridge(dev, encoder); + if (ret) + return 0; + } /* * create and initialize a connector for this sub driver and @@ -48,7 +91,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, goto err_destroy_encoder; } - subdrv->encoder = encoder; subdrv->connector = connector; return 0; -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
* [PATCH v3 5/5] ARM: dts: Add ptn3460 to exynos5250-snow 2013-10-10 22:26 ` [PATCH v3 " Sean Paul ` (3 preceding siblings ...) 2013-10-10 22:26 ` [PATCH v3 4/5] drm/exynos: Initialize ptn3460 if present Sean Paul @ 2013-10-10 22:26 ` Sean Paul 4 siblings, 0 replies; 51+ messages in thread From: Sean Paul @ 2013-10-10 22:26 UTC (permalink / raw) To: kgene.kim, dri-devel, linux-samsung-soc, linux-arm-kernel, linux-kernel, linux-doc, devicetree, inki.dae Cc: airlied, Sean Paul This patch adds a node for the ptn3460 DP-LVDS chip in the exynos5250-snow board dts file. Signed-off-by: Sean Paul <seanpaul@chromium.org> --- v2: Changed node name to lvds-bridge v3: No changes arch/arm/boot/dts/exynos5250-snow.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index f813644..8c92df8 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -33,6 +33,13 @@ sd3_bus4: sd3-bus-width4 { samsung,pin-drv = <0>; }; + + ptn3460_gpios: ptn3460-gpios { + samsung,pins = "gpy2-5", "gpx1-5"; + samsung,pin-function = <1>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; }; gpio-keys { @@ -186,6 +193,18 @@ samsung,vbus-gpio = <&gpx1 1 0>; }; + i2c@12CD0000 { + lvds-bridge@20 { + compatible = "nxp,ptn3460"; + reg = <0x20>; + powerdown-gpio = <&gpy2 5 0>; + reset-gpio = <&gpx1 5 0>; + edid-emulation = <5>; + pinctrl-names = "default"; + pinctrl-0 = <&ptn3460_gpios>; + }; + }; + dp-controller@145B0000 { samsung,color-space = <0>; samsung,dynamic-range = <0>; -- 1.8.4 ^ permalink raw reply related [flat|nested] 51+ messages in thread
end of thread, other threads:[~2013-10-10 22:26 UTC | newest] Thread overview: 51+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-10-01 23:40 [PATCH 0/5] Add some missing bits for exynos5250-snow Sean Paul 2013-10-01 23:40 ` [PATCH 1/5] ARM: dts: Add fimd display-timings " Sean Paul 2013-10-01 23:40 ` [PATCH 2/5] ARM: dts: Add dp-controller node to exynos5250-snow Sean Paul 2013-10-02 21:10 ` Olof Johansson 2013-10-03 16:06 ` Sean Paul 2013-10-01 23:40 ` [PATCH 4/5] drm/exynos: Initialize ptn3460 if present Sean Paul [not found] ` <1380670860-17621-5-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2013-10-03 14:43 ` Inki Dae 2013-10-03 15:02 ` Sean Paul 2013-10-03 17:18 ` Inki Dae 2013-10-03 17:27 ` Sean Paul 2013-10-03 18:10 ` Inki Dae 2013-10-01 23:41 ` [PATCH 5/5] ARM: dts: Add ptn3460 to exynos5250-snow Sean Paul [not found] ` <1380670860-17621-1-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2013-10-01 23:40 ` [PATCH 3/5] drm/bridge: Add PTN3460 bridge driver Sean Paul 2013-10-02 21:20 ` Olof Johansson 2013-10-03 13:55 ` Inki Dae [not found] ` <CAAQKjZN_r-=-sj=Vb-o-KUS4ab5=cjCq1ni3VZeMeVc3NL=MMg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2013-10-03 14:57 ` Sean Paul 2013-10-03 17:39 ` Inki Dae 2013-10-03 18:01 ` Olof Johansson 2013-10-04 2:05 ` Inki Dae 2013-10-09 18:29 ` Mark Brown 2013-10-10 4:18 ` Inki Dae 2013-10-10 9:37 ` Mark Brown 2013-10-10 11:40 ` Inki Dae 2013-10-10 12:23 ` Mark Brown [not found] ` <CAAQKjZPwyKCpju4Ndd+MB_aN24-zA5xTHFsFsun2617h7YT6dw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2013-10-03 18:09 ` Sean Paul 2013-10-03 18:23 ` Inki Dae 2013-10-03 18:32 ` Sean Paul 2013-10-04 1:59 ` Inki Dae 2013-10-02 21:07 ` [PATCH 0/5] Add some missing bits for exynos5250-snow Olof Johansson 2013-10-03 22:28 ` [PATCH v2 " Sean Paul 2013-10-03 22:28 ` [PATCH v2 1/5] ARM: dts: Add fimd display-timings " Sean Paul [not found] ` <1380839303-4834-2-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2013-10-04 2:20 ` Jingoo Han 2013-10-03 22:28 ` [PATCH v2 2/5] ARM: dts: Add dp-controller node to exynos5250-snow Sean Paul 2013-10-04 2:24 ` Jingoo Han 2013-10-03 22:28 ` [PATCH v2 3/5] drm/bridge: Add PTN3460 bridge driver Sean Paul 2013-10-03 22:28 ` [PATCH v2 4/5] drm/exynos: Initialize ptn3460 if present Sean Paul 2013-10-04 2:29 ` Inki Dae 2013-10-04 2:41 ` Sean Paul 2013-10-04 4:18 ` Inki Dae [not found] ` <CAAQKjZMfP_Cgo5hPPTiwKa_+Ph+GUt2Fbdtipd5V=CQEDy3eSQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2013-10-04 14:17 ` Sean Paul [not found] ` <CAOw6vbL_W-8S+htX9KB2ABbtr9+JhfxHuL2ikJG7CrqEkeo9NA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2013-10-04 15:01 ` Inki Dae 2013-10-04 15:04 ` Sean Paul [not found] ` <CAOw6vbKm+N8ZNyL8HQNhm2TnQOD8---1DkxE-n1LxWz-Y2=MNw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2013-10-04 16:01 ` Inki Dae 2013-10-03 22:28 ` [PATCH v2 5/5] ARM: dts: Add ptn3460 to exynos5250-snow Sean Paul 2013-10-03 22:35 ` [PATCH v2 0/5] Add some missing bits for exynos5250-snow Olof Johansson 2013-10-10 22:26 ` [PATCH v3 " Sean Paul 2013-10-10 22:26 ` [PATCH v3 1/5] ARM: dts: Add fimd display-timings " Sean Paul 2013-10-10 22:26 ` [PATCH v3 2/5] ARM: dts: Add dp-controller node to exynos5250-snow Sean Paul 2013-10-10 22:26 ` [PATCH v3 3/5] drm/bridge: Add PTN3460 bridge driver Sean Paul 2013-10-10 22:26 ` [PATCH v3 4/5] drm/exynos: Initialize ptn3460 if present Sean Paul 2013-10-10 22:26 ` [PATCH v3 5/5] ARM: dts: Add ptn3460 to exynos5250-snow Sean Paul
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).