From patchwork Wed Nov 2 16:32:16 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jyri Sarha X-Patchwork-Id: 9409483 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id AD76D6022E for ; Wed, 2 Nov 2016 16:32:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9FECD2A1FD for ; Wed, 2 Nov 2016 16:32:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 94E292A1FC; Wed, 2 Nov 2016 16:32:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-3.7 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RCVD_IN_SORBS_SPAM autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 129BB29F9A for ; Wed, 2 Nov 2016 16:32:32 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 3FE3B6E5C9; Wed, 2 Nov 2016 16:32:31 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from comal.ext.ti.com (comal.ext.ti.com [198.47.26.152]) by gabe.freedesktop.org (Postfix) with ESMTPS id AFCB26E5C9 for ; Wed, 2 Nov 2016 16:32:30 +0000 (UTC) Received: from dflxv15.itg.ti.com ([128.247.5.124]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id uA2GWQbO022160; Wed, 2 Nov 2016 11:32:26 -0500 Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id uA2GWQx0023523; Wed, 2 Nov 2016 11:32:26 -0500 Received: from dlep32.itg.ti.com (157.170.170.100) by DFLE72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.3.294.0; Wed, 2 Nov 2016 11:32:25 -0500 Received: from jadmar.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep32.itg.ti.com (8.14.3/8.13.8) with ESMTP id uA2GWIT2004822; Wed, 2 Nov 2016 11:32:24 -0500 From: Jyri Sarha To: , Subject: [PATCH 2/3] drm/bridge: Add ti-ftp410 HDMI transmitter driver Date: Wed, 2 Nov 2016 18:32:16 +0200 Message-ID: <9b6a6a4405de344cb9fbea735fea37adee1d726e.1478103726.git.jsarha@ti.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: References: MIME-Version: 1.0 Cc: bcousson@baylibre.com, khilman@baylibre.com, Jyri Sarha , bgolaszewski@baylibre.com, tomi.valkeinen@ti.com, laurent.pinchart@ideasonboard.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP Add very basic ti-ftp410 HDMI transmitter driver. The only feature separating this from a completely dummy bridge is the DDC i2c support. However, other HW specific features may be added later when needed. For instance there is a set of registers behind i2c if it is connected. The implementations is tested against my new tilcdc bridge support and works with BeagleBone DVI-D Cape Rev A3. A DT binding document is also added. Signed-off-by: Jyri Sarha --- .../bindings/display/bridge/ti,tfp410.txt | 30 ++++ drivers/gpu/drm/bridge/Kconfig | 7 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/ti-tfp410.c | 199 +++++++++++++++++++++ 4 files changed, 237 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/bridge/ti,tfp410.txt create mode 100644 drivers/gpu/drm/bridge/ti-tfp410.c diff --git a/Documentation/devicetree/bindings/display/bridge/ti,tfp410.txt b/Documentation/devicetree/bindings/display/bridge/ti,tfp410.txt new file mode 100644 index 0000000..dc93713 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/ti,tfp410.txt @@ -0,0 +1,30 @@ +TFP410 HDMI/DVI bridge bindings + +Required properties: + - compatible: "ti,tfp410" + +Optional properties: + - ddc-i2c: phandle of an I2C controller used for DDC EDID probing + +Optional subnodes: + - video input: this subnode can contain a video input port node + to connect the bridge to a display controller output (See this + documentation [1]). + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + hdmi-bridge { + compatible = "ti,tfp410"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + bridge_in: endpoint { + remote-endpoint = <&dc_out>; + }; + }; + }; + }; diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index bd6acc8..a424e03 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -81,6 +81,13 @@ config DRM_TOSHIBA_TC358767 ---help--- Toshiba TC358767 eDP bridge chip driver. +config DRM_TI_TFP410 + tristate "TI TFP410 DVI/HDMI bridge" + depends on OF + select DRM_KMS_HELPER + ---help--- + Texas Instruments TFP410 DVI/HDMI Transmitter driver + source "drivers/gpu/drm/bridge/analogix/Kconfig" source "drivers/gpu/drm/bridge/adv7511/Kconfig" diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 97ed1a5..8b065d9 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_DRM_SII902X) += sii902x.o obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ +obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c new file mode 100644 index 0000000..b0753d2 --- /dev/null +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2016 Texas Instruments + * Author: Jyri Sarha + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + */ + +#include +#include + +#include +#include +#include +#include + +struct tfp410 { + struct drm_bridge bridge; + struct drm_connector connector; + + struct i2c_adapter *ddc; + + struct device *dev; +}; + +static inline struct tfp410 * +drm_bridge_to_tfp410(struct drm_bridge *bridge) +{ + return container_of(bridge, struct tfp410, bridge); +} + +static inline struct tfp410 * +drm_connector_to_tfp410(struct drm_connector *connector) +{ + return container_of(connector, struct tfp410, connector); +} + +static int tfp410_get_modes(struct drm_connector *connector) +{ + struct tfp410 *hdmi = drm_connector_to_tfp410(connector); + struct edid *edid; + int ret; + + if (!hdmi->ddc) + goto fallback; + + edid = drm_get_edid(connector, hdmi->ddc); + if (!edid) { + DRM_INFO("EDID read failed. Fallback to standard modes\n"); + goto fallback; + } + + drm_mode_connector_update_edid_property(connector, edid); + + return drm_add_edid_modes(connector, edid); +fallback: + /* No EDID, fallback on the XGA standard modes */ + ret = drm_add_modes_noedid(connector, 1920, 1200); + + /* And prefer a mode pretty much anything can handle */ + drm_set_preferred_mode(connector, 1024, 768); + + return ret; +} + +static const struct drm_connector_helper_funcs tfp410_con_helper_funcs = { + .get_modes = tfp410_get_modes, +}; + +static enum drm_connector_status +tfp410_connector_detect(struct drm_connector *connector, bool force) +{ + struct tfp410 *hdmi = drm_connector_to_tfp410(connector); + + if (hdmi->ddc) { + if (drm_probe_ddc(hdmi->ddc)) + return connector_status_connected; + else + return connector_status_disconnected; + } + + return connector_status_unknown; +} + +static const struct drm_connector_funcs tfp410_con_funcs = { + .dpms = drm_atomic_helper_connector_dpms, + .detect = tfp410_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int tfp410_attach(struct drm_bridge *bridge) +{ + struct tfp410 *hdmi = drm_bridge_to_tfp410(bridge); + int ret; + + if (!bridge->encoder) { + dev_err(hdmi->dev, "Missing encoder\n"); + return -ENODEV; + } + + drm_connector_helper_add(&hdmi->connector, + &tfp410_con_helper_funcs); + ret = drm_connector_init(bridge->dev, &hdmi->connector, + &tfp410_con_funcs, DRM_MODE_CONNECTOR_HDMIA); + if (ret) { + dev_err(hdmi->dev, "drm_connector_init() failed: %d\n", ret); + return ret; + } + + drm_mode_connector_attach_encoder(&hdmi->connector, + bridge->encoder); + + return 0; +} + +static const struct drm_bridge_funcs tfp410_bridge_funcs = { + .attach = tfp410_attach, +}; + +static int tfp410_probe(struct platform_device *pdev) +{ + struct device_node *ddc_phandle; + struct tfp410 *hdmi; + int ret; + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, "device-tree data is missing\n"); + return -ENXIO; + } + + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + platform_set_drvdata(pdev, hdmi); + + ddc_phandle = of_parse_phandle(pdev->dev.of_node, "ddc-i2c", 0); + if (ddc_phandle) { + hdmi->ddc = of_get_i2c_adapter_by_node(ddc_phandle); + of_node_put(ddc_phandle); + if (!hdmi->ddc) + return -EPROBE_DEFER; + } else { + dev_info(&pdev->dev, + "No ddc i2c bus, disabling EDID readout\n"); + } + + hdmi->bridge.funcs = &tfp410_bridge_funcs; + hdmi->bridge.of_node = pdev->dev.of_node; + hdmi->dev = &pdev->dev; + + ret = drm_bridge_add(&hdmi->bridge); + if (ret) { + dev_err(&pdev->dev, "drm_bridge_add() failed: %d\n", ret); + goto fail; + } + + return 0; +fail: + i2c_put_adapter(hdmi->ddc); + return ret; +} + +static int tfp410_remove(struct platform_device *pdev) +{ + struct tfp410 *hdmi = platform_get_drvdata(pdev); + + drm_bridge_remove(&hdmi->bridge); + + if (hdmi->ddc) + i2c_put_adapter(hdmi->ddc); + + return 0; +} + +static const struct of_device_id tfp410_match[] = { + { .compatible = "ti,tfp410" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tfp410_match); + +struct platform_driver tfp410_driver = { + .probe = tfp410_probe, + .remove = tfp410_remove, + .driver = { + .name = "tfp410-bridge", + .of_match_table = tfp410_match, + }, +}; +module_platform_driver(tfp410_driver); + +MODULE_AUTHOR("Jyri Sarha "); +MODULE_DESCRIPTION("TI TFP410 HDMI bridge driver"); +MODULE_LICENSE("GPL");