diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/dss')
31 files changed, 616 insertions, 983 deletions
diff --git a/drivers/gpu/drm/omapdrm/dss/Kconfig b/drivers/gpu/drm/omapdrm/dss/Kconfig index f24ebf7f61dd..956f23e1452d 100644 --- a/drivers/gpu/drm/omapdrm/dss/Kconfig +++ b/drivers/gpu/drm/omapdrm/dss/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config OMAP2_DSS_INIT bool diff --git a/drivers/gpu/drm/omapdrm/dss/Makefile b/drivers/gpu/drm/omapdrm/dss/Makefile index 904101c5e79d..5950c3f52c2e 100644 --- a/drivers/gpu/drm/omapdrm/dss/Makefile +++ b/drivers/gpu/drm/omapdrm/dss/Makefile @@ -6,7 +6,7 @@ omapdss-base-y := base.o display.o dss-of.o output.o obj-$(CONFIG_OMAP2_DSS) += omapdss.o # Core DSS files -omapdss-y := core.o dss.o dispc.o dispc_coefs.o \ +omapdss-y := dss.o dispc.o dispc_coefs.o \ pll.o video-pll.o omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index 472f56e3de70..a1970b9db6ab 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP Display Subsystem Base * * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. */ #include <linux/kernel.h> @@ -19,6 +11,7 @@ #include <linux/mutex.h> #include <linux/of.h> #include <linux/of_graph.h> +#include <linux/platform_device.h> #include "dss.h" #include "omapdss.h" @@ -112,13 +105,12 @@ void omapdss_device_put(struct omap_dss_device *dssdev) } EXPORT_SYMBOL(omapdss_device_put); -struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src, - unsigned int port) +struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node) { struct omap_dss_device *dssdev; list_for_each_entry(dssdev, &omapdss_devices_list, list) { - if (dssdev->dev->of_node == src && dssdev->of_ports & BIT(port)) + if (dssdev->dev->of_node == node) return omapdss_device_get(dssdev); } @@ -126,13 +118,10 @@ struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src, } /* - * Search for the next device starting at @from. The type argument specfies - * which device types to consider when searching. Searching for multiple types - * is supported by and'ing their type flags. Release the reference to the @from - * device, and acquire a reference to the returned device if found. + * Search for the next output device starting at @from. Release the reference to + * the @from device, and acquire a reference to the returned device if found. */ -struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from, - enum omap_dss_device_type type) +struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from) { struct omap_dss_device *dssdev; struct list_head *list; @@ -160,15 +149,8 @@ struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from, goto done; } - /* - * Accept display entities if the display type is requested, - * and output entities if the output type is requested. - */ - if ((type & OMAP_DSS_DEVICE_TYPE_DISPLAY) && - !dssdev->output_type) - goto done; - if ((type & OMAP_DSS_DEVICE_TYPE_OUTPUT) && dssdev->id && - dssdev->next) + if (dssdev->id && + (dssdev->next || dssdev->bridge || dssdev->panel)) goto done; } @@ -183,7 +165,12 @@ done: mutex_unlock(&omapdss_devices_lock); return dssdev; } -EXPORT_SYMBOL(omapdss_device_get_next); +EXPORT_SYMBOL(omapdss_device_next_output); + +static bool omapdss_device_is_connected(struct omap_dss_device *dssdev) +{ + return dssdev->dss; +} int omapdss_device_connect(struct dss_device *dss, struct omap_dss_device *src, @@ -191,7 +178,19 @@ int omapdss_device_connect(struct dss_device *dss, { int ret; - dev_dbg(dst->dev, "connect\n"); + dev_dbg(&dss->pdev->dev, "connect(%s, %s)\n", + src ? dev_name(src->dev) : "NULL", + dst ? dev_name(dst->dev) : "NULL"); + + 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. + */ + return src && (src->bridge || src->panel) ? 0 : -EINVAL; + } if (omapdss_device_is_connected(dst)) return -EBUSY; @@ -204,12 +203,6 @@ int omapdss_device_connect(struct dss_device *dss, return ret; } - if (src) { - WARN_ON(src->dst); - dst->src = src; - src->dst = dst; - } - return 0; } EXPORT_SYMBOL_GPL(omapdss_device_connect); @@ -217,19 +210,20 @@ EXPORT_SYMBOL_GPL(omapdss_device_connect); void omapdss_device_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dev_dbg(dst->dev, "disconnect\n"); + struct dss_device *dss = src ? src->dss : dst->dss; - if (!dst->id && !omapdss_device_is_connected(dst)) { - WARN_ON(dst->output_type); + dev_dbg(&dss->pdev->dev, "disconnect(%s, %s)\n", + src ? dev_name(src->dev) : "NULL", + dst ? dev_name(dst->dev) : "NULL"); + + if (!dst) { + WARN_ON(!src->bridge && !src->panel); return; } - if (src) { - if (WARN_ON(dst != src->dst)) - return; - - dst->src = NULL; - src->dst = NULL; + if (!dst->id && !omapdss_device_is_connected(dst)) { + WARN_ON(!dst->display); + return; } WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED); @@ -239,6 +233,58 @@ void omapdss_device_disconnect(struct omap_dss_device *src, } 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) + dssdev->ops->enable(dssdev); + + omapdss_device_enable(dssdev->next); + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; +} +EXPORT_SYMBOL_GPL(omapdss_device_enable); + +void omapdss_device_disable(struct omap_dss_device *dssdev) +{ + if (!dssdev) + return; + + omapdss_device_disable(dssdev->next); + + if (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 */ @@ -249,6 +295,7 @@ struct omapdss_comp_node { struct list_head list; struct device_node *node; bool dss_core_component; + const char *compat; }; static bool omapdss_list_contains(const struct device_node *node) @@ -266,13 +313,20 @@ static bool omapdss_list_contains(const struct device_node *node) static void omapdss_walk_device(struct device *dev, struct device_node *node, bool dss_core) { + struct omapdss_comp_node *comp; struct device_node *n; - struct omapdss_comp_node *comp = devm_kzalloc(dev, sizeof(*comp), - GFP_KERNEL); + const char *compat; + int ret; + ret = of_property_read_string(node, "compatible", &compat); + if (ret < 0) + return; + + comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); if (comp) { comp->node = node; comp->dss_core_component = dss_core; + comp->compat = compat; list_add(&comp->list, &omapdss_comp_list); } @@ -312,12 +366,8 @@ void omapdss_gather_components(struct device *dev) omapdss_walk_device(dev, dev->of_node, true); - for_each_available_child_of_node(dev->of_node, child) { - if (!of_find_property(child, "compatible", NULL)) - continue; - + for_each_available_child_of_node(dev->of_node, child) omapdss_walk_device(dev, child, true); - } } EXPORT_SYMBOL(omapdss_gather_components); @@ -325,6 +375,8 @@ static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp) { if (comp->dss_core_component) return true; + if (!strstarts(comp->compat, "omapdss,")) + return true; if (omapdss_device_is_registered(comp->node)) return true; diff --git a/drivers/gpu/drm/omapdrm/dss/core.c b/drivers/gpu/drm/omapdrm/dss/core.c deleted file mode 100644 index a2edabc9f6b3..000000000000 --- a/drivers/gpu/drm/omapdrm/dss/core.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <[email protected]> - * - * Some code and ideas taken from drivers/video/omap/ driver - * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#define DSS_SUBSYS_NAME "CORE" - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> - -#include "omapdss.h" -#include "dss.h" - -/* INIT */ -static struct platform_driver * const omap_dss_drivers[] = { - &omap_dsshw_driver, - &omap_dispchw_driver, -#ifdef CONFIG_OMAP2_DSS_DSI - &omap_dsihw_driver, -#endif -#ifdef CONFIG_OMAP2_DSS_VENC - &omap_venchw_driver, -#endif -#ifdef CONFIG_OMAP4_DSS_HDMI - &omapdss_hdmi4hw_driver, -#endif -#ifdef CONFIG_OMAP5_DSS_HDMI - &omapdss_hdmi5hw_driver, -#endif -}; - -static int __init omap_dss_init(void) -{ - return platform_register_drivers(omap_dss_drivers, - ARRAY_SIZE(omap_dss_drivers)); -} - -static void __exit omap_dss_exit(void) -{ - platform_unregister_drivers(omap_dss_drivers, - ARRAY_SIZE(omap_dss_drivers)); -} - -module_init(omap_dss_init); -module_exit(omap_dss_exit); - -MODULE_AUTHOR("Tomi Valkeinen <[email protected]>"); -MODULE_DESCRIPTION("OMAP2/3 Display Subsystem"); -MODULE_LICENSE("GPL v2"); - diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index ba82d916719c..413dbdd1771e 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <[email protected]> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DISPC" @@ -125,6 +114,7 @@ struct dispc_features { const unsigned int num_reg_fields; const enum omap_overlay_caps *overlay_caps; const u32 **supported_color_modes; + const u32 *supported_scaler_color_modes; unsigned int num_mgrs; unsigned int num_ovls; unsigned int buffer_size_unit; @@ -195,9 +185,6 @@ struct dispc_device { struct regmap *syscon_pol; u32 syscon_pol_offset; - - /* DISPC_CONTROL & DISPC_CONFIG lock*/ - spinlock_t control_lock; }; enum omap_color_component { @@ -379,25 +366,17 @@ static inline u32 dispc_read_reg(struct dispc_device *dispc, u16 idx) static u32 mgr_fld_read(struct dispc_device *dispc, enum omap_channel channel, enum mgr_reg_fields regfld) { - const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld]; + const struct dispc_reg_field *rfld = &mgr_desc[channel].reg_desc[regfld]; - return REG_GET(dispc, rfld.reg, rfld.high, rfld.low); + return REG_GET(dispc, rfld->reg, rfld->high, rfld->low); } static void mgr_fld_write(struct dispc_device *dispc, enum omap_channel channel, enum mgr_reg_fields regfld, int val) { - const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld]; - const bool need_lock = rfld.reg == DISPC_CONTROL || rfld.reg == DISPC_CONFIG; - unsigned long flags; + const struct dispc_reg_field *rfld = &mgr_desc[channel].reg_desc[regfld]; - if (need_lock) { - spin_lock_irqsave(&dispc->control_lock, flags); - REG_FLD_MOD(dispc, rfld.reg, val, rfld.high, rfld.low); - spin_unlock_irqrestore(&dispc->control_lock, flags); - } else { - REG_FLD_MOD(dispc, rfld.reg, val, rfld.high, rfld.low); - } + REG_FLD_MOD(dispc, rfld->reg, val, rfld->high, rfld->low); } static int dispc_get_num_ovls(struct dispc_device *dispc) @@ -2521,6 +2500,19 @@ static int dispc_ovl_calc_scaling(struct dispc_device *dispc, if (width == out_width && height == out_height) return 0; + if (dispc->feat->supported_scaler_color_modes) { + const u32 *modes = dispc->feat->supported_scaler_color_modes; + unsigned int i; + + for (i = 0; modes[i]; ++i) { + if (modes[i] == fourcc) + break; + } + + if (modes[i] == 0) + return -EINVAL; + } + if (plane == OMAP_DSS_WB) { switch (fourcc) { case DRM_FORMAT_NV12: @@ -4236,6 +4228,12 @@ static const u32 *omap4_dispc_supported_color_modes[] = { DRM_FORMAT_RGBX8888), }; +static const u32 omap3_dispc_supported_scaler_color_modes[] = { + DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565, DRM_FORMAT_YUYV, + DRM_FORMAT_UYVY, + 0, +}; + static const struct dispc_features omap24xx_dispc_feats = { .sw_start = 5, .fp_start = 15, @@ -4264,6 +4262,7 @@ static const struct dispc_features omap24xx_dispc_feats = { .num_reg_fields = ARRAY_SIZE(omap2_dispc_reg_fields), .overlay_caps = omap2_dispc_overlay_caps, .supported_color_modes = omap2_dispc_supported_color_modes, + .supported_scaler_color_modes = COLOR_ARRAY(DRM_FORMAT_XRGB8888), .num_mgrs = 2, .num_ovls = 3, .buffer_size_unit = 1, @@ -4298,6 +4297,7 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats = { .num_reg_fields = ARRAY_SIZE(omap3_dispc_reg_fields), .overlay_caps = omap3430_dispc_overlay_caps, .supported_color_modes = omap3_dispc_supported_color_modes, + .supported_scaler_color_modes = omap3_dispc_supported_scaler_color_modes, .num_mgrs = 2, .num_ovls = 3, .buffer_size_unit = 1, @@ -4332,6 +4332,7 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats = { .num_reg_fields = ARRAY_SIZE(omap3_dispc_reg_fields), .overlay_caps = omap3430_dispc_overlay_caps, .supported_color_modes = omap3_dispc_supported_color_modes, + .supported_scaler_color_modes = omap3_dispc_supported_scaler_color_modes, .num_mgrs = 2, .num_ovls = 3, .buffer_size_unit = 1, @@ -4366,6 +4367,7 @@ static const struct dispc_features omap36xx_dispc_feats = { .num_reg_fields = ARRAY_SIZE(omap3_dispc_reg_fields), .overlay_caps = omap3630_dispc_overlay_caps, .supported_color_modes = omap3_dispc_supported_color_modes, + .supported_scaler_color_modes = omap3_dispc_supported_scaler_color_modes, .num_mgrs = 2, .num_ovls = 3, .buffer_size_unit = 1, @@ -4400,6 +4402,7 @@ static const struct dispc_features am43xx_dispc_feats = { .num_reg_fields = ARRAY_SIZE(omap3_dispc_reg_fields), .overlay_caps = omap3430_dispc_overlay_caps, .supported_color_modes = omap3_dispc_supported_color_modes, + .supported_scaler_color_modes = omap3_dispc_supported_scaler_color_modes, .num_mgrs = 1, .num_ovls = 3, .buffer_size_unit = 1, @@ -4620,11 +4623,10 @@ static int dispc_errata_i734_wa_init(struct dispc_device *dispc) i734_buf.size = i734.ovli.width * i734.ovli.height * color_mode_to_bpp(i734.ovli.fourcc) / 8; - i734_buf.vaddr = dma_alloc_writecombine(&dispc->pdev->dev, - i734_buf.size, &i734_buf.paddr, - GFP_KERNEL); + i734_buf.vaddr = dma_alloc_wc(&dispc->pdev->dev, i734_buf.size, + &i734_buf.paddr, GFP_KERNEL); if (!i734_buf.vaddr) { - dev_err(&dispc->pdev->dev, "%s: dma_alloc_writecombine failed\n", + dev_err(&dispc->pdev->dev, "%s: dma_alloc_wc failed\n", __func__); return -ENOMEM; } @@ -4637,8 +4639,8 @@ static void dispc_errata_i734_wa_fini(struct dispc_device *dispc) if (!dispc->feat->has_gamma_i734_bug) return; - dma_free_writecombine(&dispc->pdev->dev, i734_buf.size, i734_buf.vaddr, - i734_buf.paddr); + dma_free_wc(&dispc->pdev->dev, i734_buf.size, i734_buf.vaddr, + i734_buf.paddr); } static void dispc_errata_i734_wa(struct dispc_device *dispc) @@ -4780,8 +4782,6 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) platform_set_drvdata(pdev, dispc); dispc->dss = dss; - spin_lock_init(&dispc->control_lock); - /* * The OMAP3-based models can't be told apart using the compatible * string, use SoC device matching. diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.h b/drivers/gpu/drm/omapdrm/dss/dispc.h index e901dd1e4365..2348faf88768 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.h +++ b/drivers/gpu/drm/omapdrm/dss/dispc.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Archit Taneja <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAP2_DISPC_REG_H diff --git a/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c b/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c index 44804c8c8777..bccb28de5a59 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Chandrabhanu Mahapatra <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index 34b2a4ef63a4..8a3f61f5825f 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <[email protected]> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DISPLAY" @@ -23,6 +12,9 @@ #include <linux/kernel.h> #include <linux/of.h> +#include <drm/drm_connector.h> +#include <drm/drm_modes.h> + #include "omapdss.h" static int disp_num_counter; @@ -39,8 +31,6 @@ void omapdss_display_init(struct omap_dss_device *dssdev) if (id < 0) id = disp_num_counter++; - dssdev->alias_id = id; - /* Use 'label' property for name, if it exists */ of_property_read_string(dssdev->dev->of_node, "label", &dssdev->name); @@ -58,3 +48,22 @@ struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output) return omapdss_device_get(output); } EXPORT_SYMBOL_GPL(omapdss_display_get); + +int omapdss_display_get_modes(struct drm_connector *connector, + const struct videomode *vm) +{ + struct drm_display_mode *mode; + + mode = drm_mode_create(connector->dev); + if (!mode) + return 0; + + drm_display_mode_from_videomode(vm, mode); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + return 1; +} +EXPORT_SYMBOL_GPL(omapdss_display_get_modes); diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index ca4f3c4c6318..95147437b990 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <[email protected]> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DPI" @@ -47,8 +36,8 @@ struct dpi_data { struct mutex lock; - struct videomode vm; struct dss_lcd_mgr_config mgr_config; + unsigned long pixelclock; int data_lines; struct omap_dss_device output; @@ -347,16 +336,15 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, static int dpi_set_mode(struct dpi_data *dpi) { - const struct videomode *vm = &dpi->vm; int lck_div = 0, pck_div = 0; unsigned long fck = 0; int r = 0; if (dpi->pll) r = dpi_set_pll_clk(dpi, dpi->output.dispc_channel, - vm->pixelclock, &fck, &lck_div, &pck_div); + dpi->pixelclock, &fck, &lck_div, &pck_div); else - r = dpi_set_dispc_clk(dpi, vm->pixelclock, &fck, + r = dpi_set_dispc_clk(dpi, dpi->pixelclock, &fck, &lck_div, &pck_div); if (r) return r; @@ -378,7 +366,7 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi) dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config); } -static int dpi_display_enable(struct omap_dss_device *dssdev) +static void dpi_display_enable(struct omap_dss_device *dssdev) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); struct omap_dss_device *out = &dpi->output; @@ -386,12 +374,6 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) mutex_lock(&dpi->lock); - if (!out->dispc_channel_connected) { - DSSERR("failed to enable display: no output/manager\n"); - r = -ENODEV; - goto err_no_out_mgr; - } - if (dpi->vdds_dsi_reg) { r = regulator_enable(dpi->vdds_dsi_reg); if (r) @@ -426,7 +408,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) mutex_unlock(&dpi->lock); - return 0; + return; err_mgr_enable: err_set_mode: @@ -439,9 +421,7 @@ err_get_dispc: if (dpi->vdds_dsi_reg) regulator_disable(dpi->vdds_dsi_reg); err_reg_enable: -err_no_out_mgr: mutex_unlock(&dpi->lock); - return r; } static void dpi_display_disable(struct omap_dss_device *dssdev) @@ -467,7 +447,7 @@ static void dpi_display_disable(struct omap_dss_device *dssdev) } static void dpi_set_timings(struct omap_dss_device *dssdev, - const struct videomode *vm) + const struct drm_display_mode *mode) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); @@ -475,13 +455,13 @@ static void dpi_set_timings(struct omap_dss_device *dssdev, mutex_lock(&dpi->lock); - dpi->vm = *vm; + dpi->pixelclock = mode->clock * 1000; mutex_unlock(&dpi->lock); } static int dpi_check_timings(struct omap_dss_device *dssdev, - struct videomode *vm) + struct drm_display_mode *mode) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); int lck_div, pck_div; @@ -490,20 +470,20 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, struct dpi_clk_calc_ctx ctx; bool ok; - if (vm->hactive % 8 != 0) + if (mode->hdisplay % 8 != 0) return -EINVAL; - if (vm->pixelclock == 0) + if (mode->clock == 0) return -EINVAL; if (dpi->pll) { - ok = dpi_pll_clk_calc(dpi, vm->pixelclock, &ctx); + 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, vm->pixelclock, &ctx); + ok = dpi_dss_clk_calc(dpi, mode->clock * 1000, &ctx); if (!ok) return -EINVAL; @@ -515,7 +495,7 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, pck = fck / lck_div / pck_div; - vm->pixelclock = pck; + mode->clock = pck / 1000; return 0; } @@ -596,23 +576,15 @@ static int dpi_connect(struct omap_dss_device *src, struct omap_dss_device *dst) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dst); - int r; dpi_init_pll(dpi); - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - dst->dispc_channel_connected = true; - return 0; + return omapdss_device_connect(dst->dss, dst, dst->next); } static void dpi_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dst->dispc_channel_connected = false; - omapdss_device_disconnect(dst, dst->next); } @@ -651,25 +623,15 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port) out->dev = &dpi->pdev->dev; out->id = OMAP_DSS_OUTPUT_DPI; - out->output_type = OMAP_DISPLAY_TYPE_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->owner = THIS_MODULE; - out->next = omapdss_of_find_connected_device(out->dev->of_node, 0); - if (IS_ERR(out->next)) { - if (PTR_ERR(out->next) != -EPROBE_DEFER) - dev_err(out->dev, "failed to find video sink\n"); - return PTR_ERR(out->next); - } - - r = omapdss_output_validate(out); - if (r) { - omapdss_device_put(out->next); - out->next = NULL; + r = omapdss_device_init_output(out); + if (r < 0) return r; - } omapdss_device_register(out); @@ -681,9 +643,8 @@ static void dpi_uninit_output_port(struct device_node *port) struct dpi_data *dpi = port->data; struct omap_dss_device *out = &dpi->output; - if (out->next) - omapdss_device_put(out->next); omapdss_device_unregister(out); + omapdss_device_cleanup_output(out); } static const struct soc_device_attribute dpi_soc_devices[] = { diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 64fb788b6647..da16ea095f13 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DSI" @@ -1342,12 +1331,9 @@ static int dsi_pll_enable(struct dss_pll *pll) */ dsi_enable_scp_clk(dsi); - if (!dsi->vdds_dsi_enabled) { - r = regulator_enable(dsi->vdds_dsi_reg); - if (r) - goto err0; - dsi->vdds_dsi_enabled = true; - } + r = regulator_enable(dsi->vdds_dsi_reg); + if (r) + goto err0; /* XXX PLL does not come out of reset without this... */ dispc_pck_free_enable(dsi->dss->dispc, 1); @@ -1372,36 +1358,25 @@ static int dsi_pll_enable(struct dss_pll *pll) return 0; err1: - if (dsi->vdds_dsi_enabled) { - regulator_disable(dsi->vdds_dsi_reg); - dsi->vdds_dsi_enabled = false; - } + regulator_disable(dsi->vdds_dsi_reg); err0: dsi_disable_scp_clk(dsi); dsi_runtime_put(dsi); return r; } -static void dsi_pll_uninit(struct dsi_data *dsi, bool disconnect_lanes) +static void dsi_pll_disable(struct dss_pll *pll) { + struct dsi_data *dsi = container_of(pll, struct dsi_data, pll); + dsi_pll_power(dsi, DSI_PLL_POWER_OFF); - if (disconnect_lanes) { - WARN_ON(!dsi->vdds_dsi_enabled); - regulator_disable(dsi->vdds_dsi_reg); - dsi->vdds_dsi_enabled = false; - } + + regulator_disable(dsi->vdds_dsi_reg); dsi_disable_scp_clk(dsi); dsi_runtime_put(dsi); - DSSDBG("PLL uninit done\n"); -} - -static void dsi_pll_disable(struct dss_pll *pll) -{ - struct dsi_data *dsi = container_of(pll, struct dsi_data, pll); - - dsi_pll_uninit(dsi, true); + DSSDBG("PLL disable done\n"); } static int dsi_dump_dsi_clocks(struct seq_file *s, void *p) @@ -3573,7 +3548,7 @@ static int dsi_proto_config(struct dsi_data *dsi) static void dsi_proto_timings(struct dsi_data *dsi) { - unsigned int tlpx, tclk_zero, tclk_prepare, tclk_trail; + unsigned int tlpx, tclk_zero, tclk_prepare; unsigned int tclk_pre, tclk_post; unsigned int ths_prepare, ths_prepare_ths_zero, ths_zero; unsigned int ths_trail, ths_exit; @@ -3592,7 +3567,6 @@ static void dsi_proto_timings(struct dsi_data *dsi) r = dsi_read_reg(dsi, DSI_DSIPHY_CFG1); tlpx = FLD_GET(r, 20, 16) * 2; - tclk_trail = FLD_GET(r, 15, 8); tclk_zero = FLD_GET(r, 7, 0); r = dsi_read_reg(dsi, DSI_DSIPHY_CFG2); @@ -3753,19 +3727,13 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) { struct dsi_data *dsi = to_dsi_data(dssdev); int bpp = dsi_get_pixel_size(dsi->pix_fmt); - struct omap_dss_device *out = &dsi->output; u8 data_type; u16 word_count; int r; - if (!out->dispc_channel_connected) { - DSSERR("failed to enable display: no output/manager\n"); - return -ENODEV; - } - r = dsi_display_init_dispc(dsi); if (r) - goto err_init_dispc; + return r; if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { switch (dsi->pix_fmt) { @@ -3814,7 +3782,6 @@ err_mgr_enable: } err_pix_fmt: dsi_display_uninit_dispc(dsi); -err_init_dispc: return r; } @@ -4096,11 +4063,11 @@ static int dsi_display_init_dsi(struct dsi_data *dsi) r = dss_pll_enable(&dsi->pll); if (r) - goto err0; + return r; r = dsi_configure_dsi_clocks(dsi); if (r) - goto err1; + goto err0; dss_select_dsi_clk_source(dsi->dss, dsi->module_id, dsi->module_id == 0 ? @@ -4108,6 +4075,14 @@ static int dsi_display_init_dsi(struct dsi_data *dsi) DSSDBG("PLL OK\n"); + if (!dsi->vdds_dsi_enabled) { + r = regulator_enable(dsi->vdds_dsi_reg); + if (r) + goto err1; + + dsi->vdds_dsi_enabled = true; + } + r = dsi_cio_init(dsi); if (r) goto err2; @@ -4136,10 +4111,13 @@ static int dsi_display_init_dsi(struct dsi_data *dsi) err3: dsi_cio_uninit(dsi); err2: - dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); + regulator_disable(dsi->vdds_dsi_reg); + dsi->vdds_dsi_enabled = false; err1: - dss_pll_disable(&dsi->pll); + dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); err0: + dss_pll_disable(&dsi->pll); + return r; } @@ -4158,13 +4136,18 @@ static void dsi_display_uninit_dsi(struct dsi_data *dsi, bool disconnect_lanes, dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); dsi_cio_uninit(dsi); - dsi_pll_uninit(dsi, disconnect_lanes); + dss_pll_disable(&dsi->pll); + + if (disconnect_lanes) { + regulator_disable(dsi->vdds_dsi_reg); + dsi->vdds_dsi_enabled = false; + } } -static int dsi_display_enable(struct omap_dss_device *dssdev) +static void dsi_display_enable(struct omap_dss_device *dssdev) { struct dsi_data *dsi = to_dsi_data(dssdev); - int r = 0; + int r; DSSDBG("dsi_display_enable\n"); @@ -4184,14 +4167,13 @@ static int dsi_display_enable(struct omap_dss_device *dssdev) mutex_unlock(&dsi->lock); - return 0; + return; err_init_dsi: dsi_runtime_put(dsi); err_get_dsi: mutex_unlock(&dsi->lock); DSSDBG("dsi_display_enable FAILED\n"); - return r; } static void dsi_display_disable(struct omap_dss_device *dssdev, @@ -4888,21 +4870,12 @@ static int dsi_get_clocks(struct dsi_data *dsi) static int dsi_connect(struct omap_dss_device *src, struct omap_dss_device *dst) { - int r; - - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - dst->dispc_channel_connected = true; - return 0; + return omapdss_device_connect(dst->dss, dst, dst->next); } static void dsi_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dst->dispc_channel_connected = false; - omapdss_device_disconnect(dst, dst->next); } @@ -5138,29 +5111,19 @@ static int dsi_init_output(struct dsi_data *dsi) out->id = dsi->module_id == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; - out->output_type = OMAP_DISPLAY_TYPE_DSI; + out->type = OMAP_DISPLAY_TYPE_DSI; out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1"; out->dispc_channel = dsi_get_channel(dsi); out->ops = &dsi_ops; out->owner = THIS_MODULE; out->of_ports = BIT(0); - out->bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE + out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE | DRM_BUS_FLAG_DE_HIGH - | DRM_BUS_FLAG_SYNC_NEGEDGE; - - out->next = omapdss_of_find_connected_device(out->dev->of_node, 0); - if (IS_ERR(out->next)) { - if (PTR_ERR(out->next) != -EPROBE_DEFER) - dev_err(out->dev, "failed to find video sink\n"); - return PTR_ERR(out->next); - } + | DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE; - r = omapdss_output_validate(out); - if (r) { - omapdss_device_put(out->next); - out->next = NULL; + r = omapdss_device_init_output(out); + if (r < 0) return r; - } omapdss_device_register(out); @@ -5171,9 +5134,8 @@ static void dsi_uninit_output(struct dsi_data *dsi) { struct omap_dss_device *out = &dsi->output; - if (out->next) - omapdss_device_put(out->next); omapdss_device_unregister(out); + omapdss_device_cleanup_output(out); } static int dsi_probe_of(struct dsi_data *dsi) diff --git a/drivers/gpu/drm/omapdrm/dss/dss-of.c b/drivers/gpu/drm/omapdrm/dss/dss-of.c index 0422597ac6b0..b7981f3b80ad 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss-of.c +++ b/drivers/gpu/drm/omapdrm/dss/dss-of.c @@ -1,82 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * Author: Tomi Valkeinen <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ -#include <linux/device.h> #include <linux/err.h> -#include <linux/module.h> #include <linux/of.h> #include <linux/of_graph.h> -#include <linux/seq_file.h> #include "omapdss.h" -static struct device_node * -dss_of_port_get_parent_device(struct device_node *port) -{ - struct device_node *np; - int i; - - if (!port) - return NULL; - - np = of_get_parent(port); - - for (i = 0; i < 2 && np; ++i) { - struct property *prop; - - prop = of_find_property(np, "compatible", NULL); - - if (prop) - return np; - - np = of_get_next_parent(np); - } - - return NULL; -} - struct omap_dss_device * omapdss_of_find_connected_device(struct device_node *node, unsigned int port) { - struct device_node *src_node; - struct device_node *src_port; - struct device_node *ep; - struct omap_dss_device *src; - u32 port_number = 0; + struct device_node *remote_node; + struct omap_dss_device *dssdev; - /* Get the endpoint... */ - ep = of_graph_get_endpoint_by_regs(node, port, 0); - if (!ep) + remote_node = of_graph_get_remote_node(node, port, 0); + if (!remote_node) return NULL; - /* ... and its remote port... */ - src_port = of_graph_get_remote_port(ep); - of_node_put(ep); - if (!src_port) - return NULL; - - /* ... and the remote port's number and parent... */ - of_property_read_u32(src_port, "reg", &port_number); - src_node = dss_of_port_get_parent_device(src_port); - of_node_put(src_port); - if (!src_node) - return ERR_PTR(-EINVAL); - - /* ... and finally the connected device. */ - src = omapdss_find_device_by_port(src_node, port_number); - of_node_put(src_node); + dssdev = omapdss_find_device_by_node(remote_node); + of_node_put(remote_node); - return src ? src : ERR_PTR(-EPROBE_DEFER); + 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 7553c7fc1c45..225ec808b01a 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <[email protected]> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DSS" @@ -934,7 +923,6 @@ dss_debugfs_create_file(struct dss_device *dss, const char *name, void *data) { struct dss_debugfs_entry *entry; - struct dentry *d; entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) @@ -942,15 +930,9 @@ dss_debugfs_create_file(struct dss_device *dss, const char *name, entry->show_fn = show_fn; entry->data = data; + entry->dentry = debugfs_create_file(name, 0444, dss->debugfs.root, + entry, &dss_debug_fops); - d = debugfs_create_file(name, 0444, dss->debugfs.root, entry, - &dss_debug_fops); - if (IS_ERR(d)) { - kfree(entry); - return ERR_CAST(d); - } - - entry->dentry = d; return entry; } @@ -1101,7 +1083,7 @@ static const struct dss_features omap34xx_dss_feats = { static const struct dss_features omap3630_dss_feats = { .model = DSS_MODEL_OMAP3, - .fck_div_max = 32, + .fck_div_max = 31, .fck_freq_max = 173000000, .dss_fck_multiplier = 1, .parent_clk_name = "dpll4_ck", @@ -1560,7 +1542,7 @@ static void dss_shutdown(struct platform_device *pdev) DSSDBG("shutdown\n"); - for_each_dss_display(dssdev) { + for_each_dss_output(dssdev) { if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) dssdev->ops->disable(dssdev); } @@ -1616,3 +1598,40 @@ struct platform_driver omap_dsshw_driver = { .suppress_bind_attrs = true, }, }; + +/* INIT */ +static struct platform_driver * const omap_dss_drivers[] = { + &omap_dsshw_driver, + &omap_dispchw_driver, +#ifdef CONFIG_OMAP2_DSS_DSI + &omap_dsihw_driver, +#endif +#ifdef CONFIG_OMAP2_DSS_VENC + &omap_venchw_driver, +#endif +#ifdef CONFIG_OMAP4_DSS_HDMI + &omapdss_hdmi4hw_driver, +#endif +#ifdef CONFIG_OMAP5_DSS_HDMI + &omapdss_hdmi5hw_driver, +#endif +}; + +static int __init omap_dss_init(void) +{ + return platform_register_drivers(omap_dss_drivers, + ARRAY_SIZE(omap_dss_drivers)); +} + +static void __exit omap_dss_exit(void) +{ + platform_unregister_drivers(omap_dss_drivers, + ARRAY_SIZE(omap_dss_drivers)); +} + +module_init(omap_dss_init); +module_exit(omap_dss_exit); + +MODULE_AUTHOR("Tomi Valkeinen <[email protected]>"); +MODULE_DESCRIPTION("OMAP2/3/4/5 Display Subsystem"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 37790c363128..2b404bcb41dd 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <[email protected]> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAP2_DSS_H diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h index 7f0dc490a31d..c867552c925c 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * HDMI driver definition for TI OMAP4 Processor. * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _HDMI_H diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index aabdda394c9c..0f557fad4513 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI interface DSS driver for TI's OMAP4 family of SoCs. * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ * Authors: Yong Zhi * Mythri pk <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "HDMI" @@ -249,15 +238,15 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi) } static void hdmi_display_set_timings(struct omap_dss_device *dssdev, - const struct videomode *vm) + const struct drm_display_mode *mode) { struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); mutex_lock(&hdmi->lock); - hdmi->cfg.vm = *vm; + drm_display_mode_to_videomode(mode, &hdmi->cfg.vm); - dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock); + dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000); mutex_unlock(&hdmi->lock); } @@ -312,26 +301,20 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd) hdmi_wp_audio_enable(&hd->wp, false); } -static int hdmi_display_enable(struct omap_dss_device *dssdev) +static void hdmi_display_enable(struct omap_dss_device *dssdev) { struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); unsigned long flags; - int r = 0; + int r; DSSDBG("ENTER hdmi_display_enable\n"); mutex_lock(&hdmi->lock); - if (!dssdev->dispc_channel_connected) { - DSSERR("failed to enable display: no output/manager\n"); - r = -ENODEV; - goto err0; - } - r = hdmi_power_on_full(hdmi); if (r) { DSSERR("failed to power on device\n"); - goto err0; + goto done; } if (hdmi->audio_configured) { @@ -351,12 +334,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) hdmi->display_enabled = true; spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); +done: mutex_unlock(&hdmi->lock); - return 0; - -err0: - mutex_unlock(&hdmi->lock); - return r; } static void hdmi_display_disable(struct omap_dss_device *dssdev) @@ -417,21 +396,12 @@ void hdmi4_core_disable(struct hdmi_core_data *core) static int hdmi_connect(struct omap_dss_device *src, struct omap_dss_device *dst) { - int r; - - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - dst->dispc_channel_connected = true; - return 0; + return omapdss_device_connect(dst->dss, dst, dst->next); } static void hdmi_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dst->dispc_channel_connected = false; - omapdss_device_disconnect(dst, dst->next); } @@ -698,7 +668,7 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi) out->dev = &hdmi->pdev->dev; out->id = OMAP_DSS_OUTPUT_HDMI; - out->output_type = OMAP_DISPLAY_TYPE_HDMI; + out->type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; out->ops = &hdmi_ops; @@ -706,19 +676,9 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi) out->of_ports = BIT(0); out->ops_flags = OMAP_DSS_DEVICE_OP_EDID; - out->next = omapdss_of_find_connected_device(out->dev->of_node, 0); - if (IS_ERR(out->next)) { - if (PTR_ERR(out->next) != -EPROBE_DEFER) - dev_err(out->dev, "failed to find video sink\n"); - return PTR_ERR(out->next); - } - - r = omapdss_output_validate(out); - if (r) { - omapdss_device_put(out->next); - out->next = NULL; + r = omapdss_device_init_output(out); + if (r < 0) return r; - } omapdss_device_register(out); @@ -729,9 +689,8 @@ static void hdmi4_uninit_output(struct omap_hdmi *hdmi) { struct omap_dss_device *out = &hdmi->output; - if (out->next) - omapdss_device_put(out->next); omapdss_device_unregister(out); + omapdss_device_cleanup_output(out); } static int hdmi4_probe_of(struct omap_hdmi *hdmi) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c index 340383150fb9..ebf9c96d43ee 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c @@ -175,6 +175,7 @@ static int hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) REG_FLD_MOD(core->base, HDMI_CORE_SYS_INTR_UNMASK4, 0, 3, 3); hdmi_wp_clear_irqenable(core->wp, HDMI_IRQ_CORE); hdmi_wp_set_irqstatus(core->wp, HDMI_IRQ_CORE); + REG_FLD_MOD(core->wp->base, HDMI_WP_CLK, 0, 5, 0); hdmi4_core_disable(core); return 0; } @@ -182,16 +183,24 @@ static int hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) if (err) return err; + /* + * Initialize CEC clock divider: CEC needs 2MHz clock hence + * set the divider to 24 to get 48/24=2MHz clock + */ + REG_FLD_MOD(core->wp->base, HDMI_WP_CLK, 0x18, 5, 0); + /* Clear TX FIFO */ if (!hdmi_cec_clear_tx_fifo(adap)) { pr_err("cec-%s: could not clear TX FIFO\n", adap->name); - return -EIO; + err = -EIO; + goto err_disable_clk; } /* Clear RX FIFO */ if (!hdmi_cec_clear_rx_fifo(adap)) { pr_err("cec-%s: could not clear RX FIFO\n", adap->name); - return -EIO; + err = -EIO; + goto err_disable_clk; } /* Clear CEC interrupts */ @@ -236,6 +245,12 @@ static int hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) hdmi_write_reg(core->base, HDMI_CEC_INT_STATUS_1, temp); } return 0; + +err_disable_clk: + REG_FLD_MOD(core->wp->base, HDMI_WP_CLK, 0, 5, 0); + hdmi4_core_disable(core); + + return err; } static int hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) @@ -333,11 +348,8 @@ int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core, return ret; core->wp = wp; - /* - * Initialize CEC clock divider: CEC needs 2MHz clock hence - * set the devider to 24 to get 48/24=2MHz clock - */ - REG_FLD_MOD(core->wp->base, HDMI_WP_CLK, 0x18, 5, 0); + /* Disable clock initially, hdmi_cec_adap_enable() manages it */ + REG_FLD_MOD(core->wp->base, HDMI_WP_CLK, 0, 5, 0); ret = cec_register_adapter(core->adap, &pdev->dev); if (ret < 0) { diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c index 813ba42f2753..ea5d5c228534 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI TI81xx, TI38xx, TI OMAP4 etc IP driver Library * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ * Authors: Yong Zhi * Mythri pk <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "HDMICORE" @@ -553,8 +542,9 @@ static void hdmi_core_audio_config(struct hdmi_core_data *core, } /* Set ACR clock divisor */ - REG_FLD_MOD(av_base, - HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0); + if (cfg->use_mclk) + REG_FLD_MOD(av_base, HDMI_CORE_AV_FREQ_SVAL, + cfg->mclk_mode, 2, 0); r = hdmi_read_reg(av_base, HDMI_CORE_AV_ACR_CTRL); /* @@ -686,7 +676,7 @@ int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, struct hdmi_audio_format audio_format; struct hdmi_audio_dma audio_dma; struct hdmi_core_audio_config acore; - int err, n, cts, channel_count; + int n, cts, channel_count; unsigned int fs_nr; bool word_length_16b = false; @@ -708,7 +698,7 @@ int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, else acore.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT; /* - * The I2S input word length is twice the lenght given in the IEC-60958 + * The I2S input word length is twice the length given in the IEC-60958 * status word. If the word size is greater than * 20 bits, increment by one. */ @@ -748,7 +738,7 @@ int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, return -EINVAL; } - err = hdmi_compute_acr(pclk, fs_nr, &n, &cts); + hdmi_compute_acr(pclk, fs_nr, &n, &cts); /* Audio clock regeneration settings */ acore.n = n; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h index 337a317c1a27..11c4b7ba1eee 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * HDMI header definition for OMAP4 HDMI core IP * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _HDMI4_CORE_H_ diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 9e8556f67a29..d9463b332554 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI driver for OMAP5 * @@ -8,18 +9,6 @@ * Mythri pk * Archit Taneja <[email protected]> * Tomi Valkeinen <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "HDMI" @@ -248,15 +237,15 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi) } static void hdmi_display_set_timings(struct omap_dss_device *dssdev, - const struct videomode *vm) + const struct drm_display_mode *mode) { struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); mutex_lock(&hdmi->lock); - hdmi->cfg.vm = *vm; + drm_display_mode_to_videomode(mode, &hdmi->cfg.vm); - dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock); + dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000); mutex_unlock(&hdmi->lock); } @@ -320,26 +309,20 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd) REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2); } -static int hdmi_display_enable(struct omap_dss_device *dssdev) +static void hdmi_display_enable(struct omap_dss_device *dssdev) { struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); unsigned long flags; - int r = 0; + int r; DSSDBG("ENTER hdmi_display_enable\n"); mutex_lock(&hdmi->lock); - if (!dssdev->dispc_channel_connected) { - DSSERR("failed to enable display: no output/manager\n"); - r = -ENODEV; - goto err0; - } - r = hdmi_power_on_full(hdmi); if (r) { DSSERR("failed to power on device\n"); - goto err0; + goto done; } if (hdmi->audio_configured) { @@ -359,12 +342,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) hdmi->display_enabled = true; spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); +done: mutex_unlock(&hdmi->lock); - return 0; - -err0: - mutex_unlock(&hdmi->lock); - return r; } static void hdmi_display_disable(struct omap_dss_device *dssdev) @@ -422,21 +401,12 @@ static void hdmi_core_disable(struct omap_hdmi *hdmi) static int hdmi_connect(struct omap_dss_device *src, struct omap_dss_device *dst) { - int r; - - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - dst->dispc_channel_connected = true; - return 0; + return omapdss_device_connect(dst->dss, dst, dst->next); } static void hdmi_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dst->dispc_channel_connected = false; - omapdss_device_disconnect(dst, dst->next); } @@ -682,7 +652,7 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi) out->dev = &hdmi->pdev->dev; out->id = OMAP_DSS_OUTPUT_HDMI; - out->output_type = OMAP_DISPLAY_TYPE_HDMI; + out->type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; out->ops = &hdmi_ops; @@ -690,19 +660,9 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi) out->of_ports = BIT(0); out->ops_flags = OMAP_DSS_DEVICE_OP_EDID; - out->next = omapdss_of_find_connected_device(out->dev->of_node, 0); - if (IS_ERR(out->next)) { - if (PTR_ERR(out->next) != -EPROBE_DEFER) - dev_err(out->dev, "failed to find video sink\n"); - return PTR_ERR(out->next); - } - - r = omapdss_output_validate(out); - if (r) { - omapdss_device_put(out->next); - out->next = NULL; + r = omapdss_device_init_output(out); + if (r < 0) return r; - } omapdss_device_register(out); @@ -713,9 +673,8 @@ static void hdmi5_uninit_output(struct omap_hdmi *hdmi) { struct omap_dss_device *out = &hdmi->output; - if (out->next) - omapdss_device_put(out->next); omapdss_device_unregister(out); + omapdss_device_cleanup_output(out); } 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 02efabc7ed76..ff4d35c8771f 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP5 HDMI CORE IP driver library * @@ -7,18 +8,6 @@ * Mythri pk * Archit Taneja <[email protected]> * Tomi Valkeinen <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> @@ -34,24 +23,12 @@ #include "hdmi5_core.h" -/* only 24 bit color depth used for now */ -static const struct csc_table csc_table_deepcolor[] = { - /* HDMI_DEEP_COLOR_24BIT */ - [0] = { 7036, 0, 0, 32, 0, 7036, 0, 32, 0, 0, 7036, 32, }, - /* HDMI_DEEP_COLOR_30BIT */ - [1] = { 7015, 0, 0, 128, 0, 7015, 0, 128, 0, 0, 7015, 128, }, - /* HDMI_DEEP_COLOR_36BIT */ - [2] = { 7010, 0, 0, 512, 0, 7010, 0, 512, 0, 0, 7010, 512, }, - /* FULL RANGE */ - [3] = { 8192, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 8192, 0, }, -}; - static void hdmi_core_ddc_init(struct hdmi_core_data *core) { void __iomem *base = core->base; const unsigned long long iclk = 266000000; /* DSS L3 ICLK */ - const unsigned int ss_scl_high = 4600; /* ns */ - const unsigned int ss_scl_low = 5400; /* ns */ + const unsigned int ss_scl_high = 4700; /* ns */ + const unsigned int ss_scl_low = 5500; /* ns */ const unsigned int fs_scl_high = 600; /* ns */ const unsigned int fs_scl_low = 1300; /* ns */ const unsigned int sda_hold = 1000; /* ns */ @@ -408,14 +385,6 @@ static void hdmi_core_config_video_packetizer(struct hdmi_core_data *core) REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 0 : 2, 1, 0); } -static void hdmi_core_config_csc(struct hdmi_core_data *core) -{ - int clr_depth = 0; /* 24 bit color depth */ - - /* CSC_COLORDEPTH */ - REG_FLD_MOD(core->base, HDMI_CORE_CSC_SCALE, clr_depth, 7, 4); -} - static void hdmi_core_config_video_sampler(struct hdmi_core_data *core) { int video_mapping = 1; /* for 24 bit color depth */ @@ -480,47 +449,67 @@ static void hdmi_core_write_avi_infoframe(struct hdmi_core_data *core, REG_FLD_MOD(base, HDMI_CORE_FC_PRCONF, pr, 3, 0); } -static void hdmi_core_csc_config(struct hdmi_core_data *core, - struct csc_table csc_coeff) +static void hdmi_core_write_csc(struct hdmi_core_data *core, + const struct csc_table *csc_coeff) { void __iomem *base = core->base; - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A1_MSB, csc_coeff.a1 >> 8 , 6, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A1_LSB, csc_coeff.a1, 7, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A2_MSB, csc_coeff.a2 >> 8, 6, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A2_LSB, csc_coeff.a2, 7, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A3_MSB, csc_coeff.a3 >> 8, 6, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A3_LSB, csc_coeff.a3, 7, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A4_MSB, csc_coeff.a4 >> 8, 6, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A4_LSB, csc_coeff.a4, 7, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B1_MSB, csc_coeff.b1 >> 8, 6, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B1_LSB, csc_coeff.b1, 7, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B2_MSB, csc_coeff.b2 >> 8, 6, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B2_LSB, csc_coeff.b2, 7, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B3_MSB, csc_coeff.b3 >> 8, 6, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B3_LSB, csc_coeff.b3, 7, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B4_MSB, csc_coeff.b4 >> 8, 6, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B4_LSB, csc_coeff.b4, 7, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C1_MSB, csc_coeff.c1 >> 8, 6, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C1_LSB, csc_coeff.c1, 7, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C2_MSB, csc_coeff.c2 >> 8, 6, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C2_LSB, csc_coeff.c2, 7, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C3_MSB, csc_coeff.c3 >> 8, 6, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C3_LSB, csc_coeff.c3, 7, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C4_MSB, csc_coeff.c4 >> 8, 6, 0); - REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C4_LSB, csc_coeff.c4, 7, 0); - + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A1_MSB, csc_coeff->a1 >> 8, 6, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A1_LSB, csc_coeff->a1, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A2_MSB, csc_coeff->a2 >> 8, 6, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A2_LSB, csc_coeff->a2, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A3_MSB, csc_coeff->a3 >> 8, 6, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A3_LSB, csc_coeff->a3, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A4_MSB, csc_coeff->a4 >> 8, 6, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A4_LSB, csc_coeff->a4, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B1_MSB, csc_coeff->b1 >> 8, 6, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B1_LSB, csc_coeff->b1, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B2_MSB, csc_coeff->b2 >> 8, 6, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B2_LSB, csc_coeff->b2, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B3_MSB, csc_coeff->b3 >> 8, 6, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B3_LSB, csc_coeff->b3, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B4_MSB, csc_coeff->b4 >> 8, 6, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B4_LSB, csc_coeff->b4, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C1_MSB, csc_coeff->c1 >> 8, 6, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C1_LSB, csc_coeff->c1, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C2_MSB, csc_coeff->c2 >> 8, 6, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C2_LSB, csc_coeff->c2, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C3_MSB, csc_coeff->c3 >> 8, 6, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C3_LSB, csc_coeff->c3, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C4_MSB, csc_coeff->c4 >> 8, 6, 0); + REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C4_LSB, csc_coeff->c4, 7, 0); + + /* enable CSC */ REG_FLD_MOD(base, HDMI_CORE_MC_FLOWCTRL, 0x1, 0, 0); } -static void hdmi_core_configure_range(struct hdmi_core_data *core) +static void hdmi_core_configure_range(struct hdmi_core_data *core, + enum hdmi_quantization_range range) { - struct csc_table csc_coeff = { 0 }; + static const struct csc_table csc_limited_range = { + 7036, 0, 0, 32, 0, 7036, 0, 32, 0, 0, 7036, 32 + }; + static const struct csc_table csc_full_range = { + 8192, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 8192, 0 + }; + const struct csc_table *csc_coeff; + + /* CSC_COLORDEPTH = 24 bits*/ + REG_FLD_MOD(core->base, HDMI_CORE_CSC_SCALE, 0, 7, 4); + + switch (range) { + case HDMI_QUANTIZATION_RANGE_FULL: + csc_coeff = &csc_full_range; + break; - /* support limited range with 24 bit color depth for now */ - csc_coeff = csc_table_deepcolor[0]; + case HDMI_QUANTIZATION_RANGE_DEFAULT: + case HDMI_QUANTIZATION_RANGE_LIMITED: + default: + csc_coeff = &csc_limited_range; + break; + } - hdmi_core_csc_config(core, csc_coeff); + hdmi_core_write_csc(core, csc_coeff); } static void hdmi_core_enable_video_path(struct hdmi_core_data *core) @@ -611,9 +600,20 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, struct videomode vm; struct hdmi_video_format video_format; struct hdmi_core_vid_config v_core_cfg; + enum hdmi_quantization_range range; hdmi_core_mask_interrupts(core); + if (cfg->hdmi_dvi_mode == HDMI_HDMI) { + char vic = cfg->infoframe.video_code; + + /* All CEA modes other than VIC 1 use limited quantization range. */ + range = vic > 1 ? HDMI_QUANTIZATION_RANGE_LIMITED : + HDMI_QUANTIZATION_RANGE_FULL; + } else { + range = HDMI_QUANTIZATION_RANGE_FULL; + } + hdmi_core_init(&v_core_cfg, cfg); hdmi_wp_init_vid_fmt_timings(&video_format, &vm, cfg); @@ -627,9 +627,8 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, hdmi_wp_video_config_interface(wp, &vm); - /* support limited range with 24 bit color depth for now */ - hdmi_core_configure_range(core); - cfg->infoframe.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED; + hdmi_core_configure_range(core, range); + cfg->infoframe.quantization_range = range; /* * configure core video part, set software reset in the core @@ -639,7 +638,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, hdmi_core_video_config(core, &v_core_cfg); hdmi_core_config_video_packetizer(core); - hdmi_core_config_csc(core); hdmi_core_config_video_sampler(core); if (cfg->hdmi_dvi_mode == HDMI_HDMI) @@ -809,7 +807,7 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, struct hdmi_audio_format audio_format; struct hdmi_audio_dma audio_dma; struct hdmi_core_audio_config core_cfg; - int err, n, cts, channel_count; + int n, cts, channel_count; unsigned int fs_nr; bool word_length_16b = false; @@ -852,7 +850,7 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, return -EINVAL; } - err = hdmi_compute_acr(pclk, fs_nr, &n, &cts); + hdmi_compute_acr(pclk, fs_nr, &n, &cts); core_cfg.n = n; core_cfg.cts = cts; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h index f2f1022c5516..f10b8a283011 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * HDMI driver definition for TI OMAP5 processors. * * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _HDMI5_CORE_H_ diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c index 9915923a53bd..00bbf24488c1 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI PHY * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c index e7be3707d147..cf2b000f397f 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI PLL * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #define DSS_SUBSYS_NAME "HDMIPLL" diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c index 100efb9f08c6..32f45f4f569d 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI wrapper * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #define DSS_SUBSYS_NAME "HDMIWP" diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c index 3bfb95d230e0..31502857f013 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c +++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ * Author: Tomi Valkeinen <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ /* @@ -184,6 +173,16 @@ 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" }, + {}, +}; + static int __init omapdss_boot_init(void) { struct device_node *dss, *child; @@ -210,7 +209,7 @@ static int __init omapdss_boot_init(void) n = list_first_entry(&dss_conv_list, struct dss_conv_node, list); - if (!n->root) + if (of_match_node(omapdss_of_fixups_whitelist, n->node)) omapdss_omapify_node(n->node); list_del(&n->list); diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 33e15cb77efa..79f6b195c7cf 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -1,25 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ * Author: Tomi Valkeinen <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAP_DRM_DSS_H #define __OMAP_DRM_DSS_H #include <linux/list.h> -#include <linux/kobject.h> #include <linux/device.h> #include <linux/interrupt.h> #include <video/videomode.h> @@ -68,6 +56,7 @@ struct dss_lcd_mgr_config; struct snd_aes_iec958; struct snd_cea_861_aud_if; struct hdmi_avi_infoframe; +struct drm_connector; enum omap_display_type { OMAP_DISPLAY_TYPE_NONE = 0, @@ -360,15 +349,15 @@ struct omap_dss_device_ops { void (*disconnect)(struct omap_dss_device *dssdev, struct omap_dss_device *dst); - int (*enable)(struct omap_dss_device *dssdev); + 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 videomode *vm); - void (*get_timings)(struct omap_dss_device *dssdev, - struct videomode *vm); + struct drm_display_mode *mode); void (*set_timings)(struct omap_dss_device *dssdev, - const struct videomode *vm); + const struct drm_display_mode *mode); bool (*detect)(struct omap_dss_device *dssdev); @@ -380,6 +369,9 @@ struct omap_dss_device_ops { 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; @@ -390,42 +382,40 @@ struct omap_dss_device_ops { * 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 readind EDID + * @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), -}; - -enum omap_dss_device_type { - OMAP_DSS_DEVICE_TYPE_OUTPUT = (1 << 0), - OMAP_DSS_DEVICE_TYPE_DISPLAY = (1 << 1), + OMAP_DSS_DEVICE_OP_MODES = BIT(3), }; struct omap_dss_device { - struct kobject kobj; struct device *dev; struct module *owner; struct dss_device *dss; - struct omap_dss_device *src; - struct omap_dss_device *dst; struct omap_dss_device *next; + struct drm_bridge *bridge; + struct drm_panel *panel; struct list_head list; - unsigned int alias_id; - + /* + * DSS type that this device generates (for DSS internal devices) or + * requires (for external encoders, connectors and panels). Must be a + * non-zero (different than OMAP_DISPLAY_TYPE_NONE) value. + */ enum omap_display_type type; + /* - * DSS output type that this device generates (for DSS internal devices) - * or requires (for external encoders). Must be OMAP_DISPLAY_TYPE_NONE - * for display devices (connectors and panels) and to non-zero value for - * all other devices. + * True if the device is a display (panel or connector) at the end of + * the pipeline, false otherwise. */ - enum omap_display_type output_type; + bool display; const char *name; @@ -434,9 +424,6 @@ struct omap_dss_device { unsigned long ops_flags; u32 bus_flags; - /* helper variable for driver suspend/resume */ - bool activate_after_resume; - enum omap_display_caps caps; enum omap_dss_display_state state; @@ -445,7 +432,6 @@ struct omap_dss_device { /* DISPC channel for this output */ enum omap_channel dispc_channel; - bool dispc_channel_connected; /* output instance */ enum omap_dss_output_id id; @@ -465,9 +451,6 @@ struct omap_dss_driver { int (*memory_read)(struct omap_dss_device *dssdev, void *buf, size_t size, u16 x, u16 y, u16 w, u16 h); - - void (*get_size)(struct omap_dss_device *dssdev, - unsigned int *width, unsigned int *height); }; struct dss_device *omapdss_get_dss(void); @@ -477,32 +460,35 @@ static inline bool omapdss_is_initialized(void) return !!omapdss_get_dss(); } -#define for_each_dss_display(d) \ - while ((d = omapdss_device_get_next(d, OMAP_DSS_DEVICE_TYPE_DISPLAY)) != NULL) 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); void omapdss_device_register(struct omap_dss_device *dssdev); void omapdss_device_unregister(struct omap_dss_device *dssdev); struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev); void omapdss_device_put(struct omap_dss_device *dssdev); -struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src, - unsigned int port); -struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from, - enum omap_dss_device_type type); +struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node); int omapdss_device_connect(struct dss_device *dss, struct omap_dss_device *src, 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); int omap_dss_get_num_overlays(void); #define for_each_dss_output(d) \ - while ((d = omapdss_device_get_next(d, OMAP_DSS_DEVICE_TYPE_OUTPUT)) != NULL) -int omapdss_output_validate(struct omap_dss_device *out); + 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); +void omapdss_device_cleanup_output(struct omap_dss_device *out); typedef void (*omap_dispc_isr_t) (void *arg, u32 mask); int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask); @@ -511,11 +497,6 @@ int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask); int omapdss_compat_init(void); void omapdss_compat_uninit(void); -static inline bool omapdss_device_is_connected(struct omap_dss_device *dssdev) -{ - return dssdev->src; -} - static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev) { return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE; diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index 18505bc70f7e..0693d34fca1b 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -1,39 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ * Author: Archit Taneja <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/bitops.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/of_graph.h> + +#include <drm/drm_bridge.h> +#include <drm/drm_panel.h> #include "dss.h" #include "omapdss.h" -int omapdss_output_validate(struct omap_dss_device *out) +int omapdss_device_init_output(struct omap_dss_device *out) { - if (out->next && out->output_type != out->next->type) { + struct device_node *remote_node; + + remote_node = of_graph_get_remote_node(out->dev->of_node, + ffs(out->of_ports) - 1, 0); + if (!remote_node) { + dev_dbg(out->dev, "failed to find video sink\n"); + return 0; + } + + out->next = omapdss_find_device_by_node(remote_node); + out->bridge = of_drm_find_bridge(remote_node); + out->panel = of_drm_find_panel(remote_node); + if (IS_ERR(out->panel)) + out->panel = NULL; + + of_node_put(remote_node); + + 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; } - return 0; + return out->next || out->bridge || out->panel ? 0 : -EPROBE_DEFER; +} +EXPORT_SYMBOL(omapdss_device_init_output); + +void omapdss_device_cleanup_output(struct omap_dss_device *out) +{ + if (out->next) + omapdss_device_put(out->next); } -EXPORT_SYMBOL(omapdss_output_validate); +EXPORT_SYMBOL(omapdss_device_cleanup_output); int dss_install_mgr_ops(struct dss_device *dss, const struct dss_mgr_ops *mgr_ops, diff --git a/drivers/gpu/drm/omapdrm/dss/pll.c b/drivers/gpu/drm/omapdrm/dss/pll.c index ff362b38bf0d..1212f3cc52d1 100644 --- a/drivers/gpu/drm/omapdrm/dss/pll.c +++ b/drivers/gpu/drm/omapdrm/dss/pll.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "PLL" diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index b2fe2387037a..3b447c01fa2a 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "SDI" @@ -37,7 +26,7 @@ struct sdi_device { struct regulator *vdds_sdi_reg; struct dss_lcd_mgr_config mgr_config; - struct videomode vm; + unsigned long pixelclock; int datapairs; struct omap_dss_device output; @@ -129,27 +118,22 @@ static void sdi_config_lcd_manager(struct sdi_device *sdi) dss_mgr_set_lcd_config(&sdi->output, &sdi->mgr_config); } -static int sdi_display_enable(struct omap_dss_device *dssdev) +static void sdi_display_enable(struct omap_dss_device *dssdev) { struct sdi_device *sdi = dssdev_to_sdi(dssdev); struct dispc_clock_info dispc_cinfo; unsigned long fck; int r; - if (!sdi->output.dispc_channel_connected) { - DSSERR("failed to enable display: no output/manager\n"); - return -ENODEV; - } - r = regulator_enable(sdi->vdds_sdi_reg); if (r) - goto err_reg_enable; + return; r = dispc_runtime_get(sdi->dss->dispc); if (r) goto err_get_dispc; - r = sdi_calc_clock_div(sdi, sdi->vm.pixelclock, &fck, &dispc_cinfo); + r = sdi_calc_clock_div(sdi, sdi->pixelclock, &fck, &dispc_cinfo); if (r) goto err_calc_clock_div; @@ -185,7 +169,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_mgr_enable; - return 0; + return; err_mgr_enable: dss_sdi_disable(sdi->dss); @@ -195,8 +179,6 @@ err_calc_clock_div: dispc_runtime_put(sdi->dss->dispc); err_get_dispc: regulator_disable(sdi->vdds_sdi_reg); -err_reg_enable: - return r; } static void sdi_display_disable(struct omap_dss_device *dssdev) @@ -213,36 +195,37 @@ static void sdi_display_disable(struct omap_dss_device *dssdev) } static void sdi_set_timings(struct omap_dss_device *dssdev, - const struct videomode *vm) + const struct drm_display_mode *mode) { struct sdi_device *sdi = dssdev_to_sdi(dssdev); - sdi->vm = *vm; + sdi->pixelclock = mode->clock * 1000; } static int sdi_check_timings(struct omap_dss_device *dssdev, - struct videomode *vm) + struct drm_display_mode *mode) { 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; - if (vm->pixelclock == 0) + if (pixelclock == 0) return -EINVAL; - r = sdi_calc_clock_div(sdi, vm->pixelclock, &fck, &dispc_cinfo); + 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 != vm->pixelclock) { + if (pck != pixelclock) { DSSWARN("Pixel clock adjusted from %lu Hz to %lu Hz\n", - vm->pixelclock, pck); + pixelclock, pck); - vm->pixelclock = pck; + mode->clock = pck / 1000; } return 0; @@ -251,21 +234,12 @@ static int sdi_check_timings(struct omap_dss_device *dssdev, static int sdi_connect(struct omap_dss_device *src, struct omap_dss_device *dst) { - int r; - - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - dst->dispc_channel_connected = true; - return 0; + return omapdss_device_connect(dst->dss, dst, dst->next); } static void sdi_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dst->dispc_channel_connected = false; - omapdss_device_disconnect(dst, dst->next); } @@ -287,29 +261,19 @@ static int sdi_init_output(struct sdi_device *sdi) out->dev = &sdi->pdev->dev; out->id = OMAP_DSS_OUTPUT_SDI; - out->output_type = OMAP_DISPLAY_TYPE_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->owner = THIS_MODULE; - out->bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE /* 15.5.9.1.2 */ - | DRM_BUS_FLAG_SYNC_POSEDGE; - - out->next = omapdss_of_find_connected_device(out->dev->of_node, 1); - if (IS_ERR(out->next)) { - if (PTR_ERR(out->next) != -EPROBE_DEFER) - dev_err(out->dev, "failed to find video sink\n"); - return PTR_ERR(out->next); - } + out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE /* 15.5.9.1.2 */ + | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE; - r = omapdss_output_validate(out); - if (r) { - omapdss_device_put(out->next); - out->next = NULL; + r = omapdss_device_init_output(out); + if (r < 0) return r; - } omapdss_device_register(out); @@ -318,9 +282,8 @@ static int sdi_init_output(struct sdi_device *sdi) static void sdi_uninit_output(struct sdi_device *sdi) { - if (sdi->output.next) - omapdss_device_put(sdi->output.next); omapdss_device_unregister(&sdi->output); + omapdss_device_cleanup_output(&sdi->output); } 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 b5f52727f8b1..596a297d5813 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <[email protected]> * * VENC settings from TI's DSS driver - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "VENC" @@ -267,63 +256,40 @@ enum venc_videomode { VENC_MODE_NTSC, }; -static const struct videomode omap_dss_pal_vm = { - .hactive = 720, - .vactive = 574, - .pixelclock = 13500000, - .hsync_len = 64, - .hfront_porch = 12, - .hback_porch = 68, - .vsync_len = 5, - .vfront_porch = 5, - .vback_porch = 41, - - .flags = DISPLAY_FLAGS_INTERLACED | DISPLAY_FLAGS_HSYNC_LOW | - DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_DE_HIGH | - DISPLAY_FLAGS_PIXDATA_POSEDGE | - DISPLAY_FLAGS_SYNC_NEGEDGE, +static const struct drm_display_mode omap_dss_pal_mode = { + .hdisplay = 720, + .hsync_start = 732, + .hsync_end = 796, + .htotal = 864, + .vdisplay = 574, + .vsync_start = 579, + .vsync_end = 584, + .vtotal = 625, + .clock = 13500, + + .flags = DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC | + DRM_MODE_FLAG_NVSYNC, }; -static const struct videomode omap_dss_ntsc_vm = { - .hactive = 720, - .vactive = 482, - .pixelclock = 13500000, - .hsync_len = 64, - .hfront_porch = 16, - .hback_porch = 58, - .vsync_len = 6, - .vfront_porch = 6, - .vback_porch = 31, - - .flags = DISPLAY_FLAGS_INTERLACED | DISPLAY_FLAGS_HSYNC_LOW | - DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_DE_HIGH | - DISPLAY_FLAGS_PIXDATA_POSEDGE | - DISPLAY_FLAGS_SYNC_NEGEDGE, +static const struct drm_display_mode omap_dss_ntsc_mode = { + .hdisplay = 720, + .hsync_start = 736, + .hsync_end = 800, + .htotal = 858, + .vdisplay = 482, + .vsync_start = 488, + .vsync_end = 494, + .vtotal = 525, + .clock = 13500, + + .flags = DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC | + DRM_MODE_FLAG_NVSYNC, }; -static enum venc_videomode venc_get_videomode(const struct videomode *vm) -{ - if (!(vm->flags & DISPLAY_FLAGS_INTERLACED)) - return VENC_MODE_UNKNOWN; - - if (vm->pixelclock == omap_dss_pal_vm.pixelclock && - vm->hactive == omap_dss_pal_vm.hactive && - vm->vactive == omap_dss_pal_vm.vactive) - return VENC_MODE_PAL; - - if (vm->pixelclock == omap_dss_ntsc_vm.pixelclock && - vm->hactive == omap_dss_ntsc_vm.hactive && - vm->vactive == omap_dss_ntsc_vm.vactive) - return VENC_MODE_NTSC; - - return VENC_MODE_UNKNOWN; -} - struct venc_device { struct platform_device *pdev; void __iomem *base; struct mutex venc_lock; - u32 wss_data; struct regulator *vdda_dac_reg; struct dss_device *dss; @@ -331,7 +297,7 @@ struct venc_device { struct clk *tv_dac_clk; - struct videomode vm; + const struct venc_config *config; enum omap_dss_venc_type type; bool invert_polarity; bool requires_tv_dac_clk; @@ -367,8 +333,7 @@ static void venc_write_config(struct venc_device *venc, venc_write_reg(venc, VENC_BLACK_LEVEL, config->black_level); venc_write_reg(venc, VENC_BLANK_LEVEL, config->blank_level); venc_write_reg(venc, VENC_M_CONTROL, config->m_control); - venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | - venc->wss_data); + venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data); venc_write_reg(venc, VENC_S_CARR, config->s_carr); venc_write_reg(venc, VENC_L21__WC_CTL, config->l21__wc_ctl); venc_write_reg(venc, VENC_SAVID__EAVID, config->savid__eavid); @@ -452,18 +417,6 @@ static void venc_runtime_put(struct venc_device *venc) WARN_ON(r < 0 && r != -ENOSYS); } -static const struct venc_config *venc_timings_to_config(const struct videomode *vm) -{ - switch (venc_get_videomode(vm)) { - default: - WARN_ON_ONCE(1); - case VENC_MODE_PAL: - return &venc_config_pal_trm; - case VENC_MODE_NTSC: - return &venc_config_ntsc_trm; - } -} - static int venc_power_on(struct venc_device *venc) { u32 l; @@ -474,7 +427,7 @@ static int venc_power_on(struct venc_device *venc) goto err0; venc_reset(venc); - venc_write_config(venc, venc_timings_to_config(&venc->vm)); + venc_write_config(venc, venc->config); dss_set_venc_output(venc->dss, venc->type); dss_set_dac_pwrdn_bgz(venc->dss, 1); @@ -524,33 +477,17 @@ static void venc_power_off(struct venc_device *venc) venc_runtime_put(venc); } -static int venc_display_enable(struct omap_dss_device *dssdev) +static void venc_display_enable(struct omap_dss_device *dssdev) { struct venc_device *venc = dssdev_to_venc(dssdev); - int r; DSSDBG("venc_display_enable\n"); mutex_lock(&venc->venc_lock); - if (!dssdev->dispc_channel_connected) { - DSSERR("Failed to enable display: no output/manager\n"); - r = -ENODEV; - goto err0; - } - - r = venc_power_on(venc); - if (r) - goto err0; - - venc->wss_data = 0; - - mutex_unlock(&venc->venc_lock); + venc_power_on(venc); - return 0; -err0: mutex_unlock(&venc->venc_lock); - return r; } static void venc_display_disable(struct omap_dss_device *dssdev) @@ -566,30 +503,70 @@ static void venc_display_disable(struct omap_dss_device *dssdev) mutex_unlock(&venc->venc_lock); } -static void venc_get_timings(struct omap_dss_device *dssdev, - struct videomode *vm) +static int venc_get_modes(struct omap_dss_device *dssdev, + struct drm_connector *connector) { - struct venc_device *venc = dssdev_to_venc(dssdev); + 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); + } - mutex_lock(&venc->venc_lock); - *vm = venc->vm; - mutex_unlock(&venc->venc_lock); + return ARRAY_SIZE(modes); +} + +static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mode) +{ + if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) + return VENC_MODE_UNKNOWN; + + if (mode->clock == omap_dss_pal_mode.clock && + mode->hdisplay == omap_dss_pal_mode.hdisplay && + mode->vdisplay == omap_dss_pal_mode.vdisplay) + return VENC_MODE_PAL; + + if (mode->clock == omap_dss_ntsc_mode.clock && + mode->hdisplay == omap_dss_ntsc_mode.hdisplay && + mode->vdisplay == omap_dss_ntsc_mode.vdisplay) + return VENC_MODE_NTSC; + + return VENC_MODE_UNKNOWN; } static void venc_set_timings(struct omap_dss_device *dssdev, - const struct videomode *vm) + 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); - /* Reset WSS data when the TV standard changes. */ - if (memcmp(&venc->vm, vm, sizeof(*vm))) - venc->wss_data = 0; + switch (venc_mode) { + default: + WARN_ON_ONCE(1); + /* Fall-through */ + case VENC_MODE_PAL: + venc->config = &venc_config_pal_trm; + break; - venc->vm = *vm; + case VENC_MODE_NTSC: + venc->config = &venc_config_ntsc_trm; + break; + } dispc_set_tv_pclk(venc->dss->dispc, 13500000); @@ -597,22 +574,26 @@ static void venc_set_timings(struct omap_dss_device *dssdev, } static int venc_check_timings(struct omap_dss_device *dssdev, - struct videomode *vm) + struct drm_display_mode *mode) { DSSDBG("venc_check_timings\n"); - switch (venc_get_videomode(vm)) { + switch (venc_get_videomode(mode)) { case VENC_MODE_PAL: - *vm = omap_dss_pal_vm; - return 0; + drm_mode_copy(mode, &omap_dss_pal_mode); + break; case VENC_MODE_NTSC: - *vm = omap_dss_ntsc_vm; - return 0; + 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) @@ -695,21 +676,12 @@ static int venc_get_clocks(struct venc_device *venc) static int venc_connect(struct omap_dss_device *src, struct omap_dss_device *dst) { - int r; - - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - dst->dispc_channel_connected = true; - return 0; + return omapdss_device_connect(dst->dss, dst, dst->next); } static void venc_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dst->dispc_channel_connected = false; - omapdss_device_disconnect(dst, dst->next); } @@ -721,8 +693,9 @@ static const struct omap_dss_device_ops venc_ops = { .disable = venc_display_disable, .check_timings = venc_check_timings, - .get_timings = venc_get_timings, .set_timings = venc_set_timings, + + .get_modes = venc_get_modes, }; /* ----------------------------------------------------------------------------- @@ -776,26 +749,17 @@ static int venc_init_output(struct venc_device *venc) out->dev = &venc->pdev->dev; out->id = OMAP_DSS_OUTPUT_VENC; - out->output_type = OMAP_DISPLAY_TYPE_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->ops_flags = OMAP_DSS_DEVICE_OP_MODES; - out->next = omapdss_of_find_connected_device(out->dev->of_node, 0); - if (IS_ERR(out->next)) { - if (PTR_ERR(out->next) != -EPROBE_DEFER) - dev_err(out->dev, "failed to find video sink\n"); - return PTR_ERR(out->next); - } - - r = omapdss_output_validate(out); - if (r) { - omapdss_device_put(out->next); - out->next = NULL; + r = omapdss_device_init_output(out); + if (r < 0) return r; - } omapdss_device_register(out); @@ -804,9 +768,8 @@ static int venc_init_output(struct venc_device *venc) static void venc_uninit_output(struct venc_device *venc) { - if (venc->output.next) - omapdss_device_put(venc->output.next); omapdss_device_unregister(&venc->output); + omapdss_device_cleanup_output(&venc->output); } static int venc_probe_of(struct venc_device *venc) @@ -878,8 +841,7 @@ static int venc_probe(struct platform_device *pdev) mutex_init(&venc->venc_lock); - venc->wss_data = 0; - venc->vm = omap_dss_pal_vm; + venc->config = &venc_config_pal_trm; venc_mem = platform_get_resource(venc->pdev, IORESOURCE_MEM, 0); venc->base = devm_ioremap_resource(&pdev->dev, venc_mem); diff --git a/drivers/gpu/drm/omapdrm/dss/video-pll.c b/drivers/gpu/drm/omapdrm/dss/video-pll.c index cb46311f92c9..a612e2696dbc 100644 --- a/drivers/gpu/drm/omapdrm/dss/video-pll.c +++ b/drivers/gpu/drm/omapdrm/dss/video-pll.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include <linux/clk.h> |