From 6778948f9de86c3cfaf36725a7c87dcff9ba247f Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 08:20:59 +0000 Subject: [PATCH] kernel_5.10 no rt --- kernel/drivers/gpu/drm/omapdrm/omap_drv.c | 479 +++++++++++++++++++++++++++++------------------------------ 1 files changed, 238 insertions(+), 241 deletions(-) diff --git a/kernel/drivers/gpu/drm/omapdrm/omap_drv.c b/kernel/drivers/gpu/drm/omapdrm/omap_drv.c index 1b6601e..53d5e18 100644 --- a/kernel/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/kernel/drivers/gpu/drm/omapdrm/omap_drv.c @@ -1,26 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob@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/>. */ +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/sort.h> #include <linux/sys_soc.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_crtc_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_bridge_connector.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_file.h> +#include <drm/drm_ioctl.h> +#include <drm/drm_panel.h> +#include <drm/drm_prime.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> #include "omap_dmm_tiler.h" #include "omap_drv.h" @@ -127,65 +127,66 @@ .atomic_commit = drm_atomic_helper_commit, }; -static int get_connector_type(struct omap_dss_device *dssdev) +static void omap_disconnect_pipelines(struct drm_device *ddev) { - switch (dssdev->type) { - case OMAP_DISPLAY_TYPE_HDMI: - return DRM_MODE_CONNECTOR_HDMIA; - case OMAP_DISPLAY_TYPE_DVI: - return DRM_MODE_CONNECTOR_DVID; - case OMAP_DISPLAY_TYPE_DSI: - return DRM_MODE_CONNECTOR_DSI; - case OMAP_DISPLAY_TYPE_DPI: - case OMAP_DISPLAY_TYPE_DBI: - return DRM_MODE_CONNECTOR_DPI; - case OMAP_DISPLAY_TYPE_VENC: - /* TODO: This could also be composite */ - return DRM_MODE_CONNECTOR_SVIDEO; - case OMAP_DISPLAY_TYPE_SDI: - return DRM_MODE_CONNECTOR_LVDS; - default: - return DRM_MODE_CONNECTOR_Unknown; + struct omap_drm_private *priv = ddev->dev_private; + unsigned int i; + + for (i = 0; i < priv->num_pipes; i++) { + struct omap_drm_pipeline *pipe = &priv->pipes[i]; + + omapdss_device_disconnect(NULL, pipe->output); + + omapdss_device_put(pipe->output); + pipe->output = NULL; } + + memset(&priv->channels, 0, sizeof(priv->channels)); + + priv->num_pipes = 0; } -static void omap_disconnect_dssdevs(void) +static int omap_connect_pipelines(struct drm_device *ddev) { - struct omap_dss_device *dssdev = NULL; - - for_each_dss_dev(dssdev) - dssdev->driver->disconnect(dssdev); -} - -static int omap_connect_dssdevs(void) -{ + struct omap_drm_private *priv = ddev->dev_private; + struct omap_dss_device *output = NULL; int r; - struct omap_dss_device *dssdev = NULL; - if (!omapdss_stack_is_ready()) - return -EPROBE_DEFER; - - for_each_dss_dev(dssdev) { - r = dssdev->driver->connect(dssdev); + for_each_dss_output(output) { + r = omapdss_device_connect(priv->dss, NULL, output); if (r == -EPROBE_DEFER) { - omap_dss_put_device(dssdev); - goto cleanup; + omapdss_device_put(output); + return r; } else if (r) { - dev_warn(dssdev->dev, "could not connect display: %s\n", - dssdev->name); + dev_warn(output->dev, "could not connect output %s\n", + output->name); + } else { + struct omap_drm_pipeline *pipe; + + pipe = &priv->pipes[priv->num_pipes++]; + pipe->output = omapdss_device_get(output); + + if (priv->num_pipes == ARRAY_SIZE(priv->pipes)) { + /* To balance the 'for_each_dss_output' loop */ + omapdss_device_put(output); + break; + } } } return 0; +} -cleanup: - /* - * if we are deferring probe, we disconnect the devices we previously - * connected - */ - omap_disconnect_dssdevs(); +static int omap_compare_pipelines(const void *a, const void *b) +{ + const struct omap_drm_pipeline *pipe1 = a; + const struct omap_drm_pipeline *pipe2 = b; - return r; + if (pipe1->alias_id > pipe2->alias_id) + return 1; + else if (pipe1->alias_id < pipe2->alias_id) + return -1; + return 0; } static int omap_modeset_init_properties(struct drm_device *dev) @@ -201,15 +202,40 @@ return 0; } +static int omap_display_id(struct omap_dss_device *output) +{ + struct device_node *node = NULL; + + if (output->next) { + struct omap_dss_device *display = output; + + while (display->next) + display = display->next; + + node = display->dev->of_node; + } else if (output->bridge) { + struct drm_bridge *bridge = output->bridge; + + while (drm_bridge_get_next_bridge(bridge)) + bridge = drm_bridge_get_next_bridge(bridge); + + node = bridge->of_node; + } + + return node ? of_alias_get_id(node, "display") : -ENODEV; +} + static int omap_modeset_init(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; - struct omap_dss_device *dssdev = NULL; int num_ovls = priv->dispc_ops->get_num_ovls(priv->dispc); int num_mgrs = priv->dispc_ops->get_num_mgrs(priv->dispc); - int num_crtcs, crtc_idx, plane_idx; + unsigned int i; int ret; u32 plane_crtc_mask; + + if (!omapdss_stack_is_ready()) + return -EPROBE_DEFER; drm_mode_config_init(dev); @@ -225,87 +251,114 @@ * configuration does not match the expectations or exceeds * the available resources, the configuration is rejected. */ - num_crtcs = 0; - for_each_dss_dev(dssdev) - if (omapdss_device_is_connected(dssdev)) - num_crtcs++; + ret = omap_connect_pipelines(dev); + if (ret < 0) + return ret; - if (num_crtcs > num_mgrs || num_crtcs > num_ovls || - num_crtcs > ARRAY_SIZE(priv->crtcs) || - num_crtcs > ARRAY_SIZE(priv->planes) || - num_crtcs > ARRAY_SIZE(priv->encoders) || - num_crtcs > ARRAY_SIZE(priv->connectors)) { + if (priv->num_pipes > num_mgrs || priv->num_pipes > num_ovls) { dev_err(dev->dev, "%s(): Too many connected displays\n", __func__); return -EINVAL; } - /* All planes can be put to any CRTC */ - plane_crtc_mask = (1 << num_crtcs) - 1; + /* Create all planes first. They can all be put to any CRTC. */ + plane_crtc_mask = (1 << priv->num_pipes) - 1; - dssdev = NULL; - - crtc_idx = 0; - plane_idx = 0; - for_each_dss_dev(dssdev) { - struct drm_connector *connector; - struct drm_encoder *encoder; - struct drm_plane *plane; - struct drm_crtc *crtc; - - if (!omapdss_device_is_connected(dssdev)) - continue; - - encoder = omap_encoder_init(dev, dssdev); - if (!encoder) - return -ENOMEM; - - connector = omap_connector_init(dev, - get_connector_type(dssdev), dssdev, encoder); - if (!connector) - return -ENOMEM; - - plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_PRIMARY, - plane_crtc_mask); - if (IS_ERR(plane)) - return PTR_ERR(plane); - - crtc = omap_crtc_init(dev, plane, dssdev); - if (IS_ERR(crtc)) - return PTR_ERR(crtc); - - drm_connector_attach_encoder(connector, encoder); - encoder->possible_crtcs = (1 << crtc_idx); - - priv->crtcs[priv->num_crtcs++] = crtc; - priv->planes[priv->num_planes++] = plane; - priv->encoders[priv->num_encoders++] = encoder; - priv->connectors[priv->num_connectors++] = connector; - - plane_idx++; - crtc_idx++; - } - - /* - * Create normal planes for the remaining overlays: - */ - for (; plane_idx < num_ovls; plane_idx++) { + for (i = 0; i < num_ovls; i++) { + enum drm_plane_type type = i < priv->num_pipes + ? DRM_PLANE_TYPE_PRIMARY + : DRM_PLANE_TYPE_OVERLAY; struct drm_plane *plane; if (WARN_ON(priv->num_planes >= ARRAY_SIZE(priv->planes))) return -EINVAL; - plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_OVERLAY, - plane_crtc_mask); + plane = omap_plane_init(dev, i, type, plane_crtc_mask); if (IS_ERR(plane)) return PTR_ERR(plane); priv->planes[priv->num_planes++] = plane; } - DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n", - priv->num_planes, priv->num_crtcs, priv->num_encoders, - priv->num_connectors); + /* + * Create the encoders, attach the bridges and get the pipeline alias + * IDs. + */ + for (i = 0; i < priv->num_pipes; i++) { + struct omap_drm_pipeline *pipe = &priv->pipes[i]; + int id; + + pipe->encoder = omap_encoder_init(dev, pipe->output); + if (!pipe->encoder) + return -ENOMEM; + + if (pipe->output->bridge) { + ret = drm_bridge_attach(pipe->encoder, + pipe->output->bridge, NULL, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret < 0) { + dev_err(priv->dev, + "unable to attach bridge %pOF\n", + pipe->output->bridge->of_node); + return ret; + } + } + + id = omap_display_id(pipe->output); + pipe->alias_id = id >= 0 ? id : i; + } + + /* Sort the pipelines by DT aliases. */ + sort(priv->pipes, priv->num_pipes, sizeof(priv->pipes[0]), + omap_compare_pipelines, NULL); + + /* + * Populate the pipeline lookup table by DISPC channel. Only one display + * is allowed per channel. + */ + for (i = 0; i < priv->num_pipes; ++i) { + struct omap_drm_pipeline *pipe = &priv->pipes[i]; + enum omap_channel channel = pipe->output->dispc_channel; + + if (WARN_ON(priv->channels[channel] != NULL)) + return -EINVAL; + + priv->channels[channel] = pipe; + } + + /* Create the connectors and CRTCs. */ + for (i = 0; i < priv->num_pipes; i++) { + struct omap_drm_pipeline *pipe = &priv->pipes[i]; + struct drm_encoder *encoder = pipe->encoder; + struct drm_crtc *crtc; + + if (pipe->output->next) { + pipe->connector = omap_connector_init(dev, pipe->output, + encoder); + if (!pipe->connector) + return -ENOMEM; + } else { + pipe->connector = drm_bridge_connector_init(dev, encoder); + if (IS_ERR(pipe->connector)) { + dev_err(priv->dev, + "unable to create bridge connector for %s\n", + pipe->output->name); + return PTR_ERR(pipe->connector); + } + } + + drm_connector_attach_encoder(pipe->connector, encoder); + + crtc = omap_crtc_init(dev, pipe, priv->planes[i]); + if (IS_ERR(crtc)) + return PTR_ERR(crtc); + + encoder->possible_crtcs = 1 << i; + pipe->crtc = crtc; + } + + DBG("registered %u planes, %u crtcs/encoders/connectors\n", + priv->num_planes, priv->num_pipes); dev->mode_config.min_width = 8; dev->mode_config.min_height = 2; @@ -332,29 +385,48 @@ return 0; } +static void omap_modeset_fini(struct drm_device *ddev) +{ + omap_drm_irq_uninstall(ddev); + + drm_mode_config_cleanup(ddev); +} + /* * Enable the HPD in external components if supported */ -static void omap_modeset_enable_external_hpd(void) +static void omap_modeset_enable_external_hpd(struct drm_device *ddev) { - struct omap_dss_device *dssdev = NULL; + struct omap_drm_private *priv = ddev->dev_private; + unsigned int i; - for_each_dss_dev(dssdev) { - if (dssdev->driver->enable_hpd) - dssdev->driver->enable_hpd(dssdev); + for (i = 0; i < priv->num_pipes; i++) { + struct drm_connector *connector = priv->pipes[i].connector; + + if (!connector) + continue; + + if (priv->pipes[i].output->bridge) + drm_bridge_connector_enable_hpd(connector); } } /* * Disable the HPD in external components if supported */ -static void omap_modeset_disable_external_hpd(void) +static void omap_modeset_disable_external_hpd(struct drm_device *ddev) { - struct omap_dss_device *dssdev = NULL; + struct omap_drm_private *priv = ddev->dev_private; + unsigned int i; - for_each_dss_dev(dssdev) { - if (dssdev->driver->disable_hpd) - dssdev->driver->disable_hpd(dssdev); + for (i = 0; i < priv->num_pipes; i++) { + struct drm_connector *connector = priv->pipes[i].connector; + + if (!connector) + continue; + + if (priv->pipes[i].output->bridge) + drm_bridge_connector_disable_hpd(connector); } } @@ -375,20 +447,6 @@ case OMAP_PARAM_CHIPSET_ID: args->value = priv->omaprev; break; - default: - DBG("unknown parameter %lld", args->param); - return -EINVAL; - } - - return 0; -} - -static int ioctl_set_param(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_omap_param *args = data; - - switch (args->param) { default: DBG("unknown parameter %lld", args->param); return -EINVAL; @@ -428,26 +486,26 @@ args->size = omap_gem_mmap_size(obj); args->offset = omap_gem_mmap_offset(obj); - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put(obj); return ret; } static const struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = { DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param, - DRM_AUTH | DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, drm_invalid_op, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), /* Deprecated, to be removed. */ DRM_IOCTL_DEF_DRV(OMAP_GEM_CPU_PREP, drm_noop, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), /* Deprecated, to be removed. */ DRM_IOCTL_DEF_DRV(OMAP_GEM_CPU_FINI, drm_noop, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(OMAP_GEM_INFO, ioctl_gem_info, - DRM_AUTH | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), }; /* @@ -482,7 +540,7 @@ }; static struct drm_driver omap_drm_driver = { - .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_RENDER, .open = dev_open, .lastclose = drm_fb_helper_lastclose, @@ -520,10 +578,17 @@ { const struct soc_device_attribute *soc; struct drm_device *ddev; - unsigned int i; int ret; DBG("%s", dev_name(dev)); + + /* Allocate and initialize the DRM device. */ + ddev = drm_dev_alloc(&omap_drm_driver, dev); + if (IS_ERR(ddev)) + return PTR_ERR(ddev); + + priv->ddev = ddev; + ddev->dev_private = priv; priv->dev = dev; priv->dss = omapdss_get_dss(); @@ -532,26 +597,12 @@ omap_crtc_pre_init(priv); - ret = omap_connect_dssdevs(); - if (ret) - goto err_crtc_uninit; - soc = soc_device_match(omapdrm_soc_devices); priv->omaprev = soc ? (unsigned int)soc->data : 0; priv->wq = alloc_ordered_workqueue("omapdrm", 0); mutex_init(&priv->list_lock); INIT_LIST_HEAD(&priv->obj_list); - - /* Allocate and initialize the DRM device. */ - ddev = drm_dev_alloc(&omap_drm_driver, priv->dev); - if (IS_ERR(ddev)) { - ret = PTR_ERR(ddev); - goto err_destroy_wq; - } - - priv->ddev = ddev; - ddev->dev_private = priv; /* Get memory bandwidth limits */ if (priv->dispc_ops->get_memory_bandwidth_limit) @@ -563,23 +614,20 @@ ret = omap_modeset_init(ddev); if (ret) { dev_err(priv->dev, "omap_modeset_init failed: ret=%d\n", ret); - goto err_free_drm_dev; + goto err_gem_deinit; } /* Initialize vblank handling, start with all CRTCs disabled. */ - ret = drm_vblank_init(ddev, priv->num_crtcs); + ret = drm_vblank_init(ddev, priv->num_pipes); if (ret) { dev_err(priv->dev, "could not init vblank\n"); goto err_cleanup_modeset; } - for (i = 0; i < priv->num_crtcs; i++) - drm_crtc_vblank_off(priv->crtcs[i]); - omap_fbdev_init(ddev); drm_kms_helper_poll_init(ddev); - omap_modeset_enable_external_hpd(); + omap_modeset_enable_external_hpd(ddev); /* * Register the DRM device with the core and the connectors with @@ -592,21 +640,18 @@ return 0; err_cleanup_helpers: - omap_modeset_disable_external_hpd(); + omap_modeset_disable_external_hpd(ddev); drm_kms_helper_poll_fini(ddev); omap_fbdev_fini(ddev); err_cleanup_modeset: - drm_mode_config_cleanup(ddev); - omap_drm_irq_uninstall(ddev); -err_free_drm_dev: + omap_modeset_fini(ddev); +err_gem_deinit: omap_gem_deinit(ddev); - drm_dev_unref(ddev); -err_destroy_wq: destroy_workqueue(priv->wq); - omap_disconnect_dssdevs(); -err_crtc_uninit: - omap_crtc_pre_uninit(); + omap_disconnect_pipelines(ddev); + omap_crtc_pre_uninit(priv); + drm_dev_put(ddev); return ret; } @@ -618,24 +663,22 @@ drm_dev_unregister(ddev); - omap_modeset_disable_external_hpd(); + omap_modeset_disable_external_hpd(ddev); drm_kms_helper_poll_fini(ddev); omap_fbdev_fini(ddev); drm_atomic_helper_shutdown(ddev); - drm_mode_config_cleanup(ddev); - - omap_drm_irq_uninstall(ddev); + omap_modeset_fini(ddev); omap_gem_deinit(ddev); - - drm_dev_unref(ddev); destroy_workqueue(priv->wq); - omap_disconnect_dssdevs(); - omap_crtc_pre_uninit(); + omap_disconnect_pipelines(ddev); + omap_crtc_pre_uninit(priv); + + drm_dev_put(ddev); } static int pdev_probe(struct platform_device *pdev) @@ -646,7 +689,7 @@ if (omapdss_is_initialized() == false) return -EPROBE_DEFER; - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (ret) { dev_err(&pdev->dev, "Failed to set the DMA mask\n"); return ret; @@ -677,54 +720,12 @@ } #ifdef CONFIG_PM_SLEEP -static int omap_drm_suspend_all_displays(void) -{ - struct omap_dss_device *dssdev = NULL; - - for_each_dss_dev(dssdev) { - if (!dssdev->driver) - continue; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - dssdev->driver->disable(dssdev); - dssdev->activate_after_resume = true; - } else { - dssdev->activate_after_resume = false; - } - } - - return 0; -} - -static int omap_drm_resume_all_displays(void) -{ - struct omap_dss_device *dssdev = NULL; - - for_each_dss_dev(dssdev) { - if (!dssdev->driver) - continue; - - if (dssdev->activate_after_resume) { - dssdev->driver->enable(dssdev); - dssdev->activate_after_resume = false; - } - } - - return 0; -} - static int omap_drm_suspend(struct device *dev) { struct omap_drm_private *priv = dev_get_drvdata(dev); struct drm_device *drm_dev = priv->ddev; - drm_kms_helper_poll_disable(drm_dev); - - drm_modeset_lock_all(drm_dev); - omap_drm_suspend_all_displays(); - drm_modeset_unlock_all(drm_dev); - - return 0; + return drm_mode_config_helper_suspend(drm_dev); } static int omap_drm_resume(struct device *dev) @@ -732,11 +733,7 @@ struct omap_drm_private *priv = dev_get_drvdata(dev); struct drm_device *drm_dev = priv->ddev; - drm_modeset_lock_all(drm_dev); - omap_drm_resume_all_displays(); - drm_modeset_unlock_all(drm_dev); - - drm_kms_helper_poll_enable(drm_dev); + drm_mode_config_helper_resume(drm_dev); return omap_gem_resume(drm_dev); } -- Gitblit v1.6.2