mirror of
https://git.yoctoproject.org/meta-arm
synced 2026-07-24 18:37:07 +00:00
785f8bf4c1
Add patches for SCMI, MHUv2 and DRM. Also update the kernel config to enable boot to Android home screen instead of just console. Change-Id: Ic2af15441667b967ef360d8410de94e83eb73de4 Signed-off-by: Anders Dellien <anders.dellien@arm.com> Signed-off-by: Jon Mason <jon.mason@arm.com>
365 lines
10 KiB
Diff
365 lines
10 KiB
Diff
From 7863ac1515009547bae3a66e0808e72b3bdcf8c8 Mon Sep 17 00:00:00 2001
|
|
From: Tushar Khandelwal <tushar.khandelwal@arm.com>
|
|
Date: Tue, 16 Jun 2020 12:39:06 +0000
|
|
Subject: [PATCH 1/9] drm: Add component-aware simple encoder
|
|
|
|
This is a simple DRM encoder that gets its connector timings information
|
|
from a OF subnode in the device tree and exposes that as a "discovered"
|
|
panel. It can be used together with component-based DRM drivers in an
|
|
emulated environment where no real encoder or connector hardware exists
|
|
and the display output is configured outside the kernel.
|
|
|
|
Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
|
|
|
|
Upstream-Status: Backport [https://git.linaro.org/landing-teams/working/arm/kernel-release.git/commit/?h=latest-armlt&id=15283f7be4b1e586702551e85b4caf06531ac2fc]
|
|
---
|
|
drivers/gpu/drm/Kconfig | 11 +
|
|
drivers/gpu/drm/Makefile | 2 +
|
|
drivers/gpu/drm/drm_virtual_encoder.c | 299 ++++++++++++++++++++++++++
|
|
3 files changed, 312 insertions(+)
|
|
create mode 100644 drivers/gpu/drm/drm_virtual_encoder.c
|
|
|
|
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
|
|
index e67c194c2aca..c95279cd9341 100644
|
|
--- a/drivers/gpu/drm/Kconfig
|
|
+++ b/drivers/gpu/drm/Kconfig
|
|
@@ -265,6 +265,17 @@ config DRM_VKMS
|
|
|
|
If M is selected the module will be called vkms.
|
|
|
|
+config DRM_VIRT_ENCODER
|
|
+ tristate "Virtual OF-based encoder"
|
|
+ depends on DRM && OF
|
|
+ select VIDEOMODE_HELPERS
|
|
+ help
|
|
+ Choose this option to get a virtual encoder and its associated
|
|
+ connector that will use the device tree to read the display
|
|
+ timings information. If M is selected the module will be called
|
|
+ drm_vencoder.
|
|
+
|
|
+
|
|
config DRM_ATI_PCIGART
|
|
bool
|
|
|
|
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
|
|
index 82ff826b33cc..d2ab6fc64932 100644
|
|
--- a/drivers/gpu/drm/Makefile
|
|
+++ b/drivers/gpu/drm/Makefile
|
|
@@ -53,6 +53,8 @@ drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
|
|
|
|
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
|
|
obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
|
|
+drm_vencoder-y := drm_virtual_encoder.o
|
|
+obj-$(CONFIG_DRM_VIRT_ENCODER) += drm_vencoder.o
|
|
|
|
obj-$(CONFIG_DRM) += drm.o
|
|
obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
|
|
diff --git a/drivers/gpu/drm/drm_virtual_encoder.c b/drivers/gpu/drm/drm_virtual_encoder.c
|
|
new file mode 100644
|
|
index 000000000000..4fd2098df286
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/drm_virtual_encoder.c
|
|
@@ -0,0 +1,299 @@
|
|
+/*
|
|
+ * Copyright (C) 2016 ARM Limited
|
|
+ * Author: Liviu Dudau <Liviu.Dudau@arm.com>
|
|
+ *
|
|
+ * Dummy encoder and connector that use the OF to "discover" the attached
|
|
+ * display timings. Can be used in situations where the encoder and connector's
|
|
+ * functionality are emulated and no setup steps are needed, or to describe
|
|
+ * attached panels for which no driver exists but can be used without
|
|
+ * additional hardware setup.
|
|
+ *
|
|
+ * The encoder also uses the component framework so that it can be a quick
|
|
+ * replacement for existing drivers when testing in an emulated environment.
|
|
+ *
|
|
+ * This file is subject to the terms and conditions of the GNU General Public
|
|
+ * License. See the file COPYING in the main directory of this archive
|
|
+ * for more details.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <drm/drm_crtc.h>
|
|
+#include <drm/drm_atomic_helper.h>
|
|
+#include <drm/drm_crtc_helper.h>
|
|
+#include <drm/drm_probe_helper.h>
|
|
+#include <drm/drm_print.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <drm/drm_of.h>
|
|
+#include <linux/component.h>
|
|
+#include <video/display_timing.h>
|
|
+#include <video/of_display_timing.h>
|
|
+#include <video/videomode.h>
|
|
+
|
|
+struct drm_virt_priv {
|
|
+ struct drm_connector connector;
|
|
+ struct drm_encoder encoder;
|
|
+ struct display_timings *timings;
|
|
+};
|
|
+
|
|
+#define connector_to_drm_virt_priv(x) \
|
|
+ container_of(x, struct drm_virt_priv, connector)
|
|
+
|
|
+#define encoder_to_drm_virt_priv(x) \
|
|
+ container_of(x, struct drm_virt_priv, encoder)
|
|
+
|
|
+static void drm_virtcon_destroy(struct drm_connector *connector)
|
|
+{
|
|
+ struct drm_virt_priv *conn = connector_to_drm_virt_priv(connector);
|
|
+
|
|
+ drm_connector_cleanup(connector);
|
|
+ display_timings_release(conn->timings);
|
|
+}
|
|
+
|
|
+static enum drm_connector_status
|
|
+drm_virtcon_detect(struct drm_connector *connector, bool force)
|
|
+{
|
|
+ return connector_status_connected;
|
|
+}
|
|
+
|
|
+static const struct drm_connector_funcs drm_virtcon_funcs = {
|
|
+ .reset = drm_atomic_helper_connector_reset,
|
|
+ .detect = drm_virtcon_detect,
|
|
+ .fill_modes = drm_helper_probe_single_connector_modes,
|
|
+ .destroy = drm_virtcon_destroy,
|
|
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
|
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
|
+};
|
|
+
|
|
+static int drm_virtcon_get_modes(struct drm_connector *connector)
|
|
+{
|
|
+ struct drm_virt_priv *conn = connector_to_drm_virt_priv(connector);
|
|
+ struct display_timings *timings = conn->timings;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < timings->num_timings; i++) {
|
|
+ struct drm_display_mode *mode = drm_mode_create(connector->dev);
|
|
+ struct videomode vm;
|
|
+
|
|
+ if (videomode_from_timings(timings, &vm, i))
|
|
+ break;
|
|
+
|
|
+ drm_display_mode_from_videomode(&vm, mode);
|
|
+ mode->type = DRM_MODE_TYPE_DRIVER;
|
|
+ if (timings->native_mode == i)
|
|
+ mode->type = DRM_MODE_TYPE_PREFERRED;
|
|
+
|
|
+ drm_mode_set_name(mode);
|
|
+ drm_mode_probed_add(connector, mode);
|
|
+ }
|
|
+
|
|
+ return i;
|
|
+}
|
|
+
|
|
+static int drm_virtcon_mode_valid(struct drm_connector *connector,
|
|
+ struct drm_display_mode *mode)
|
|
+{
|
|
+ return MODE_OK;
|
|
+}
|
|
+
|
|
+struct drm_encoder *drm_virtcon_best_encoder(struct drm_connector *connector)
|
|
+{
|
|
+ struct drm_virt_priv *priv = connector_to_drm_virt_priv(connector);
|
|
+
|
|
+ return &priv->encoder;
|
|
+}
|
|
+
|
|
+struct drm_encoder *
|
|
+drm_virtcon_atomic_best_encoder(struct drm_connector *connector,
|
|
+ struct drm_connector_state *connector_state)
|
|
+{
|
|
+ struct drm_virt_priv *priv = connector_to_drm_virt_priv(connector);
|
|
+
|
|
+ return &priv->encoder;
|
|
+}
|
|
+
|
|
+static const struct drm_connector_helper_funcs drm_virtcon_helper_funcs = {
|
|
+ .get_modes = drm_virtcon_get_modes,
|
|
+ .mode_valid = drm_virtcon_mode_valid,
|
|
+ .best_encoder = drm_virtcon_best_encoder,
|
|
+ .atomic_best_encoder = drm_virtcon_atomic_best_encoder,
|
|
+};
|
|
+
|
|
+static void drm_vencoder_destroy(struct drm_encoder *encoder)
|
|
+{
|
|
+ drm_encoder_cleanup(encoder);
|
|
+}
|
|
+
|
|
+static const struct drm_encoder_funcs drm_vencoder_funcs = {
|
|
+ .destroy = drm_vencoder_destroy,
|
|
+};
|
|
+
|
|
+static void drm_vencoder_dpms(struct drm_encoder *encoder, int mode)
|
|
+{
|
|
+ /* nothing needed */
|
|
+}
|
|
+
|
|
+static bool drm_vencoder_mode_fixup(struct drm_encoder *encoder,
|
|
+ const struct drm_display_mode *mode,
|
|
+ struct drm_display_mode *adjusted_mode)
|
|
+{
|
|
+ /* nothing needed */
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static void drm_vencoder_prepare(struct drm_encoder *encoder)
|
|
+{
|
|
+ drm_vencoder_dpms(encoder, DRM_MODE_DPMS_OFF);
|
|
+}
|
|
+
|
|
+static void drm_vencoder_commit(struct drm_encoder *encoder)
|
|
+{
|
|
+ drm_vencoder_dpms(encoder, DRM_MODE_DPMS_ON);
|
|
+}
|
|
+
|
|
+static void drm_vencoder_mode_set(struct drm_encoder *encoder,
|
|
+ struct drm_display_mode *mode,
|
|
+ struct drm_display_mode *adjusted_mode)
|
|
+{
|
|
+ /* nothing needed */
|
|
+}
|
|
+
|
|
+static const struct drm_encoder_helper_funcs drm_vencoder_helper_funcs = {
|
|
+ .dpms = drm_vencoder_dpms,
|
|
+ .mode_fixup = drm_vencoder_mode_fixup,
|
|
+ .prepare = drm_vencoder_prepare,
|
|
+ .commit = drm_vencoder_commit,
|
|
+ .mode_set = drm_vencoder_mode_set,
|
|
+};
|
|
+
|
|
+static int drm_vencoder_bind(struct device *dev, struct device *master,
|
|
+ void *data)
|
|
+{
|
|
+ struct drm_encoder *encoder;
|
|
+ struct drm_virt_priv *con;
|
|
+ struct drm_connector *connector;
|
|
+ struct drm_device *drm = data;
|
|
+ u32 crtcs = 0;
|
|
+ int ret;
|
|
+
|
|
+ con = devm_kzalloc(dev, sizeof(*con), GFP_KERNEL);
|
|
+ if (!con)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ dev_set_drvdata(dev, con);
|
|
+ connector = &con->connector;
|
|
+ encoder = &con->encoder;
|
|
+
|
|
+ if (dev->of_node) {
|
|
+ struct drm_bridge *bridge;
|
|
+ crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
|
|
+ bridge = of_drm_find_bridge(dev->of_node);
|
|
+ if (bridge) {
|
|
+ ret = drm_bridge_attach(encoder, bridge, NULL);
|
|
+ if (ret) {
|
|
+ DRM_ERROR("Failed to initialize bridge\n");
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+ con->timings = of_get_display_timings(dev->of_node);
|
|
+ if (!con->timings) {
|
|
+ dev_err(dev, "failed to get display panel timings\n");
|
|
+ return ENXIO;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* If no CRTCs were found, fall back to the old encoder's behaviour */
|
|
+ if (crtcs == 0) {
|
|
+ dev_warn(dev, "Falling back to first CRTC\n");
|
|
+ crtcs = 1 << 0;
|
|
+ }
|
|
+
|
|
+ encoder->possible_crtcs = crtcs ? crtcs : 1;
|
|
+ encoder->possible_clones = 0;
|
|
+
|
|
+ ret = drm_encoder_init(drm, encoder, &drm_vencoder_funcs,
|
|
+ DRM_MODE_ENCODER_VIRTUAL, NULL);
|
|
+ if (ret)
|
|
+ goto encoder_init_err;
|
|
+
|
|
+ drm_encoder_helper_add(encoder, &drm_vencoder_helper_funcs);
|
|
+
|
|
+ /* bogus values, pretend we're a 24" screen for DPI calculations */
|
|
+ connector->display_info.width_mm = 519;
|
|
+ connector->display_info.height_mm = 324;
|
|
+ connector->interlace_allowed = false;
|
|
+ connector->doublescan_allowed = false;
|
|
+ connector->polled = 0;
|
|
+
|
|
+ ret = drm_connector_init(drm, connector, &drm_virtcon_funcs,
|
|
+ DRM_MODE_CONNECTOR_VIRTUAL);
|
|
+ if (ret)
|
|
+ goto connector_init_err;
|
|
+
|
|
+ drm_connector_helper_add(connector, &drm_virtcon_helper_funcs);
|
|
+
|
|
+ drm_connector_register(connector);
|
|
+
|
|
+ ret = drm_connector_attach_encoder(connector, encoder);
|
|
+ if (ret)
|
|
+ goto attach_err;
|
|
+
|
|
+ return ret;
|
|
+
|
|
+attach_err:
|
|
+ drm_connector_unregister(connector);
|
|
+ drm_connector_cleanup(connector);
|
|
+connector_init_err:
|
|
+ drm_encoder_cleanup(encoder);
|
|
+encoder_init_err:
|
|
+ display_timings_release(con->timings);
|
|
+
|
|
+ return ret;
|
|
+};
|
|
+
|
|
+static void drm_vencoder_unbind(struct device *dev, struct device *master,
|
|
+ void *data)
|
|
+{
|
|
+ struct drm_virt_priv *con = dev_get_drvdata(dev);
|
|
+
|
|
+ drm_connector_unregister(&con->connector);
|
|
+ drm_connector_cleanup(&con->connector);
|
|
+ drm_encoder_cleanup(&con->encoder);
|
|
+ display_timings_release(con->timings);
|
|
+}
|
|
+
|
|
+static const struct component_ops drm_vencoder_ops = {
|
|
+ .bind = drm_vencoder_bind,
|
|
+ .unbind = drm_vencoder_unbind,
|
|
+};
|
|
+
|
|
+static int drm_vencoder_probe(struct platform_device *pdev)
|
|
+{
|
|
+ return component_add(&pdev->dev, &drm_vencoder_ops);
|
|
+}
|
|
+
|
|
+static int drm_vencoder_remove(struct platform_device *pdev)
|
|
+{
|
|
+ component_del(&pdev->dev, &drm_vencoder_ops);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct of_device_id drm_vencoder_of_match[] = {
|
|
+ { .compatible = "drm,virtual-encoder", },
|
|
+ {},
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, drm_vencoder_of_match);
|
|
+
|
|
+static struct platform_driver drm_vencoder_driver = {
|
|
+ .probe = drm_vencoder_probe,
|
|
+ .remove = drm_vencoder_remove,
|
|
+ .driver = {
|
|
+ .name = "drm_vencoder",
|
|
+ .of_match_table = drm_vencoder_of_match,
|
|
+ },
|
|
+};
|
|
+
|
|
+module_platform_driver(drm_vencoder_driver);
|
|
+
|
|
+MODULE_AUTHOR("Liviu Dudau");
|
|
+MODULE_DESCRIPTION("Virtual DRM Encoder");
|
|
+MODULE_LICENSE("GPL v2");
|
|
--
|
|
2.17.1
|
|
|