diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm')
33 files changed, 993 insertions, 1882 deletions
diff --git a/drivers/gpu/drm/omapdrm/displays/Kconfig b/drivers/gpu/drm/omapdrm/displays/Kconfig index b562a8cd61bf..f2be594c7eff 100644 --- a/drivers/gpu/drm/omapdrm/displays/Kconfig +++ b/drivers/gpu/drm/omapdrm/displays/Kconfig @@ -1,28 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menu "OMAPDRM External Display Device Drivers" -config DRM_OMAP_ENCODER_OPA362 - tristate "OPA362 external analog amplifier" - help - Driver for OPA362 external analog TV amplifier controlled - through a GPIO. - -config DRM_OMAP_ENCODER_TPD12S015 - tristate "TPD12S015 HDMI ESD protection and level shifter" - help - Driver for TPD12S015, which offers HDMI ESD protection and level - shifting. - -config DRM_OMAP_CONNECTOR_HDMI - tristate "HDMI Connector" - help - Driver for a generic HDMI connector. - -config DRM_OMAP_CONNECTOR_ANALOG_TV - tristate "Analog TV Connector" - help - Driver for a generic analog TV connector. - config DRM_OMAP_PANEL_DSI_CM tristate "Generic DSI Command Mode Panel" depends on BACKLIGHT_CLASS_DEVICE diff --git a/drivers/gpu/drm/omapdrm/displays/Makefile b/drivers/gpu/drm/omapdrm/displays/Makefile index cb76859dc574..488ddf153613 100644 --- a/drivers/gpu/drm/omapdrm/displays/Makefile +++ b/drivers/gpu/drm/omapdrm/displays/Makefile @@ -1,6 +1,2 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_DRM_OMAP_ENCODER_OPA362) += encoder-opa362.o -obj-$(CONFIG_DRM_OMAP_ENCODER_TPD12S015) += encoder-tpd12s015.o -obj-$(CONFIG_DRM_OMAP_CONNECTOR_HDMI) += connector-hdmi.o -obj-$(CONFIG_DRM_OMAP_CONNECTOR_ANALOG_TV) += connector-analog-tv.o obj-$(CONFIG_DRM_OMAP_PANEL_DSI_CM) += panel-dsi-cm.o diff --git a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c deleted file mode 100644 index 0d20fab605d7..000000000000 --- a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Analog TV Connector driver - * - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - */ - -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/of.h> - -#include "../dss/omapdss.h" - -struct panel_drv_data { - struct omap_dss_device dssdev; - - struct device *dev; -}; - -#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) - -static int tvc_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return 0; -} - -static void tvc_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ -} - -static const struct omap_dss_device_ops tvc_ops = { - .connect = tvc_connect, - .disconnect = tvc_disconnect, -}; - -static int tvc_probe(struct platform_device *pdev) -{ - struct panel_drv_data *ddata; - struct omap_dss_device *dssdev; - - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); - if (!ddata) - return -ENOMEM; - - platform_set_drvdata(pdev, ddata); - ddata->dev = &pdev->dev; - - dssdev = &ddata->dssdev; - dssdev->ops = &tvc_ops; - dssdev->dev = &pdev->dev; - dssdev->type = OMAP_DISPLAY_TYPE_VENC; - dssdev->display = true; - dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(0); - - omapdss_display_init(dssdev); - omapdss_device_register(dssdev); - - return 0; -} - -static int __exit tvc_remove(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - - omapdss_device_unregister(&ddata->dssdev); - - return 0; -} - -static const struct of_device_id tvc_of_match[] = { - { .compatible = "omapdss,svideo-connector", }, - { .compatible = "omapdss,composite-video-connector", }, - {}, -}; - -MODULE_DEVICE_TABLE(of, tvc_of_match); - -static struct platform_driver tvc_connector_driver = { - .probe = tvc_probe, - .remove = __exit_p(tvc_remove), - .driver = { - .name = "connector-analog-tv", - .of_match_table = tvc_of_match, - .suppress_bind_attrs = true, - }, -}; - -module_platform_driver(tvc_connector_driver); - -MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); -MODULE_DESCRIPTION("Analog TV Connector driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c deleted file mode 100644 index f5d69d810bb8..000000000000 --- a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c +++ /dev/null @@ -1,183 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * HDMI Connector driver - * - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - */ - -#include <linux/gpio/consumer.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> -#include <linux/slab.h> - -#include "../dss/omapdss.h" - -struct panel_drv_data { - struct omap_dss_device dssdev; - void (*hpd_cb)(void *cb_data, enum drm_connector_status status); - void *hpd_cb_data; - struct mutex hpd_lock; - - struct device *dev; - - struct gpio_desc *hpd_gpio; -}; - -#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) - -static int hdmic_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return 0; -} - -static void hdmic_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ -} - -static bool hdmic_detect(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - return gpiod_get_value_cansleep(ddata->hpd_gpio); -} - -static void hdmic_register_hpd_cb(struct omap_dss_device *dssdev, - void (*cb)(void *cb_data, - enum drm_connector_status status), - void *cb_data) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - mutex_lock(&ddata->hpd_lock); - ddata->hpd_cb = cb; - ddata->hpd_cb_data = cb_data; - mutex_unlock(&ddata->hpd_lock); -} - -static void hdmic_unregister_hpd_cb(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - mutex_lock(&ddata->hpd_lock); - ddata->hpd_cb = NULL; - ddata->hpd_cb_data = NULL; - mutex_unlock(&ddata->hpd_lock); -} - -static const struct omap_dss_device_ops hdmic_ops = { - .connect = hdmic_connect, - .disconnect = hdmic_disconnect, - - .detect = hdmic_detect, - .register_hpd_cb = hdmic_register_hpd_cb, - .unregister_hpd_cb = hdmic_unregister_hpd_cb, -}; - -static irqreturn_t hdmic_hpd_isr(int irq, void *data) -{ - struct panel_drv_data *ddata = data; - - mutex_lock(&ddata->hpd_lock); - if (ddata->hpd_cb) { - enum drm_connector_status status; - - if (hdmic_detect(&ddata->dssdev)) - status = connector_status_connected; - else - status = connector_status_disconnected; - - ddata->hpd_cb(ddata->hpd_cb_data, status); - } - mutex_unlock(&ddata->hpd_lock); - - return IRQ_HANDLED; -} - -static int hdmic_probe(struct platform_device *pdev) -{ - struct panel_drv_data *ddata; - struct omap_dss_device *dssdev; - struct gpio_desc *gpio; - int r; - - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); - if (!ddata) - return -ENOMEM; - - platform_set_drvdata(pdev, ddata); - ddata->dev = &pdev->dev; - - mutex_init(&ddata->hpd_lock); - - /* HPD GPIO */ - gpio = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN); - if (IS_ERR(gpio)) { - dev_err(&pdev->dev, "failed to parse HPD gpio\n"); - return PTR_ERR(gpio); - } - - ddata->hpd_gpio = gpio; - - if (ddata->hpd_gpio) { - r = devm_request_threaded_irq(&pdev->dev, - gpiod_to_irq(ddata->hpd_gpio), - NULL, hdmic_hpd_isr, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, - "hdmic hpd", ddata); - if (r) - return r; - } - - dssdev = &ddata->dssdev; - dssdev->ops = &hdmic_ops; - dssdev->dev = &pdev->dev; - dssdev->type = OMAP_DISPLAY_TYPE_HDMI; - dssdev->display = true; - dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(0); - dssdev->ops_flags = ddata->hpd_gpio - ? OMAP_DSS_DEVICE_OP_DETECT | OMAP_DSS_DEVICE_OP_HPD - : 0; - - omapdss_display_init(dssdev); - omapdss_device_register(dssdev); - - return 0; -} - -static int __exit hdmic_remove(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - - omapdss_device_unregister(&ddata->dssdev); - - return 0; -} - -static const struct of_device_id hdmic_of_match[] = { - { .compatible = "omapdss,hdmi-connector", }, - {}, -}; - -MODULE_DEVICE_TABLE(of, hdmic_of_match); - -static struct platform_driver hdmi_connector_driver = { - .probe = hdmic_probe, - .remove = __exit_p(hdmic_remove), - .driver = { - .name = "connector-hdmi", - .of_match_table = hdmic_of_match, - .suppress_bind_attrs = true, - }, -}; - -module_platform_driver(hdmi_connector_driver); - -MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); -MODULE_DESCRIPTION("HDMI Connector driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c deleted file mode 100644 index b992387ed674..000000000000 --- a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * OPA362 analog video amplifier with output/power control - * - * Copyright (C) 2014 Golden Delicious Computers - * Author: H. Nikolaus Schaller <hns@goldelico.com> - * - * based on encoder-tfp410 - * - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - */ - -#include <linux/gpio/consumer.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> - -#include "../dss/omapdss.h" - -struct panel_drv_data { - struct omap_dss_device dssdev; - - struct gpio_desc *enable_gpio; -}; - -#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) - -static int opa362_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return omapdss_device_connect(dst->dss, dst, dst->next); -} - -static void opa362_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - omapdss_device_disconnect(dst, dst->next); -} - -static void opa362_enable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - if (ddata->enable_gpio) - gpiod_set_value_cansleep(ddata->enable_gpio, 1); -} - -static void opa362_disable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - if (ddata->enable_gpio) - gpiod_set_value_cansleep(ddata->enable_gpio, 0); -} - -static const struct omap_dss_device_ops opa362_ops = { - .connect = opa362_connect, - .disconnect = opa362_disconnect, - .enable = opa362_enable, - .disable = opa362_disable, -}; - -static int opa362_probe(struct platform_device *pdev) -{ - struct panel_drv_data *ddata; - struct omap_dss_device *dssdev; - struct gpio_desc *gpio; - - dev_dbg(&pdev->dev, "probe\n"); - - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); - if (!ddata) - return -ENOMEM; - - platform_set_drvdata(pdev, ddata); - - gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW); - if (IS_ERR(gpio)) - return PTR_ERR(gpio); - - ddata->enable_gpio = gpio; - - dssdev = &ddata->dssdev; - dssdev->ops = &opa362_ops; - dssdev->dev = &pdev->dev; - dssdev->type = OMAP_DISPLAY_TYPE_VENC; - dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(1) | BIT(0); - - dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1); - if (IS_ERR(dssdev->next)) { - if (PTR_ERR(dssdev->next) != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to find video sink\n"); - return PTR_ERR(dssdev->next); - } - - omapdss_device_register(dssdev); - - return 0; -} - -static int __exit opa362_remove(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct omap_dss_device *dssdev = &ddata->dssdev; - - if (dssdev->next) - omapdss_device_put(dssdev->next); - omapdss_device_unregister(&ddata->dssdev); - - opa362_disable(dssdev); - - return 0; -} - -static const struct of_device_id opa362_of_match[] = { - { .compatible = "omapdss,ti,opa362", }, - {}, -}; -MODULE_DEVICE_TABLE(of, opa362_of_match); - -static struct platform_driver opa362_driver = { - .probe = opa362_probe, - .remove = __exit_p(opa362_remove), - .driver = { - .name = "amplifier-opa362", - .of_match_table = opa362_of_match, - .suppress_bind_attrs = true, - }, -}; - -module_platform_driver(opa362_driver); - -MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>"); -MODULE_DESCRIPTION("OPA362 analog video amplifier with output/power control"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c deleted file mode 100644 index 089105c5aa0a..000000000000 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * TPD12S015 HDMI ESD protection & level shifter chip driver - * - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - */ - -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/platform_device.h> -#include <linux/gpio/consumer.h> -#include <linux/mutex.h> - -#include "../dss/omapdss.h" - -struct panel_drv_data { - struct omap_dss_device dssdev; - void (*hpd_cb)(void *cb_data, enum drm_connector_status status); - void *hpd_cb_data; - struct mutex hpd_lock; - - struct gpio_desc *ct_cp_hpd_gpio; - struct gpio_desc *ls_oe_gpio; - struct gpio_desc *hpd_gpio; -}; - -#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) - -static int tpd_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - struct panel_drv_data *ddata = to_panel_data(dst); - int r; - - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1); - gpiod_set_value_cansleep(ddata->ls_oe_gpio, 1); - - /* DC-DC converter needs at max 300us to get to 90% of 5V */ - udelay(300); - - return 0; -} - -static void tpd_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - struct panel_drv_data *ddata = to_panel_data(dst); - - gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0); - gpiod_set_value_cansleep(ddata->ls_oe_gpio, 0); - - omapdss_device_disconnect(dst, dst->next); -} - -static bool tpd_detect(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - return gpiod_get_value_cansleep(ddata->hpd_gpio); -} - -static void tpd_register_hpd_cb(struct omap_dss_device *dssdev, - void (*cb)(void *cb_data, - enum drm_connector_status status), - void *cb_data) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - mutex_lock(&ddata->hpd_lock); - ddata->hpd_cb = cb; - ddata->hpd_cb_data = cb_data; - mutex_unlock(&ddata->hpd_lock); -} - -static void tpd_unregister_hpd_cb(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - mutex_lock(&ddata->hpd_lock); - ddata->hpd_cb = NULL; - ddata->hpd_cb_data = NULL; - mutex_unlock(&ddata->hpd_lock); -} - -static const struct omap_dss_device_ops tpd_ops = { - .connect = tpd_connect, - .disconnect = tpd_disconnect, - .detect = tpd_detect, - .register_hpd_cb = tpd_register_hpd_cb, - .unregister_hpd_cb = tpd_unregister_hpd_cb, -}; - -static irqreturn_t tpd_hpd_isr(int irq, void *data) -{ - struct panel_drv_data *ddata = data; - - mutex_lock(&ddata->hpd_lock); - if (ddata->hpd_cb) { - enum drm_connector_status status; - - if (tpd_detect(&ddata->dssdev)) - status = connector_status_connected; - else - status = connector_status_disconnected; - - ddata->hpd_cb(ddata->hpd_cb_data, status); - } - mutex_unlock(&ddata->hpd_lock); - - return IRQ_HANDLED; -} - -static int tpd_probe(struct platform_device *pdev) -{ - struct omap_dss_device *dssdev; - struct panel_drv_data *ddata; - int r; - struct gpio_desc *gpio; - - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); - if (!ddata) - return -ENOMEM; - - platform_set_drvdata(pdev, ddata); - - gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0, - GPIOD_OUT_LOW); - if (IS_ERR(gpio)) - return PTR_ERR(gpio); - - ddata->ct_cp_hpd_gpio = gpio; - - gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1, - GPIOD_OUT_LOW); - if (IS_ERR(gpio)) - return PTR_ERR(gpio); - - ddata->ls_oe_gpio = gpio; - - gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2, - GPIOD_IN); - if (IS_ERR(gpio)) - return PTR_ERR(gpio); - - ddata->hpd_gpio = gpio; - - mutex_init(&ddata->hpd_lock); - - r = devm_request_threaded_irq(&pdev->dev, gpiod_to_irq(ddata->hpd_gpio), - NULL, tpd_hpd_isr, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "tpd12s015 hpd", ddata); - if (r) - return r; - - dssdev = &ddata->dssdev; - dssdev->ops = &tpd_ops; - dssdev->dev = &pdev->dev; - dssdev->type = OMAP_DISPLAY_TYPE_HDMI; - dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(1) | BIT(0); - dssdev->ops_flags = OMAP_DSS_DEVICE_OP_DETECT - | OMAP_DSS_DEVICE_OP_HPD; - - dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1); - if (IS_ERR(dssdev->next)) { - if (PTR_ERR(dssdev->next) != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to find video sink\n"); - return PTR_ERR(dssdev->next); - } - - omapdss_device_register(dssdev); - - return 0; -} - -static int __exit tpd_remove(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct omap_dss_device *dssdev = &ddata->dssdev; - - if (dssdev->next) - omapdss_device_put(dssdev->next); - omapdss_device_unregister(&ddata->dssdev); - - return 0; -} - -static const struct of_device_id tpd_of_match[] = { - { .compatible = "omapdss,ti,tpd12s015", }, - {}, -}; - -MODULE_DEVICE_TABLE(of, tpd_of_match); - -static struct platform_driver tpd_driver = { - .probe = tpd_probe, - .remove = __exit_p(tpd_remove), - .driver = { - .name = "tpd12s015", - .of_match_table = tpd_of_match, - .suppress_bind_attrs = true, - }, -}; - -module_platform_driver(tpd_driver); - -MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); -MODULE_DESCRIPTION("TPD12S015 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index 564e3e1a1891..3484b5d4a91c 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -678,7 +678,7 @@ static int dsicm_power_on(struct panel_drv_data *ddata) if (r) goto err; - ddata->enabled = 1; + ddata->enabled = true; if (!ddata->intro_printed) { dev_info(&ddata->pdev->dev, "panel revision %02x.%02x.%02x\n", @@ -729,7 +729,7 @@ static void dsicm_power_off(struct panel_drv_data *ddata) if (ddata->vpnl) regulator_disable(ddata->vpnl); - ddata->enabled = 0; + ddata->enabled = false; } static int dsicm_panel_reset(struct panel_drv_data *ddata) @@ -1265,7 +1265,7 @@ static int dsicm_probe(struct platform_device *pdev) dssdev->type = OMAP_DISPLAY_TYPE_DSI; dssdev->display = true; dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(0); + dssdev->of_port = 0; dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES; dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | diff --git a/drivers/gpu/drm/omapdrm/dss/Makefile b/drivers/gpu/drm/omapdrm/dss/Makefile index 5950c3f52c2e..f967e6948f2e 100644 --- a/drivers/gpu/drm/omapdrm/dss/Makefile +++ b/drivers/gpu/drm/omapdrm/dss/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o obj-$(CONFIG_OMAP_DSS_BASE) += omapdss-base.o -omapdss-base-y := base.o display.o dss-of.o output.o +omapdss-base-y := base.o display.o output.o obj-$(CONFIG_OMAP2_DSS) += omapdss.o # Core DSS files diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index a1970b9db6ab..c7650a7c155d 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -149,8 +149,7 @@ struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from) goto done; } - if (dssdev->id && - (dssdev->next || dssdev->bridge || dssdev->panel)) + if (dssdev->id && (dssdev->next || dssdev->bridge)) goto done; } @@ -185,11 +184,10 @@ int omapdss_device_connect(struct dss_device *dss, if (!dst) { /* * The destination is NULL when the source is connected to a - * bridge or panel instead of a DSS device. Stop here, we will - * attach the bridge or panel later when we will have a DRM - * encoder. + * bridge instead of a DSS device. Stop here, we will attach + * the bridge later when we will have a DRM encoder. */ - return src && (src->bridge || src->panel) ? 0 : -EINVAL; + return src && src->bridge ? 0 : -EINVAL; } if (omapdss_device_is_connected(dst)) @@ -197,10 +195,12 @@ int omapdss_device_connect(struct dss_device *dss, dst->dss = dss; - ret = dst->ops->connect(src, dst); - if (ret < 0) { - dst->dss = NULL; - return ret; + if (dst->ops && dst->ops->connect) { + ret = dst->ops->connect(src, dst); + if (ret < 0) { + dst->dss = NULL; + return ret; + } } return 0; @@ -217,7 +217,7 @@ void omapdss_device_disconnect(struct omap_dss_device *src, dst ? dev_name(dst->dev) : "NULL"); if (!dst) { - WARN_ON(!src->bridge && !src->panel); + WARN_ON(!src->bridge); return; } @@ -228,29 +228,18 @@ void omapdss_device_disconnect(struct omap_dss_device *src, WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED); - dst->ops->disconnect(src, dst); + if (dst->ops && dst->ops->disconnect) + dst->ops->disconnect(src, dst); dst->dss = NULL; } EXPORT_SYMBOL_GPL(omapdss_device_disconnect); -void omapdss_device_pre_enable(struct omap_dss_device *dssdev) -{ - if (!dssdev) - return; - - omapdss_device_pre_enable(dssdev->next); - - if (dssdev->ops->pre_enable) - dssdev->ops->pre_enable(dssdev); -} -EXPORT_SYMBOL_GPL(omapdss_device_pre_enable); - void omapdss_device_enable(struct omap_dss_device *dssdev) { if (!dssdev) return; - if (dssdev->ops->enable) + if (dssdev->ops && dssdev->ops->enable) dssdev->ops->enable(dssdev); omapdss_device_enable(dssdev->next); @@ -266,25 +255,11 @@ void omapdss_device_disable(struct omap_dss_device *dssdev) omapdss_device_disable(dssdev->next); - if (dssdev->ops->disable) + if (dssdev->ops && dssdev->ops->disable) dssdev->ops->disable(dssdev); } EXPORT_SYMBOL_GPL(omapdss_device_disable); -void omapdss_device_post_disable(struct omap_dss_device *dssdev) -{ - if (!dssdev) - return; - - if (dssdev->ops->post_disable) - dssdev->ops->post_disable(dssdev); - - omapdss_device_post_disable(dssdev->next); - - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; -} -EXPORT_SYMBOL_GPL(omapdss_device_post_disable); - /* ----------------------------------------------------------------------------- * Components Handling */ diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index 8a3f61f5825f..3b82158b1bfd 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -40,15 +40,6 @@ void omapdss_display_init(struct omap_dss_device *dssdev) } EXPORT_SYMBOL_GPL(omapdss_display_init); -struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output) -{ - while (output->next) - output = output->next; - - return omapdss_device_get(output); -} -EXPORT_SYMBOL_GPL(omapdss_display_get); - int omapdss_display_get_modes(struct drm_connector *connector, const struct videomode *vm) { diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 95147437b990..5110acb0c6c1 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -9,20 +9,22 @@ #define DSS_SUBSYS_NAME "DPI" -#include <linux/kernel.h> +#include <linux/clk.h> #include <linux/delay.h> -#include <linux/export.h> #include <linux/err.h> #include <linux/errno.h> +#include <linux/export.h> +#include <linux/kernel.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/string.h> -#include <linux/of.h> -#include <linux/clk.h> #include <linux/sys_soc.h> -#include "omapdss.h" +#include <drm/drm_bridge.h> + #include "dss.h" +#include "omapdss.h" struct dpi_data { struct platform_device *pdev; @@ -34,19 +36,19 @@ struct dpi_data { enum dss_clk_source clk_src; struct dss_pll *pll; - struct mutex lock; - struct dss_lcd_mgr_config mgr_config; unsigned long pixelclock; int data_lines; struct omap_dss_device output; + struct drm_bridge bridge; }; -static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev) -{ - return container_of(dssdev, struct dpi_data, output); -} +#define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge) + +/* ----------------------------------------------------------------------------- + * Clock Handling and PLL + */ static enum dss_clk_source dpi_get_clk_src_dra7xx(struct dpi_data *dpi, enum omap_channel channel) @@ -283,9 +285,7 @@ static bool dpi_dss_clk_calc(struct dpi_data *dpi, unsigned long pck, -static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel, - unsigned long pck_req, unsigned long *fck, int *lck_div, - int *pck_div) +static int dpi_set_pll_clk(struct dpi_data *dpi, unsigned long pck_req) { struct dpi_clk_calc_ctx ctx; int r; @@ -299,19 +299,15 @@ static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel, if (r) return r; - dss_select_lcd_clk_source(dpi->dss, channel, dpi->clk_src); + dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel, + dpi->clk_src); dpi->mgr_config.clock_info = ctx.dispc_cinfo; - *fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; - *lck_div = ctx.dispc_cinfo.lck_div; - *pck_div = ctx.dispc_cinfo.pck_div; - return 0; } -static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, - unsigned long *fck, int *lck_div, int *pck_div) +static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req) { struct dpi_clk_calc_ctx ctx; int r; @@ -327,29 +323,19 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, dpi->mgr_config.clock_info = ctx.dispc_cinfo; - *fck = ctx.fck; - *lck_div = ctx.dispc_cinfo.lck_div; - *pck_div = ctx.dispc_cinfo.pck_div; - return 0; } static int dpi_set_mode(struct dpi_data *dpi) { - int lck_div = 0, pck_div = 0; - unsigned long fck = 0; - int r = 0; + int r; if (dpi->pll) - r = dpi_set_pll_clk(dpi, dpi->output.dispc_channel, - dpi->pixelclock, &fck, &lck_div, &pck_div); + r = dpi_set_pll_clk(dpi, dpi->pixelclock); else - r = dpi_set_dispc_clk(dpi, dpi->pixelclock, &fck, - &lck_div, &pck_div); - if (r) - return r; + r = dpi_set_dispc_clk(dpi, dpi->pixelclock); - return 0; + return r; } static void dpi_config_lcd_manager(struct dpi_data *dpi) @@ -366,25 +352,149 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi) dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config); } -static void dpi_display_enable(struct omap_dss_device *dssdev) +static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock) +{ + int lck_div, pck_div; + unsigned long fck; + struct dpi_clk_calc_ctx ctx; + + if (dpi->pll) { + if (!dpi_pll_clk_calc(dpi, *clock, &ctx)) + return -EINVAL; + + fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; + } else { + if (!dpi_dss_clk_calc(dpi, *clock, &ctx)) + return -EINVAL; + + fck = ctx.fck; + } + + lck_div = ctx.dispc_cinfo.lck_div; + pck_div = ctx.dispc_cinfo.pck_div; + + *clock = fck / lck_div / pck_div; + + return 0; +} + +static int dpi_verify_pll(struct dss_pll *pll) { - struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - struct omap_dss_device *out = &dpi->output; int r; - mutex_lock(&dpi->lock); + /* do initial setup with the PLL to see if it is operational */ + + r = dss_pll_enable(pll); + if (r) + return r; + + dss_pll_disable(pll); + + return 0; +} + +static void dpi_init_pll(struct dpi_data *dpi) +{ + struct dss_pll *pll; + + if (dpi->pll) + return; + + dpi->clk_src = dpi_get_clk_src(dpi); + + pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src); + if (!pll) + return; + + if (dpi_verify_pll(pll)) { + DSSWARN("PLL not operational\n"); + return; + } + + dpi->pll = pll; +} + +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + +static int dpi_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct dpi_data *dpi = drm_bridge_to_dpi(bridge); + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) + return -EINVAL; + + dpi_init_pll(dpi); + + return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge, + bridge, flags); +} + +static enum drm_mode_status +dpi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) +{ + struct dpi_data *dpi = drm_bridge_to_dpi(bridge); + unsigned long clock = mode->clock * 1000; + int ret; + + if (mode->hdisplay % 8 != 0) + return MODE_BAD_WIDTH; + + if (mode->clock == 0) + return MODE_NOCLOCK; + + ret = dpi_clock_update(dpi, &clock); + if (ret < 0) + return MODE_CLOCK_RANGE; + + return MODE_OK; +} + +static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct dpi_data *dpi = drm_bridge_to_dpi(bridge); + unsigned long clock = mode->clock * 1000; + int ret; + + ret = dpi_clock_update(dpi, &clock); + if (ret < 0) + return false; + + adjusted_mode->clock = clock / 1000; + + return true; +} + +static void dpi_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct dpi_data *dpi = drm_bridge_to_dpi(bridge); + + dpi->pixelclock = adjusted_mode->clock * 1000; +} + +static void dpi_bridge_enable(struct drm_bridge *bridge) +{ + struct dpi_data *dpi = drm_bridge_to_dpi(bridge); + int r; if (dpi->vdds_dsi_reg) { r = regulator_enable(dpi->vdds_dsi_reg); if (r) - goto err_reg_enable; + return; } r = dispc_runtime_get(dpi->dss->dispc); if (r) goto err_get_dispc; - r = dss_dpi_select_source(dpi->dss, dpi->id, out->dispc_channel); + r = dss_dpi_select_source(dpi->dss, dpi->id, dpi->output.dispc_channel); if (r) goto err_src_sel; @@ -406,8 +516,6 @@ static void dpi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_mgr_enable; - mutex_unlock(&dpi->lock); - return; err_mgr_enable: @@ -420,15 +528,11 @@ err_src_sel: err_get_dispc: if (dpi->vdds_dsi_reg) regulator_disable(dpi->vdds_dsi_reg); -err_reg_enable: - mutex_unlock(&dpi->lock); } -static void dpi_display_disable(struct omap_dss_device *dssdev) +static void dpi_bridge_disable(struct drm_bridge *bridge) { - struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - - mutex_lock(&dpi->lock); + struct dpi_data *dpi = drm_bridge_to_dpi(bridge); dss_mgr_disable(&dpi->output); @@ -442,99 +546,34 @@ static void dpi_display_disable(struct omap_dss_device *dssdev) if (dpi->vdds_dsi_reg) regulator_disable(dpi->vdds_dsi_reg); - - mutex_unlock(&dpi->lock); } -static void dpi_set_timings(struct omap_dss_device *dssdev, - const struct drm_display_mode *mode) -{ - struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - - DSSDBG("dpi_set_timings\n"); - - mutex_lock(&dpi->lock); - - dpi->pixelclock = mode->clock * 1000; - - mutex_unlock(&dpi->lock); -} +static const struct drm_bridge_funcs dpi_bridge_funcs = { + .attach = dpi_bridge_attach, + .mode_valid = dpi_bridge_mode_valid, + .mode_fixup = dpi_bridge_mode_fixup, + .mode_set = dpi_bridge_mode_set, + .enable = dpi_bridge_enable, + .disable = dpi_bridge_disable, +}; -static int dpi_check_timings(struct omap_dss_device *dssdev, - struct drm_display_mode *mode) +static void dpi_bridge_init(struct dpi_data *dpi) { - struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - int lck_div, pck_div; - unsigned long fck; - unsigned long pck; - struct dpi_clk_calc_ctx ctx; - bool ok; + dpi->bridge.funcs = &dpi_bridge_funcs; + dpi->bridge.of_node = dpi->pdev->dev.of_node; + dpi->bridge.type = DRM_MODE_CONNECTOR_DPI; - if (mode->hdisplay % 8 != 0) - return -EINVAL; - - if (mode->clock == 0) - return -EINVAL; - - if (dpi->pll) { - ok = dpi_pll_clk_calc(dpi, mode->clock * 1000, &ctx); - if (!ok) - return -EINVAL; - - fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; - } else { - ok = dpi_dss_clk_calc(dpi, mode->clock * 1000, &ctx); - if (!ok) - return -EINVAL; - - fck = ctx.fck; - } - - lck_div = ctx.dispc_cinfo.lck_div; - pck_div = ctx.dispc_cinfo.pck_div; - - pck = fck / lck_div / pck_div; - - mode->clock = pck / 1000; - - return 0; + drm_bridge_add(&dpi->bridge); } -static int dpi_verify_pll(struct dss_pll *pll) +static void dpi_bridge_cleanup(struct dpi_data *dpi) { - int r; - - /* do initial setup with the PLL to see if it is operational */ - - r = dss_pll_enable(pll); - if (r) - return r; - - dss_pll_disable(pll); - - return 0; + drm_bridge_remove(&dpi->bridge); } -static void dpi_init_pll(struct dpi_data *dpi) -{ - struct dss_pll *pll; - - if (dpi->pll) - return; - - dpi->clk_src = dpi_get_clk_src(dpi); - - pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src); - if (!pll) - return; - - if (dpi_verify_pll(pll)) { - DSSWARN("PLL not operational\n"); - return; - } - - dpi->pll = pll; -} +/* ----------------------------------------------------------------------------- + * Initialisation and Cleanup + */ /* * Return a hardcoded channel for the DPI output. This should work for @@ -572,39 +611,14 @@ static enum omap_channel dpi_get_channel(struct dpi_data *dpi) } } -static int dpi_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - struct dpi_data *dpi = dpi_get_data_from_dssdev(dst); - - dpi_init_pll(dpi); - - return omapdss_device_connect(dst->dss, dst, dst->next); -} - -static void dpi_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - omapdss_device_disconnect(dst, dst->next); -} - -static const struct omap_dss_device_ops dpi_ops = { - .connect = dpi_connect, - .disconnect = dpi_disconnect, - - .enable = dpi_display_enable, - .disable = dpi_display_disable, - - .check_timings = dpi_check_timings, - .set_timings = dpi_set_timings, -}; - static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port) { struct omap_dss_device *out = &dpi->output; u32 port_num = 0; int r; + dpi_bridge_init(dpi); + of_property_read_u32(port, "reg", &port_num); dpi->id = port_num <= 2 ? port_num : 0; @@ -625,13 +639,14 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port) out->id = OMAP_DSS_OUTPUT_DPI; out->type = OMAP_DISPLAY_TYPE_DPI; out->dispc_channel = dpi_get_channel(dpi); - out->of_ports = BIT(port_num); - out->ops = &dpi_ops; + out->of_port = port_num; out->owner = THIS_MODULE; - r = omapdss_device_init_output(out); - if (r < 0) + r = omapdss_device_init_output(out, &dpi->bridge); + if (r < 0) { + dpi_bridge_cleanup(dpi); return r; + } omapdss_device_register(out); @@ -645,8 +660,14 @@ static void dpi_uninit_output_port(struct device_node *port) omapdss_device_unregister(out); omapdss_device_cleanup_output(out); + + dpi_bridge_cleanup(dpi); } +/* ----------------------------------------------------------------------------- + * Initialisation and Cleanup + */ + static const struct soc_device_attribute dpi_soc_devices[] = { { .machine = "OMAP3[456]*" }, { .machine = "[AD]M37*" }, @@ -706,8 +727,6 @@ int dpi_init_port(struct dss_device *dss, struct platform_device *pdev, dpi->dss = dss; port->data = dpi; - mutex_init(&dpi->lock); - r = dpi_init_regulator(dpi); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index da16ea095f13..79ddfbfd1b58 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -5116,12 +5116,12 @@ static int dsi_init_output(struct dsi_data *dsi) out->dispc_channel = dsi_get_channel(dsi); out->ops = &dsi_ops; out->owner = THIS_MODULE; - out->of_ports = BIT(0); + out->of_port = 0; out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE | DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE; - r = omapdss_device_init_output(out); + r = omapdss_device_init_output(out, NULL); if (r < 0) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/dss-of.c b/drivers/gpu/drm/omapdrm/dss/dss-of.c deleted file mode 100644 index b7981f3b80ad..000000000000 --- a/drivers/gpu/drm/omapdrm/dss/dss-of.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - */ - -#include <linux/err.h> -#include <linux/of.h> -#include <linux/of_graph.h> - -#include "omapdss.h" - -struct omap_dss_device * -omapdss_of_find_connected_device(struct device_node *node, unsigned int port) -{ - struct device_node *remote_node; - struct omap_dss_device *dssdev; - - remote_node = of_graph_get_remote_node(node, port, 0); - if (!remote_node) - return NULL; - - dssdev = omapdss_find_device_by_node(remote_node); - of_node_put(remote_node); - - return dssdev ? dssdev : ERR_PTR(-EPROBE_DEFER); -} -EXPORT_SYMBOL_GPL(omapdss_of_find_connected_device); diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 225ec808b01a..b76fc2b56227 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1151,46 +1151,38 @@ static const struct dss_features dra7xx_dss_feats = { .has_lcd_clk_src = true, }; -static int dss_init_ports(struct dss_device *dss) +static void __dss_uninit_ports(struct dss_device *dss, unsigned int num_ports) { struct platform_device *pdev = dss->pdev; struct device_node *parent = pdev->dev.of_node; struct device_node *port; unsigned int i; - int r; - for (i = 0; i < dss->feat->num_ports; i++) { + for (i = 0; i < num_ports; i++) { port = of_graph_get_port_by_id(parent, i); if (!port) continue; switch (dss->feat->ports[i]) { case OMAP_DISPLAY_TYPE_DPI: - r = dpi_init_port(dss, pdev, port, dss->feat->model); - if (r) - return r; + dpi_uninit_port(port); break; - case OMAP_DISPLAY_TYPE_SDI: - r = sdi_init_port(dss, pdev, port); - if (r) - return r; + sdi_uninit_port(port); break; - default: break; } } - - return 0; } -static void dss_uninit_ports(struct dss_device *dss) +static int dss_init_ports(struct dss_device *dss) { struct platform_device *pdev = dss->pdev; struct device_node *parent = pdev->dev.of_node; struct device_node *port; - int i; + unsigned int i; + int r; for (i = 0; i < dss->feat->num_ports; i++) { port = of_graph_get_port_by_id(parent, i); @@ -1199,15 +1191,32 @@ static void dss_uninit_ports(struct dss_device *dss) switch (dss->feat->ports[i]) { case OMAP_DISPLAY_TYPE_DPI: - dpi_uninit_port(port); + r = dpi_init_port(dss, pdev, port, dss->feat->model); + if (r) + goto error; break; + case OMAP_DISPLAY_TYPE_SDI: - sdi_uninit_port(port); + r = sdi_init_port(dss, pdev, port); + if (r) + goto error; break; + default: break; } } + + return 0; + +error: + __dss_uninit_ports(dss, i); + return r; +} + +static void dss_uninit_ports(struct dss_device *dss) +{ + __dss_uninit_ports(dss, dss->feat->num_ports); } static int dss_video_pll_probe(struct dss_device *dss) @@ -1543,7 +1552,8 @@ static void dss_shutdown(struct platform_device *pdev) DSSDBG("shutdown\n"); for_each_dss_output(dssdev) { - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE && + dssdev->ops && dssdev->ops->disable) dssdev->ops->disable(dssdev); } } diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h index c867552c925c..3a40833d3368 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h @@ -14,6 +14,7 @@ #include <linux/hdmi.h> #include <sound/omap-hdmi-audio.h> #include <media/cec.h> +#include <drm/drm_bridge.h> #include "omapdss.h" #include "dss.h" @@ -364,6 +365,7 @@ struct omap_hdmi { bool core_enabled; struct omap_dss_device output; + struct drm_bridge bridge; struct platform_device *audio_pdev; void (*audio_abort_cb)(struct device *dev); @@ -378,6 +380,6 @@ struct omap_hdmi { bool display_enabled; }; -#define dssdev_to_hdmi(dssdev) container_of(dssdev, struct omap_hdmi, output) +#define drm_bridge_to_hdmi(b) container_of(b, struct omap_hdmi, bridge) #endif diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 0f557fad4513..2578c95570f6 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -28,6 +28,9 @@ #include <sound/omap-hdmi-audio.h> #include <media/cec.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_state_helper.h> + #include "omapdss.h" #include "hdmi4_core.h" #include "hdmi4_cec.h" @@ -237,20 +240,6 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi) hdmi_power_off_core(hdmi); } -static void hdmi_display_set_timings(struct omap_dss_device *dssdev, - const struct drm_display_mode *mode) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - mutex_lock(&hdmi->lock); - - drm_display_mode_to_videomode(mode, &hdmi->cfg.vm); - - dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000); - - mutex_unlock(&hdmi->lock); -} - static int hdmi_dump_regs(struct seq_file *s, void *p) { struct omap_hdmi *hdmi = s->private; @@ -272,57 +261,139 @@ static int hdmi_dump_regs(struct seq_file *s, void *p) return 0; } -static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len) +static void hdmi_start_audio_stream(struct omap_hdmi *hd) { - int r; + hdmi_wp_audio_enable(&hd->wp, true); + hdmi4_audio_start(&hd->core, &hd->wp); +} - mutex_lock(&hdmi->lock); +static void hdmi_stop_audio_stream(struct omap_hdmi *hd) +{ + hdmi4_audio_stop(&hd->core, &hd->wp); + hdmi_wp_audio_enable(&hd->wp, false); +} - r = hdmi_runtime_get(hdmi); - BUG_ON(r); +int hdmi4_core_enable(struct hdmi_core_data *core) +{ + struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); + int r = 0; - r = hdmi4_read_edid(&hdmi->core, buf, len); + DSSDBG("ENTER omapdss_hdmi4_core_enable\n"); + + mutex_lock(&hdmi->lock); + + r = hdmi_power_on_core(hdmi); + if (r) { + DSSERR("failed to power on device\n"); + goto err0; + } - hdmi_runtime_put(hdmi); mutex_unlock(&hdmi->lock); + return 0; +err0: + mutex_unlock(&hdmi->lock); return r; } -static void hdmi_start_audio_stream(struct omap_hdmi *hd) +void hdmi4_core_disable(struct hdmi_core_data *core) { - hdmi_wp_audio_enable(&hd->wp, true); - hdmi4_audio_start(&hd->core, &hd->wp); + struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); + + DSSDBG("Enter omapdss_hdmi4_core_disable\n"); + + mutex_lock(&hdmi->lock); + + hdmi_power_off_core(hdmi); + + mutex_unlock(&hdmi->lock); } -static void hdmi_stop_audio_stream(struct omap_hdmi *hd) +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + +static int hdmi4_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) { - hdmi4_audio_stop(&hd->core, &hd->wp); - hdmi_wp_audio_enable(&hd->wp, false); + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) + return -EINVAL; + + return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge, + bridge, flags); } -static void hdmi_display_enable(struct omap_dss_device *dssdev) +static void hdmi4_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + + mutex_lock(&hdmi->lock); + + drm_display_mode_to_videomode(adjusted_mode, &hdmi->cfg.vm); + + dispc_set_tv_pclk(hdmi->dss->dispc, adjusted_mode->clock * 1000); + + mutex_unlock(&hdmi->lock); +} + +static void hdmi4_bridge_enable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) +{ + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + struct drm_atomic_state *state = bridge_state->base.state; + struct drm_connector_state *conn_state; + struct drm_connector *connector; + struct drm_crtc_state *crtc_state; unsigned long flags; - int r; + int ret; + + /* + * None of these should fail, as the bridge can't be enabled without a + * valid CRTC to connector path with fully populated new states. + */ + connector = drm_atomic_get_new_connector_for_encoder(state, + bridge->encoder); + if (WARN_ON(!connector)) + return; + conn_state = drm_atomic_get_new_connector_state(state, connector); + if (WARN_ON(!conn_state)) + return; + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + if (WARN_ON(!crtc_state)) + return; + + hdmi->cfg.hdmi_dvi_mode = connector->display_info.is_hdmi + ? HDMI_HDMI : HDMI_DVI; - DSSDBG("ENTER hdmi_display_enable\n"); + if (connector->display_info.is_hdmi) { + const struct drm_display_mode *mode; + struct hdmi_avi_infoframe avi; + + mode = &crtc_state->adjusted_mode; + ret = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector, + mode); + if (ret == 0) + hdmi->cfg.infoframe = avi; + } mutex_lock(&hdmi->lock); - r = hdmi_power_on_full(hdmi); - if (r) { + ret = hdmi_power_on_full(hdmi); + if (ret) { DSSERR("failed to power on device\n"); goto done; } if (hdmi->audio_configured) { - r = hdmi4_audio_config(&hdmi->core, &hdmi->wp, - &hdmi->audio_config, - hdmi->cfg.vm.pixelclock); - if (r) { - DSSERR("Error restoring audio configuration: %d", r); + ret = hdmi4_audio_config(&hdmi->core, &hdmi->wp, + &hdmi->audio_config, + hdmi->cfg.vm.pixelclock); + if (ret) { + DSSERR("Error restoring audio configuration: %d", ret); hdmi->audio_abort_cb(&hdmi->pdev->dev); hdmi->audio_configured = false; } @@ -338,13 +409,12 @@ done: mutex_unlock(&hdmi->lock); } -static void hdmi_display_disable(struct omap_dss_device *dssdev) +static void hdmi4_bridge_disable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); unsigned long flags; - DSSDBG("Enter hdmi_display_disable\n"); - mutex_lock(&hdmi->lock); spin_lock_irqsave(&hdmi->audio_playing_lock, flags); @@ -357,58 +427,21 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev) mutex_unlock(&hdmi->lock); } -int hdmi4_core_enable(struct hdmi_core_data *core) +static void hdmi4_bridge_hpd_notify(struct drm_bridge *bridge, + enum drm_connector_status status) { - struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); - int r = 0; - - DSSDBG("ENTER omapdss_hdmi4_core_enable\n"); - - mutex_lock(&hdmi->lock); - - r = hdmi_power_on_core(hdmi); - if (r) { - DSSERR("failed to power on device\n"); - goto err0; - } - - mutex_unlock(&hdmi->lock); - return 0; - -err0: - mutex_unlock(&hdmi->lock); - return r; -} - -void hdmi4_core_disable(struct hdmi_core_data *core) -{ - struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); - - DSSDBG("Enter omapdss_hdmi4_core_disable\n"); - - mutex_lock(&hdmi->lock); - - hdmi_power_off_core(hdmi); - - mutex_unlock(&hdmi->lock); -} - -static int hdmi_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return omapdss_device_connect(dst->dss, dst, dst->next); -} + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); -static void hdmi_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - omapdss_device_disconnect(dst, dst->next); + if (status == connector_status_disconnected) + hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID); } -static int hdmi_read_edid(struct omap_dss_device *dssdev, - u8 *edid, int len) +static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + struct edid *edid = NULL; + unsigned int cec_addr; bool need_enable; int r; @@ -417,63 +450,65 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, if (need_enable) { r = hdmi4_core_enable(&hdmi->core); if (r) - return r; + return NULL; } - r = read_edid(hdmi, edid, len); - if (r >= 256) - hdmi4_cec_set_phys_addr(&hdmi->core, - cec_get_edid_phys_addr(edid, r, NULL)); - else - hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID); - if (need_enable) - hdmi4_core_disable(&hdmi->core); + mutex_lock(&hdmi->lock); + r = hdmi_runtime_get(hdmi); + BUG_ON(r); - return r; -} + r = hdmi4_core_ddc_init(&hdmi->core); + if (r) + goto done; -static void hdmi_lost_hotplug(struct omap_dss_device *dssdev) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + edid = drm_do_get_edid(connector, hdmi4_core_ddc_read, &hdmi->core); - hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID); -} +done: + hdmi_runtime_put(hdmi); + mutex_unlock(&hdmi->lock); -static int hdmi_set_infoframe(struct omap_dss_device *dssdev, - const struct hdmi_avi_infoframe *avi) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + if (edid && edid->extensions) { + unsigned int len = (edid->extensions + 1) * EDID_LENGTH; - hdmi->cfg.infoframe = *avi; - return 0; -} + cec_addr = cec_get_edid_phys_addr((u8 *)edid, len, NULL); + } else { + cec_addr = CEC_PHYS_ADDR_INVALID; + } -static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, - bool hdmi_mode) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + hdmi4_cec_set_phys_addr(&hdmi->core, cec_addr); - hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; - return 0; -} + if (need_enable) + hdmi4_core_disable(&hdmi->core); -static const struct omap_dss_device_ops hdmi_ops = { - .connect = hdmi_connect, - .disconnect = hdmi_disconnect, + return edid; +} - .enable = hdmi_display_enable, - .disable = hdmi_display_disable, +static const struct drm_bridge_funcs hdmi4_bridge_funcs = { + .attach = hdmi4_bridge_attach, + .mode_set = hdmi4_bridge_mode_set, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_enable = hdmi4_bridge_enable, + .atomic_disable = hdmi4_bridge_disable, + .hpd_notify = hdmi4_bridge_hpd_notify, + .get_edid = hdmi4_bridge_get_edid, +}; - .set_timings = hdmi_display_set_timings, +static void hdmi4_bridge_init(struct omap_hdmi *hdmi) +{ + hdmi->bridge.funcs = &hdmi4_bridge_funcs; + hdmi->bridge.of_node = hdmi->pdev->dev.of_node; + hdmi->bridge.ops = DRM_BRIDGE_OP_EDID; + hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; - .read_edid = hdmi_read_edid, + drm_bridge_add(&hdmi->bridge); +} - .hdmi = { - .lost_hotplug = hdmi_lost_hotplug, - .set_infoframe = hdmi_set_infoframe, - .set_hdmi_mode = hdmi_set_hdmi_mode, - }, -}; +static void hdmi4_bridge_cleanup(struct omap_hdmi *hdmi) +{ + drm_bridge_remove(&hdmi->bridge); +} /* ----------------------------------------------------------------------------- * Audio Callbacks @@ -666,19 +701,21 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi) struct omap_dss_device *out = &hdmi->output; int r; + hdmi4_bridge_init(hdmi); + out->dev = &hdmi->pdev->dev; out->id = OMAP_DSS_OUTPUT_HDMI; out->type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; - out->ops = &hdmi_ops; out->owner = THIS_MODULE; - out->of_ports = BIT(0); - out->ops_flags = OMAP_DSS_DEVICE_OP_EDID; + out->of_port = 0; - r = omapdss_device_init_output(out); - if (r < 0) + r = omapdss_device_init_output(out, &hdmi->bridge); + if (r < 0) { + hdmi4_bridge_cleanup(hdmi); return r; + } omapdss_device_register(out); @@ -691,6 +728,8 @@ static void hdmi4_uninit_output(struct omap_hdmi *hdmi) omapdss_device_unregister(out); omapdss_device_cleanup_output(out); + + hdmi4_bridge_cleanup(hdmi); } static int hdmi4_probe_of(struct omap_hdmi *hdmi) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c index ea5d5c228534..751985a2679a 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c @@ -32,7 +32,7 @@ static inline void __iomem *hdmi_av_base(struct hdmi_core_data *core) return core->base + HDMI_CORE_AV; } -static int hdmi_core_ddc_init(struct hdmi_core_data *core) +int hdmi4_core_ddc_init(struct hdmi_core_data *core) { void __iomem *base = core->base; @@ -74,13 +74,11 @@ static int hdmi_core_ddc_init(struct hdmi_core_data *core) return 0; } -static int hdmi_core_ddc_edid(struct hdmi_core_data *core, - u8 *pedid, int ext) +int hdmi4_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len) { + struct hdmi_core_data *core = data; void __iomem *base = core->base; u32 i; - char checksum; - u32 offset = 0; /* HDMI_CORE_DDC_STATUS_IN_PROG */ if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, @@ -89,24 +87,21 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core, return -ETIMEDOUT; } - if (ext % 2 != 0) - offset = 0x80; - /* Load Segment Address Register */ - REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, ext / 2, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, block / 2, 7, 0); /* Load Slave Address Register */ REG_FLD_MOD(base, HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1); /* Load Offset Address Register */ - REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, offset, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, block % 2 ? 0x80 : 0, 7, 0); /* Load Byte Count */ - REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, 0x80, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, len, 7, 0); REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT2, 0x0, 1, 0); /* Set DDC_CMD */ - if (ext) + if (block) REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x4, 3, 0); else REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x2, 3, 0); @@ -122,7 +117,7 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core, return -EIO; } - for (i = 0; i < 0x80; ++i) { + for (i = 0; i < len; ++i) { int t; /* IN_PROG */ @@ -141,48 +136,12 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core, udelay(1); } - pedid[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0); - } - - checksum = 0; - for (i = 0; i < 0x80; ++i) - checksum += pedid[i]; - - if (checksum != 0) { - DSSERR("E-EDID checksum failed!!\n"); - return -EIO; + buf[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0); } return 0; } -int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len) -{ - int r, l; - - if (len < 128) - return -EINVAL; - - r = hdmi_core_ddc_init(core); - if (r) - return r; - - r = hdmi_core_ddc_edid(core, edid, 0); - if (r) - return r; - - l = 128; - - if (len >= 128 * 2 && edid[0x7e] > 0) { - r = hdmi_core_ddc_edid(core, edid + 0x80, 1); - if (r) - return r; - l += 128; - } - - return l; -} - static void hdmi_core_init(struct hdmi_core_video_config *video_cfg) { DSSDBG("Enter hdmi_core_init\n"); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h index 11c4b7ba1eee..dc64ae2aa300 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h @@ -249,7 +249,9 @@ struct hdmi_core_packet_enable_repeat { u32 generic_pkt_repeat; }; -int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len); +int hdmi4_core_ddc_init(struct hdmi_core_data *core); +int hdmi4_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len); + void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, struct hdmi_config *cfg); void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index d9463b332554..4d4c1fabd0a1 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -31,6 +31,9 @@ #include <linux/of_graph.h> #include <sound/omap-hdmi-audio.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_state_helper.h> + #include "omapdss.h" #include "hdmi5_core.h" #include "dss.h" @@ -236,20 +239,6 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi) hdmi_power_off_core(hdmi); } -static void hdmi_display_set_timings(struct omap_dss_device *dssdev, - const struct drm_display_mode *mode) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - mutex_lock(&hdmi->lock); - - drm_display_mode_to_videomode(mode, &hdmi->cfg.vm); - - dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000); - - mutex_unlock(&hdmi->lock); -} - static int hdmi_dump_regs(struct seq_file *s, void *p) { struct omap_hdmi *hdmi = s->private; @@ -271,66 +260,138 @@ static int hdmi_dump_regs(struct seq_file *s, void *p) return 0; } -static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len) +static void hdmi_start_audio_stream(struct omap_hdmi *hd) { - int r; - int idlemode; + REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); + hdmi_wp_audio_enable(&hd->wp, true); + hdmi_wp_audio_core_req_enable(&hd->wp, true); +} - mutex_lock(&hdmi->lock); +static void hdmi_stop_audio_stream(struct omap_hdmi *hd) +{ + hdmi_wp_audio_core_req_enable(&hd->wp, false); + hdmi_wp_audio_enable(&hd->wp, false); + REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2); +} - r = hdmi_runtime_get(hdmi); - BUG_ON(r); +static int hdmi_core_enable(struct omap_hdmi *hdmi) +{ + int r = 0; - idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); - /* No-idle mode */ - REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); + DSSDBG("ENTER omapdss_hdmi_core_enable\n"); - r = hdmi5_read_edid(&hdmi->core, buf, len); + mutex_lock(&hdmi->lock); - REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); + r = hdmi_power_on_core(hdmi); + if (r) { + DSSERR("failed to power on device\n"); + goto err0; + } - hdmi_runtime_put(hdmi); mutex_unlock(&hdmi->lock); + return 0; +err0: + mutex_unlock(&hdmi->lock); return r; } -static void hdmi_start_audio_stream(struct omap_hdmi *hd) +static void hdmi_core_disable(struct omap_hdmi *hdmi) { - REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); - hdmi_wp_audio_enable(&hd->wp, true); - hdmi_wp_audio_core_req_enable(&hd->wp, true); + DSSDBG("Enter omapdss_hdmi_core_disable\n"); + + mutex_lock(&hdmi->lock); + + hdmi_power_off_core(hdmi); + + mutex_unlock(&hdmi->lock); } -static void hdmi_stop_audio_stream(struct omap_hdmi *hd) +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + +static int hdmi5_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) { - hdmi_wp_audio_core_req_enable(&hd->wp, false); - hdmi_wp_audio_enable(&hd->wp, false); - REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2); + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) + return -EINVAL; + + return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge, + bridge, flags); } -static void hdmi_display_enable(struct omap_dss_device *dssdev) +static void hdmi5_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - unsigned long flags; - int r; + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + + mutex_lock(&hdmi->lock); - DSSDBG("ENTER hdmi_display_enable\n"); + drm_display_mode_to_videomode(adjusted_mode, &hdmi->cfg.vm); + + dispc_set_tv_pclk(hdmi->dss->dispc, adjusted_mode->clock * 1000); + + mutex_unlock(&hdmi->lock); +} + +static void hdmi5_bridge_enable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) +{ + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + struct drm_atomic_state *state = bridge_state->base.state; + struct drm_connector_state *conn_state; + struct drm_connector *connector; + struct drm_crtc_state *crtc_state; + unsigned long flags; + int ret; + + /* + * None of these should fail, as the bridge can't be enabled without a + * valid CRTC to connector path with fully populated new states. + */ + connector = drm_atomic_get_new_connector_for_encoder(state, + bridge->encoder); + if (WARN_ON(!connector)) + return; + conn_state = drm_atomic_get_new_connector_state(state, connector); + if (WARN_ON(!conn_state)) + return; + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + if (WARN_ON(!crtc_state)) + return; + + hdmi->cfg.hdmi_dvi_mode = connector->display_info.is_hdmi + ? HDMI_HDMI : HDMI_DVI; + + if (connector->display_info.is_hdmi) { + const struct drm_display_mode *mode; + struct hdmi_avi_infoframe avi; + + mode = &crtc_state->adjusted_mode; + ret = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector, + mode); + if (ret == 0) + hdmi->cfg.infoframe = avi; + } mutex_lock(&hdmi->lock); - r = hdmi_power_on_full(hdmi); - if (r) { + ret = hdmi_power_on_full(hdmi); + if (ret) { DSSERR("failed to power on device\n"); goto done; } if (hdmi->audio_configured) { - r = hdmi5_audio_config(&hdmi->core, &hdmi->wp, - &hdmi->audio_config, - hdmi->cfg.vm.pixelclock); - if (r) { - DSSERR("Error restoring audio configuration: %d", r); + ret = hdmi5_audio_config(&hdmi->core, &hdmi->wp, + &hdmi->audio_config, + hdmi->cfg.vm.pixelclock); + if (ret) { + DSSERR("Error restoring audio configuration: %d", ret); hdmi->audio_abort_cb(&hdmi->pdev->dev); hdmi->audio_configured = false; } @@ -346,13 +407,12 @@ done: mutex_unlock(&hdmi->lock); } -static void hdmi_display_disable(struct omap_dss_device *dssdev) +static void hdmi5_bridge_disable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); unsigned long flags; - DSSDBG("Enter hdmi_display_disable\n"); - mutex_lock(&hdmi->lock); spin_lock_irqsave(&hdmi->audio_playing_lock, flags); @@ -365,109 +425,74 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev) mutex_unlock(&hdmi->lock); } -static int hdmi_core_enable(struct omap_hdmi *hdmi) +static struct edid *hdmi5_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) { - int r = 0; - - DSSDBG("ENTER omapdss_hdmi_core_enable\n"); + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + struct edid *edid; + bool need_enable; + int idlemode; + int r; - mutex_lock(&hdmi->lock); + need_enable = hdmi->core_enabled == false; - r = hdmi_power_on_core(hdmi); - if (r) { - DSSERR("failed to power on device\n"); - goto err0; + if (need_enable) { + r = hdmi_core_enable(hdmi); + if (r) + return NULL; } - mutex_unlock(&hdmi->lock); - return 0; - -err0: - mutex_unlock(&hdmi->lock); - return r; -} - -static void hdmi_core_disable(struct omap_hdmi *hdmi) -{ - DSSDBG("Enter omapdss_hdmi_core_disable\n"); - mutex_lock(&hdmi->lock); + r = hdmi_runtime_get(hdmi); + BUG_ON(r); - hdmi_power_off_core(hdmi); - - mutex_unlock(&hdmi->lock); -} - -static int hdmi_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return omapdss_device_connect(dst->dss, dst, dst->next); -} + idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); + /* No-idle mode */ + REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); -static void hdmi_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - omapdss_device_disconnect(dst, dst->next); -} + hdmi5_core_ddc_init(&hdmi->core); -static int hdmi_read_edid(struct omap_dss_device *dssdev, - u8 *edid, int len) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - bool need_enable; - int r; + edid = drm_do_get_edid(connector, hdmi5_core_ddc_read, &hdmi->core); - need_enable = hdmi->core_enabled == false; + hdmi5_core_ddc_uninit(&hdmi->core); - if (need_enable) { - r = hdmi_core_enable(hdmi); - if (r) - return r; - } + REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); - r = read_edid(hdmi, edid, len); + hdmi_runtime_put(hdmi); + mutex_unlock(&hdmi->lock); if (need_enable) hdmi_core_disable(hdmi); - return r; + return (struct edid *)edid; } -static int hdmi_set_infoframe(struct omap_dss_device *dssdev, - const struct hdmi_avi_infoframe *avi) +static const struct drm_bridge_funcs hdmi5_bridge_funcs = { + .attach = hdmi5_bridge_attach, + .mode_set = hdmi5_bridge_mode_set, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_enable = hdmi5_bridge_enable, + .atomic_disable = hdmi5_bridge_disable, + .get_edid = hdmi5_bridge_get_edid, +}; + +static void hdmi5_bridge_init(struct omap_hdmi *hdmi) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + hdmi->bridge.funcs = &hdmi5_bridge_funcs; + hdmi->bridge.of_node = hdmi->pdev->dev.of_node; + hdmi->bridge.ops = DRM_BRIDGE_OP_EDID; + hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; - hdmi->cfg.infoframe = *avi; - return 0; + drm_bridge_add(&hdmi->bridge); } -static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, - bool hdmi_mode) +static void hdmi5_bridge_cleanup(struct omap_hdmi *hdmi) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; - return 0; + drm_bridge_remove(&hdmi->bridge); } -static const struct omap_dss_device_ops hdmi_ops = { - .connect = hdmi_connect, - .disconnect = hdmi_disconnect, - - .enable = hdmi_display_enable, - .disable = hdmi_display_disable, - - .set_timings = hdmi_display_set_timings, - - .read_edid = hdmi_read_edid, - - .hdmi = { - .set_infoframe = hdmi_set_infoframe, - .set_hdmi_mode = hdmi_set_hdmi_mode, - }, -}; - /* ----------------------------------------------------------------------------- * Audio Callbacks */ @@ -650,19 +675,21 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi) struct omap_dss_device *out = &hdmi->output; int r; + hdmi5_bridge_init(hdmi); + out->dev = &hdmi->pdev->dev; out->id = OMAP_DSS_OUTPUT_HDMI; out->type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; - out->ops = &hdmi_ops; out->owner = THIS_MODULE; - out->of_ports = BIT(0); - out->ops_flags = OMAP_DSS_DEVICE_OP_EDID; + out->of_port = 0; - r = omapdss_device_init_output(out); - if (r < 0) + r = omapdss_device_init_output(out, &hdmi->bridge); + if (r < 0) { + hdmi5_bridge_cleanup(hdmi); return r; + } omapdss_device_register(out); @@ -675,6 +702,8 @@ static void hdmi5_uninit_output(struct omap_hdmi *hdmi) omapdss_device_unregister(out); omapdss_device_cleanup_output(out); + + hdmi5_bridge_cleanup(hdmi); } static int hdmi5_probe_of(struct omap_hdmi *hdmi) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c index ff4d35c8771f..7dd587035160 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c @@ -23,7 +23,7 @@ #include "hdmi5_core.h" -static void hdmi_core_ddc_init(struct hdmi_core_data *core) +void hdmi5_core_ddc_init(struct hdmi_core_data *core) { void __iomem *base = core->base; const unsigned long long iclk = 266000000; /* DSS L3 ICLK */ @@ -102,7 +102,7 @@ static void hdmi_core_ddc_init(struct hdmi_core_data *core) REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x0, 2, 2); } -static void hdmi_core_ddc_uninit(struct hdmi_core_data *core) +void hdmi5_core_ddc_uninit(struct hdmi_core_data *core) { void __iomem *base = core->base; @@ -112,14 +112,14 @@ static void hdmi_core_ddc_uninit(struct hdmi_core_data *core) REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 2, 2); } -static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext) +int hdmi5_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len) { + struct hdmi_core_data *core = data; void __iomem *base = core->base; u8 cur_addr; - char checksum = 0; const int retries = 1000; - u8 seg_ptr = ext / 2; - u8 edidbase = ((ext % 2) * 0x80); + u8 seg_ptr = block / 2; + u8 edidbase = ((block % 2) * EDID_LENGTH); REG_FLD_MOD(base, HDMI_CORE_I2CM_SEGPTR, seg_ptr, 7, 0); @@ -127,7 +127,7 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext) * TODO: We use polling here, although we probably should use proper * interrupts. */ - for (cur_addr = 0; cur_addr < 128; ++cur_addr) { + for (cur_addr = 0; cur_addr < len; ++cur_addr) { int i; /* clear ERROR and DONE */ @@ -164,45 +164,13 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext) return -EIO; } - pedid[cur_addr] = REG_GET(base, HDMI_CORE_I2CM_DATAI, 7, 0); - checksum += pedid[cur_addr]; + buf[cur_addr] = REG_GET(base, HDMI_CORE_I2CM_DATAI, 7, 0); } return 0; } -int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len) -{ - int r, n, i; - int max_ext_blocks = (len / 128) - 1; - - if (len < 128) - return -EINVAL; - - hdmi_core_ddc_init(core); - - r = hdmi_core_ddc_edid(core, edid, 0); - if (r) - goto out; - - n = edid[0x7e]; - - if (n > max_ext_blocks) - n = max_ext_blocks; - - for (i = 1; i <= n; i++) { - r = hdmi_core_ddc_edid(core, edid + i * EDID_LENGTH, i); - if (r) - goto out; - } - -out: - hdmi_core_ddc_uninit(core); - - return r ? r : len; -} - void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s) { diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h index f10b8a283011..65eadefdb3f9 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h @@ -281,7 +281,10 @@ struct csc_table { u16 c1, c2, c3, c4; }; -int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len); +void hdmi5_core_ddc_init(struct hdmi_core_data *core); +int hdmi5_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len); +void hdmi5_core_ddc_uninit(struct hdmi_core_data *core); + void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s); int hdmi5_core_handle_irqs(struct hdmi_core_data *core); void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c index 31502857f013..00372f4ce711 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c +++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c @@ -174,12 +174,7 @@ static const struct of_device_id omapdss_of_match[] __initconst = { }; static const struct of_device_id omapdss_of_fixups_whitelist[] __initconst = { - { .compatible = "composite-video-connector" }, - { .compatible = "hdmi-connector" }, { .compatible = "panel-dsi-cm" }, - { .compatible = "svideo-connector" }, - { .compatible = "ti,opa362" }, - { .compatible = "ti,tpd12s015" }, {}, }; @@ -192,7 +187,7 @@ static int __init omapdss_boot_init(void) dss = of_find_matching_node(NULL, omapdss_of_match); if (dss == NULL || !of_device_is_available(dss)) - return 0; + goto put_node; omapdss_walk_device(dss, true); @@ -217,6 +212,8 @@ static int __init omapdss_boot_init(void) kfree(n); } +put_node: + of_node_put(dss); return 0; } diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 79f6b195c7cf..ab19d4af8de7 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -285,13 +285,6 @@ struct omap_dss_writeback_info { u8 pre_mult_alpha; }; -struct omapdss_hdmi_ops { - void (*lost_hotplug)(struct omap_dss_device *dssdev); - int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode); - int (*set_infoframe)(struct omap_dss_device *dssdev, - const struct hdmi_avi_infoframe *avi); -}; - struct omapdss_dsi_ops { void (*disable)(struct omap_dss_device *dssdev, bool disconnect_lanes, bool enter_ulps); @@ -349,46 +342,23 @@ struct omap_dss_device_ops { void (*disconnect)(struct omap_dss_device *dssdev, struct omap_dss_device *dst); - void (*pre_enable)(struct omap_dss_device *dssdev); void (*enable)(struct omap_dss_device *dssdev); void (*disable)(struct omap_dss_device *dssdev); - void (*post_disable)(struct omap_dss_device *dssdev); int (*check_timings)(struct omap_dss_device *dssdev, struct drm_display_mode *mode); - void (*set_timings)(struct omap_dss_device *dssdev, - const struct drm_display_mode *mode); - - bool (*detect)(struct omap_dss_device *dssdev); - - void (*register_hpd_cb)(struct omap_dss_device *dssdev, - void (*cb)(void *cb_data, - enum drm_connector_status status), - void *cb_data); - void (*unregister_hpd_cb)(struct omap_dss_device *dssdev); - - int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len); int (*get_modes)(struct omap_dss_device *dssdev, struct drm_connector *connector); - union { - const struct omapdss_hdmi_ops hdmi; - const struct omapdss_dsi_ops dsi; - }; + const struct omapdss_dsi_ops dsi; }; /** * enum omap_dss_device_ops_flag - Indicates which device ops are supported - * @OMAP_DSS_DEVICE_OP_DETECT: The device supports output connection detection - * @OMAP_DSS_DEVICE_OP_HPD: The device supports all hot-plug-related operations - * @OMAP_DSS_DEVICE_OP_EDID: The device supports reading EDID * @OMAP_DSS_DEVICE_OP_MODES: The device supports reading modes */ enum omap_dss_device_ops_flag { - OMAP_DSS_DEVICE_OP_DETECT = BIT(0), - OMAP_DSS_DEVICE_OP_HPD = BIT(1), - OMAP_DSS_DEVICE_OP_EDID = BIT(2), OMAP_DSS_DEVICE_OP_MODES = BIT(3), }; @@ -400,6 +370,7 @@ struct omap_dss_device { struct dss_device *dss; struct omap_dss_device *next; struct drm_bridge *bridge; + struct drm_bridge *next_bridge; struct drm_panel *panel; struct list_head list; @@ -436,8 +407,8 @@ struct omap_dss_device { /* output instance */ enum omap_dss_output_id id; - /* bitmask of port numbers in DT */ - unsigned int of_ports; + /* port number in DT */ + unsigned int of_port; }; struct omap_dss_driver { @@ -461,7 +432,6 @@ static inline bool omapdss_is_initialized(void) } void omapdss_display_init(struct omap_dss_device *dssdev); -struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output); int omapdss_display_get_modes(struct drm_connector *connector, const struct videomode *vm); @@ -475,10 +445,8 @@ int omapdss_device_connect(struct dss_device *dss, struct omap_dss_device *dst); void omapdss_device_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst); -void omapdss_device_pre_enable(struct omap_dss_device *dssdev); void omapdss_device_enable(struct omap_dss_device *dssdev); void omapdss_device_disable(struct omap_dss_device *dssdev); -void omapdss_device_post_disable(struct omap_dss_device *dssdev); int omap_dss_get_num_overlay_managers(void); @@ -487,7 +455,8 @@ int omap_dss_get_num_overlays(void); #define for_each_dss_output(d) \ while ((d = omapdss_device_next_output(d)) != NULL) struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from); -int omapdss_device_init_output(struct omap_dss_device *out); +int omapdss_device_init_output(struct omap_dss_device *out, + struct drm_bridge *local_bridge); void omapdss_device_cleanup_output(struct omap_dss_device *out); typedef void (*omap_dispc_isr_t) (void *arg, u32 mask); @@ -502,9 +471,6 @@ static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev) return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE; } -struct omap_dss_device * -omapdss_of_find_connected_device(struct device_node *node, unsigned int port); - enum dss_writeback_channel { DSS_WB_LCD1_MGR = 0, DSS_WB_LCD2_MGR = 1, diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index 0693d34fca1b..ce21c798cca6 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -4,7 +4,6 @@ * Author: Archit Taneja <archit@ti.com> */ -#include <linux/bitops.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -18,12 +17,14 @@ #include "dss.h" #include "omapdss.h" -int omapdss_device_init_output(struct omap_dss_device *out) +int omapdss_device_init_output(struct omap_dss_device *out, + struct drm_bridge *local_bridge) { struct device_node *remote_node; + int ret; remote_node = of_graph_get_remote_node(out->dev->of_node, - ffs(out->of_ports) - 1, 0); + out->of_port, 0); if (!remote_node) { dev_dbg(out->dev, "failed to find video sink\n"); return 0; @@ -39,17 +40,55 @@ int omapdss_device_init_output(struct omap_dss_device *out) if (out->next && out->type != out->next->type) { dev_err(out->dev, "output type and display type don't match\n"); - omapdss_device_put(out->next); - out->next = NULL; - return -EINVAL; + ret = -EINVAL; + goto error; } - return out->next || out->bridge || out->panel ? 0 : -EPROBE_DEFER; + if (out->panel) { + struct drm_bridge *bridge; + + bridge = drm_panel_bridge_add(out->panel); + if (IS_ERR(bridge)) { + dev_err(out->dev, + "unable to create panel bridge (%ld)\n", + PTR_ERR(bridge)); + ret = PTR_ERR(bridge); + goto error; + } + + out->bridge = bridge; + } + + if (local_bridge) { + if (!out->bridge) { + ret = -EPROBE_DEFER; + goto error; + } + + out->next_bridge = out->bridge; + out->bridge = local_bridge; + } + + if (!out->next && !out->bridge) { + ret = -EPROBE_DEFER; + goto error; + } + + return 0; + +error: + omapdss_device_cleanup_output(out); + out->next = NULL; + return ret; } EXPORT_SYMBOL(omapdss_device_init_output); void omapdss_device_cleanup_output(struct omap_dss_device *out) { + if (out->bridge && out->panel) + drm_panel_bridge_remove(out->next_bridge ? + out->next_bridge : out->bridge); + if (out->next) omapdss_device_put(out->next); } diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index 3b447c01fa2a..417a8740ad0a 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -6,17 +6,19 @@ #define DSS_SUBSYS_NAME "SDI" -#include <linux/kernel.h> #include <linux/delay.h> #include <linux/err.h> -#include <linux/regulator/consumer.h> #include <linux/export.h> +#include <linux/kernel.h> +#include <linux/of.h> #include <linux/platform_device.h> +#include <linux/regulator/consumer.h> #include <linux/string.h> -#include <linux/of.h> -#include "omapdss.h" +#include <drm/drm_bridge.h> + #include "dss.h" +#include "omapdss.h" struct sdi_device { struct platform_device *pdev; @@ -30,9 +32,11 @@ struct sdi_device { int datapairs; struct omap_dss_device output; + struct drm_bridge bridge; }; -#define dssdev_to_sdi(dssdev) container_of(dssdev, struct sdi_device, output) +#define drm_bridge_to_sdi(bridge) \ + container_of(bridge, struct sdi_device, bridge) struct sdi_clk_calc_ctx { struct sdi_device *sdi; @@ -118,9 +122,82 @@ static void sdi_config_lcd_manager(struct sdi_device *sdi) dss_mgr_set_lcd_config(&sdi->output, &sdi->mgr_config); } -static void sdi_display_enable(struct omap_dss_device *dssdev) +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + +static int sdi_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) + return -EINVAL; + + return drm_bridge_attach(bridge->encoder, sdi->output.next_bridge, + bridge, flags); +} + +static enum drm_mode_status +sdi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) +{ + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); + unsigned long pixelclock = mode->clock * 1000; + struct dispc_clock_info dispc_cinfo; + unsigned long fck; + int ret; + + if (pixelclock == 0) + return MODE_NOCLOCK; + + ret = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo); + if (ret < 0) + return MODE_CLOCK_RANGE; + + return MODE_OK; +} + +static bool sdi_bridge_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); + unsigned long pixelclock = mode->clock * 1000; + struct dispc_clock_info dispc_cinfo; + unsigned long fck; + unsigned long pck; + int ret; + + ret = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo); + if (ret < 0) + return false; + + pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div; + + if (pck != pixelclock) + dev_dbg(&sdi->pdev->dev, + "pixel clock adjusted from %lu Hz to %lu Hz\n", + pixelclock, pck); + + adjusted_mode->clock = pck / 1000; + + return true; +} + +static void sdi_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); + + sdi->pixelclock = adjusted_mode->clock * 1000; +} + +static void sdi_bridge_enable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) { - struct sdi_device *sdi = dssdev_to_sdi(dssdev); + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); struct dispc_clock_info dispc_cinfo; unsigned long fck; int r; @@ -181,9 +258,10 @@ err_get_dispc: regulator_disable(sdi->vdds_sdi_reg); } -static void sdi_display_disable(struct omap_dss_device *dssdev) +static void sdi_bridge_disable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) { - struct sdi_device *sdi = dssdev_to_sdi(dssdev); + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); dss_mgr_disable(&sdi->output); @@ -194,86 +272,56 @@ static void sdi_display_disable(struct omap_dss_device *dssdev) regulator_disable(sdi->vdds_sdi_reg); } -static void sdi_set_timings(struct omap_dss_device *dssdev, - const struct drm_display_mode *mode) -{ - struct sdi_device *sdi = dssdev_to_sdi(dssdev); - - sdi->pixelclock = mode->clock * 1000; -} +static const struct drm_bridge_funcs sdi_bridge_funcs = { + .attach = sdi_bridge_attach, + .mode_valid = sdi_bridge_mode_valid, + .mode_fixup = sdi_bridge_mode_fixup, + .mode_set = sdi_bridge_mode_set, + .atomic_enable = sdi_bridge_enable, + .atomic_disable = sdi_bridge_disable, +}; -static int sdi_check_timings(struct omap_dss_device *dssdev, - struct drm_display_mode *mode) +static void sdi_bridge_init(struct sdi_device *sdi) { - struct sdi_device *sdi = dssdev_to_sdi(dssdev); - struct dispc_clock_info dispc_cinfo; - unsigned long pixelclock = mode->clock * 1000; - unsigned long fck; - unsigned long pck; - int r; + sdi->bridge.funcs = &sdi_bridge_funcs; + sdi->bridge.of_node = sdi->pdev->dev.of_node; + sdi->bridge.type = DRM_MODE_CONNECTOR_LVDS; - if (pixelclock == 0) - return -EINVAL; - - r = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo); - if (r) - return r; - - pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div; - - if (pck != pixelclock) { - DSSWARN("Pixel clock adjusted from %lu Hz to %lu Hz\n", - pixelclock, pck); - - mode->clock = pck / 1000; - } - - return 0; + drm_bridge_add(&sdi->bridge); } -static int sdi_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) +static void sdi_bridge_cleanup(struct sdi_device *sdi) { - return omapdss_device_connect(dst->dss, dst, dst->next); + drm_bridge_remove(&sdi->bridge); } -static void sdi_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - omapdss_device_disconnect(dst, dst->next); -} - -static const struct omap_dss_device_ops sdi_ops = { - .connect = sdi_connect, - .disconnect = sdi_disconnect, - - .enable = sdi_display_enable, - .disable = sdi_display_disable, - - .check_timings = sdi_check_timings, - .set_timings = sdi_set_timings, -}; +/* ----------------------------------------------------------------------------- + * Initialisation and Cleanup + */ static int sdi_init_output(struct sdi_device *sdi) { struct omap_dss_device *out = &sdi->output; int r; + sdi_bridge_init(sdi); + out->dev = &sdi->pdev->dev; out->id = OMAP_DSS_OUTPUT_SDI; out->type = OMAP_DISPLAY_TYPE_SDI; out->name = "sdi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_LCD; /* We have SDI only on OMAP3, where it's on port 1 */ - out->of_ports = BIT(1); - out->ops = &sdi_ops; + out->of_port = 1; out->owner = THIS_MODULE; out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE /* 15.5.9.1.2 */ | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE; - r = omapdss_device_init_output(out); - if (r < 0) + r = omapdss_device_init_output(out, &sdi->bridge); + if (r < 0) { + sdi_bridge_cleanup(sdi); return r; + } omapdss_device_register(out); @@ -284,6 +332,8 @@ static void sdi_uninit_output(struct sdi_device *sdi) { omapdss_device_unregister(&sdi->output); omapdss_device_cleanup_output(&sdi->output); + + sdi_bridge_cleanup(sdi); } int sdi_init_port(struct dss_device *dss, struct platform_device *pdev, diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 596a297d5813..766553bb2f87 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -13,7 +13,6 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/io.h> -#include <linux/mutex.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/string.h> @@ -26,6 +25,8 @@ #include <linux/component.h> #include <linux/sys_soc.h> +#include <drm/drm_bridge.h> + #include "omapdss.h" #include "dss.h" @@ -289,7 +290,6 @@ static const struct drm_display_mode omap_dss_ntsc_mode = { struct venc_device { struct platform_device *pdev; void __iomem *base; - struct mutex venc_lock; struct regulator *vdda_dac_reg; struct dss_device *dss; @@ -303,9 +303,10 @@ struct venc_device { bool requires_tv_dac_clk; struct omap_dss_device output; + struct drm_bridge bridge; }; -#define dssdev_to_venc(dssdev) container_of(dssdev, struct venc_device, output) +#define drm_bridge_to_venc(b) container_of(b, struct venc_device, bridge) static inline void venc_write_reg(struct venc_device *venc, int idx, u32 val) { @@ -477,56 +478,6 @@ static void venc_power_off(struct venc_device *venc) venc_runtime_put(venc); } -static void venc_display_enable(struct omap_dss_device *dssdev) -{ - struct venc_device *venc = dssdev_to_venc(dssdev); - - DSSDBG("venc_display_enable\n"); - - mutex_lock(&venc->venc_lock); - - venc_power_on(venc); - - mutex_unlock(&venc->venc_lock); -} - -static void venc_display_disable(struct omap_dss_device *dssdev) -{ - struct venc_device *venc = dssdev_to_venc(dssdev); - - DSSDBG("venc_display_disable\n"); - - mutex_lock(&venc->venc_lock); - - venc_power_off(venc); - - mutex_unlock(&venc->venc_lock); -} - -static int venc_get_modes(struct omap_dss_device *dssdev, - struct drm_connector *connector) -{ - static const struct drm_display_mode *modes[] = { - &omap_dss_pal_mode, - &omap_dss_ntsc_mode, - }; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(modes); ++i) { - struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, modes[i]); - if (!mode) - return i; - - mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; - drm_mode_set_name(mode); - drm_mode_probed_add(connector, mode); - } - - return ARRAY_SIZE(modes); -} - static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mode) { if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) @@ -545,57 +496,6 @@ static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mod return VENC_MODE_UNKNOWN; } -static void venc_set_timings(struct omap_dss_device *dssdev, - const struct drm_display_mode *mode) -{ - struct venc_device *venc = dssdev_to_venc(dssdev); - enum venc_videomode venc_mode = venc_get_videomode(mode); - - DSSDBG("venc_set_timings\n"); - - mutex_lock(&venc->venc_lock); - - switch (venc_mode) { - default: - WARN_ON_ONCE(1); - /* Fall-through */ - case VENC_MODE_PAL: - venc->config = &venc_config_pal_trm; - break; - - case VENC_MODE_NTSC: - venc->config = &venc_config_ntsc_trm; - break; - } - - dispc_set_tv_pclk(venc->dss->dispc, 13500000); - - mutex_unlock(&venc->venc_lock); -} - -static int venc_check_timings(struct omap_dss_device *dssdev, - struct drm_display_mode *mode) -{ - DSSDBG("venc_check_timings\n"); - - switch (venc_get_videomode(mode)) { - case VENC_MODE_PAL: - drm_mode_copy(mode, &omap_dss_pal_mode); - break; - - case VENC_MODE_NTSC: - drm_mode_copy(mode, &omap_dss_ntsc_mode); - break; - - default: - return -EINVAL; - } - - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - drm_mode_set_name(mode); - return 0; -} - static int venc_dump_regs(struct seq_file *s, void *p) { struct venc_device *venc = s->private; @@ -673,31 +573,149 @@ static int venc_get_clocks(struct venc_device *venc) return 0; } -static int venc_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + +static int venc_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct venc_device *venc = drm_bridge_to_venc(bridge); + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) + return -EINVAL; + + return drm_bridge_attach(bridge->encoder, venc->output.next_bridge, + bridge, flags); +} + +static enum drm_mode_status +venc_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) +{ + switch (venc_get_videomode(mode)) { + case VENC_MODE_PAL: + case VENC_MODE_NTSC: + return MODE_OK; + + default: + return MODE_BAD; + } +} + +static bool venc_bridge_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + const struct drm_display_mode *venc_mode; + + switch (venc_get_videomode(adjusted_mode)) { + case VENC_MODE_PAL: + venc_mode = &omap_dss_pal_mode; + break; + + case VENC_MODE_NTSC: + venc_mode = &omap_dss_ntsc_mode; + break; + + default: + return false; + } + + drm_mode_copy(adjusted_mode, venc_mode); + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + drm_mode_set_name(adjusted_mode); + + return true; +} + +static void venc_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct venc_device *venc = drm_bridge_to_venc(bridge); + enum venc_videomode venc_mode = venc_get_videomode(adjusted_mode); + + switch (venc_mode) { + default: + WARN_ON_ONCE(1); + /* Fall-through */ + case VENC_MODE_PAL: + venc->config = &venc_config_pal_trm; + break; + + case VENC_MODE_NTSC: + venc->config = &venc_config_ntsc_trm; + break; + } + + dispc_set_tv_pclk(venc->dss->dispc, 13500000); +} + +static void venc_bridge_enable(struct drm_bridge *bridge) { - return omapdss_device_connect(dst->dss, dst, dst->next); + struct venc_device *venc = drm_bridge_to_venc(bridge); + + venc_power_on(venc); } -static void venc_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) +static void venc_bridge_disable(struct drm_bridge *bridge) { - omapdss_device_disconnect(dst, dst->next); + struct venc_device *venc = drm_bridge_to_venc(bridge); + + venc_power_off(venc); } -static const struct omap_dss_device_ops venc_ops = { - .connect = venc_connect, - .disconnect = venc_disconnect, +static int venc_bridge_get_modes(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + static const struct drm_display_mode *modes[] = { + &omap_dss_pal_mode, + &omap_dss_ntsc_mode, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(modes); ++i) { + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, modes[i]); + if (!mode) + return i; - .enable = venc_display_enable, - .disable = venc_display_disable, + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + } - .check_timings = venc_check_timings, - .set_timings = venc_set_timings, + return ARRAY_SIZE(modes); +} - .get_modes = venc_get_modes, +static const struct drm_bridge_funcs venc_bridge_funcs = { + .attach = venc_bridge_attach, + .mode_valid = venc_bridge_mode_valid, + .mode_fixup = venc_bridge_mode_fixup, + .mode_set = venc_bridge_mode_set, + .enable = venc_bridge_enable, + .disable = venc_bridge_disable, + .get_modes = venc_bridge_get_modes, }; +static void venc_bridge_init(struct venc_device *venc) +{ + venc->bridge.funcs = &venc_bridge_funcs; + venc->bridge.of_node = venc->pdev->dev.of_node; + venc->bridge.ops = DRM_BRIDGE_OP_MODES; + venc->bridge.type = DRM_MODE_CONNECTOR_SVIDEO; + venc->bridge.interlace_allowed = true; + + drm_bridge_add(&venc->bridge); +} + +static void venc_bridge_cleanup(struct venc_device *venc) +{ + drm_bridge_remove(&venc->bridge); +} + /* ----------------------------------------------------------------------------- * Component Bind & Unbind */ @@ -747,19 +765,22 @@ static int venc_init_output(struct venc_device *venc) struct omap_dss_device *out = &venc->output; int r; + venc_bridge_init(venc); + out->dev = &venc->pdev->dev; out->id = OMAP_DSS_OUTPUT_VENC; out->type = OMAP_DISPLAY_TYPE_VENC; out->name = "venc.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; - out->ops = &venc_ops; out->owner = THIS_MODULE; - out->of_ports = BIT(0); + out->of_port = 0; out->ops_flags = OMAP_DSS_DEVICE_OP_MODES; - r = omapdss_device_init_output(out); - if (r < 0) + r = omapdss_device_init_output(out, &venc->bridge); + if (r < 0) { + venc_bridge_cleanup(venc); return r; + } omapdss_device_register(out); @@ -770,6 +791,8 @@ static void venc_uninit_output(struct venc_device *venc) { omapdss_device_unregister(&venc->output); omapdss_device_cleanup_output(&venc->output); + + venc_bridge_cleanup(venc); } static int venc_probe_of(struct venc_device *venc) @@ -839,8 +862,6 @@ static int venc_probe(struct platform_device *pdev) if (soc_device_match(venc_soc_devices)) venc->requires_tv_dac_clk = true; - mutex_init(&venc->venc_lock); - venc->config = &venc_config_pal_trm; venc_mem = platform_get_resource(venc->pdev, IORESOURCE_MEM, 0); diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index 94cded387174..528764566b17 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -6,7 +6,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> -#include <drm/drm_panel.h> #include <drm/drm_probe_helper.h> #include "omap_drv.h" @@ -20,124 +19,12 @@ struct omap_connector { struct drm_connector base; struct omap_dss_device *output; - struct omap_dss_device *hpd; - bool hdmi_mode; }; -static void omap_connector_hpd_notify(struct drm_connector *connector, - enum drm_connector_status status) -{ - struct omap_connector *omap_connector = to_omap_connector(connector); - struct omap_dss_device *dssdev; - - if (status != connector_status_disconnected) - return; - - /* - * Notify all devics in the pipeline of disconnection. This is required - * to let the HDMI encoders reset their internal state related to - * connection status, such as the CEC address. - */ - for (dssdev = omap_connector->output; dssdev; dssdev = dssdev->next) { - if (dssdev->ops && dssdev->ops->hdmi.lost_hotplug) - dssdev->ops->hdmi.lost_hotplug(dssdev); - } -} - -static void omap_connector_hpd_cb(void *cb_data, - enum drm_connector_status status) -{ - struct omap_connector *omap_connector = cb_data; - struct drm_connector *connector = &omap_connector->base; - struct drm_device *dev = connector->dev; - enum drm_connector_status old_status; - - mutex_lock(&dev->mode_config.mutex); - old_status = connector->status; - connector->status = status; - mutex_unlock(&dev->mode_config.mutex); - - if (old_status == status) - return; - - omap_connector_hpd_notify(connector, status); - - drm_kms_helper_hotplug_event(dev); -} - -void omap_connector_enable_hpd(struct drm_connector *connector) -{ - struct omap_connector *omap_connector = to_omap_connector(connector); - struct omap_dss_device *hpd = omap_connector->hpd; - - if (hpd) - hpd->ops->register_hpd_cb(hpd, omap_connector_hpd_cb, - omap_connector); -} - -void omap_connector_disable_hpd(struct drm_connector *connector) -{ - struct omap_connector *omap_connector = to_omap_connector(connector); - struct omap_dss_device *hpd = omap_connector->hpd; - - if (hpd) - hpd->ops->unregister_hpd_cb(hpd); -} - -bool omap_connector_get_hdmi_mode(struct drm_connector *connector) -{ - struct omap_connector *omap_connector = to_omap_connector(connector); - - return omap_connector->hdmi_mode; -} - -static struct omap_dss_device * -omap_connector_find_device(struct drm_connector *connector, - enum omap_dss_device_ops_flag op) -{ - struct omap_connector *omap_connector = to_omap_connector(connector); - struct omap_dss_device *dssdev = NULL; - struct omap_dss_device *d; - - for (d = omap_connector->output; d; d = d->next) { - if (d->ops_flags & op) - dssdev = d; - } - - return dssdev; -} - static enum drm_connector_status omap_connector_detect( struct drm_connector *connector, bool force) { - struct omap_dss_device *dssdev; - enum drm_connector_status status; - - dssdev = omap_connector_find_device(connector, - OMAP_DSS_DEVICE_OP_DETECT); - - if (dssdev) { - status = dssdev->ops->detect(dssdev) - ? connector_status_connected - : connector_status_disconnected; - - omap_connector_hpd_notify(connector, status); - } else { - switch (connector->connector_type) { - case DRM_MODE_CONNECTOR_DPI: - case DRM_MODE_CONNECTOR_LVDS: - case DRM_MODE_CONNECTOR_DSI: - status = connector_status_connected; - break; - default: - status = connector_status_unknown; - break; - } - } - - VERB("%s: %d (force=%d)", connector->name, status, force); - - return status; + return connector_status_connected; } static void omap_connector_destroy(struct drm_connector *connector) @@ -146,14 +33,6 @@ static void omap_connector_destroy(struct drm_connector *connector) DBG("%s", connector->name); - if (omap_connector->hpd) { - struct omap_dss_device *hpd = omap_connector->hpd; - - hpd->ops->unregister_hpd_cb(hpd); - omapdss_device_put(hpd); - omap_connector->hpd = NULL; - } - drm_connector_unregister(connector); drm_connector_cleanup(connector); @@ -162,81 +41,27 @@ static void omap_connector_destroy(struct drm_connector *connector) kfree(omap_connector); } -#define MAX_EDID 512 - -static int omap_connector_get_modes_edid(struct drm_connector *connector, - struct omap_dss_device *dssdev) -{ - struct omap_connector *omap_connector = to_omap_connector(connector); - enum drm_connector_status status; - void *edid; - int n; - - status = omap_connector_detect(connector, false); - if (status != connector_status_connected) - goto no_edid; - - edid = kzalloc(MAX_EDID, GFP_KERNEL); - if (!edid) - goto no_edid; - - if (dssdev->ops->read_edid(dssdev, edid, MAX_EDID) <= 0 || - !drm_edid_is_valid(edid)) { - kfree(edid); - goto no_edid; - } - - drm_connector_update_edid_property(connector, edid); - n = drm_add_edid_modes(connector, edid); - - omap_connector->hdmi_mode = drm_detect_hdmi_monitor(edid); - - kfree(edid); - return n; - -no_edid: - drm_connector_update_edid_property(connector, NULL); - return 0; -} - static int omap_connector_get_modes(struct drm_connector *connector) { struct omap_connector *omap_connector = to_omap_connector(connector); - struct omap_dss_device *dssdev; + struct omap_dss_device *dssdev = NULL; + struct omap_dss_device *d; DBG("%s", connector->name); /* - * If display exposes EDID, then we parse that in the normal way to - * build table of supported modes. + * If the display pipeline reports modes (e.g. with a fixed resolution + * panel or an analog TV output), query it. */ - dssdev = omap_connector_find_device(connector, - OMAP_DSS_DEVICE_OP_EDID); - if (dssdev) - return omap_connector_get_modes_edid(connector, dssdev); + for (d = omap_connector->output; d; d = d->next) { + if (d->ops_flags & OMAP_DSS_DEVICE_OP_MODES) + dssdev = d; + } - /* - * Otherwise if the display pipeline reports modes (e.g. with a fixed - * resolution panel or an analog TV output), query it. - */ - dssdev = omap_connector_find_device(connector, - OMAP_DSS_DEVICE_OP_MODES); if (dssdev) return dssdev->ops->get_modes(dssdev, connector); - /* - * Otherwise if the display pipeline uses a drm_panel, we delegate the - * operation to the panel API. - */ - if (omap_connector->output->panel) - return drm_panel_get_modes(omap_connector->output->panel, - connector); - - /* - * We can't retrieve modes, which can happen for instance for a DVI or - * VGA output with the DDC bus unconnected. The KMS core will add the - * default modes. - */ + /* We can't retrieve modes. The KMS core will add the default modes. */ return 0; } @@ -249,7 +74,7 @@ enum drm_mode_status omap_connector_mode_fixup(struct omap_dss_device *dssdev, drm_mode_copy(adjusted_mode, mode); for (; dssdev; dssdev = dssdev->next) { - if (!dssdev->ops->check_timings) + if (!dssdev->ops || !dssdev->ops->check_timings) continue; ret = dssdev->ops->check_timings(dssdev, adjusted_mode); @@ -298,35 +123,6 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = { .mode_valid = omap_connector_mode_valid, }; -static int omap_connector_get_type(struct omap_dss_device *output) -{ - struct omap_dss_device *display; - enum omap_display_type type; - - display = omapdss_display_get(output); - type = display->type; - omapdss_device_put(display); - - switch (type) { - case OMAP_DISPLAY_TYPE_HDMI: - return DRM_MODE_CONNECTOR_HDMIA; - case OMAP_DISPLAY_TYPE_DVI: - return DRM_MODE_CONNECTOR_DVID; - case OMAP_DISPLAY_TYPE_DSI: - return DRM_MODE_CONNECTOR_DSI; - case OMAP_DISPLAY_TYPE_DPI: - case OMAP_DISPLAY_TYPE_DBI: - return DRM_MODE_CONNECTOR_DPI; - case OMAP_DISPLAY_TYPE_VENC: - /* TODO: This could also be composite */ - return DRM_MODE_CONNECTOR_SVIDEO; - case OMAP_DISPLAY_TYPE_SDI: - return DRM_MODE_CONNECTOR_LVDS; - default: - return DRM_MODE_CONNECTOR_Unknown; - } -} - /* initialize connector */ struct drm_connector *omap_connector_init(struct drm_device *dev, struct omap_dss_device *output, @@ -334,7 +130,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, { struct drm_connector *connector = NULL; struct omap_connector *omap_connector; - struct omap_dss_device *dssdev; DBG("%s", output->name); @@ -349,27 +144,9 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, connector->doublescan_allowed = 0; drm_connector_init(dev, connector, &omap_connector_funcs, - omap_connector_get_type(output)); + DRM_MODE_CONNECTOR_DSI); drm_connector_helper_add(connector, &omap_connector_helper_funcs); - /* - * Initialize connector status handling. First try to find a device that - * supports hot-plug reporting. If it fails, fall back to a device that - * support polling. If that fails too, we don't support hot-plug - * detection at all. - */ - dssdev = omap_connector_find_device(connector, OMAP_DSS_DEVICE_OP_HPD); - if (dssdev) { - omap_connector->hpd = omapdss_device_get(dssdev); - connector->polled = DRM_CONNECTOR_POLL_HPD; - } else { - dssdev = omap_connector_find_device(connector, - OMAP_DSS_DEVICE_OP_DETECT); - if (dssdev) - connector->polled = DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT; - } - return connector; fail: diff --git a/drivers/gpu/drm/omapdrm/omap_connector.h b/drivers/gpu/drm/omapdrm/omap_connector.h index 13607bda33d8..0ecd4f1655b7 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.h +++ b/drivers/gpu/drm/omapdrm/omap_connector.h @@ -21,9 +21,6 @@ struct omap_dss_device; struct drm_connector *omap_connector_init(struct drm_device *dev, struct omap_dss_device *output, struct drm_encoder *encoder); -bool omap_connector_get_hdmi_mode(struct drm_connector *connector); -void omap_connector_enable_hpd(struct drm_connector *connector); -void omap_connector_disable_hpd(struct drm_connector *connector); enum drm_mode_status omap_connector_mode_fixup(struct omap_dss_device *dssdev, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 3c5ddbf30e97..fce7e944a280 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -831,7 +831,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, * OMAP_DSS_CHANNEL_DIGIT. X server assumes 256 element gamma * tables so lets use that. Size of HW gamma table can be * extracted with dispc_mgr_gamma_size(). If it returns 0 - * gamma table is not supprted. + * gamma table is not supported. */ if (priv->dispc_ops->mgr_gamma_size(priv->dispc, channel)) { unsigned int gamma_lut_size = 256; diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index 252f5ebb1acc..42ec51bb7b1b 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -82,12 +82,11 @@ static const u32 reg[][4] = { static int dmm_dma_copy(struct dmm *dmm, dma_addr_t src, dma_addr_t dst) { - struct dma_device *dma_dev = dmm->wa_dma_chan->device; struct dma_async_tx_descriptor *tx; enum dma_status status; dma_cookie_t cookie; - tx = dma_dev->device_prep_dma_memcpy(dmm->wa_dma_chan, dst, src, 4, 0); + tx = dmaengine_prep_dma_memcpy(dmm->wa_dma_chan, dst, src, 4, 0); if (!tx) { dev_err(dmm->dev, "Failed to prepare DMA memcpy\n"); return -EIO; @@ -99,7 +98,6 @@ static int dmm_dma_copy(struct dmm *dmm, dma_addr_t src, dma_addr_t dst) return -EIO; } - dma_async_issue_pending(dmm->wa_dma_chan); status = dma_sync_wait(dmm->wa_dma_chan, cookie); if (status != DMA_COMPLETE) dev_err(dmm->dev, "i878 wa DMA copy failure\n"); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index d2750f60f519..cdafd7ef1c32 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -12,6 +12,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> +#include <drm/drm_bridge_connector.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_file.h> @@ -134,9 +135,6 @@ static void omap_disconnect_pipelines(struct drm_device *ddev) for (i = 0; i < priv->num_pipes; i++) { struct omap_drm_pipeline *pipe = &priv->pipes[i]; - if (pipe->output->panel) - drm_panel_detach(pipe->output->panel); - omapdss_device_disconnect(NULL, pipe->output); omapdss_device_put(pipe->output); @@ -209,11 +207,12 @@ static int omap_display_id(struct omap_dss_device *output) struct device_node *node = NULL; if (output->next) { - struct omap_dss_device *display; + struct omap_dss_device *display = output; + + while (display->next) + display = display->next; - display = omapdss_display_get(output); node = display->dev->of_node; - omapdss_device_put(display); } else if (output->bridge) { struct drm_bridge *bridge = output->bridge; @@ -221,8 +220,6 @@ static int omap_display_id(struct omap_dss_device *output) bridge = drm_bridge_get_next_bridge(bridge); node = bridge->of_node; - } else if (output->panel) { - node = output->panel->dev->of_node; } return node ? of_alias_get_id(node, "display") : -ENODEV; @@ -297,9 +294,14 @@ static int omap_modeset_init(struct drm_device *dev) if (pipe->output->bridge) { ret = drm_bridge_attach(pipe->encoder, - pipe->output->bridge, NULL); - if (ret < 0) + pipe->output->bridge, NULL, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret < 0) { + dev_err(priv->dev, + "unable to attach bridge %pOF\n", + pipe->output->bridge->of_node); return ret; + } } id = omap_display_id(pipe->output); @@ -330,20 +332,28 @@ static int omap_modeset_init(struct drm_device *dev) struct drm_encoder *encoder = pipe->encoder; struct drm_crtc *crtc; - if (!pipe->output->bridge) { + if (pipe->output->next) { pipe->connector = omap_connector_init(dev, pipe->output, encoder); if (!pipe->connector) return -ENOMEM; + } else { + pipe->connector = drm_bridge_connector_init(dev, encoder); + if (IS_ERR(pipe->connector)) { + dev_err(priv->dev, + "unable to create bridge connector for %s\n", + pipe->output->name); + return PTR_ERR(pipe->connector); + } + } - drm_connector_attach_encoder(pipe->connector, encoder); + drm_connector_attach_encoder(pipe->connector, encoder); - if (pipe->output->panel) { - ret = drm_panel_attach(pipe->output->panel, - pipe->connector); - if (ret < 0) - return ret; - } + if (pipe->output->panel) { + ret = drm_panel_attach(pipe->output->panel, + pipe->connector); + if (ret < 0) + return ret; } crtc = omap_crtc_init(dev, pipe, priv->planes[i]); @@ -382,6 +392,23 @@ static int omap_modeset_init(struct drm_device *dev) return 0; } +static void omap_modeset_fini(struct drm_device *ddev) +{ + struct omap_drm_private *priv = ddev->dev_private; + unsigned int i; + + omap_drm_irq_uninstall(ddev); + + for (i = 0; i < priv->num_pipes; i++) { + struct omap_drm_pipeline *pipe = &priv->pipes[i]; + + if (pipe->output->panel) + drm_panel_detach(pipe->output->panel); + } + + drm_mode_config_cleanup(ddev); +} + /* * Enable the HPD in external components if supported */ @@ -391,8 +418,13 @@ static void omap_modeset_enable_external_hpd(struct drm_device *ddev) unsigned int i; for (i = 0; i < priv->num_pipes; i++) { - if (priv->pipes[i].connector) - omap_connector_enable_hpd(priv->pipes[i].connector); + struct drm_connector *connector = priv->pipes[i].connector; + + if (!connector) + continue; + + if (priv->pipes[i].output->bridge) + drm_bridge_connector_enable_hpd(connector); } } @@ -405,8 +437,13 @@ static void omap_modeset_disable_external_hpd(struct drm_device *ddev) unsigned int i; for (i = 0; i < priv->num_pipes; i++) { - if (priv->pipes[i].connector) - omap_connector_disable_hpd(priv->pipes[i].connector); + struct drm_connector *connector = priv->pipes[i].connector; + + if (!connector) + continue; + + if (priv->pipes[i].output->bridge) + drm_bridge_connector_disable_hpd(connector); } } @@ -629,8 +666,7 @@ err_cleanup_helpers: omap_fbdev_fini(ddev); err_cleanup_modeset: - drm_mode_config_cleanup(ddev); - omap_drm_irq_uninstall(ddev); + omap_modeset_fini(ddev); err_gem_deinit: omap_gem_deinit(ddev); destroy_workqueue(priv->wq); @@ -655,9 +691,7 @@ static void omapdrm_cleanup(struct omap_drm_private *priv) drm_atomic_helper_shutdown(ddev); - drm_mode_config_cleanup(ddev); - - omap_drm_irq_uninstall(ddev); + omap_modeset_fini(ddev); omap_gem_deinit(ddev); destroy_workqueue(priv->wq); diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 4f2165a37795..ae4b867a67a3 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -10,7 +10,6 @@ #include <drm/drm_crtc.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_edid.h> -#include <drm/drm_panel.h> #include "omap_drv.h" @@ -70,30 +69,6 @@ static void omap_encoder_update_videomode_flags(struct videomode *vm, } } -static void omap_encoder_hdmi_mode_set(struct drm_connector *connector, - struct drm_encoder *encoder, - struct drm_display_mode *adjusted_mode) -{ - struct omap_encoder *omap_encoder = to_omap_encoder(encoder); - struct omap_dss_device *dssdev = omap_encoder->output; - bool hdmi_mode; - - hdmi_mode = omap_connector_get_hdmi_mode(connector); - - if (dssdev->ops->hdmi.set_hdmi_mode) - dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode); - - if (hdmi_mode && dssdev->ops->hdmi.set_infoframe) { - struct hdmi_avi_infoframe avi; - int r; - - r = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector, - adjusted_mode); - if (r == 0) - dssdev->ops->hdmi.set_infoframe(dssdev, &avi); - } -} - static void omap_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -138,17 +113,8 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, bus_flags = connector->display_info.bus_flags; omap_encoder_update_videomode_flags(&vm, bus_flags); - /* Set timings for all devices in the display pipeline. */ + /* Set timings for the dss manager. */ dss_mgr_set_timings(output, &vm); - - for (dssdev = output; dssdev; dssdev = dssdev->next) { - if (dssdev->ops->set_timings) - dssdev->ops->set_timings(dssdev, adjusted_mode); - } - - /* Set the HDMI mode and HDMI infoframe if applicable. */ - if (output->type == OMAP_DISPLAY_TYPE_HDMI) - omap_encoder_hdmi_mode_set(connector, encoder, adjusted_mode); } static void omap_encoder_disable(struct drm_encoder *encoder) @@ -159,33 +125,12 @@ static void omap_encoder_disable(struct drm_encoder *encoder) dev_dbg(dev->dev, "disable(%s)\n", dssdev->name); - /* Disable the panel if present. */ - if (dssdev->panel) { - drm_panel_disable(dssdev->panel); - drm_panel_unprepare(dssdev->panel); - } - /* * Disable the chain of external devices, starting at the one at the - * internal encoder's output. + * internal encoder's output. This is used for DSI outputs only, as + * dssdev->next is NULL for all other outputs. */ omapdss_device_disable(dssdev->next); - - /* - * Disable the internal encoder. This will disable the DSS output. The - * DSI is treated as an exception as DSI pipelines still use the legacy - * flow where the pipeline output controls the encoder. - */ - if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) { - dssdev->ops->disable(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - } - - /* - * Perform the post-disable operations on the chain of external devices - * to complete the display pipeline disable. - */ - omapdss_device_post_disable(dssdev->next); } static void omap_encoder_enable(struct drm_encoder *encoder) @@ -196,30 +141,12 @@ static void omap_encoder_enable(struct drm_encoder *encoder) dev_dbg(dev->dev, "enable(%s)\n", dssdev->name); - /* Prepare the chain of external devices for pipeline enable. */ - omapdss_device_pre_enable(dssdev->next); - - /* - * Enable the internal encoder. This will enable the DSS output. The - * DSI is treated as an exception as DSI pipelines still use the legacy - * flow where the pipeline output controls the encoder. - */ - if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) { - dssdev->ops->enable(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - } - /* * Enable the chain of external devices, starting at the one at the - * internal encoder's output. + * internal encoder's output. This is used for DSI outputs only, as + * dssdev->next is NULL for all other outputs. */ omapdss_device_enable(dssdev->next); - - /* Enable the panel if present. */ - if (dssdev->panel) { - drm_panel_prepare(dssdev->panel); - drm_panel_enable(dssdev->panel); - } } static int omap_encoder_atomic_check(struct drm_encoder *encoder, diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index b06e5cbfd03a..09a84919ef73 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -242,14 +242,10 @@ void omap_fbdev_init(struct drm_device *dev) drm_fb_helper_prepare(dev, helper, &omap_fb_helper_funcs); - ret = drm_fb_helper_init(dev, helper, priv->num_pipes); + ret = drm_fb_helper_init(dev, helper); if (ret) goto fail; - ret = drm_fb_helper_single_add_all_connectors(helper); - if (ret) - goto fini; - ret = drm_fb_helper_initial_config(helper, 32); if (ret) goto fini; |