This patch tries to seperate drm_bridge implementation into 2 parts, a drm part and a non_drm part. A set of helper functions are defined in this patch to make bridge driver probe independent of the drm flow. The bridge devices register themselves on a lookup table when they get probed by calling "drm_bridge_add_for_lookup". The parent encoder driver waits till the bridge is available in the lookup table(by calling "of_drm_find_bridge") and then continues with its initialization. The encoder driver should call "drm_bridge_attach_encoder" to pass on the drm_device and the encoder pointers to the bridge object. Now that the drm_device pointer is available, the encoder then calls "bridge->funcs->post_encoder_init" to allow the bridge to continue registering itself with the drm core. Also, non driver model based ptn3460 driver is removed in this patch. Signed-off-by: Ajay Kumar <ajaykumar.rs@xxxxxxxxxxx> --- .../devicetree/bindings/drm/bridge/ptn3460.txt | 27 -- drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/bridge/Kconfig | 12 +- drivers/gpu/drm/bridge/Makefile | 2 - drivers/gpu/drm/bridge/ptn3460.c | 343 -------------------- drivers/gpu/drm/drm_bridge.c | 89 +++++ drivers/gpu/drm/drm_crtc.c | 9 +- drivers/gpu/drm/exynos/Kconfig | 3 +- drivers/gpu/drm/exynos/exynos_dp_core.c | 57 ++-- drivers/gpu/drm/exynos/exynos_dp_core.h | 1 + drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 3 +- include/drm/bridge/ptn3460.h | 37 --- include/drm/drm_crtc.h | 16 +- 13 files changed, 147 insertions(+), 453 deletions(-) delete mode 100644 Documentation/devicetree/bindings/drm/bridge/ptn3460.txt delete mode 100644 drivers/gpu/drm/bridge/ptn3460.c create mode 100644 drivers/gpu/drm/drm_bridge.c delete 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 deleted file mode 100644 index 52b93b2..0000000 --- a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt +++ /dev/null @@ -1,27 +0,0 @@ -ptn3460 bridge bindings - -Required properties: - - compatible: "nxp,ptn3460" - - reg: i2c address of the bridge - - powerdown-gpio: OF device-tree gpio specification - - reset-gpio: OF device-tree gpio specification - - edid-emulation: The EDID emulation entry to use - +-------+------------+------------------+ - | Value | Resolution | Description | - | 0 | 1024x768 | NXP Generic | - | 1 | 1920x1080 | NXP Generic | - | 2 | 1920x1080 | NXP Generic | - | 3 | 1600x900 | Samsung LTM200KT | - | 4 | 1920x1080 | Samsung LTM230HT | - | 5 | 1366x768 | NXP Generic | - | 6 | 1600x900 | ChiMei M215HGE | - +-------+------------+------------------+ - -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/Makefile b/drivers/gpu/drm/Makefile index af9a609..14a8b45 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -20,6 +20,7 @@ drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o drm-$(CONFIG_PCI) += ati_pcigart.o drm-$(CONFIG_DRM_PANEL) += drm_panel.o +drm-$(CONFIG_DRM_BRIDGE) += drm_bridge.o drm-usb-y := drm_usb.o diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 884923f..1e2f96c 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -1,5 +1,9 @@ -config DRM_PTN3460 - tristate "PTN3460 DP/LVDS bridge" +config DRM_BRIDGE + tristate depends on DRM - select DRM_KMS_HELPER - ---help--- + help + Bridge registration and lookup framework. + +menu "bridge chips" + depends on DRM_BRIDGE +endmenu diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index b4733e1..be16eca 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -1,3 +1 @@ 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 deleted file mode 100644 index d466696..0000000 --- a/drivers/gpu/drm/bridge/ptn3460.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * 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; -} - -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, - .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_connector_register(&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; -} -EXPORT_SYMBOL(ptn3460_init); diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c new file mode 100644 index 0000000..84645e6 --- /dev/null +++ b/drivers/gpu/drm/drm_bridge.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <linux/err.h> +#include <linux/module.h> + +#include <drm/drm_crtc.h> + +static DEFINE_MUTEX(bridge_lock); +static LIST_HEAD(bridge_lookup); + +int drm_bridge_add_for_lookup(struct drm_bridge *bridge) +{ + mutex_lock(&bridge_lock); + list_add_tail(&bridge->head, &bridge_lookup); + mutex_unlock(&bridge_lock); + + return 0; +} +EXPORT_SYMBOL(drm_bridge_add_for_lookup); + +void drm_bridge_remove_from_lookup(struct drm_bridge *bridge) +{ + mutex_lock(&bridge_lock); + list_del_init(&bridge->head); + mutex_unlock(&bridge_lock); +} +EXPORT_SYMBOL(drm_bridge_remove_from_lookup); + +int drm_bridge_attach_encoder(struct drm_bridge *bridge, + struct drm_encoder *encoder) +{ + if (!bridge || !encoder) + return -EINVAL; + + if (bridge->encoder) + return -EBUSY; + + encoder->bridge = bridge; + bridge->encoder = encoder; + bridge->drm_dev = encoder->dev; + + return 0; +} +EXPORT_SYMBOL(drm_bridge_attach_encoder); + +#ifdef CONFIG_OF +struct drm_bridge *of_drm_find_bridge(struct device_node *np) +{ + struct drm_bridge *bridge; + + mutex_lock(&bridge_lock); + + list_for_each_entry(bridge, &bridge_lookup, head) { + if (bridge->dev->of_node == np) { + mutex_unlock(&bridge_lock); + return bridge; + } + } + + mutex_unlock(&bridge_lock); + return NULL; +} +EXPORT_SYMBOL(of_drm_find_bridge); +#endif + +MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@xxxxxxxxxxx>"); +MODULE_DESCRIPTION("DRM bridge infrastructure"); +MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 1ccf5cb..436e75d 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -993,7 +993,6 @@ EXPORT_SYMBOL(drm_connector_unplug_all); * drm_bridge_init - initialize a drm transcoder/bridge * @dev: drm device * @bridge: transcoder/bridge to set up - * @funcs: bridge function table * * Initialises a preallocated bridge. Bridges should be * subclassed as part of driver connector objects. @@ -1001,8 +1000,7 @@ EXPORT_SYMBOL(drm_connector_unplug_all); * Returns: * Zero on success, error code on failure. */ -int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, - const struct drm_bridge_funcs *funcs) +int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge) { int ret; @@ -1012,8 +1010,7 @@ int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, if (ret) goto out; - bridge->dev = dev; - bridge->funcs = funcs; + bridge->drm_dev = dev; list_add_tail(&bridge->head, &dev->mode_config.bridge_list); dev->mode_config.num_bridge++; @@ -1032,7 +1029,7 @@ EXPORT_SYMBOL(drm_bridge_init); */ void drm_bridge_cleanup(struct drm_bridge *bridge) { - struct drm_device *dev = bridge->dev; + struct drm_device *dev = bridge->drm_dev; drm_modeset_lock_all(dev); drm_mode_object_put(dev, &bridge->base); diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 7f9f6f9..bdef294 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -51,9 +51,10 @@ config DRM_EXYNOS_DSI config DRM_EXYNOS_DP bool "EXYNOS DRM DP driver support" - depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) + depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS default DRM_EXYNOS select DRM_PANEL + select DRM_BRIDGE help This enables support for DP device. diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 49356cc..055a9e1 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -28,7 +28,6 @@ #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_panel.h> -#include <drm/bridge/ptn3460.h> #include "exynos_drm_drv.h" #include "exynos_dp_core.h" @@ -986,33 +985,23 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { .best_encoder = exynos_dp_best_encoder, }; -static bool find_bridge(const char *compat, struct bridge_init *bridge) +static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp, + struct drm_encoder *encoder) { - 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; + dp->bridge->connector_polled = DRM_CONNECTOR_POLL_HPD; + ret = drm_bridge_attach_encoder(dp->bridge, encoder); + if (ret) { + DRM_ERROR("Failed to attach bridge to encoder\n"); + return ret; } - return 0; + + /* Allow the bridge to continue with rest of initialization */ + if (dp->bridge->funcs && dp->bridge->funcs->post_encoder_init) + return dp->bridge->funcs->post_encoder_init(dp->bridge); + + return -ENODEV; } static int exynos_dp_create_connector(struct exynos_drm_display *display, @@ -1025,9 +1014,11 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display, dp->encoder = encoder; /* Pre-empt DP connector creation if there's a bridge */ - ret = exynos_drm_attach_lcd_bridge(dp->drm_dev, encoder); - if (ret) - return 0; + if (dp->bridge) { + ret = exynos_drm_attach_lcd_bridge(dp, encoder); + if (!ret) + return 0; + } connector->polled = DRM_CONNECTOR_POLL_HPD; @@ -1279,7 +1270,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; - if (!dp->panel) { + if (!dp->panel && !dp->bridge) { ret = exynos_dp_dt_parse_panel(dp); if (ret) return ret; @@ -1370,7 +1361,7 @@ static const struct component_ops exynos_dp_ops = { static int exynos_dp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *panel_node; + struct device_node *panel_node, *bridge_node; struct exynos_dp_device *dp; int ret; @@ -1392,6 +1383,14 @@ static int exynos_dp_probe(struct platform_device *pdev) return -EPROBE_DEFER; } + bridge_node = of_parse_phandle(dev->of_node, "bridge", 0); + if (bridge_node) { + dp->bridge = of_drm_find_bridge(bridge_node); + of_node_put(bridge_node); + if (!dp->bridge) + return -EPROBE_DEFER; + } + exynos_dp_display.ctx = dp; ret = component_add(&pdev->dev, &exynos_dp_ops); diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h index a1aee69..3b0ba93 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.h +++ b/drivers/gpu/drm/exynos/exynos_dp_core.h @@ -150,6 +150,7 @@ struct exynos_dp_device { struct drm_connector connector; struct drm_encoder *encoder; struct drm_panel *panel; + struct drm_bridge *bridge; struct clk *clock; unsigned int irq; void __iomem *reg_base; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index f6cf745..0309539 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -221,8 +221,9 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi) hdmi_bridge->hdmi = hdmi_reference(hdmi); bridge = &hdmi_bridge->base; + bridge->funcs = &hdmi_bridge_funcs; - drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs); + drm_bridge_init(hdmi->dev, bridge); return bridge; diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h deleted file mode 100644 index ff62344..0000000 --- a/include/drm/bridge/ptn3460.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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; - -#if defined(CONFIG_DRM_PTN3460) || defined(CONFIG_DRM_PTN3460_MODULE) - -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 diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index e529b68..e5a41ad 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -619,6 +619,7 @@ struct drm_plane { /** * drm_bridge_funcs - drm_bridge control functions + * @post_encoder_init: called by the parent encoder * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge * @disable: Called right before encoder prepare, disables the bridge * @post_disable: Called right after encoder prepare, for lockstepped disable @@ -628,6 +629,7 @@ struct drm_plane { * @destroy: make object go away */ struct drm_bridge_funcs { + int (*post_encoder_init)(struct drm_bridge *bridge); bool (*mode_fixup)(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); @@ -648,15 +650,19 @@ struct drm_bridge_funcs { * @base: base mode object * @funcs: control functions * @driver_private: pointer to the bridge driver's internal context + * @connector_polled: polled flag needed for registering connector */ struct drm_bridge { - struct drm_device *dev; + struct device *dev; + struct drm_device *drm_dev; + struct drm_encoder *encoder; struct list_head head; struct drm_mode_object base; const struct drm_bridge_funcs *funcs; void *driver_private; + int connector_polled; }; /** @@ -895,8 +901,12 @@ extern void drm_connector_cleanup(struct drm_connector *connector); /* helper to unplug all connectors from sysfs for device */ extern void drm_connector_unplug_all(struct drm_device *dev); -extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, - const struct drm_bridge_funcs *funcs); +extern int drm_bridge_add_for_lookup(struct drm_bridge *bridge); +extern void drm_bridge_remove_from_lookup(struct drm_bridge *bridge); +extern struct drm_bridge *of_drm_find_bridge(struct device_node *np); +extern int drm_bridge_attach_encoder(struct drm_bridge *bridge, + struct drm_encoder *encoder); +extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge); extern void drm_bridge_cleanup(struct drm_bridge *bridge); extern int drm_encoder_init(struct drm_device *dev, -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html