mirror of
https://abf.rosa.ru/djam/kernel-5.15.git
synced 2025-02-23 04:42:47 +00:00
1597 lines
45 KiB
Diff
1597 lines
45 KiB
Diff
From 197e983093dcce390087f586143845b079489875 Mon Sep 17 00:00:00 2001
|
|
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
|
|
Date: Thu, 30 Apr 2020 15:46:43 +0400
|
|
Subject: [PATCH 614/634] drm: added Baikal-M SoC video display unit driver
|
|
|
|
Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru>
|
|
Signed-off-by: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
|
|
---
|
|
drivers/gpu/drm/Kconfig | 1 +
|
|
drivers/gpu/drm/Makefile | 1 +
|
|
drivers/gpu/drm/baikal/Kconfig | 15 +
|
|
drivers/gpu/drm/baikal/Makefile | 10 +
|
|
drivers/gpu/drm/baikal/baikal-hdmi.c | 119 ++++++
|
|
drivers/gpu/drm/baikal/baikal_vdu_connector.c | 118 ++++++
|
|
drivers/gpu/drm/baikal/baikal_vdu_crtc.c | 337 ++++++++++++++++
|
|
drivers/gpu/drm/baikal/baikal_vdu_debugfs.c | 87 +++++
|
|
drivers/gpu/drm/baikal/baikal_vdu_drm.h | 65 ++++
|
|
drivers/gpu/drm/baikal/baikal_vdu_drv.c | 363 ++++++++++++++++++
|
|
drivers/gpu/drm/baikal/baikal_vdu_plane.c | 209 ++++++++++
|
|
drivers/gpu/drm/baikal/baikal_vdu_regs.h | 139 +++++++
|
|
drivers/gpu/drm/bridge/Kconfig | 7 +
|
|
13 files changed, 1471 insertions(+)
|
|
create mode 100644 drivers/gpu/drm/baikal/Kconfig
|
|
create mode 100644 drivers/gpu/drm/baikal/Makefile
|
|
create mode 100644 drivers/gpu/drm/baikal/baikal-hdmi.c
|
|
create mode 100644 drivers/gpu/drm/baikal/baikal_vdu_connector.c
|
|
create mode 100644 drivers/gpu/drm/baikal/baikal_vdu_crtc.c
|
|
create mode 100644 drivers/gpu/drm/baikal/baikal_vdu_debugfs.c
|
|
create mode 100644 drivers/gpu/drm/baikal/baikal_vdu_drm.h
|
|
create mode 100644 drivers/gpu/drm/baikal/baikal_vdu_drv.c
|
|
create mode 100644 drivers/gpu/drm/baikal/baikal_vdu_plane.c
|
|
create mode 100644 drivers/gpu/drm/baikal/baikal_vdu_regs.h
|
|
|
|
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
|
|
index cea777ae7..bb77bf9b6 100644
|
|
--- a/drivers/gpu/drm/Kconfig
|
|
+++ b/drivers/gpu/drm/Kconfig
|
|
@@ -222,6 +222,7 @@ config DRM_SCHED
|
|
source "drivers/gpu/drm/i2c/Kconfig"
|
|
|
|
source "drivers/gpu/drm/arm/Kconfig"
|
|
+source "drivers/gpu/drm/baikal/Kconfig"
|
|
|
|
config DRM_RADEON
|
|
tristate "ATI Radeon"
|
|
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
|
|
index ad1112154..964d306ea 100644
|
|
--- a/drivers/gpu/drm/Makefile
|
|
+++ b/drivers/gpu/drm/Makefile
|
|
@@ -128,3 +128,4 @@ obj-$(CONFIG_DRM_TIDSS) += tidss/
|
|
obj-y += xlnx/
|
|
obj-y += gud/
|
|
obj-$(CONFIG_DRM_HYPERV) += hyperv/
|
|
+obj-$(CONFIG_DRM_BAIKAL_VDU) += baikal/
|
|
diff --git a/drivers/gpu/drm/baikal/Kconfig b/drivers/gpu/drm/baikal/Kconfig
|
|
new file mode 100644
|
|
index 000000000..7f3661ae5
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/baikal/Kconfig
|
|
@@ -0,0 +1,15 @@
|
|
+config DRM_BAIKAL_VDU
|
|
+ tristate "DRM Support for Baikal-M VDU"
|
|
+ depends on DRM
|
|
+ depends on ARM || ARM64 || COMPILE_TEST
|
|
+ depends on COMMON_CLK
|
|
+ default y if ARCH_BAIKAL
|
|
+ select DRM_KMS_HELPER
|
|
+ select DRM_KMS_CMA_HELPER
|
|
+ select DRM_GEM_CMA_HELPER
|
|
+ select DRM_PANEL
|
|
+ select DRM_BAIKAL_HDMI
|
|
+ select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
|
|
+ help
|
|
+ Choose this option for DRM support for the Baikal-M Video Display Unit (VDU).
|
|
+ If M is selected the module will be called baikal_vdu_drm.
|
|
diff --git a/drivers/gpu/drm/baikal/Makefile b/drivers/gpu/drm/baikal/Makefile
|
|
new file mode 100644
|
|
index 000000000..eb029494e
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/baikal/Makefile
|
|
@@ -0,0 +1,10 @@
|
|
+# SPDX-License-Identifier: GPL-2.0
|
|
+baikal_vdu_drm-y += baikal_vdu_connector.o \
|
|
+ baikal_vdu_crtc.o \
|
|
+ baikal_vdu_drv.o \
|
|
+ baikal_vdu_plane.o
|
|
+
|
|
+baikal_vdu_drm-$(CONFIG_DEBUG_FS) += baikal_vdu_debugfs.o
|
|
+
|
|
+obj-$(CONFIG_DRM_BAIKAL_VDU) += baikal_vdu_drm.o
|
|
+obj-$(CONFIG_DRM_BAIKAL_HDMI) += baikal-hdmi.o
|
|
diff --git a/drivers/gpu/drm/baikal/baikal-hdmi.c b/drivers/gpu/drm/baikal/baikal-hdmi.c
|
|
new file mode 100644
|
|
index 000000000..6a55d03d9
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/baikal/baikal-hdmi.c
|
|
@@ -0,0 +1,119 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Baikal Electronics BE-M1000 DesignWare HDMI 2.0 Tx PHY support driver
|
|
+ *
|
|
+ * Copyright (C) 2019-2021 Baikal Electronics JSC
|
|
+ *
|
|
+ * Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
|
|
+ *
|
|
+ * Parts of this file were based on sources as follows:
|
|
+ *
|
|
+ * Copyright (C) 2016 Renesas Electronics Corporation
|
|
+ *
|
|
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <drm/drm_modes.h>
|
|
+
|
|
+#include <drm/bridge/dw_hdmi.h>
|
|
+
|
|
+int fixed_clock = 0;
|
|
+int max_clock = 0;
|
|
+
|
|
+static const struct dw_hdmi_mpll_config baikal_hdmi_mpll_cfg[] = {
|
|
+ /* pixelclk opmode gmp */
|
|
+ { 44900000, { { 0x00b3, 0x0000 }, }, },
|
|
+ { 90000000, { { 0x0072, 0x0001 }, }, },
|
|
+ { 182750000, { { 0x0051, 0x0002 }, }, },
|
|
+ { 340000000, { { 0x0040, 0x0003 }, }, },
|
|
+ { 594000000, { { 0x1a40, 0x0003 }, }, },
|
|
+ { ~0UL, { { 0x0000, 0x0000 }, }, }
|
|
+};
|
|
+
|
|
+static const struct dw_hdmi_curr_ctrl baikal_hdmi_cur_ctr[] = {
|
|
+ /* pixelclk current */
|
|
+ { 44900000, { 0x0000, }, },
|
|
+ { 90000000, { 0x0008, }, },
|
|
+ { 182750000, { 0x001b, }, },
|
|
+ { 340000000, { 0x0036, }, },
|
|
+ { 594000000, { 0x003f, }, },
|
|
+ { ~0UL, { 0x0000, }, }
|
|
+};
|
|
+
|
|
+static const struct dw_hdmi_phy_config baikal_hdmi_phy_cfg[] = {
|
|
+ /* pixelclk symbol term vlev */
|
|
+ { 148250000, 0x8009, 0x0004, 0x0232},
|
|
+ { 218250000, 0x8009, 0x0004, 0x0230},
|
|
+ { 288000000, 0x8009, 0x0004, 0x0273},
|
|
+ { 340000000, 0x8029, 0x0004, 0x0273},
|
|
+ { 594000000, 0x8039, 0x0004, 0x014a},
|
|
+ { ~0UL, 0x0000, 0x0000, 0x0000}
|
|
+};
|
|
+
|
|
+static enum drm_mode_status baikal_hdmi_mode_valid(struct dw_hdmi *hdmi,
|
|
+ void *data,
|
|
+ const struct drm_display_info *info,
|
|
+ const struct drm_display_mode *mode)
|
|
+{
|
|
+ if (mode->clock < 13500)
|
|
+ return MODE_CLOCK_LOW;
|
|
+ if (mode->clock >= 340000)
|
|
+ return MODE_CLOCK_HIGH;
|
|
+ if (fixed_clock && mode->clock != fixed_clock)
|
|
+ return MODE_BAD;
|
|
+ if (max_clock && mode->clock > max_clock)
|
|
+ return MODE_BAD;
|
|
+
|
|
+ return MODE_OK;
|
|
+}
|
|
+
|
|
+static struct dw_hdmi_plat_data baikal_dw_hdmi_plat_data = {
|
|
+ .mpll_cfg = baikal_hdmi_mpll_cfg,
|
|
+ .cur_ctr = baikal_hdmi_cur_ctr,
|
|
+ .phy_config = baikal_hdmi_phy_cfg,
|
|
+ .mode_valid = baikal_hdmi_mode_valid,
|
|
+};
|
|
+
|
|
+static int baikal_dw_hdmi_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct dw_hdmi *hdmi;
|
|
+ hdmi = dw_hdmi_probe(pdev, &baikal_dw_hdmi_plat_data);
|
|
+ if (IS_ERR(hdmi)) {
|
|
+ return PTR_ERR(hdmi);
|
|
+ } else {
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int baikal_dw_hdmi_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
|
|
+ dw_hdmi_remove(hdmi);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct of_device_id baikal_dw_hdmi_of_table[] = {
|
|
+ { .compatible = "baikal,hdmi" },
|
|
+ { /* Sentinel */ },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, baikal_dw_hdmi_of_table);
|
|
+
|
|
+static struct platform_driver baikal_dw_hdmi_platform_driver = {
|
|
+ .probe = baikal_dw_hdmi_probe,
|
|
+ .remove = baikal_dw_hdmi_remove,
|
|
+ .driver = {
|
|
+ .name = "baikal-dw-hdmi",
|
|
+ .of_match_table = baikal_dw_hdmi_of_table,
|
|
+ },
|
|
+};
|
|
+
|
|
+module_param(fixed_clock, int, 0644);
|
|
+module_param(max_clock, int, 0644);
|
|
+
|
|
+module_platform_driver(baikal_dw_hdmi_platform_driver);
|
|
+
|
|
+MODULE_AUTHOR("Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>");
|
|
+MODULE_DESCRIPTION("Baikal BE-M1000 SoC DesignWare HDMI 2.0 Tx + Gen2 PHY Driver");
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_connector.c b/drivers/gpu/drm/baikal/baikal_vdu_connector.c
|
|
new file mode 100644
|
|
index 000000000..2f20cf3da
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/baikal/baikal_vdu_connector.c
|
|
@@ -0,0 +1,118 @@
|
|
+/*
|
|
+ * Copyright (C) 2019-2020 Baikal Electronics JSC
|
|
+ *
|
|
+ * Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
|
|
+ *
|
|
+ * Parts of this file were based on sources as follows:
|
|
+ *
|
|
+ * Copyright (c) 2006-2008 Intel Corporation
|
|
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
|
|
+ * Copyright (C) 2011 Texas Instruments
|
|
+ * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
|
|
+ *
|
|
+ * This program is free software and is provided to you under the terms of the
|
|
+ * GNU General Public License version 2 as published by the Free Software
|
|
+ * Foundation, and any use by you of this program is subject to the terms of
|
|
+ * such GNU licence.
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * baikal_vdu_connector.c
|
|
+ * Implementation of the connector functions for Baikal Electronics BE-M1000 SoC's VDU
|
|
+ */
|
|
+#include <linux/version.h>
|
|
+#include <linux/shmem_fs.h>
|
|
+#include <linux/dma-buf.h>
|
|
+
|
|
+#include <drm/drm_atomic_helper.h>
|
|
+#include <drm/drm_crtc_helper.h>
|
|
+#include <drm/drm_of.h>
|
|
+#include <drm/drm_panel.h>
|
|
+#include <drm/drm_probe_helper.h>
|
|
+
|
|
+#include "baikal_vdu_drm.h"
|
|
+#include "baikal_vdu_regs.h"
|
|
+
|
|
+#define to_baikal_vdu_private(x) \
|
|
+ container_of(x, struct baikal_vdu_private, connector)
|
|
+
|
|
+static void baikal_vdu_drm_connector_destroy(struct drm_connector *connector)
|
|
+{
|
|
+ drm_connector_unregister(connector);
|
|
+ drm_connector_cleanup(connector);
|
|
+}
|
|
+
|
|
+static enum drm_connector_status baikal_vdu_drm_connector_detect(
|
|
+ struct drm_connector *connector, bool force)
|
|
+{
|
|
+ struct baikal_vdu_private *priv = to_baikal_vdu_private(connector);
|
|
+
|
|
+ return (priv->panel ?
|
|
+ connector_status_connected :
|
|
+ connector_status_disconnected);
|
|
+}
|
|
+
|
|
+static int baikal_vdu_drm_connector_helper_get_modes(
|
|
+ struct drm_connector *connector)
|
|
+{
|
|
+ struct baikal_vdu_private *priv = to_baikal_vdu_private(connector);
|
|
+
|
|
+ if (!priv->panel)
|
|
+ return 0;
|
|
+
|
|
+ return drm_panel_get_modes(priv->panel, connector);
|
|
+}
|
|
+
|
|
+const struct drm_connector_funcs connector_funcs = {
|
|
+ .fill_modes = drm_helper_probe_single_connector_modes,
|
|
+ .destroy = baikal_vdu_drm_connector_destroy,
|
|
+ .detect = baikal_vdu_drm_connector_detect,
|
|
+ .reset = drm_atomic_helper_connector_reset,
|
|
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
|
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
|
+};
|
|
+
|
|
+const struct drm_connector_helper_funcs connector_helper_funcs = {
|
|
+ .get_modes = baikal_vdu_drm_connector_helper_get_modes,
|
|
+};
|
|
+
|
|
+static const struct drm_encoder_funcs encoder_funcs = {
|
|
+ .destroy = drm_encoder_cleanup,
|
|
+};
|
|
+
|
|
+int baikal_vdu_lvds_connector_create(struct drm_device *dev)
|
|
+{
|
|
+ struct baikal_vdu_private *priv = dev->dev_private;
|
|
+ struct drm_connector *connector = &priv->connector;
|
|
+ struct drm_encoder *encoder = &priv->encoder;
|
|
+ int ret = 0;
|
|
+
|
|
+ ret = drm_connector_init(dev, connector, &connector_funcs,
|
|
+ DRM_MODE_CONNECTOR_LVDS);
|
|
+ if (ret) {
|
|
+ dev_err(dev->dev, "drm_connector_init failed: %d\n", ret);
|
|
+ goto out;
|
|
+ }
|
|
+ drm_connector_helper_add(connector, &connector_helper_funcs);
|
|
+ ret = drm_encoder_init(dev, encoder, &encoder_funcs,
|
|
+ DRM_MODE_ENCODER_LVDS, NULL);
|
|
+ if (ret) {
|
|
+ dev_err(dev->dev, "drm_encoder_init failed: %d\n", ret);
|
|
+ goto out;
|
|
+ }
|
|
+ encoder->crtc = &priv->crtc;
|
|
+ encoder->possible_crtcs = drm_crtc_mask(encoder->crtc);
|
|
+ ret = drm_connector_attach_encoder(connector, encoder);
|
|
+ if (ret) {
|
|
+ dev_err(dev->dev, "drm_connector_attach_encoder failed: %d\n", ret);
|
|
+ goto out;
|
|
+ }
|
|
+ ret = drm_connector_register(connector);
|
|
+ if (ret) {
|
|
+ dev_err(dev->dev, "drm_connector_register failed: %d\n", ret);
|
|
+ goto out;
|
|
+ }
|
|
+out:
|
|
+ return ret;
|
|
+}
|
|
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_crtc.c b/drivers/gpu/drm/baikal/baikal_vdu_crtc.c
|
|
new file mode 100644
|
|
index 000000000..039150c59
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/baikal/baikal_vdu_crtc.c
|
|
@@ -0,0 +1,337 @@
|
|
+/*
|
|
+ * Copyright (C) 2019-2020 Baikal Electronics JSC
|
|
+ *
|
|
+ * Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
|
|
+ *
|
|
+ * Parts of this file were based on sources as follows:
|
|
+ *
|
|
+ * Copyright (c) 2006-2008 Intel Corporation
|
|
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
|
|
+ * Copyright (C) 2011 Texas Instruments
|
|
+ * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
|
|
+ *
|
|
+ * This program is free software and is provided to you under the terms of the
|
|
+ * GNU General Public License version 2 as published by the Free Software
|
|
+ * Foundation, and any use by you of this program is subject to the terms of
|
|
+ * such GNU licence.
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * baikal_vdu_crtc.c
|
|
+ * Implementation of the CRTC functions for Baikal Electronics BE-M1000 VDU driver
|
|
+ */
|
|
+#include <linux/clk.h>
|
|
+#include <linux/version.h>
|
|
+#include <linux/shmem_fs.h>
|
|
+#include <linux/dma-buf.h>
|
|
+
|
|
+#include <drm/drm_atomic_helper.h>
|
|
+#include <drm/drm_crtc_helper.h>
|
|
+#include <drm/drm_panel.h>
|
|
+#include <drm/drm_vblank.h>
|
|
+
|
|
+#include "baikal_vdu_drm.h"
|
|
+#include "baikal_vdu_regs.h"
|
|
+
|
|
+struct baikal_vdu_crtc_mode_fixup {
|
|
+ int vdisplay;
|
|
+ int vfp_add;
|
|
+};
|
|
+
|
|
+static const struct baikal_vdu_crtc_mode_fixup mode_fixups[] = {
|
|
+ { 480, 38 },
|
|
+ { 600, 8 },
|
|
+ { 720, 43 },
|
|
+ { 768, 43 },
|
|
+ { 800, 71 },
|
|
+ { 864, 71 },
|
|
+ { 900, 71 },
|
|
+ { 960, 71 },
|
|
+ { 1024, 25 },
|
|
+ { 1050, 25 },
|
|
+ { 1080, 8 },
|
|
+ { 1200, 32 },
|
|
+ { 1440, 27 },
|
|
+ { ~0U },
|
|
+};
|
|
+
|
|
+irqreturn_t baikal_vdu_irq(int irq, void *data)
|
|
+{
|
|
+ struct drm_device *drm = data;
|
|
+ struct baikal_vdu_private *priv = drm->dev_private;
|
|
+ irqreturn_t status = IRQ_NONE;
|
|
+ u32 raw_stat;
|
|
+ u32 irq_stat;
|
|
+
|
|
+ irq_stat = readl(priv->regs + IVR);
|
|
+ raw_stat = readl(priv->regs + ISR);
|
|
+
|
|
+ if (irq_stat & INTR_VCT) {
|
|
+ priv->counters[10]++;
|
|
+ drm_crtc_handle_vblank(&priv->crtc);
|
|
+ status = IRQ_HANDLED;
|
|
+ }
|
|
+
|
|
+ if (irq_stat & INTR_FER) {
|
|
+ priv->counters[11]++;
|
|
+ priv->counters[12] = readl(priv->regs + DBAR);
|
|
+ priv->counters[13] = readl(priv->regs + DCAR);
|
|
+ priv->counters[14] = readl(priv->regs + MRR);
|
|
+ status = IRQ_HANDLED;
|
|
+ }
|
|
+
|
|
+ priv->counters[3] |= raw_stat;
|
|
+
|
|
+ /* Clear all interrupts */
|
|
+ writel(irq_stat, priv->regs + ISR);
|
|
+
|
|
+ return status;
|
|
+}
|
|
+
|
|
+bool baikal_vdu_crtc_mode_fixup(struct drm_crtc *crtc,
|
|
+ const struct drm_display_mode *mode,
|
|
+ struct drm_display_mode *adjusted_mode)
|
|
+{
|
|
+ struct baikal_vdu_private *priv = crtc->dev->dev_private;
|
|
+
|
|
+ memcpy(adjusted_mode, mode, sizeof(*mode));
|
|
+
|
|
+ if (!priv->mode_fixup)
|
|
+ return true;
|
|
+
|
|
+ if (priv->mode_fixup == -1) {
|
|
+ const struct baikal_vdu_crtc_mode_fixup *fixups = mode_fixups;
|
|
+ for (; fixups && fixups->vdisplay != ~0U; ++fixups) {
|
|
+ if (mode->vdisplay <= fixups->vdisplay)
|
|
+ break;
|
|
+ }
|
|
+ if (fixups->vdisplay == ~0U)
|
|
+ return true;
|
|
+ else
|
|
+ priv->mode_fixup = fixups->vfp_add;
|
|
+ }
|
|
+
|
|
+ adjusted_mode->vtotal += priv->mode_fixup;
|
|
+ adjusted_mode->vsync_start += priv->mode_fixup;
|
|
+ adjusted_mode->vsync_end += priv->mode_fixup;
|
|
+ adjusted_mode->clock = mode->clock * adjusted_mode->vtotal / mode->vtotal;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static void baikal_vdu_crtc_helper_mode_set_nofb(struct drm_crtc *crtc)
|
|
+{
|
|
+ struct drm_device *dev = crtc->dev;
|
|
+ struct baikal_vdu_private *priv = dev->dev_private;
|
|
+ const struct drm_display_mode *orig_mode = &crtc->state->mode;
|
|
+ const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
|
|
+ unsigned int ppl, hsw, hfp, hbp;
|
|
+ unsigned int lpp, vsw, vfp, vbp;
|
|
+ unsigned int reg;
|
|
+
|
|
+ drm_mode_debug_printmodeline(orig_mode);
|
|
+ drm_mode_debug_printmodeline(mode);
|
|
+
|
|
+ ppl = mode->hdisplay / 16;
|
|
+ if (priv->panel) {
|
|
+ hsw = mode->hsync_end - mode->hsync_start;
|
|
+ hfp = mode->hsync_start - mode->hdisplay - 1;
|
|
+ } else {
|
|
+ hsw = mode->hsync_end - mode->hsync_start - 1;
|
|
+ hfp = mode->hsync_start - mode->hdisplay;
|
|
+ }
|
|
+ hbp = mode->htotal - mode->hsync_end;
|
|
+
|
|
+ lpp = mode->vdisplay;
|
|
+ vsw = mode->vsync_end - mode->vsync_start;
|
|
+ vfp = mode->vsync_start - mode->vdisplay;
|
|
+ vbp = mode->vtotal - mode->vsync_end;
|
|
+
|
|
+ writel((HTR_HFP(hfp) & HTR_HFP_MASK) |
|
|
+ (HTR_PPL(ppl) & HTR_PPL_MASK) |
|
|
+ (HTR_HBP(hbp) & HTR_HBP_MASK) |
|
|
+ (HTR_HSW(hsw) & HTR_HSW_MASK),
|
|
+ priv->regs + HTR);
|
|
+
|
|
+ if (mode->hdisplay > 4080 || ppl * 16 != mode->hdisplay)
|
|
+ writel((HPPLOR_HPPLO(mode->hdisplay) & HPPLOR_HPPLO_MASK) | HPPLOR_HPOE,
|
|
+ priv->regs + HPPLOR);
|
|
+
|
|
+ writel((VTR1_VSW(vsw) & VTR1_VSW_MASK) |
|
|
+ (VTR1_VFP(vfp) & VTR1_VFP_MASK) |
|
|
+ (VTR1_VBP(vbp) & VTR1_VBP_MASK),
|
|
+ priv->regs + VTR1);
|
|
+
|
|
+ writel(lpp & VTR2_LPP_MASK, priv->regs + VTR2);
|
|
+
|
|
+ writel((HVTER_VSWE(vsw >> VTR1_VSW_LSB_WIDTH) & HVTER_VSWE_MASK) |
|
|
+ (HVTER_HSWE(hsw >> HTR_HSW_LSB_WIDTH) & HVTER_HSWE_MASK) |
|
|
+ (HVTER_VBPE(vbp >> VTR1_VBP_LSB_WIDTH) & HVTER_VBPE_MASK) |
|
|
+ (HVTER_VFPE(vfp >> VTR1_VFP_LSB_WIDTH) & HVTER_VFPE_MASK) |
|
|
+ (HVTER_HBPE(hbp >> HTR_HBP_LSB_WIDTH) & HVTER_HBPE_MASK) |
|
|
+ (HVTER_HFPE(hfp >> HTR_HFP_LSB_WIDTH) & HVTER_HFPE_MASK),
|
|
+ priv->regs + HVTER);
|
|
+
|
|
+ /* Set polarities */
|
|
+ reg = readl(priv->regs + CR1);
|
|
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
|
|
+ reg |= CR1_VSP;
|
|
+ else
|
|
+ reg &= ~CR1_VSP;
|
|
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
|
|
+ reg |= CR1_HSP;
|
|
+ else
|
|
+ reg &= ~CR1_HSP;
|
|
+ reg |= CR1_DEP; // set DE to active high;
|
|
+ writel(reg, priv->regs + CR1);
|
|
+
|
|
+ crtc->hwmode = crtc->state->adjusted_mode;
|
|
+}
|
|
+
|
|
+static void baikal_vdu_crtc_helper_enable(struct drm_crtc *crtc,
|
|
+ struct drm_atomic_state *state)
|
|
+{
|
|
+ struct baikal_vdu_private *priv = crtc->dev->dev_private;
|
|
+ struct drm_panel *panel = priv->panel;
|
|
+ struct device_node *panel_node;
|
|
+ const char *data_mapping;
|
|
+ u32 cntl, gpio;
|
|
+
|
|
+ DRM_DEV_DEBUG_DRIVER(crtc->dev->dev, "enabling pixel clock\n");
|
|
+ clk_prepare_enable(priv->clk);
|
|
+
|
|
+ drm_panel_prepare(panel);
|
|
+
|
|
+ writel(ISCR_VSC_VFP, priv->regs + ISCR);
|
|
+
|
|
+ /* release clock reset; enable clocking */
|
|
+ cntl = readl(priv->regs + PCTR);
|
|
+ cntl |= PCTR_PCR + PCTR_PCI;
|
|
+ writel(cntl, priv->regs + PCTR);
|
|
+
|
|
+ /* Set 16-word input FIFO watermark */
|
|
+ /* Enable and Power Up */
|
|
+ cntl = readl(priv->regs + CR1);
|
|
+ cntl &= ~CR1_FDW_MASK;
|
|
+ cntl |= CR1_LCE + CR1_FDW_16_WORDS;
|
|
+
|
|
+ if (priv->type == VDU_TYPE_LVDS) {
|
|
+ panel_node = panel->dev->of_node;
|
|
+ if (of_property_read_string(panel_node, "data-mapping", &data_mapping)) {
|
|
+ cntl |= CR1_OPS_LCD18;
|
|
+ } else if (strncmp(data_mapping, "vesa-24", 7))
|
|
+ cntl |= CR1_OPS_LCD24;
|
|
+ else if (strncmp(data_mapping, "jeida-18", 8))
|
|
+ cntl |= CR1_OPS_LCD18;
|
|
+ else {
|
|
+ dev_warn(crtc->dev->dev, "%s data mapping is not supported, vesa-24 is set\n", data_mapping);
|
|
+ cntl |= CR1_OPS_LCD24;
|
|
+ }
|
|
+ gpio = GPIOR_UHD_ENB;
|
|
+ if (priv->ep_count == 4)
|
|
+ gpio |= GPIOR_UHD_QUAD_PORT;
|
|
+ else if (priv->ep_count == 2)
|
|
+ gpio |= GPIOR_UHD_DUAL_PORT;
|
|
+ else
|
|
+ gpio |= GPIOR_UHD_SNGL_PORT;
|
|
+ writel(gpio, priv->regs + GPIOR);
|
|
+ } else
|
|
+ cntl |= CR1_OPS_LCD24;
|
|
+ writel(cntl, priv->regs + CR1);
|
|
+
|
|
+ drm_panel_enable(priv->panel);
|
|
+ drm_crtc_vblank_on(crtc);
|
|
+}
|
|
+
|
|
+void baikal_vdu_crtc_helper_disable(struct drm_crtc *crtc)
|
|
+{
|
|
+ struct baikal_vdu_private *priv = crtc->dev->dev_private;
|
|
+
|
|
+ drm_crtc_vblank_off(crtc);
|
|
+ drm_panel_disable(priv->panel);
|
|
+
|
|
+ drm_panel_unprepare(priv->panel);
|
|
+
|
|
+ /* Disable clock */
|
|
+ DRM_DEV_DEBUG_DRIVER(crtc->dev->dev, "disabling pixel clock\n");
|
|
+ clk_disable_unprepare(priv->clk);
|
|
+}
|
|
+
|
|
+static void baikal_vdu_crtc_helper_atomic_flush(struct drm_crtc *crtc,
|
|
+ struct drm_atomic_state *state)
|
|
+{
|
|
+ struct drm_pending_vblank_event *event = crtc->state->event;
|
|
+
|
|
+ if (event) {
|
|
+ crtc->state->event = NULL;
|
|
+
|
|
+ spin_lock_irq(&crtc->dev->event_lock);
|
|
+ if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0)
|
|
+ drm_crtc_arm_vblank_event(crtc, event);
|
|
+ else
|
|
+ drm_crtc_send_vblank_event(crtc, event);
|
|
+ spin_unlock_irq(&crtc->dev->event_lock);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int baikal_vdu_enable_vblank(struct drm_crtc *crtc)
|
|
+{
|
|
+ struct baikal_vdu_private *priv = crtc->dev->dev_private;
|
|
+
|
|
+ /* clear interrupt status */
|
|
+ writel(0x3ffff, priv->regs + ISR);
|
|
+
|
|
+ writel(INTR_VCT + INTR_FER, priv->regs + IMR);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void baikal_vdu_disable_vblank(struct drm_crtc *crtc)
|
|
+{
|
|
+ struct baikal_vdu_private *priv = crtc->dev->dev_private;
|
|
+
|
|
+ /* clear interrupt status */
|
|
+ writel(0x3ffff, priv->regs + ISR);
|
|
+
|
|
+ writel(INTR_FER, priv->regs + IMR);
|
|
+}
|
|
+
|
|
+const struct drm_crtc_funcs crtc_funcs = {
|
|
+ .set_config = drm_atomic_helper_set_config,
|
|
+ .page_flip = drm_atomic_helper_page_flip,
|
|
+ .reset = drm_atomic_helper_crtc_reset,
|
|
+ .destroy = drm_crtc_cleanup,
|
|
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
|
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
|
+ .enable_vblank = baikal_vdu_enable_vblank,
|
|
+ .disable_vblank = baikal_vdu_disable_vblank,
|
|
+};
|
|
+
|
|
+const struct drm_crtc_helper_funcs crtc_helper_funcs = {
|
|
+ .mode_fixup = baikal_vdu_crtc_mode_fixup,
|
|
+ .mode_set_nofb = baikal_vdu_crtc_helper_mode_set_nofb,
|
|
+ .atomic_flush = baikal_vdu_crtc_helper_atomic_flush,
|
|
+ .disable = baikal_vdu_crtc_helper_disable,
|
|
+ .atomic_enable = baikal_vdu_crtc_helper_enable,
|
|
+};
|
|
+
|
|
+int baikal_vdu_crtc_create(struct drm_device *dev)
|
|
+{
|
|
+ struct baikal_vdu_private *priv = dev->dev_private;
|
|
+ struct drm_crtc *crtc = &priv->crtc;
|
|
+
|
|
+ drm_crtc_init_with_planes(dev, crtc,
|
|
+ &priv->primary, NULL,
|
|
+ &crtc_funcs, "primary");
|
|
+ drm_crtc_helper_add(crtc, &crtc_helper_funcs);
|
|
+
|
|
+ /* XXX: The runtime clock disabling still results in
|
|
+ * occasional system hangs, and needs debugging.
|
|
+ */
|
|
+
|
|
+ DRM_DEV_DEBUG_DRIVER(crtc->dev->dev, "enabling pixel clock\n");
|
|
+ clk_prepare_enable(priv->clk);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_debugfs.c b/drivers/gpu/drm/baikal/baikal_vdu_debugfs.c
|
|
new file mode 100644
|
|
index 000000000..77be6aa58
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/baikal/baikal_vdu_debugfs.c
|
|
@@ -0,0 +1,87 @@
|
|
+/*
|
|
+ * Copyright (C) 2019-2020 Baikal Electronics JSC
|
|
+ *
|
|
+ * Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
|
|
+ *
|
|
+ * Parts of this file were based on sources as follows:
|
|
+ *
|
|
+ * Copyright © 2017 Broadcom
|
|
+ *
|
|
+ * 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/seq_file.h>
|
|
+#include <linux/device.h>
|
|
+#include <drm/drm_debugfs.h>
|
|
+#include <drm/drm_device.h>
|
|
+#include <drm/drm_file.h>
|
|
+
|
|
+#include "baikal_vdu_drm.h"
|
|
+#include "baikal_vdu_regs.h"
|
|
+
|
|
+#define REGDEF(reg) { reg, #reg }
|
|
+static const struct {
|
|
+ u32 reg;
|
|
+ const char *name;
|
|
+} baikal_vdu_reg_defs[] = {
|
|
+ REGDEF(CR1),
|
|
+ REGDEF(HTR),
|
|
+ REGDEF(VTR1),
|
|
+ REGDEF(VTR2),
|
|
+ REGDEF(PCTR),
|
|
+ REGDEF(ISR),
|
|
+ REGDEF(IMR),
|
|
+ REGDEF(IVR),
|
|
+ REGDEF(ISCR),
|
|
+ REGDEF(DBAR),
|
|
+ REGDEF(DCAR),
|
|
+ REGDEF(DEAR),
|
|
+ REGDEF(HVTER),
|
|
+ REGDEF(HPPLOR),
|
|
+ REGDEF(GPIOR),
|
|
+ REGDEF(OWER),
|
|
+ REGDEF(OWXSER0),
|
|
+ REGDEF(OWYSER0),
|
|
+ REGDEF(OWDBAR0),
|
|
+ REGDEF(OWDCAR0),
|
|
+ REGDEF(OWDEAR0),
|
|
+ REGDEF(OWXSER1),
|
|
+ REGDEF(OWYSER1),
|
|
+ REGDEF(OWDBAR1),
|
|
+ REGDEF(OWDCAR1),
|
|
+ REGDEF(OWDEAR1),
|
|
+ REGDEF(MRR),
|
|
+};
|
|
+
|
|
+int baikal_vdu_debugfs_regs(struct seq_file *m, void *unused)
|
|
+{
|
|
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
|
|
+ struct drm_device *dev = node->minor->dev;
|
|
+ struct baikal_vdu_private *priv = dev->dev_private;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(baikal_vdu_reg_defs); i++) {
|
|
+ seq_printf(m, "%s (0x%04x): 0x%08x\n",
|
|
+ baikal_vdu_reg_defs[i].name, baikal_vdu_reg_defs[i].reg,
|
|
+ readl(priv->regs + baikal_vdu_reg_defs[i].reg));
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(priv->counters); i++) {
|
|
+ seq_printf(m, "COUNTER[%d]: 0x%08x\n", i, priv->counters[i]);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct drm_info_list baikal_vdu_debugfs_list[] = {
|
|
+ {"regs", baikal_vdu_debugfs_regs, 0},
|
|
+};
|
|
+
|
|
+void baikal_vdu_debugfs_init(struct drm_minor *minor)
|
|
+{
|
|
+ drm_debugfs_create_files(baikal_vdu_debugfs_list,
|
|
+ ARRAY_SIZE(baikal_vdu_debugfs_list),
|
|
+ minor->debugfs_root, minor);
|
|
+}
|
|
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_drm.h b/drivers/gpu/drm/baikal/baikal_vdu_drm.h
|
|
new file mode 100644
|
|
index 000000000..755d4abee
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/baikal/baikal_vdu_drm.h
|
|
@@ -0,0 +1,65 @@
|
|
+/*
|
|
+ * Copyright (C) 2019-2020 Baikal Electronics JSC
|
|
+ *
|
|
+ * Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
|
|
+ *
|
|
+ * Parts of this file were based on sources as follows:
|
|
+ *
|
|
+ * Copyright (c) 2006-2008 Intel Corporation
|
|
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
|
|
+ * Copyright (C) 2011 Texas Instruments
|
|
+ * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
|
|
+ *
|
|
+ * This program is free software and is provided to you under the terms of the
|
|
+ * GNU General Public License version 2 as published by the Free Software
|
|
+ * Foundation, and any use by you of this program is subject to the terms of
|
|
+ * such GNU licence.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __BAIKAL_VDU_DRM_H__
|
|
+#define __BAIKAL_VDU_DRM_H__
|
|
+
|
|
+#include <drm/drm_gem.h>
|
|
+#include <drm/drm_simple_kms_helper.h>
|
|
+
|
|
+#define VDU_TYPE_HDMI 0
|
|
+#define VDU_TYPE_LVDS 1
|
|
+
|
|
+struct baikal_vdu_private {
|
|
+ struct drm_device *drm;
|
|
+
|
|
+ unsigned int irq;
|
|
+ bool irq_enabled;
|
|
+
|
|
+ struct drm_connector connector;
|
|
+ struct drm_crtc crtc;
|
|
+ struct drm_encoder encoder;
|
|
+ struct drm_panel *panel;
|
|
+ struct drm_bridge *bridge;
|
|
+ struct drm_plane primary;
|
|
+
|
|
+ void *regs;
|
|
+ struct clk *clk;
|
|
+ u32 counters[20];
|
|
+ int mode_fixup;
|
|
+ int type;
|
|
+ u32 ep_count;
|
|
+ u32 fb_addr;
|
|
+ u32 fb_end;
|
|
+
|
|
+ struct gpio_desc *enable_gpio;
|
|
+};
|
|
+
|
|
+/* CRTC Functions */
|
|
+int baikal_vdu_crtc_create(struct drm_device *dev);
|
|
+irqreturn_t baikal_vdu_irq(int irq, void *data);
|
|
+
|
|
+int baikal_vdu_primary_plane_init(struct drm_device *dev);
|
|
+
|
|
+/* Connector Functions */
|
|
+int baikal_vdu_lvds_connector_create(struct drm_device *dev);
|
|
+
|
|
+void baikal_vdu_debugfs_init(struct drm_minor *minor);
|
|
+
|
|
+#endif /* __BAIKAL_VDU_DRM_H__ */
|
|
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_drv.c b/drivers/gpu/drm/baikal/baikal_vdu_drv.c
|
|
new file mode 100644
|
|
index 000000000..af0e0ca19
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/baikal/baikal_vdu_drv.c
|
|
@@ -0,0 +1,363 @@
|
|
+/*
|
|
+ * Copyright (C) 2019-2020 Baikal Electronics JSC
|
|
+ *
|
|
+ * Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
|
|
+ * All bugs by Alexey Sheplyakov <asheplyakov@altlinux.org>
|
|
+ *
|
|
+ * This driver is based on ARM PL111 DRM driver
|
|
+ *
|
|
+ * Parts of this file were based on sources as follows:
|
|
+ *
|
|
+ * Copyright (c) 2006-2008 Intel Corporation
|
|
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
|
|
+ * Copyright (C) 2011 Texas Instruments
|
|
+ * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
|
|
+ *
|
|
+ * This program is free software and is provided to you under the terms of the
|
|
+ * GNU General Public License version 2 as published by the Free Software
|
|
+ * Foundation, and any use by you of this program is subject to the terms of
|
|
+ * such GNU licence.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/arm-smccc.h>
|
|
+#include <linux/irq.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of_graph.h>
|
|
+#include <linux/platform_device.h>
|
|
+
|
|
+#include <drm/drm_atomic_helper.h>
|
|
+#include <drm/drm_aperture.h>
|
|
+#include <drm/drm_bridge.h>
|
|
+#include <drm/drm_connector.h>
|
|
+#include <drm/drm_crtc_helper.h>
|
|
+#include <drm/drm_drv.h>
|
|
+#include <drm/drm_gem_cma_helper.h>
|
|
+#include <drm/drm_fb_cma_helper.h>
|
|
+#include <drm/drm_fb_helper.h>
|
|
+#include <drm/drm_gem_framebuffer_helper.h>
|
|
+#include <drm/drm_of.h>
|
|
+#include <drm/drm_probe_helper.h>
|
|
+#include <drm/drm_vblank.h>
|
|
+
|
|
+#include "baikal_vdu_drm.h"
|
|
+#include "baikal_vdu_regs.h"
|
|
+
|
|
+#define DRIVER_NAME "baikal-vdu"
|
|
+#define DRIVER_DESC "DRM module for Baikal VDU"
|
|
+#define DRIVER_DATE "20200131"
|
|
+
|
|
+#define BAIKAL_SMC_SCP_LOG_DISABLE 0x82000200
|
|
+
|
|
+int mode_fixup = 0;
|
|
+
|
|
+static struct drm_mode_config_funcs mode_config_funcs = {
|
|
+ .fb_create = drm_gem_fb_create,
|
|
+ .atomic_check = drm_atomic_helper_check,
|
|
+ .atomic_commit = drm_atomic_helper_commit,
|
|
+};
|
|
+
|
|
+static const struct drm_encoder_funcs baikal_vdu_encoder_funcs = {
|
|
+ .destroy = drm_encoder_cleanup,
|
|
+};
|
|
+
|
|
+DEFINE_DRM_GEM_CMA_FOPS(drm_fops);
|
|
+
|
|
+static struct drm_driver vdu_drm_driver = {
|
|
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
|
|
+ .ioctls = NULL,
|
|
+ .fops = &drm_fops,
|
|
+ .name = DRIVER_NAME,
|
|
+ .desc = DRIVER_DESC,
|
|
+ .date = DRIVER_DATE,
|
|
+ .major = 1,
|
|
+ .minor = 0,
|
|
+ .patchlevel = 0,
|
|
+ DRM_GEM_CMA_DRIVER_OPS,
|
|
+#if defined(CONFIG_DEBUG_FS)
|
|
+ .debugfs_init = baikal_vdu_debugfs_init,
|
|
+#endif
|
|
+};
|
|
+
|
|
+static int vdu_modeset_init(struct drm_device *dev)
|
|
+{
|
|
+ struct drm_mode_config *mode_config;
|
|
+ struct baikal_vdu_private *priv = dev->dev_private;
|
|
+ struct arm_smccc_res res;
|
|
+ int ret = 0, ep_count = 0;
|
|
+
|
|
+ if (priv == NULL)
|
|
+ return -EINVAL;
|
|
+
|
|
+ drm_mode_config_init(dev);
|
|
+ mode_config = &dev->mode_config;
|
|
+ mode_config->funcs = &mode_config_funcs;
|
|
+ mode_config->min_width = 1;
|
|
+ mode_config->max_width = 4096;
|
|
+ mode_config->min_height = 1;
|
|
+ mode_config->max_height = 4096;
|
|
+
|
|
+ ret = baikal_vdu_primary_plane_init(dev);
|
|
+ if (ret != 0) {
|
|
+ dev_err(dev->dev, "Failed to init primary plane\n");
|
|
+ goto out_config;
|
|
+ }
|
|
+
|
|
+ ret = baikal_vdu_crtc_create(dev);
|
|
+ if (ret) {
|
|
+ dev_err(dev->dev, "Failed to create crtc\n");
|
|
+ goto out_config;
|
|
+ }
|
|
+
|
|
+ ret = drm_of_find_panel_or_bridge(dev->dev->of_node, -1, -1,
|
|
+ &priv->panel,
|
|
+ &priv->bridge);
|
|
+ if (ret == -EPROBE_DEFER) {
|
|
+ dev_info(dev->dev, "Bridge probe deferred\n");
|
|
+ goto out_config;
|
|
+ }
|
|
+ ep_count = of_graph_get_endpoint_count(dev->dev->of_node);
|
|
+ if (ep_count <= 0) {
|
|
+ dev_err(dev->dev, "no endpoints connected to panel/bridge\n");
|
|
+ goto out_config;
|
|
+ }
|
|
+ priv->ep_count = ep_count;
|
|
+
|
|
+ if (priv->bridge) {
|
|
+ struct drm_encoder *encoder = &priv->encoder;
|
|
+ ret = drm_encoder_init(dev, encoder, &baikal_vdu_encoder_funcs,
|
|
+ DRM_MODE_ENCODER_NONE, NULL);
|
|
+ if (ret) {
|
|
+ dev_err(dev->dev, "failed to create DRM encoder\n");
|
|
+ goto out_config;
|
|
+ }
|
|
+ encoder->crtc = &priv->crtc;
|
|
+ encoder->possible_crtcs = drm_crtc_mask(encoder->crtc);
|
|
+ priv->bridge->encoder = &priv->encoder;
|
|
+ ret = drm_bridge_attach(&priv->encoder, priv->bridge, NULL, 0);
|
|
+ if (ret) {
|
|
+ dev_err(dev->dev, "Failed to attach DRM bridge %d\n", ret);
|
|
+ goto out_config;
|
|
+ }
|
|
+ } else if (priv->panel) {
|
|
+ dev_dbg(dev->dev, "panel has %d endpoints\n", priv->ep_count);
|
|
+ ret = baikal_vdu_lvds_connector_create(dev);
|
|
+ if (ret) {
|
|
+ dev_err(dev->dev, "Failed to create DRM connector\n");
|
|
+ goto out_config;
|
|
+ }
|
|
+ } else
|
|
+ ret = -EINVAL;
|
|
+
|
|
+ if (ret) {
|
|
+ dev_err(dev->dev, "No bridge or panel attached!\n");
|
|
+ goto out_config;
|
|
+ }
|
|
+
|
|
+ priv->clk = clk_get(dev->dev, "pclk");
|
|
+ if (IS_ERR(priv->clk)) {
|
|
+ dev_err(dev->dev, "fatal: unable to get pclk, err %ld\n", PTR_ERR(priv->clk));
|
|
+ ret = PTR_ERR(priv->clk);
|
|
+ goto out_config;
|
|
+ }
|
|
+
|
|
+ priv->mode_fixup = mode_fixup;
|
|
+
|
|
+ drm_aperture_remove_framebuffers(false, &vdu_drm_driver);
|
|
+
|
|
+ ret = drm_vblank_init(dev, 1);
|
|
+ if (ret != 0) {
|
|
+ dev_err(dev->dev, "Failed to init vblank\n");
|
|
+ goto out_clk;
|
|
+ }
|
|
+
|
|
+ arm_smccc_smc(BAIKAL_SMC_SCP_LOG_DISABLE, 0, 0, 0, 0, 0, 0, 0, &res);
|
|
+
|
|
+ drm_mode_config_reset(dev);
|
|
+
|
|
+ drm_kms_helper_poll_init(dev);
|
|
+
|
|
+ ret = drm_dev_register(dev, 0);
|
|
+ if (ret)
|
|
+ goto out_clk;
|
|
+
|
|
+ drm_fbdev_generic_setup(dev, 32);
|
|
+ goto finish;
|
|
+
|
|
+out_clk:
|
|
+ clk_put(priv->clk);
|
|
+out_config:
|
|
+ drm_mode_config_cleanup(dev);
|
|
+finish:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+
|
|
+static int baikal_vdu_irq_install(struct baikal_vdu_private *priv, int irq)
|
|
+{
|
|
+ int ret;
|
|
+ ret= request_irq(irq, baikal_vdu_irq, 0, DRIVER_NAME, priv->drm);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ priv->irq_enabled = true;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void baikal_vdu_irq_uninstall(struct baikal_vdu_private *priv)
|
|
+{
|
|
+ if (priv->irq_enabled) {
|
|
+ priv->irq_enabled = false;
|
|
+ disable_irq(priv->irq);
|
|
+ free_irq(priv->irq, priv->drm);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int vdu_maybe_enable_lvds(struct baikal_vdu_private *vdu)
|
|
+{
|
|
+ int err = 0;
|
|
+ struct device *dev;
|
|
+ if (!vdu->drm) {
|
|
+ pr_err("%s: vdu->drm is NULL\n", __func__);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ dev = vdu->drm->dev;
|
|
+
|
|
+ vdu->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
|
|
+ if (IS_ERR(vdu->enable_gpio)) {
|
|
+ err = (int)PTR_ERR(vdu->enable_gpio);
|
|
+ dev_err(dev, "failed to get enable-gpios, error %d\n", err);
|
|
+ vdu->enable_gpio = NULL;
|
|
+ return err;
|
|
+ }
|
|
+ if (vdu->enable_gpio) {
|
|
+ dev_dbg(dev, "%s: setting enable-gpio\n", __func__);
|
|
+ gpiod_set_value_cansleep(vdu->enable_gpio, 1);
|
|
+ } else {
|
|
+ dev_dbg(dev, "%s: no enable-gpios, assuming it's handled by panel-lvds\n", __func__);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int baikal_vdu_drm_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct baikal_vdu_private *priv;
|
|
+ struct drm_device *drm;
|
|
+ struct resource *mem;
|
|
+ int irq;
|
|
+ int ret;
|
|
+
|
|
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
+ if (!priv)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ drm = drm_dev_alloc(&vdu_drm_driver, dev);
|
|
+ if (IS_ERR(drm))
|
|
+ return PTR_ERR(drm);
|
|
+ platform_set_drvdata(pdev, drm);
|
|
+ priv->drm = drm;
|
|
+ drm->dev_private = priv;
|
|
+
|
|
+ if (!(mem = platform_get_resource(pdev, IORESOURCE_MEM, 0))) {
|
|
+ dev_err(dev, "%s no MMIO resource specified\n", __func__);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ priv->regs = devm_ioremap_resource(dev, mem);
|
|
+ if (IS_ERR(priv->regs)) {
|
|
+ dev_err(dev, "%s MMIO allocation failed\n", __func__);
|
|
+ return PTR_ERR(priv->regs);
|
|
+ }
|
|
+
|
|
+ /* turn off interrupts before requesting the irq */
|
|
+ writel(0, priv->regs + IMR);
|
|
+
|
|
+ irq = platform_get_irq(pdev, 0);
|
|
+ if (irq < 0) {
|
|
+ dev_err(dev, "%s no IRQ resource specified\n", __func__);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ priv->irq = irq;
|
|
+
|
|
+ ret = baikal_vdu_irq_install(priv, irq);
|
|
+ if (ret != 0) {
|
|
+ dev_err(dev, "%s IRQ %d allocation failed\n", __func__, irq);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if (pdev->dev.of_node && of_property_read_bool(pdev->dev.of_node, "lvds-out")) {
|
|
+ priv->type = VDU_TYPE_LVDS;
|
|
+ if (of_property_read_u32(pdev->dev.of_node, "num-lanes", &priv->ep_count))
|
|
+ priv->ep_count = 1;
|
|
+ }
|
|
+ else
|
|
+ priv->type = VDU_TYPE_HDMI;
|
|
+
|
|
+ ret = vdu_modeset_init(drm);
|
|
+ if (ret != 0) {
|
|
+ dev_err(dev, "Failed to init modeset\n");
|
|
+ goto dev_unref;
|
|
+ }
|
|
+
|
|
+ ret = vdu_maybe_enable_lvds(priv);
|
|
+ if (ret != 0) {
|
|
+ dev_err(dev, "failed to enable LVDS\n");
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+dev_unref:
|
|
+ writel(0, priv->regs + IMR);
|
|
+ writel(0x3ffff, priv->regs + ISR);
|
|
+ baikal_vdu_irq_uninstall(priv);
|
|
+ drm->dev_private = NULL;
|
|
+ drm_dev_put(drm);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int baikal_vdu_drm_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct drm_device *drm;
|
|
+ struct baikal_vdu_private *priv;
|
|
+
|
|
+ drm = platform_get_drvdata(pdev);
|
|
+ if (!drm) {
|
|
+ return -1;
|
|
+ }
|
|
+ priv = drm->dev_private;
|
|
+
|
|
+ drm_dev_unregister(drm);
|
|
+ drm_mode_config_cleanup(drm);
|
|
+ baikal_vdu_irq_uninstall(priv);
|
|
+ drm->dev_private = NULL;
|
|
+ drm_dev_put(drm);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct of_device_id baikal_vdu_of_match[] = {
|
|
+ { .compatible = "baikal,vdu" },
|
|
+ { },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, baikal_vdu_of_match);
|
|
+
|
|
+static struct platform_driver baikal_vdu_platform_driver = {
|
|
+ .probe = baikal_vdu_drm_probe,
|
|
+ .remove = baikal_vdu_drm_remove,
|
|
+ .driver = {
|
|
+ .name = DRIVER_NAME,
|
|
+ .of_match_table = baikal_vdu_of_match,
|
|
+ },
|
|
+};
|
|
+
|
|
+module_param(mode_fixup, int, 0644);
|
|
+
|
|
+module_platform_driver(baikal_vdu_platform_driver);
|
|
+
|
|
+MODULE_AUTHOR("Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>");
|
|
+MODULE_DESCRIPTION("Baikal Electronics BE-M1000 Video Display Unit (VDU) DRM Driver");
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_ALIAS("platform:" DRIVER_NAME);
|
|
+MODULE_SOFTDEP("pre: baikal_hdmi");
|
|
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_plane.c b/drivers/gpu/drm/baikal/baikal_vdu_plane.c
|
|
new file mode 100644
|
|
index 000000000..4a3e97179
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/baikal/baikal_vdu_plane.c
|
|
@@ -0,0 +1,209 @@
|
|
+/*
|
|
+ * Copyright (C) 2019-2020 Baikal Electronics JSC
|
|
+ *
|
|
+ * Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
|
|
+ *
|
|
+ * Parts of this file were based on sources as follows:
|
|
+ *
|
|
+ * Copyright (c) 2006-2008 Intel Corporation
|
|
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
|
|
+ * Copyright (C) 2011 Texas Instruments
|
|
+ * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
|
|
+ *
|
|
+ * This program is free software and is provided to you under the terms of the
|
|
+ * GNU General Public License version 2 as published by the Free Software
|
|
+ * Foundation, and any use by you of this program is subject to the terms of
|
|
+ * such GNU licence.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/clk.h>
|
|
+#include <linux/clk-provider.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/of_graph.h>
|
|
+#include <drm/drm_atomic.h>
|
|
+#include <drm/drm_atomic_helper.h>
|
|
+#include <drm/drm_fb_cma_helper.h>
|
|
+#include <drm/drm_fourcc.h>
|
|
+#include <drm/drm_gem_cma_helper.h>
|
|
+#include <drm/drm_plane_helper.h>
|
|
+
|
|
+#include "baikal_vdu_drm.h"
|
|
+#include "baikal_vdu_regs.h"
|
|
+
|
|
+static int baikal_vdu_primary_plane_atomic_check(struct drm_plane *plane,
|
|
+ struct drm_atomic_state *atomic_state)
|
|
+{
|
|
+ struct drm_device *dev = plane->dev;
|
|
+ struct baikal_vdu_private *priv = dev->dev_private;
|
|
+ struct drm_crtc_state *crtc_state;
|
|
+ struct drm_plane_state *state;
|
|
+ struct drm_display_mode *mode;
|
|
+ int rate, ret;
|
|
+ u32 cntl;
|
|
+
|
|
+ state = drm_atomic_get_new_plane_state(atomic_state, plane);
|
|
+ if (!state || !state->crtc)
|
|
+ return 0;
|
|
+
|
|
+ crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
|
|
+ if (IS_ERR(crtc_state)) {
|
|
+ ret = PTR_ERR(crtc_state);
|
|
+ dev_warn(dev->dev, "failed to get crtc_state: %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+ mode = &crtc_state->adjusted_mode;
|
|
+ rate = mode->clock * 1000;
|
|
+ if (rate == clk_get_rate(priv->clk))
|
|
+ return 0;
|
|
+
|
|
+ /* hold clock domain reset; disable clocking */
|
|
+ writel(0, priv->regs + PCTR);
|
|
+
|
|
+ if (__clk_is_enabled(priv->clk))
|
|
+ clk_disable_unprepare(priv->clk);
|
|
+ ret = clk_set_rate(priv->clk, rate);
|
|
+ DRM_DEV_DEBUG_DRIVER(dev->dev, "Requested pixel clock is %d Hz\n", rate);
|
|
+
|
|
+ if (ret < 0) {
|
|
+ DRM_ERROR("Cannot set desired pixel clock (%d Hz)\n",
|
|
+ rate);
|
|
+ ret = -EINVAL;
|
|
+ } else {
|
|
+ clk_prepare_enable(priv->clk);
|
|
+ if (__clk_is_enabled(priv->clk))
|
|
+ ret = 0;
|
|
+ else {
|
|
+ DRM_ERROR("PLL could not lock at desired frequency (%d Hz)\n",
|
|
+ rate);
|
|
+ ret = -EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* release clock domain reset; enable clocking */
|
|
+ cntl = readl(priv->regs + PCTR);
|
|
+ cntl |= PCTR_PCR + PCTR_PCI;
|
|
+ writel(cntl, priv->regs + PCTR);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void baikal_vdu_primary_plane_atomic_update(struct drm_plane *plane,
|
|
+ struct drm_atomic_state *old_state)
|
|
+{
|
|
+ struct drm_device *dev = plane->dev;
|
|
+ struct baikal_vdu_private *priv = dev->dev_private;
|
|
+ struct drm_plane_state *state = plane->state;
|
|
+ struct drm_framebuffer *fb = state->fb;
|
|
+ u32 cntl, addr, end;
|
|
+
|
|
+ if (!fb)
|
|
+ return;
|
|
+
|
|
+ addr = drm_fb_cma_get_gem_addr(fb, state, 0);
|
|
+ priv->fb_addr = addr & 0xfffffff8;
|
|
+
|
|
+ cntl = readl(priv->regs + CR1);
|
|
+ cntl &= ~CR1_BPP_MASK;
|
|
+
|
|
+ /* Note that the the hardware's format reader takes 'r' from
|
|
+ * the low bit, while DRM formats list channels from high bit
|
|
+ * to low bit as you read left to right.
|
|
+ */
|
|
+ switch (fb->format->format) {
|
|
+ case DRM_FORMAT_BGR888:
|
|
+ cntl |= CR1_BPP24 | CR1_FBP | CR1_BGR;
|
|
+ break;
|
|
+ case DRM_FORMAT_RGB888:
|
|
+ cntl |= CR1_BPP24 | CR1_FBP;
|
|
+ break;
|
|
+ case DRM_FORMAT_ABGR8888:
|
|
+ case DRM_FORMAT_XBGR8888:
|
|
+ cntl |= CR1_BPP24 | CR1_BGR;
|
|
+ break;
|
|
+ case DRM_FORMAT_ARGB8888:
|
|
+ case DRM_FORMAT_XRGB8888:
|
|
+ cntl |= CR1_BPP24;
|
|
+ break;
|
|
+ case DRM_FORMAT_BGR565:
|
|
+ cntl |= CR1_BPP16_565 | CR1_BGR;
|
|
+ break;
|
|
+ case DRM_FORMAT_RGB565:
|
|
+ cntl |= CR1_BPP16_565;
|
|
+ break;
|
|
+ case DRM_FORMAT_ABGR1555:
|
|
+ case DRM_FORMAT_XBGR1555:
|
|
+ cntl |= CR1_BPP16_555 | CR1_BGR;
|
|
+ break;
|
|
+ case DRM_FORMAT_ARGB1555:
|
|
+ case DRM_FORMAT_XRGB1555:
|
|
+ cntl |= CR1_BPP16_555;
|
|
+ break;
|
|
+ default:
|
|
+ WARN_ONCE(true, "Unknown FB format 0x%08x, set XRGB8888 instead\n",
|
|
+ fb->format->format);
|
|
+ cntl |= CR1_BPP24;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ writel(priv->fb_addr, priv->regs + DBAR);
|
|
+ end = ((priv->fb_addr + fb->height * fb->pitches[0] - 1) & MRR_DEAR_MRR_MASK) | \
|
|
+ MRR_OUTSTND_RQ(4);
|
|
+
|
|
+ if (priv->fb_end < end) {
|
|
+ writel(end, priv->regs + MRR);
|
|
+ priv->fb_end = end;
|
|
+ }
|
|
+ writel(cntl, priv->regs + CR1);
|
|
+}
|
|
+
|
|
+static const struct drm_plane_helper_funcs baikal_vdu_primary_plane_helper_funcs = {
|
|
+ .atomic_check = baikal_vdu_primary_plane_atomic_check,
|
|
+ .atomic_update = baikal_vdu_primary_plane_atomic_update,
|
|
+};
|
|
+
|
|
+static const struct drm_plane_funcs baikal_vdu_primary_plane_funcs = {
|
|
+ .update_plane = drm_atomic_helper_update_plane,
|
|
+ .disable_plane = drm_atomic_helper_disable_plane,
|
|
+ .reset = drm_atomic_helper_plane_reset,
|
|
+ .destroy = drm_plane_cleanup,
|
|
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
|
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
|
+};
|
|
+
|
|
+int baikal_vdu_primary_plane_init(struct drm_device *drm)
|
|
+{
|
|
+ struct baikal_vdu_private *priv = drm->dev_private;
|
|
+ struct drm_plane *plane = &priv->primary;
|
|
+ static const u32 formats[] = {
|
|
+ DRM_FORMAT_BGR888,
|
|
+ DRM_FORMAT_RGB888,
|
|
+ DRM_FORMAT_ABGR8888,
|
|
+ DRM_FORMAT_XBGR8888,
|
|
+ DRM_FORMAT_ARGB8888,
|
|
+ DRM_FORMAT_XRGB8888,
|
|
+ DRM_FORMAT_BGR565,
|
|
+ DRM_FORMAT_RGB565,
|
|
+ DRM_FORMAT_ABGR1555,
|
|
+ DRM_FORMAT_XBGR1555,
|
|
+ DRM_FORMAT_ARGB1555,
|
|
+ DRM_FORMAT_XRGB1555,
|
|
+ };
|
|
+ int ret;
|
|
+
|
|
+ ret = drm_universal_plane_init(drm, plane, 0,
|
|
+ &baikal_vdu_primary_plane_funcs,
|
|
+ formats,
|
|
+ ARRAY_SIZE(formats),
|
|
+ NULL,
|
|
+ DRM_PLANE_TYPE_PRIMARY,
|
|
+ NULL);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ drm_plane_helper_add(plane, &baikal_vdu_primary_plane_helper_funcs);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_regs.h b/drivers/gpu/drm/baikal/baikal_vdu_regs.h
|
|
new file mode 100644
|
|
index 000000000..5553fcac5
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/baikal/baikal_vdu_regs.h
|
|
@@ -0,0 +1,139 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2019-2021 Baikal Electronics JSC
|
|
+ *
|
|
+ * Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
|
|
+ *
|
|
+ * Parts of this file were based on sources as follows:
|
|
+ *
|
|
+ * David A Rusling
|
|
+ * Copyright (C) 2001 ARM Limited
|
|
+ */
|
|
+
|
|
+#ifndef __BAIKAL_VDU_REGS_H__
|
|
+#define __BAIKAL_VDU_REGS_H__
|
|
+
|
|
+#define CR1 0x000
|
|
+#define HTR 0x008
|
|
+#define VTR1 0x00C
|
|
+#define VTR2 0x010
|
|
+#define PCTR 0x014
|
|
+#define ISR 0x018
|
|
+#define IMR 0x01C
|
|
+#define IVR 0x020
|
|
+#define ISCR 0x024
|
|
+#define DBAR 0x028
|
|
+#define DCAR 0x02C
|
|
+#define DEAR 0x030
|
|
+#define HVTER 0x044
|
|
+#define HPPLOR 0x048
|
|
+#define GPIOR 0x1F8
|
|
+#define OWER 0x600
|
|
+#define OWXSER0 0x604
|
|
+#define OWYSER0 0x608
|
|
+#define OWDBAR0 0x60C
|
|
+#define OWDCAR0 0x610
|
|
+#define OWDEAR0 0x614
|
|
+#define OWXSER1 0x618
|
|
+#define OWYSER1 0x61C
|
|
+#define OWDBAR1 0x620
|
|
+#define OWDCAR1 0x624
|
|
+#define OWDEAR1 0x628
|
|
+#define MRR 0xFFC
|
|
+
|
|
+#define INTR_BAU BIT(7)
|
|
+#define INTR_VCT BIT(6)
|
|
+#define INTR_MBE BIT(5)
|
|
+#define INTR_FER BIT(4)
|
|
+
|
|
+#define CR1_FBP BIT(19)
|
|
+#define CR1_FDW_MASK GENMASK(17, 16)
|
|
+#define CR1_FDW_4_WORDS (0 << 16)
|
|
+#define CR1_FDW_8_WORDS (1 << 16)
|
|
+#define CR1_FDW_16_WORDS (2 << 16)
|
|
+#define CR1_OPS_LCD18 (0 << 13)
|
|
+#define CR1_OPS_LCD24 (1 << 13)
|
|
+#define CR1_OPS_565 (0 << 12)
|
|
+#define CR1_OPS_555 (1 << 12)
|
|
+#define CR1_VSP BIT(11)
|
|
+#define CR1_HSP BIT(10)
|
|
+#define CR1_DEP BIT(8)
|
|
+#define CR1_BGR BIT(5)
|
|
+#define CR1_BPP_MASK GENMASK(4, 2)
|
|
+#define CR1_BPP1 (0 << 2)
|
|
+#define CR1_BPP2 (1 << 2)
|
|
+#define CR1_BPP4 (2 << 2)
|
|
+#define CR1_BPP8 (3 << 2)
|
|
+#define CR1_BPP16 (4 << 2)
|
|
+#define CR1_BPP18 (5 << 2)
|
|
+#define CR1_BPP24 (6 << 2)
|
|
+#define CR1_LCE BIT(0)
|
|
+
|
|
+#define CR1_BPP16_555 ((CR1_BPP16) | (CR1_OPS_555))
|
|
+#define CR1_BPP16_565 ((CR1_BPP16) | (CR1_OPS_565))
|
|
+
|
|
+#define VTR1_VBP_MASK GENMASK(23, 16)
|
|
+#define VTR1_VBP(x) ((x) << 16)
|
|
+#define VTR1_VBP_LSB_WIDTH 8
|
|
+#define VTR1_VFP_MASK GENMASK(15, 8)
|
|
+#define VTR1_VFP(x) ((x) << 8)
|
|
+#define VTR1_VFP_LSB_WIDTH 8
|
|
+#define VTR1_VSW_MASK GENMASK(7, 0)
|
|
+#define VTR1_VSW(x) ((x) << 0)
|
|
+#define VTR1_VSW_LSB_WIDTH 8
|
|
+
|
|
+#define VTR2_LPP_MASK GENMASK(11, 0)
|
|
+
|
|
+#define HTR_HSW_MASK GENMASK(31, 24)
|
|
+#define HTR_HSW(x) ((x) << 24)
|
|
+#define HTR_HSW_LSB_WIDTH 8
|
|
+#define HTR_HBP_MASK GENMASK(23, 16)
|
|
+#define HTR_HBP(x) ((x) << 16)
|
|
+#define HTR_HBP_LSB_WIDTH 8
|
|
+#define HTR_PPL_MASK GENMASK(15, 8)
|
|
+#define HTR_PPL(x) ((x) << 8)
|
|
+#define HTR_HFP_MASK GENMASK(7, 0)
|
|
+#define HTR_HFP(x) ((x) << 0)
|
|
+#define HTR_HFP_LSB_WIDTH 8
|
|
+
|
|
+#define PCTR_PCI2 BIT(11)
|
|
+#define PCTR_PCR BIT(10)
|
|
+#define PCTR_PCI BIT(9)
|
|
+#define PCTR_PCB BIT(8)
|
|
+#define PCTR_PCD_MASK GENMASK(7, 0)
|
|
+#define PCTR_MAX_PCD 128
|
|
+
|
|
+#define ISCR_VSC_OFF 0x0
|
|
+#define ISCR_VSC_VSW 0x4
|
|
+#define ISCR_VSC_VBP 0x5
|
|
+#define ISCR_VSC_VACTIVE 0x6
|
|
+#define ISCR_VSC_VFP 0x7
|
|
+
|
|
+#define HVTER_VSWE_MASK GENMASK(25, 24)
|
|
+#define HVTER_VSWE(x) ((x) << 24)
|
|
+#define HVTER_HSWE_MASK GENMASK(17, 16)
|
|
+#define HVTER_HSWE(x) ((x) << 16)
|
|
+#define HVTER_VBPE_MASK GENMASK(13, 12)
|
|
+#define HVTER_VBPE(x) ((x) << 12)
|
|
+#define HVTER_VFPE_MASK GENMASK(9, 8)
|
|
+#define HVTER_VFPE(x) ((x) << 8)
|
|
+#define HVTER_HBPE_MASK GENMASK(5, 4)
|
|
+#define HVTER_HBPE(x) ((x) << 4)
|
|
+#define HVTER_HFPE_MASK GENMASK(1, 0)
|
|
+#define HVTER_HFPE(x) ((x) << 0)
|
|
+
|
|
+#define HPPLOR_HPOE BIT(31)
|
|
+#define HPPLOR_HPPLO_MASK GENMASK(11, 0)
|
|
+#define HPPLOR_HPPLO(x) ((x) << 0)
|
|
+
|
|
+#define GPIOR_UHD_MASK GENMASK(23, 16)
|
|
+#define GPIOR_UHD_SNGL_PORT (0 << 18)
|
|
+#define GPIOR_UHD_DUAL_PORT (1 << 18)
|
|
+#define GPIOR_UHD_QUAD_PORT (2 << 18)
|
|
+#define GPIOR_UHD_ENB BIT(17)
|
|
+
|
|
+#define MRR_DEAR_MRR_MASK GENMASK(31, 3)
|
|
+#define MRR_OUTSTND_RQ_MASK GENMASK(2, 0)
|
|
+#define MRR_OUTSTND_RQ(x) ((x >> 1) << 0)
|
|
+
|
|
+#endif /* __BAIKAL_VDU_REGS_H__ */
|
|
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
|
|
index 5f1778c36..c12e0c0c3 100644
|
|
--- a/drivers/gpu/drm/bridge/Kconfig
|
|
+++ b/drivers/gpu/drm/bridge/Kconfig
|
|
@@ -135,6 +135,13 @@ config DRM_LVDS_CODEC
|
|
Support for transparent LVDS encoders and decoders that don't
|
|
require any configuration.
|
|
|
|
+config DRM_BAIKAL_HDMI
|
|
+ tristate "Baikal-M HDMI transmitter"
|
|
+ default y if ARCH_BAIKAL
|
|
+ select DRM_DW_HDMI
|
|
+ help
|
|
+ Choose this if you want to use HDMI on Baikal-M.
|
|
+
|
|
config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW
|
|
tristate "MegaChips stdp4028-ge-b850v3-fw and stdp2690-ge-b850v3-fw"
|
|
depends on OF
|
|
--
|
|
2.33.2
|
|
|