3590 lines
104 KiB
Diff
3590 lines
104 KiB
Diff
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|||
|
From: "sw.multimedia" <sw.multimedia@starfivetech.com>
|
|||
|
Date: Tue, 31 Aug 2021 16:48:57 +0800
|
|||
|
Subject: drm/starfive: Add StarFive drm driver
|
|||
|
|
|||
|
Add starfive DRM Display driver framework
|
|||
|
|
|||
|
Signed-off-by: jack.zhu <jack.zhu@starfivetech.com>
|
|||
|
Signed-off-by: keith.zhao <keith.zhao@starfivetech.com>
|
|||
|
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
|
|||
|
Signed-off-by: Jose Exposito <jose.exposito89@gmail.com>
|
|||
|
Link: https://lore.kernel.org/r/a8ca722539672d6369d6e4092e1e08cb6b58c546.1645535955.git.geert@linux-m68k.org
|
|||
|
Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
|
|||
|
---
|
|||
|
drivers/gpu/drm/Kconfig | 2 +
|
|||
|
drivers/gpu/drm/Makefile | 1 +
|
|||
|
drivers/gpu/drm/starfive/Kconfig | 17 +
|
|||
|
drivers/gpu/drm/starfive/Makefile | 13 +
|
|||
|
drivers/gpu/drm/starfive/README.txt | 56 +
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_crtc.c | 511 ++++++
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_crtc.h | 86 +
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_drv.c | 265 +++
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_drv.h | 25 +
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_encoder.c | 129 ++
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_encoder.h | 18 +
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_gem.c | 346 ++++
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_gem.h | 40 +
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_lcdc.c | 512 ++++++
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_lcdc.h | 160 ++
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_plane.c | 227 +++
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_plane.h | 12 +
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_vpp.c | 806 ++++++++++
|
|||
|
drivers/gpu/drm/starfive/starfive_drm_vpp.h | 201 +++
|
|||
|
19 files changed, 3427 insertions(+)
|
|||
|
|
|||
|
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
|
|||
|
index f30f99166531..785a124b0e69 100644
|
|||
|
--- a/drivers/gpu/drm/Kconfig
|
|||
|
+++ b/drivers/gpu/drm/Kconfig
|
|||
|
@@ -347,6 +347,8 @@ source "drivers/gpu/drm/shmobile/Kconfig"
|
|||
|
|
|||
|
source "drivers/gpu/drm/sun4i/Kconfig"
|
|||
|
|
|||
|
+source "drivers/gpu/drm/starfive/Kconfig"
|
|||
|
+
|
|||
|
source "drivers/gpu/drm/omapdrm/Kconfig"
|
|||
|
|
|||
|
source "drivers/gpu/drm/tilcdc/Kconfig"
|
|||
|
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
|
|||
|
index 0b283e46f28b..ffda709edeae 100644
|
|||
|
--- a/drivers/gpu/drm/Makefile
|
|||
|
+++ b/drivers/gpu/drm/Makefile
|
|||
|
@@ -114,6 +114,7 @@ obj-y += rcar-du/
|
|||
|
obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
|
|||
|
obj-y += omapdrm/
|
|||
|
obj-$(CONFIG_DRM_SUN4I) += sun4i/
|
|||
|
+obj-$(CONFIG_DRM_STARFIVE) += starfive/
|
|||
|
obj-y += tilcdc/
|
|||
|
obj-$(CONFIG_DRM_QXL) += qxl/
|
|||
|
obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/
|
|||
|
diff --git a/drivers/gpu/drm/starfive/Kconfig b/drivers/gpu/drm/starfive/Kconfig
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..df8eea2c6549
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/Kconfig
|
|||
|
@@ -0,0 +1,17 @@
|
|||
|
+# SPDX-License-Identifier: GPL-2.0
|
|||
|
+# Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+
|
|||
|
+config DRM_STARFIVE
|
|||
|
+ tristate "DRM Support for StarFive SoCs"
|
|||
|
+ depends on DRM
|
|||
|
+ depends on SIFIVE_CCACHE
|
|||
|
+ depends on SOC_STARFIVE || COMPILE_TEST
|
|||
|
+ select DRM_GEM_DMA_HELPER
|
|||
|
+ select DRM_KMS_HELPER
|
|||
|
+ select DRM_MIPI_DSI
|
|||
|
+ select DRM_PANEL
|
|||
|
+ help
|
|||
|
+ Choose this option if you have a StarFive SoCs.
|
|||
|
+ The module will be called starfive-drm
|
|||
|
+ This driver provides kernel mode setting and
|
|||
|
+ buffer management to userspace.
|
|||
|
diff --git a/drivers/gpu/drm/starfive/Makefile b/drivers/gpu/drm/starfive/Makefile
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..8ef9e5f469fd
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/Makefile
|
|||
|
@@ -0,0 +1,13 @@
|
|||
|
+# SPDX-License-Identifier: GPL-2.0
|
|||
|
+#
|
|||
|
+# Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+#
|
|||
|
+starfive-drm-y := starfive_drm_drv.o \
|
|||
|
+ starfive_drm_gem.o \
|
|||
|
+ starfive_drm_crtc.o \
|
|||
|
+ starfive_drm_encoder.o \
|
|||
|
+ starfive_drm_plane.o \
|
|||
|
+ starfive_drm_lcdc.o \
|
|||
|
+ starfive_drm_vpp.o
|
|||
|
+
|
|||
|
+obj-$(CONFIG_DRM_STARFIVE) += starfive-drm.o
|
|||
|
diff --git a/drivers/gpu/drm/starfive/README.txt b/drivers/gpu/drm/starfive/README.txt
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..dadec80c98bf
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/README.txt
|
|||
|
@@ -0,0 +1,56 @@
|
|||
|
+Display Subsystem:(default FBdev)
|
|||
|
+
|
|||
|
+Steps switch to DRM:
|
|||
|
+1、Disable fbdev,close below config items:
|
|||
|
+CONFIG_FB_STARFIVE=y
|
|||
|
+CONFIG_FB_STARFIVE_HDMI_TDA998X=y
|
|||
|
+CONFIG_FB_STARFIVE_VIDEO=y
|
|||
|
+
|
|||
|
+2、open DRM hdmi pipeline,enable items:
|
|||
|
+CONFIG_DRM_I2C_NXP_TDA998X=y
|
|||
|
+CONFIG_DRM_I2C_NXP_TDA9950=y
|
|||
|
+CONFIG_DRM_STARFIVE=y
|
|||
|
+CONFIG_FRAMEBUFFER_CONSOLE=y
|
|||
|
+
|
|||
|
+Precautions:when use DRM hdmi pipeline,please make sure CONFIG_DRM_STARFIVE_MIPI_DSI is disable ,
|
|||
|
+ or will cause color abnormal.
|
|||
|
+
|
|||
|
+3、open DRM mipi pipeline
|
|||
|
+
|
|||
|
+enable items:
|
|||
|
+ CONFIG_PHY_M31_DPHY_RX0=y
|
|||
|
+ CONFIG_DRM_STARFIVE_MIPI_DSI=y
|
|||
|
+
|
|||
|
+
|
|||
|
+change jh7100.dtsi display-encoder as below:
|
|||
|
+
|
|||
|
+ display-encoder {
|
|||
|
+ compatible = "starfive,display-encoder";
|
|||
|
+ encoder-type = <6>; //2-TMDS, 3-LVDS, 6-DSI, 8-DPI
|
|||
|
+ status = "okay";
|
|||
|
+
|
|||
|
+ ports {
|
|||
|
+ port@0 {
|
|||
|
+ endpoint {
|
|||
|
+ remote-endpoint = <&dsi_out_port>;
|
|||
|
+ };
|
|||
|
+ };
|
|||
|
+
|
|||
|
+ port@1 {
|
|||
|
+ endpoint {
|
|||
|
+ remote-endpoint = <&crtc_0_out>;
|
|||
|
+ };
|
|||
|
+ };
|
|||
|
+ };
|
|||
|
+ };
|
|||
|
+
|
|||
|
+install libdrm:
|
|||
|
+make buildroot_initramfs-menuconfig
|
|||
|
+choose:
|
|||
|
+BR2_PACKAGE_LIBDRM=y
|
|||
|
+BR2_PACKAGE_LIBDRM_RADEON=y
|
|||
|
+BR2_PACKAGE_LIBDRM_AMDGPU=y
|
|||
|
+BR2_PACKAGE_LIBDRM_NOUVEAU=y
|
|||
|
+BR2_PACKAGE_LIBDRM_ETNAVIV=y
|
|||
|
+BR2_PACKAGE_LIBDRM_INSTALL_TESTS=y
|
|||
|
+
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_crtc.c b/drivers/gpu/drm/starfive/starfive_drm_crtc.c
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..5ba973377059
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_crtc.c
|
|||
|
@@ -0,0 +1,511 @@
|
|||
|
+// SPDX-License-Identifier: GPL-2.0
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#include <linux/clk.h>
|
|||
|
+#include <linux/component.h>
|
|||
|
+#include <linux/of_device.h>
|
|||
|
+#include <linux/reset.h>
|
|||
|
+#include <linux/delay.h>
|
|||
|
+#include <drm/drm_atomic.h>
|
|||
|
+#include <drm/drm_atomic_helper.h>
|
|||
|
+#include <drm/drm_atomic_uapi.h>
|
|||
|
+#include <drm/drm_fb_dma_helper.h>
|
|||
|
+#include <drm/drm_print.h>
|
|||
|
+#include <drm/drm_probe_helper.h>
|
|||
|
+#include <drm/drm_vblank.h>
|
|||
|
+#include <drm/drm_gem_atomic_helper.h>
|
|||
|
+#include "starfive_drm_drv.h"
|
|||
|
+#include "starfive_drm_crtc.h"
|
|||
|
+#include "starfive_drm_plane.h"
|
|||
|
+#include "starfive_drm_lcdc.h"
|
|||
|
+#include "starfive_drm_vpp.h"
|
|||
|
+//#include <video/sys_comm_regs.h>
|
|||
|
+
|
|||
|
+static inline struct drm_encoder *
|
|||
|
+starfive_head_atom_get_encoder(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ struct drm_encoder *encoder = NULL;
|
|||
|
+
|
|||
|
+ /* We only ever have a single encoder */
|
|||
|
+ drm_for_each_encoder_mask(encoder, sf_crtc->crtc.dev,
|
|||
|
+ sf_crtc->crtc.state->encoder_mask)
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ return encoder;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int ddrfmt_to_ppfmt(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ int ddrfmt = sf_crtc->ddr_format;
|
|||
|
+ int ret = 0;
|
|||
|
+
|
|||
|
+ sf_crtc->lcdcfmt = WIN_FMT_XRGB8888; //lcdc default used
|
|||
|
+ sf_crtc->pp_conn_lcdc = 1;//default config
|
|||
|
+ switch (ddrfmt) {
|
|||
|
+ case DRM_FORMAT_UYVY:
|
|||
|
+ sf_crtc->vpp_format = COLOR_YUV422_UYVY;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_VYUY:
|
|||
|
+ sf_crtc->vpp_format = COLOR_YUV422_VYUY;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_YUYV:
|
|||
|
+ sf_crtc->vpp_format = COLOR_YUV422_YUYV;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_YVYU:
|
|||
|
+ sf_crtc->vpp_format = COLOR_YUV422_YVYU;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_YUV420:
|
|||
|
+ sf_crtc->vpp_format = COLOR_YUV420P;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_NV21:
|
|||
|
+ sf_crtc->vpp_format = COLOR_YUV420_NV21;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_NV12:
|
|||
|
+ sf_crtc->vpp_format = COLOR_YUV420_NV12;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_ARGB8888:
|
|||
|
+ sf_crtc->vpp_format = COLOR_RGB888_ARGB;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_ABGR8888:
|
|||
|
+ sf_crtc->vpp_format = COLOR_RGB888_ABGR;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_RGBA8888:
|
|||
|
+ sf_crtc->vpp_format = COLOR_RGB888_RGBA;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_BGRA8888:
|
|||
|
+ sf_crtc->vpp_format = COLOR_RGB888_BGRA;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_RGB565:
|
|||
|
+ sf_crtc->vpp_format = COLOR_RGB565;
|
|||
|
+ //sf_crtc->lcdcfmt = WIN_FMT_RGB565;
|
|||
|
+ //this format no need pp, lcdc can direct read ddr buff
|
|||
|
+ //sf_crtc->pp_conn_lcdc = -1;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_XRGB1555:
|
|||
|
+ sf_crtc->lcdcfmt = WIN_FMT_XRGB1555;
|
|||
|
+ sf_crtc->pp_conn_lcdc = -1;//this format no need pp, lcdc can direct read ddr buff;
|
|||
|
+ break;
|
|||
|
+ case DRM_FORMAT_XRGB4444:
|
|||
|
+ sf_crtc->lcdcfmt = WIN_FMT_XRGB4444;
|
|||
|
+ sf_crtc->pp_conn_lcdc = -1;//this format no need pp, lcdc can direct read ddr buff;
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ default:
|
|||
|
+ ret = -1;
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return ret;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void starfive_crtc_hw_config_simple(struct starfive_crtc *starfive_crtc)
|
|||
|
+{
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_crtc_destroy(struct drm_crtc *crtc)
|
|||
|
+{
|
|||
|
+ drm_crtc_cleanup(crtc);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_crtc_destroy_state(struct drm_crtc *crtc,
|
|||
|
+ struct drm_crtc_state *state)
|
|||
|
+{
|
|||
|
+ struct starfive_crtc_state *s = to_starfive_crtc_state(state);
|
|||
|
+
|
|||
|
+ __drm_atomic_helper_crtc_destroy_state(&s->base);
|
|||
|
+ kfree(s);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_crtc_reset(struct drm_crtc *crtc)
|
|||
|
+{
|
|||
|
+ struct starfive_crtc_state *crtc_state =
|
|||
|
+ kzalloc(sizeof(*crtc_state), GFP_KERNEL);
|
|||
|
+
|
|||
|
+ if (crtc->state)
|
|||
|
+ starfive_crtc_destroy_state(crtc, crtc->state);
|
|||
|
+
|
|||
|
+ __drm_atomic_helper_crtc_reset(crtc, &crtc_state->base);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static struct drm_crtc_state *starfive_crtc_duplicate_state(struct drm_crtc *crtc)
|
|||
|
+{
|
|||
|
+ struct starfive_crtc_state *starfive_state;
|
|||
|
+
|
|||
|
+ starfive_state = kzalloc(sizeof(*starfive_state), GFP_KERNEL);
|
|||
|
+ if (!starfive_state)
|
|||
|
+ return NULL;
|
|||
|
+
|
|||
|
+ __drm_atomic_helper_crtc_duplicate_state(crtc, &starfive_state->base);
|
|||
|
+
|
|||
|
+ return &starfive_state->base;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_crtc_enable_vblank(struct drm_crtc *crtc)
|
|||
|
+{
|
|||
|
+ //need set hw
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_crtc_disable_vblank(struct drm_crtc *crtc)
|
|||
|
+{
|
|||
|
+ //need set hw
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const struct drm_crtc_funcs starfive_crtc_funcs = {
|
|||
|
+ .set_config = drm_atomic_helper_set_config,
|
|||
|
+ .page_flip = drm_atomic_helper_page_flip,
|
|||
|
+ .destroy = starfive_crtc_destroy,
|
|||
|
+ .set_property = NULL,
|
|||
|
+ .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
|
|||
|
+ .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
|
|||
|
+ .reset = starfive_crtc_reset,
|
|||
|
+ .atomic_duplicate_state = starfive_crtc_duplicate_state,
|
|||
|
+ .atomic_destroy_state = starfive_crtc_destroy_state,
|
|||
|
+ //.gamma_set = drm_atomic_helper_legacy_gamma_set,
|
|||
|
+ .enable_vblank = starfive_crtc_enable_vblank,
|
|||
|
+ .disable_vblank = starfive_crtc_disable_vblank,
|
|||
|
+ //.set_crc_source = starfive_crtc_set_crc_source,
|
|||
|
+ //.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
|||
|
+ //.verify_crc_source = starfive_crtc_verify_crc_source,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static bool starfive_crtc_mode_fixup(struct drm_crtc *crtc,
|
|||
|
+ const struct drm_display_mode *mode,
|
|||
|
+ struct drm_display_mode *adjusted_mode)
|
|||
|
+{
|
|||
|
+ /* Nothing to do here, but this callback is mandatory. */
|
|||
|
+ return true;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_crtc_atomic_check(struct drm_crtc *crtc,
|
|||
|
+ struct drm_atomic_state *state)
|
|||
|
+{
|
|||
|
+ //state->no_vblank = true; // hardware without VBLANK interrupt ???
|
|||
|
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
|
|||
|
+ crtc);
|
|||
|
+ crtc_state->no_vblank = true;
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_crtc_atomic_begin(struct drm_crtc *crtc,
|
|||
|
+ struct drm_atomic_state *old_crtc_state)
|
|||
|
+{
|
|||
|
+ //starfive_crtc_gamma_set(crtcp, crtc, old_crtc_state);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_crtc_atomic_flush(struct drm_crtc *crtc,
|
|||
|
+ struct drm_atomic_state *old_crtc_state)
|
|||
|
+{
|
|||
|
+ struct starfive_crtc *crtcp = to_starfive_crtc(crtc);
|
|||
|
+
|
|||
|
+ //starfive_flush_dcache(crtcp->dma_addr, 1920*1080*2);
|
|||
|
+ DRM_DEBUG_DRIVER("ddr_format_change [%d], dma_addr_change [%d]\n",
|
|||
|
+ crtcp->ddr_format_change, crtcp->dma_addr_change);
|
|||
|
+ if (crtcp->ddr_format_change || crtcp->dma_addr_change) {
|
|||
|
+ ddrfmt_to_ppfmt(crtcp);
|
|||
|
+ starfive_pp_update(crtcp);
|
|||
|
+ } else {
|
|||
|
+ DRM_DEBUG_DRIVER("%s with no change\n", __func__);
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_crtc_atomic_enable(struct drm_crtc *crtc,
|
|||
|
+ struct drm_atomic_state *state)
|
|||
|
+{
|
|||
|
+ struct starfive_crtc *crtcp = to_starfive_crtc(crtc);
|
|||
|
+
|
|||
|
+// enable crtc HW
|
|||
|
+#ifdef CONFIG_DRM_STARFIVE_MIPI_DSI
|
|||
|
+ dsitx_vout_init(crtcp);
|
|||
|
+ lcdc_dsi_sel(crtcp);
|
|||
|
+#else
|
|||
|
+ vout_reset(crtcp);
|
|||
|
+#endif
|
|||
|
+ ddrfmt_to_ppfmt(crtcp);
|
|||
|
+ starfive_pp_enable(crtcp);
|
|||
|
+ starfive_lcdc_enable(crtcp);
|
|||
|
+ crtcp->is_enabled = true; // should before
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_crtc_atomic_disable(struct drm_crtc *crtc,
|
|||
|
+ struct drm_atomic_state *state)
|
|||
|
+{
|
|||
|
+ struct starfive_crtc *crtcp = to_starfive_crtc(crtc);
|
|||
|
+ int pp_id;
|
|||
|
+
|
|||
|
+ for (pp_id = 0; pp_id < PP_NUM; pp_id++) {
|
|||
|
+ if (crtcp->pp[pp_id].inited == 1) {
|
|||
|
+ pp_disable_intr(crtcp, pp_id);
|
|||
|
+ vout_disable(crtcp); // disable crtc HW
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+ crtcp->is_enabled = false;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static enum drm_mode_status starfive_crtc_mode_valid(struct drm_crtc *crtc,
|
|||
|
+ const struct drm_display_mode *mode)
|
|||
|
+{
|
|||
|
+ int refresh = drm_mode_vrefresh(mode);
|
|||
|
+
|
|||
|
+ if (refresh > 60) //lcdc miss support 60+ fps
|
|||
|
+ return MODE_BAD;
|
|||
|
+ else
|
|||
|
+ return MODE_OK;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const struct drm_crtc_helper_funcs starfive_crtc_helper_funcs = {
|
|||
|
+ .mode_fixup = starfive_crtc_mode_fixup,
|
|||
|
+ .atomic_check = starfive_crtc_atomic_check,
|
|||
|
+ .atomic_begin = starfive_crtc_atomic_begin,
|
|||
|
+ .atomic_flush = starfive_crtc_atomic_flush,
|
|||
|
+ .atomic_enable = starfive_crtc_atomic_enable,
|
|||
|
+ .atomic_disable = starfive_crtc_atomic_disable,
|
|||
|
+ .mode_valid = starfive_crtc_mode_valid,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static int starfive_crtc_create(struct drm_device *drm_dev,
|
|||
|
+ struct starfive_crtc *starfive_crtc,
|
|||
|
+ const struct drm_crtc_funcs *crtc_funcs,
|
|||
|
+ const struct drm_crtc_helper_funcs *crtc_helper_funcs)
|
|||
|
+{
|
|||
|
+ struct drm_crtc *crtc = &starfive_crtc->crtc;
|
|||
|
+ struct device *dev = drm_dev->dev;
|
|||
|
+ struct device_node *port;
|
|||
|
+ int ret;
|
|||
|
+
|
|||
|
+ starfive_crtc->planes = devm_kzalloc(dev, sizeof(struct drm_plane), GFP_KERNEL);
|
|||
|
+ ret = starfive_plane_init(drm_dev, starfive_crtc, DRM_PLANE_TYPE_PRIMARY);
|
|||
|
+ if (ret) {
|
|||
|
+ dev_err(drm_dev->dev, "failed to construct primary plane\n");
|
|||
|
+ return ret;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ drm_crtc_init_with_planes(drm_dev, crtc, starfive_crtc->planes, NULL,
|
|||
|
+ crtc_funcs, NULL);
|
|||
|
+ drm_crtc_helper_add(crtc, crtc_helper_funcs);
|
|||
|
+ port = of_get_child_by_name(starfive_crtc->dev->of_node, "port");
|
|||
|
+ if (!port) {
|
|||
|
+ DRM_ERROR("no port node found in %s\n", dev->of_node->full_name);
|
|||
|
+ ret = -ENOENT;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ crtc->port = port;
|
|||
|
+ return ret;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_crtc_get_memres(struct platform_device *pdev, struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ static const char *const mem_res_name[] = {
|
|||
|
+ "lcdc", "vpp0", "vpp1", "vpp2", "clk", "rst", "sys"
|
|||
|
+ };
|
|||
|
+ int i;
|
|||
|
+
|
|||
|
+ for (i = 0; i < ARRAY_SIZE(mem_res_name); i++) {
|
|||
|
+ const char *name = mem_res_name[i];
|
|||
|
+ void __iomem *regs = devm_platform_ioremap_resource_byname(pdev, name);
|
|||
|
+
|
|||
|
+ if (IS_ERR(regs))
|
|||
|
+ return PTR_ERR(regs);
|
|||
|
+
|
|||
|
+ if (!strcmp(name, "lcdc"))
|
|||
|
+ sf_crtc->base_lcdc = regs;
|
|||
|
+ else if (!strcmp(name, "vpp0"))
|
|||
|
+ sf_crtc->base_vpp0 = regs;
|
|||
|
+ else if (!strcmp(name, "vpp1"))
|
|||
|
+ sf_crtc->base_vpp1 = regs;
|
|||
|
+ else if (!strcmp(name, "vpp2"))
|
|||
|
+ sf_crtc->base_vpp2 = regs;
|
|||
|
+ else if (!strcmp(name, "clk"))
|
|||
|
+ sf_crtc->base_clk = regs;
|
|||
|
+ else if (!strcmp(name, "rst"))
|
|||
|
+ sf_crtc->base_rst = regs;
|
|||
|
+ else if (!strcmp(name, "sys"))
|
|||
|
+ sf_crtc->base_syscfg = regs;
|
|||
|
+ else
|
|||
|
+ dev_err(&pdev->dev, "Could not match resource name\n");
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_parse_dt(struct device *dev, struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ int ret;
|
|||
|
+ struct device_node *np = dev->of_node;
|
|||
|
+ struct device_node *child;
|
|||
|
+ int pp_num = 0;
|
|||
|
+
|
|||
|
+ if (!np)
|
|||
|
+ return -EINVAL;
|
|||
|
+
|
|||
|
+ sf_crtc->pp = devm_kzalloc(dev, sizeof(struct pp_mode) * PP_NUM, GFP_KERNEL);
|
|||
|
+ if (!sf_crtc->pp)
|
|||
|
+ return -ENOMEM;
|
|||
|
+
|
|||
|
+ for_each_child_of_node(np, child) {
|
|||
|
+ if (of_property_read_u32(child, "pp-id", &pp_num)) {
|
|||
|
+ ret = -EINVAL;
|
|||
|
+ continue;
|
|||
|
+ }
|
|||
|
+ if (pp_num >= PP_NUM)
|
|||
|
+ dev_err(dev, " pp-id number %d is not support!\n", pp_num);
|
|||
|
+
|
|||
|
+ sf_crtc->pp[pp_num].pp_id = pp_num;
|
|||
|
+ sf_crtc->pp[pp_num].bus_out = of_property_read_bool(child, "sys-bus-out");
|
|||
|
+ sf_crtc->pp[pp_num].fifo_out = of_property_read_bool(child, "fifo-out");
|
|||
|
+ if (of_property_read_u32(child, "src-format", &sf_crtc->pp[pp_num].src.format)) {
|
|||
|
+ dev_err(dev, "Missing src-format property in the DT.\n");
|
|||
|
+ ret = -EINVAL;
|
|||
|
+ }
|
|||
|
+ if (of_property_read_u32(child, "src-width", &sf_crtc->pp[pp_num].src.width)) {
|
|||
|
+ dev_err(dev, "Missing src-width property in the DT. w %d\n",
|
|||
|
+ sf_crtc->pp[pp_num].src.width);
|
|||
|
+ ret = -EINVAL;
|
|||
|
+ }
|
|||
|
+ if (of_property_read_u32(child, "src-height", &sf_crtc->pp[pp_num].src.height)) {
|
|||
|
+ dev_err(dev, "Missing src-height property in the DT.\n");
|
|||
|
+ ret = -EINVAL;
|
|||
|
+ }
|
|||
|
+ if (of_property_read_u32(child, "dst-format", &sf_crtc->pp[pp_num].dst.format)) {
|
|||
|
+ dev_err(dev, "Missing dst-format property in the DT.\n");
|
|||
|
+ ret = -EINVAL;
|
|||
|
+ }
|
|||
|
+ if (of_property_read_u32(child, "dst-width", &sf_crtc->pp[pp_num].dst.width)) {
|
|||
|
+ dev_err(dev, "Missing dst-width property in the DT.\n");
|
|||
|
+ ret = -EINVAL;
|
|||
|
+ }
|
|||
|
+ if (of_property_read_u32(child, "dst-height", &sf_crtc->pp[pp_num].dst.height)) {
|
|||
|
+ dev_err(dev, "Missing dst-height property in the DT.\n");
|
|||
|
+ ret = -EINVAL;
|
|||
|
+ }
|
|||
|
+ sf_crtc->pp[pp_num].inited = 1;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return ret;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_crtc_bind(struct device *dev, struct device *master, void *data)
|
|||
|
+{
|
|||
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|||
|
+ struct drm_device *drm_dev = data;
|
|||
|
+ struct starfive_crtc *crtcp;
|
|||
|
+ int ret;
|
|||
|
+
|
|||
|
+ crtcp = devm_kzalloc(dev, sizeof(*crtcp), GFP_KERNEL);
|
|||
|
+ if (!crtcp)
|
|||
|
+ return -ENOMEM;
|
|||
|
+
|
|||
|
+ crtcp->dev = dev;
|
|||
|
+ crtcp->drm_dev = drm_dev;
|
|||
|
+ dev_set_drvdata(dev, crtcp);
|
|||
|
+
|
|||
|
+ spin_lock_init(&crtcp->reg_lock);
|
|||
|
+
|
|||
|
+ ret = starfive_crtc_get_memres(pdev, crtcp);
|
|||
|
+ if (ret)
|
|||
|
+ return ret;
|
|||
|
+
|
|||
|
+ crtcp->clk_disp_axi = devm_clk_get(dev, "disp_axi");
|
|||
|
+ if (IS_ERR(crtcp->clk_disp_axi))
|
|||
|
+ return dev_err_probe(dev, PTR_ERR(crtcp->clk_disp_axi),
|
|||
|
+ "error getting axi clock\n");
|
|||
|
+
|
|||
|
+ crtcp->clk_vout_src = devm_clk_get(dev, "disp_axi");
|
|||
|
+ if (IS_ERR(crtcp->clk_vout_src))
|
|||
|
+ return dev_err_probe(dev, PTR_ERR(crtcp->clk_vout_src),
|
|||
|
+ "error getting vout clock\n");
|
|||
|
+
|
|||
|
+ crtcp->rst_disp_axi = devm_reset_control_get_exclusive(dev, "disp_axi");
|
|||
|
+ if (IS_ERR(crtcp->rst_disp_axi))
|
|||
|
+ return dev_err_probe(dev, PTR_ERR(crtcp->rst_disp_axi),
|
|||
|
+ "error getting axi reset\n");
|
|||
|
+
|
|||
|
+ crtcp->rst_vout_src = devm_reset_control_get_exclusive(dev, "vout_src");
|
|||
|
+ if (IS_ERR(crtcp->rst_vout_src))
|
|||
|
+ return dev_err_probe(dev, PTR_ERR(crtcp->rst_vout_src),
|
|||
|
+ "error getting vout reset\n");
|
|||
|
+
|
|||
|
+ ret = starfive_parse_dt(dev, crtcp);
|
|||
|
+
|
|||
|
+ crtcp->pp_conn_lcdc = starfive_pp_get_2lcdc_id(crtcp);
|
|||
|
+
|
|||
|
+ crtcp->lcdc_irq = platform_get_irq_byname(pdev, "lcdc_irq");
|
|||
|
+ if (crtcp->lcdc_irq < 0)
|
|||
|
+ return dev_err_probe(dev, crtcp->lcdc_irq, "error getting lcdc irq\n");
|
|||
|
+
|
|||
|
+ crtcp->vpp1_irq = platform_get_irq_byname(pdev, "vpp1_irq");
|
|||
|
+ if (crtcp->vpp1_irq < 0)
|
|||
|
+ return dev_err_probe(dev, crtcp->vpp1_irq, "error getting vpp1 irq\n");
|
|||
|
+
|
|||
|
+ ret = devm_request_irq(&pdev->dev, crtcp->lcdc_irq, lcdc_isr_handler, 0,
|
|||
|
+ "sf_lcdc", crtcp);
|
|||
|
+ if (ret)
|
|||
|
+ return dev_err_probe(dev, ret, "error requesting irq %d\n", crtcp->lcdc_irq);
|
|||
|
+
|
|||
|
+ ret = devm_request_irq(&pdev->dev, crtcp->vpp1_irq, vpp1_isr_handler, 0,
|
|||
|
+ "sf_vpp1", crtcp);
|
|||
|
+ if (ret)
|
|||
|
+ return dev_err_probe(dev, ret, "error requesting irq %d\n", crtcp->vpp1_irq);
|
|||
|
+
|
|||
|
+ ret = starfive_crtc_create(drm_dev, crtcp,
|
|||
|
+ &starfive_crtc_funcs,
|
|||
|
+ &starfive_crtc_helper_funcs);
|
|||
|
+ if (ret)
|
|||
|
+ return ret;
|
|||
|
+
|
|||
|
+ crtcp->is_enabled = false;
|
|||
|
+
|
|||
|
+ /* starfive_set_crtc_possible_masks(drm_dev, crtcp); */
|
|||
|
+
|
|||
|
+ /*
|
|||
|
+ ret = drm_self_refresh_helper_init(crtcp);
|
|||
|
+ if (ret)
|
|||
|
+ DRM_DEV_DEBUG_KMS(crtcp->dev,
|
|||
|
+ "Failed to init %s with SR helpers %d, ignoring\n",
|
|||
|
+ crtcp->name, ret);
|
|||
|
+ */
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_crtc_unbind(struct device *dev, struct device *master, void *data)
|
|||
|
+{
|
|||
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|||
|
+ struct starfive_crtc *crtcp = dev_get_drvdata(dev);
|
|||
|
+
|
|||
|
+ drm_crtc_cleanup(&crtcp->crtc);
|
|||
|
+ platform_set_drvdata(pdev, NULL);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const struct component_ops starfive_crtc_component_ops = {
|
|||
|
+ .bind = starfive_crtc_bind,
|
|||
|
+ .unbind = starfive_crtc_unbind,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static const struct of_device_id starfive_crtc_driver_dt_match[] = {
|
|||
|
+ { .compatible = "starfive,jh7100-crtc" },
|
|||
|
+ { /* sentinel */ },
|
|||
|
+};
|
|||
|
+MODULE_DEVICE_TABLE(of, starfive_crtc_driver_dt_match);
|
|||
|
+
|
|||
|
+static int starfive_crtc_probe(struct platform_device *pdev)
|
|||
|
+{
|
|||
|
+ return component_add(&pdev->dev, &starfive_crtc_component_ops);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_crtc_remove(struct platform_device *pdev)
|
|||
|
+{
|
|||
|
+ component_del(&pdev->dev, &starfive_crtc_component_ops);
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+struct platform_driver starfive_crtc_driver = {
|
|||
|
+ .probe = starfive_crtc_probe,
|
|||
|
+ .remove = starfive_crtc_remove,
|
|||
|
+ .driver = {
|
|||
|
+ .name = "starfive-crtc",
|
|||
|
+ .of_match_table = of_match_ptr(starfive_crtc_driver_dt_match),
|
|||
|
+ },
|
|||
|
+};
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_crtc.h b/drivers/gpu/drm/starfive/starfive_drm_crtc.h
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..b04706ae8282
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_crtc.h
|
|||
|
@@ -0,0 +1,86 @@
|
|||
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#ifndef _STARFIVE_DRM_CRTC_H
|
|||
|
+#define _STARFIVE_DRM_CRTC_H
|
|||
|
+#include <drm/drm_crtc.h>
|
|||
|
+
|
|||
|
+enum COLOR_FORMAT {
|
|||
|
+ COLOR_YUV422_UYVY = 0, //00={Y1,V0,Y0,U0}
|
|||
|
+ COLOR_YUV422_VYUY = 1, //01={Y1,U0,Y0,V0}
|
|||
|
+ COLOR_YUV422_YUYV = 2, //10={V0,Y1,U0,Y0}
|
|||
|
+ COLOR_YUV422_YVYU = 3, //11={U0,Y1,V0,Y0}
|
|||
|
+
|
|||
|
+ COLOR_YUV420P,
|
|||
|
+ COLOR_YUV420_NV21,
|
|||
|
+ COLOR_YUV420_NV12,
|
|||
|
+
|
|||
|
+ COLOR_RGB888_ARGB,
|
|||
|
+ COLOR_RGB888_ABGR,
|
|||
|
+ COLOR_RGB888_RGBA,
|
|||
|
+ COLOR_RGB888_BGRA,
|
|||
|
+ COLOR_RGB565,
|
|||
|
+};
|
|||
|
+
|
|||
|
+struct starfive_crtc_state {
|
|||
|
+ struct drm_crtc_state base;
|
|||
|
+};
|
|||
|
+
|
|||
|
+#define to_starfive_crtc_state(s) \
|
|||
|
+ container_of(s, struct starfive_crtc_state, base)
|
|||
|
+
|
|||
|
+struct starfive_crtc {
|
|||
|
+ struct drm_crtc crtc;
|
|||
|
+ struct device *dev;
|
|||
|
+ struct drm_device *drm_dev;
|
|||
|
+ bool is_enabled;
|
|||
|
+
|
|||
|
+ void __iomem *base_clk; // 0x12240000
|
|||
|
+ void __iomem *base_rst; // 0x12250000
|
|||
|
+ void __iomem *base_syscfg; // 0x12260000
|
|||
|
+ void __iomem *base_vpp0; // 0x12040000
|
|||
|
+ void __iomem *base_vpp1; // 0x12080000
|
|||
|
+ void __iomem *base_vpp2; // 0x120c0000
|
|||
|
+ void __iomem *base_lcdc; // 0x12000000
|
|||
|
+
|
|||
|
+ struct clk *clk_disp_axi;
|
|||
|
+ struct clk *clk_vout_src;
|
|||
|
+
|
|||
|
+ struct reset_control *rst_disp_axi;
|
|||
|
+ struct reset_control *rst_vout_src;
|
|||
|
+
|
|||
|
+ int lcdc_irq;
|
|||
|
+ int vpp0_irq;
|
|||
|
+ int vpp1_irq;
|
|||
|
+ int vpp2_irq;
|
|||
|
+
|
|||
|
+ struct pp_mode *pp;
|
|||
|
+
|
|||
|
+ int win_num;
|
|||
|
+ int pp_conn_lcdc;
|
|||
|
+ unsigned int ddr_format;
|
|||
|
+ bool ddr_format_change;
|
|||
|
+ enum COLOR_FORMAT vpp_format;
|
|||
|
+ int lcdcfmt;
|
|||
|
+
|
|||
|
+ /* one time only one process allowed to config the register */
|
|||
|
+ spinlock_t reg_lock;
|
|||
|
+
|
|||
|
+ struct drm_plane *planes;
|
|||
|
+
|
|||
|
+ u8 lut_r[256];
|
|||
|
+ u8 lut_g[256];
|
|||
|
+ u8 lut_b[256];
|
|||
|
+
|
|||
|
+ bool gamma_lut;
|
|||
|
+ dma_addr_t dma_addr;
|
|||
|
+ bool dma_addr_change;
|
|||
|
+ size_t size;
|
|||
|
+};
|
|||
|
+
|
|||
|
+#define to_starfive_crtc(x) container_of(x, struct starfive_crtc, crtc)
|
|||
|
+
|
|||
|
+void starfive_crtc_hw_config_simple(struct starfive_crtc *starfive_crtc);
|
|||
|
+
|
|||
|
+#endif /* _STARFIVE_DRM_CRTC_H */
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_drv.c b/drivers/gpu/drm/starfive/starfive_drm_drv.c
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..ac9c182f502b
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_drv.c
|
|||
|
@@ -0,0 +1,265 @@
|
|||
|
+// SPDX-License-Identifier: GPL-2.0
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#include <linux/component.h>
|
|||
|
+#include <linux/iommu.h>
|
|||
|
+#include <linux/module.h>
|
|||
|
+#include <linux/of_address.h>
|
|||
|
+#include <linux/of_platform.h>
|
|||
|
+#include <linux/pm_runtime.h>
|
|||
|
+#include <linux/soc/mediatek/mtk-mmsys.h>
|
|||
|
+#include <linux/dma-mapping.h>
|
|||
|
+#include <drm/drm_atomic.h>
|
|||
|
+#include <drm/drm_atomic_helper.h>
|
|||
|
+#include <drm/drm_drv.h>
|
|||
|
+#include <drm/drm_fb_helper.h>
|
|||
|
+#include <drm/drm_fourcc.h>
|
|||
|
+#include <drm/drm_gem.h>
|
|||
|
+#include <drm/drm_gem_dma_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 "starfive_drm_drv.h"
|
|||
|
+#include "starfive_drm_gem.h"
|
|||
|
+
|
|||
|
+#define DRIVER_NAME "starfive"
|
|||
|
+#define DRIVER_DESC "starfive Soc DRM"
|
|||
|
+#define DRIVER_DATE "20210519"
|
|||
|
+#define DRIVER_MAJOR 1
|
|||
|
+#define DRIVER_MINOR 0
|
|||
|
+
|
|||
|
+static struct drm_framebuffer *
|
|||
|
+starfive_drm_mode_fb_create(struct drm_device *dev, struct drm_file *file,
|
|||
|
+ const struct drm_mode_fb_cmd2 *mode_cmd)
|
|||
|
+{
|
|||
|
+ return drm_gem_fb_create(dev, file, mode_cmd);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const struct drm_mode_config_funcs starfive_drm_mode_config_funcs = {
|
|||
|
+ .fb_create = starfive_drm_mode_fb_create,
|
|||
|
+ .atomic_check = drm_atomic_helper_check,
|
|||
|
+ .atomic_commit = drm_atomic_helper_commit,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static const struct drm_mode_config_helper_funcs starfive_drm_mode_config_helpers = {
|
|||
|
+ .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static const struct file_operations starfive_drm_driver_fops = {
|
|||
|
+ .owner = THIS_MODULE,
|
|||
|
+ .open = drm_open,
|
|||
|
+ .mmap = starfive_drm_gem_mmap,
|
|||
|
+ .poll = drm_poll,
|
|||
|
+ .read = drm_read,
|
|||
|
+ .unlocked_ioctl = drm_ioctl,
|
|||
|
+ .compat_ioctl = drm_compat_ioctl,
|
|||
|
+ .release = drm_release,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static struct drm_driver starfive_drm_driver = {
|
|||
|
+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
|
|||
|
+ .dumb_create = starfive_drm_gem_dumb_create,
|
|||
|
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
|
|||
|
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
|
|||
|
+ .gem_prime_import_sg_table = starfive_drm_gem_prime_import_sg_table,
|
|||
|
+ .gem_prime_mmap = starfive_drm_gem_mmap_buf,
|
|||
|
+ .fops = &starfive_drm_driver_fops,
|
|||
|
+ .name = DRIVER_NAME,
|
|||
|
+ .desc = DRIVER_DESC,
|
|||
|
+ .date = DRIVER_DATE,
|
|||
|
+ .major = DRIVER_MAJOR,
|
|||
|
+ .minor = DRIVER_MINOR,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static int compare_dev(struct device *dev, void *data)
|
|||
|
+{
|
|||
|
+ return dev == (struct device *)data;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_drm_match_add(struct device *dev,
|
|||
|
+ struct component_match **match,
|
|||
|
+ struct platform_driver *const *drivers,
|
|||
|
+ int count)
|
|||
|
+{
|
|||
|
+ int i;
|
|||
|
+
|
|||
|
+ for (i = 0; i < count; i++) {
|
|||
|
+ struct device_driver *drv = &drivers[i]->driver;
|
|||
|
+ struct device *p = NULL, *d;
|
|||
|
+
|
|||
|
+ while ((d = platform_find_device_by_driver(p, drv))) {
|
|||
|
+ put_device(p);
|
|||
|
+ component_match_add(dev, match, compare_dev, d);
|
|||
|
+ p = d;
|
|||
|
+ }
|
|||
|
+ put_device(p);
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_cleanup(struct drm_device *ddev)
|
|||
|
+{
|
|||
|
+ struct starfive_drm_private *private = ddev->dev_private;
|
|||
|
+
|
|||
|
+ drm_kms_helper_poll_fini(ddev);
|
|||
|
+ drm_atomic_helper_shutdown(ddev);
|
|||
|
+ drm_mode_config_cleanup(ddev);
|
|||
|
+ component_unbind_all(ddev->dev, ddev);
|
|||
|
+ kfree(private);
|
|||
|
+ ddev->dev_private = NULL;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_drm_bind(struct device *dev)
|
|||
|
+{
|
|||
|
+ struct drm_device *drm_dev;
|
|||
|
+ struct starfive_drm_private *private;
|
|||
|
+ int ret;
|
|||
|
+
|
|||
|
+ drm_dev = drm_dev_alloc(&starfive_drm_driver, dev);
|
|||
|
+ if (IS_ERR(drm_dev))
|
|||
|
+ return PTR_ERR(drm_dev);
|
|||
|
+
|
|||
|
+ dev_set_drvdata(dev, drm_dev);
|
|||
|
+
|
|||
|
+ private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL);
|
|||
|
+ if (!private) {
|
|||
|
+ ret = -ENOMEM;
|
|||
|
+ goto err_free;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ drm_dev->dev_private = private;
|
|||
|
+
|
|||
|
+ /*
|
|||
|
+ ret = starfive_drm_init_iommu(drm_dev);
|
|||
|
+ if (ret)
|
|||
|
+ goto err_free;
|
|||
|
+ */
|
|||
|
+
|
|||
|
+ ret = drmm_mode_config_init(drm_dev);
|
|||
|
+ if (ret)
|
|||
|
+ goto err_free;
|
|||
|
+
|
|||
|
+ drm_dev->mode_config.min_width = 64;
|
|||
|
+ drm_dev->mode_config.min_height = 64;
|
|||
|
+
|
|||
|
+ /*
|
|||
|
+ * set max width and height as default value(4096x4096).
|
|||
|
+ * this value would be used to check framebuffer size limitation
|
|||
|
+ * at drm_mode_addfb().
|
|||
|
+ */
|
|||
|
+ drm_dev->mode_config.max_width = 4096;
|
|||
|
+ drm_dev->mode_config.max_height = 4096;
|
|||
|
+ drm_dev->mode_config.funcs = &starfive_drm_mode_config_funcs;
|
|||
|
+ drm_dev->mode_config.helper_private = &starfive_drm_mode_config_helpers;
|
|||
|
+ drm_dev->mode_config.async_page_flip = 1;
|
|||
|
+
|
|||
|
+ ret = component_bind_all(dev, drm_dev);
|
|||
|
+ if (ret)
|
|||
|
+ goto err_free;
|
|||
|
+
|
|||
|
+ ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
|
|||
|
+ if (ret)
|
|||
|
+ goto err_cleanup;
|
|||
|
+
|
|||
|
+ drm_mode_config_reset(drm_dev);
|
|||
|
+
|
|||
|
+ /* init kms poll for handling hpd */
|
|||
|
+ drm_kms_helper_poll_init(drm_dev);
|
|||
|
+
|
|||
|
+ ret = drm_dev_register(drm_dev, 0);
|
|||
|
+ if (ret)
|
|||
|
+ goto err_cleanup;
|
|||
|
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE
|
|||
|
+ drm_fbdev_generic_setup(drm_dev, 16);
|
|||
|
+#endif
|
|||
|
+ return 0;
|
|||
|
+
|
|||
|
+err_cleanup:
|
|||
|
+ starfive_cleanup(drm_dev);
|
|||
|
+err_free:
|
|||
|
+ drm_dev_put(drm_dev);
|
|||
|
+ return ret;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_drm_unbind(struct device *dev)
|
|||
|
+{
|
|||
|
+ struct drm_device *drm_dev = dev_get_drvdata(dev);
|
|||
|
+
|
|||
|
+ drm_dev_unregister(drm_dev);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const struct component_master_ops starfive_drm_ops = {
|
|||
|
+ .bind = starfive_drm_bind,
|
|||
|
+ .unbind = starfive_drm_unbind,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static struct platform_driver * const starfive_component_drivers[] = {
|
|||
|
+ &starfive_crtc_driver,
|
|||
|
+#ifdef CONFIG_DRM_STARFIVE_MIPI_DSI
|
|||
|
+ &starfive_dsi_platform_driver,
|
|||
|
+#endif
|
|||
|
+ &starfive_encoder_driver,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static int starfive_drm_probe(struct platform_device *pdev)
|
|||
|
+{
|
|||
|
+ struct device *dev = &pdev->dev;
|
|||
|
+ struct component_match *match = NULL;
|
|||
|
+
|
|||
|
+ starfive_drm_match_add(dev, &match,
|
|||
|
+ starfive_component_drivers,
|
|||
|
+ ARRAY_SIZE(starfive_component_drivers));
|
|||
|
+ if (IS_ERR(match))
|
|||
|
+ return PTR_ERR(match);
|
|||
|
+
|
|||
|
+ return component_master_add_with_match(dev, &starfive_drm_ops, match);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_drm_remove(struct platform_device *pdev)
|
|||
|
+{
|
|||
|
+ component_master_del(&pdev->dev, &starfive_drm_ops);
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const struct of_device_id starfive_drm_dt_ids[] = {
|
|||
|
+ { .compatible = "starfive,display-subsystem" },
|
|||
|
+ { /* sentinel */ },
|
|||
|
+};
|
|||
|
+MODULE_DEVICE_TABLE(of, starfive_drm_dt_ids);
|
|||
|
+
|
|||
|
+static struct platform_driver starfive_drm_platform_driver = {
|
|||
|
+ .probe = starfive_drm_probe,
|
|||
|
+ .remove = starfive_drm_remove,
|
|||
|
+ .driver = {
|
|||
|
+ .name = "starfive-drm",
|
|||
|
+ .of_match_table = starfive_drm_dt_ids,
|
|||
|
+ //.pm = &starfive_drm_pm_ops,
|
|||
|
+ },
|
|||
|
+};
|
|||
|
+
|
|||
|
+static int __init starfive_drm_init(void)
|
|||
|
+{
|
|||
|
+ int ret;
|
|||
|
+
|
|||
|
+ ret = platform_register_drivers(starfive_component_drivers,
|
|||
|
+ ARRAY_SIZE(starfive_component_drivers));
|
|||
|
+ if (ret)
|
|||
|
+ return ret;
|
|||
|
+
|
|||
|
+ return platform_driver_register(&starfive_drm_platform_driver);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void __exit starfive_drm_exit(void)
|
|||
|
+{
|
|||
|
+ platform_unregister_drivers(starfive_component_drivers,
|
|||
|
+ ARRAY_SIZE(starfive_component_drivers));
|
|||
|
+ platform_driver_unregister(&starfive_drm_platform_driver);
|
|||
|
+}
|
|||
|
+
|
|||
|
+module_init(starfive_drm_init);
|
|||
|
+module_exit(starfive_drm_exit);
|
|||
|
+
|
|||
|
+MODULE_AUTHOR("StarFive <StarFive@starfivetech.com>");
|
|||
|
+MODULE_DESCRIPTION("StarFive SoC DRM driver");
|
|||
|
+MODULE_LICENSE("GPL v2");
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_drv.h b/drivers/gpu/drm/starfive/starfive_drm_drv.h
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..b965fa5f7252
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_drv.h
|
|||
|
@@ -0,0 +1,25 @@
|
|||
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#ifndef _STARFIVE_DRM_DRV_H
|
|||
|
+#define _STARFIVE_DRM_DRV_H
|
|||
|
+
|
|||
|
+#include <drm/drm_fb_helper.h>
|
|||
|
+#include <drm/drm_atomic_helper.h>
|
|||
|
+#include <drm/drm_gem.h>
|
|||
|
+#include <linux/module.h>
|
|||
|
+#include <linux/component.h>
|
|||
|
+
|
|||
|
+struct starfive_drm_private {
|
|||
|
+ struct drm_fb_helper fbdev_helper;
|
|||
|
+ struct drm_gem_object *fbdev_bo;
|
|||
|
+ struct mutex mm_lock;
|
|||
|
+ struct drm_mm mm;
|
|||
|
+};
|
|||
|
+
|
|||
|
+extern struct platform_driver starfive_crtc_driver;
|
|||
|
+extern struct platform_driver starfive_encoder_driver;
|
|||
|
+extern struct platform_driver starfive_dsi_platform_driver;
|
|||
|
+
|
|||
|
+#endif /* _STARFIVE_DRM_DRV_H_ */
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_encoder.c b/drivers/gpu/drm/starfive/starfive_drm_encoder.c
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..56c7f10239bc
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_encoder.c
|
|||
|
@@ -0,0 +1,129 @@
|
|||
|
+// SPDX-License-Identifier: GPL-2.0
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#include <linux/clk.h>
|
|||
|
+#include <linux/component.h>
|
|||
|
+#include <linux/of_device.h>
|
|||
|
+#include <drm/drm_atomic.h>
|
|||
|
+#include <drm/drm_atomic_helper.h>
|
|||
|
+#include <drm/drm_atomic_uapi.h>
|
|||
|
+#include <drm/drm_fb_dma_helper.h>
|
|||
|
+#include <drm/drm_print.h>
|
|||
|
+#include <drm/drm_probe_helper.h>
|
|||
|
+#include <drm/drm_vblank.h>
|
|||
|
+#include <drm/drm_of.h>
|
|||
|
+#include "starfive_drm_drv.h"
|
|||
|
+#include "starfive_drm_encoder.h"
|
|||
|
+
|
|||
|
+static void starfive_encoder_destroy(struct drm_encoder *encoder)
|
|||
|
+{
|
|||
|
+ drm_encoder_cleanup(encoder);
|
|||
|
+ kfree(encoder);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const struct drm_encoder_funcs starfive_encoder_funcs = {
|
|||
|
+ .destroy = starfive_encoder_destroy,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static int starfive_encoder_bind(struct device *dev, struct device *master, void *data)
|
|||
|
+{
|
|||
|
+ struct drm_device *drm_dev = data;
|
|||
|
+ struct device_node *np = dev->of_node;
|
|||
|
+ struct starfive_encoder *encoderp;
|
|||
|
+ int ret;
|
|||
|
+ struct drm_panel *tmp_panel;
|
|||
|
+ struct drm_bridge *tmp_bridge;
|
|||
|
+ u32 crtcs = 0;
|
|||
|
+
|
|||
|
+ encoderp = devm_kzalloc(dev, sizeof(*encoderp), GFP_KERNEL);
|
|||
|
+ if (!encoderp)
|
|||
|
+ return -ENOMEM;
|
|||
|
+
|
|||
|
+ encoderp->dev = dev;
|
|||
|
+ encoderp->drm_dev = drm_dev;
|
|||
|
+ dev_set_drvdata(dev, encoderp);
|
|||
|
+
|
|||
|
+ if (dev->of_node) {
|
|||
|
+ crtcs = drm_of_find_possible_crtcs(drm_dev, dev->of_node);
|
|||
|
+
|
|||
|
+ if (of_property_read_u32(np, "encoder-type", &encoderp->encoder_type)) {
|
|||
|
+ DRM_ERROR("Missing encoder-type property in the DT.\n");
|
|||
|
+ encoderp->encoder_type = DRM_MODE_ENCODER_TMDS;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ /* If no CRTCs were found, fall back to our old behaviour */
|
|||
|
+ if (crtcs == 0) {
|
|||
|
+ dev_warn(dev, "Falling back to first CRTC\n");
|
|||
|
+ crtcs = 1 << 0;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ encoderp->encoder.possible_crtcs = crtcs;
|
|||
|
+
|
|||
|
+ ret = drm_encoder_init(drm_dev, &encoderp->encoder,
|
|||
|
+ &starfive_encoder_funcs,
|
|||
|
+ encoderp->encoder_type, NULL);
|
|||
|
+ if (ret)
|
|||
|
+ return dev_err_probe(dev, ret, "error initializing encoder\n");
|
|||
|
+
|
|||
|
+ ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
|
|||
|
+ &tmp_panel, &tmp_bridge);
|
|||
|
+ if (ret) {
|
|||
|
+ dev_err_probe(dev, ret, "endpoint returns %d\n", ret);
|
|||
|
+ goto err_bridge;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if (tmp_panel)
|
|||
|
+ DRM_INFO("found panel on endpoint\n");
|
|||
|
+ if (tmp_bridge)
|
|||
|
+ DRM_INFO("found bridge on endpoint\n");
|
|||
|
+
|
|||
|
+ ret = drm_bridge_attach(&encoderp->encoder, tmp_bridge, NULL, 0);
|
|||
|
+ if (ret)
|
|||
|
+ goto err_bridge;
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+
|
|||
|
+err_bridge:
|
|||
|
+ drm_encoder_cleanup(&encoderp->encoder);
|
|||
|
+ return ret;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_encoder_unbind(struct device *dev, struct device *master, void *data)
|
|||
|
+{
|
|||
|
+ struct starfive_encoder *encoderp = dev_get_drvdata(dev);
|
|||
|
+
|
|||
|
+ starfive_encoder_destroy(&encoderp->encoder);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const struct component_ops starfive_encoder_component_ops = {
|
|||
|
+ .bind = starfive_encoder_bind,
|
|||
|
+ .unbind = starfive_encoder_unbind,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static const struct of_device_id starfive_encoder_driver_dt_match[] = {
|
|||
|
+ { .compatible = "starfive,display-encoder" },
|
|||
|
+ { /* sentinel */ },
|
|||
|
+};
|
|||
|
+MODULE_DEVICE_TABLE(of, starfive_encoder_driver_dt_match);
|
|||
|
+
|
|||
|
+static int starfive_encoder_probe(struct platform_device *pdev)
|
|||
|
+{
|
|||
|
+ return component_add(&pdev->dev, &starfive_encoder_component_ops);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_encoder_remove(struct platform_device *pdev)
|
|||
|
+{
|
|||
|
+ component_del(&pdev->dev, &starfive_encoder_component_ops);
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+struct platform_driver starfive_encoder_driver = {
|
|||
|
+ .probe = starfive_encoder_probe,
|
|||
|
+ .remove = starfive_encoder_remove,
|
|||
|
+ .driver = {
|
|||
|
+ .name = "display-encoder",
|
|||
|
+ .of_match_table = of_match_ptr(starfive_encoder_driver_dt_match),
|
|||
|
+ },
|
|||
|
+};
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_encoder.h b/drivers/gpu/drm/starfive/starfive_drm_encoder.h
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..5ea21441e502
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_encoder.h
|
|||
|
@@ -0,0 +1,18 @@
|
|||
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#ifndef _STARFIVE_DRM_ENCODER_H
|
|||
|
+#define _STARFIVE_DRM_ENCODER_H
|
|||
|
+
|
|||
|
+struct starfive_encoder {
|
|||
|
+ struct drm_encoder encoder;
|
|||
|
+ struct device *dev;
|
|||
|
+ struct drm_device *drm_dev;
|
|||
|
+ bool is_enabled;
|
|||
|
+ int encoder_type;
|
|||
|
+};
|
|||
|
+
|
|||
|
+#define to_starfive_encoder(x) container_of(x, struct starfive_encoder, encoder)
|
|||
|
+
|
|||
|
+#endif /* _STARFIVE_DRM_CRTC_H */
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_gem.c b/drivers/gpu/drm/starfive/starfive_drm_gem.c
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..4f0f68595da7
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_gem.c
|
|||
|
@@ -0,0 +1,346 @@
|
|||
|
+// SPDX-License-Identifier: GPL-2.0
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#include <linux/dma-buf.h>
|
|||
|
+#include <linux/iommu.h>
|
|||
|
+#include <linux/vmalloc.h>
|
|||
|
+#include <drm/drm.h>
|
|||
|
+#include <drm/drm_gem.h>
|
|||
|
+#include <drm/drm_prime.h>
|
|||
|
+#include <drm/drm_vma_manager.h>
|
|||
|
+#include <drm/drm_gem_dma_helper.h>
|
|||
|
+#include "starfive_drm_drv.h"
|
|||
|
+#include "starfive_drm_gem.h"
|
|||
|
+
|
|||
|
+static const struct drm_gem_object_funcs starfive_gem_object_funcs;
|
|||
|
+static const struct vm_operations_struct mmap_mem_ops = {
|
|||
|
+#ifdef CONFIG_HAVE_IOREMAP_PROT
|
|||
|
+ .access = generic_access_phys
|
|||
|
+#endif
|
|||
|
+};
|
|||
|
+
|
|||
|
+static int starfive_drm_gem_object_mmap_dma(struct drm_gem_object *obj,
|
|||
|
+ struct vm_area_struct *vma)
|
|||
|
+{
|
|||
|
+ struct starfive_drm_gem_obj *starfive_obj = to_starfive_gem_obj(obj);
|
|||
|
+ struct drm_device *drm = obj->dev;
|
|||
|
+
|
|||
|
+ return dma_mmap_attrs(drm->dev, vma, starfive_obj->kvaddr,
|
|||
|
+ starfive_obj->dma_addr, obj->size, starfive_obj->dma_attrs);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_drm_gem_object_mmap(struct drm_gem_object *obj,
|
|||
|
+ struct vm_area_struct *vma)
|
|||
|
+{
|
|||
|
+ int ret;
|
|||
|
+
|
|||
|
+ /*
|
|||
|
+ * We allocated a struct page table for rk_obj, so clear
|
|||
|
+ * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
|
|||
|
+ */
|
|||
|
+ vma->vm_flags &= ~VM_PFNMAP;
|
|||
|
+ ret = starfive_drm_gem_object_mmap_dma(obj, vma);
|
|||
|
+ if (ret)
|
|||
|
+ drm_gem_vm_close(vma);
|
|||
|
+
|
|||
|
+ return ret;
|
|||
|
+}
|
|||
|
+
|
|||
|
+int starfive_drm_gem_mmap_buf(struct drm_gem_object *obj,
|
|||
|
+ struct vm_area_struct *vma)
|
|||
|
+{
|
|||
|
+ int ret = drm_gem_mmap_obj(obj, obj->size, vma);
|
|||
|
+
|
|||
|
+ if (ret)
|
|||
|
+ return ret;
|
|||
|
+
|
|||
|
+ return starfive_drm_gem_object_mmap(obj, vma);
|
|||
|
+}
|
|||
|
+
|
|||
|
+int starfive_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
|
+{
|
|||
|
+ struct drm_gem_object *obj;
|
|||
|
+ int ret;
|
|||
|
+
|
|||
|
+ ret = drm_gem_mmap(filp, vma);
|
|||
|
+ if (ret)
|
|||
|
+ return ret;
|
|||
|
+
|
|||
|
+ obj = vma->vm_private_data;
|
|||
|
+
|
|||
|
+ /*
|
|||
|
+ * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the
|
|||
|
+ * whole buffer from the start.
|
|||
|
+ */
|
|||
|
+ vma->vm_pgoff = 0;
|
|||
|
+
|
|||
|
+ return starfive_drm_gem_object_mmap(obj, vma);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void starfive_drm_gem_free_object(struct drm_gem_object *obj)
|
|||
|
+{
|
|||
|
+ struct starfive_drm_gem_obj *starfive_gem = to_starfive_gem_obj(obj);
|
|||
|
+ struct drm_device *drm_dev = obj->dev;
|
|||
|
+
|
|||
|
+ if (starfive_gem->sg)
|
|||
|
+ drm_prime_gem_destroy(obj, starfive_gem->sg);
|
|||
|
+ else
|
|||
|
+ dma_free_attrs(drm_dev->dev, obj->size, starfive_gem->kvaddr,
|
|||
|
+ starfive_gem->dma_addr, starfive_gem->dma_attrs);
|
|||
|
+
|
|||
|
+ /* release file pointer to gem object. */
|
|||
|
+ drm_gem_object_release(obj);
|
|||
|
+
|
|||
|
+ kfree(starfive_gem);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static struct starfive_drm_gem_obj *
|
|||
|
+starfive_drm_gem_alloc_object(struct drm_device *drm, unsigned int size)
|
|||
|
+{
|
|||
|
+ struct starfive_drm_gem_obj *starfive_obj;
|
|||
|
+ struct drm_gem_object *obj;
|
|||
|
+ int ret;
|
|||
|
+
|
|||
|
+ starfive_obj = kzalloc(sizeof(*starfive_obj), GFP_KERNEL);
|
|||
|
+ if (!starfive_obj)
|
|||
|
+ return ERR_PTR(-ENOMEM);
|
|||
|
+
|
|||
|
+ obj = &starfive_obj->base;
|
|||
|
+ ret = drm_gem_object_init(drm, obj, round_up(size, PAGE_SIZE));
|
|||
|
+ if (ret)
|
|||
|
+ return ERR_PTR(ret);
|
|||
|
+
|
|||
|
+ return starfive_obj;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_drm_gem_alloc_dma(struct starfive_drm_gem_obj *starfive_obj,
|
|||
|
+ bool alloc_kmap)
|
|||
|
+{
|
|||
|
+ struct drm_gem_object *obj = &starfive_obj->base;
|
|||
|
+ struct drm_device *drm = obj->dev;
|
|||
|
+
|
|||
|
+ starfive_obj->dma_attrs = DMA_ATTR_WRITE_COMBINE;
|
|||
|
+ if (!alloc_kmap)
|
|||
|
+ starfive_obj->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
|
|||
|
+
|
|||
|
+ starfive_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size,
|
|||
|
+ &starfive_obj->dma_addr, GFP_KERNEL,
|
|||
|
+ starfive_obj->dma_attrs);
|
|||
|
+
|
|||
|
+ DRM_INFO("kvaddr = 0x%px\n", starfive_obj->kvaddr);
|
|||
|
+ DRM_INFO("dma_addr = 0x%llx, size = %lu\n", starfive_obj->dma_addr, obj->size);
|
|||
|
+ if (!starfive_obj->kvaddr) {
|
|||
|
+ DRM_ERROR("failed to allocate %zu byte dma buffer", obj->size);
|
|||
|
+ return -ENOMEM;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_drm_gem_alloc_buf(struct starfive_drm_gem_obj *starfive_obj,
|
|||
|
+ bool alloc_kmap)
|
|||
|
+{
|
|||
|
+ return starfive_drm_gem_alloc_dma(starfive_obj, alloc_kmap);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_drm_gem_release_object(struct starfive_drm_gem_obj *starfive_obj)
|
|||
|
+{
|
|||
|
+ drm_gem_object_release(&starfive_obj->base);
|
|||
|
+ kfree(starfive_obj);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static struct starfive_drm_gem_obj *
|
|||
|
+starfive_drm_gem_create_object(struct drm_device *drm, unsigned int size,
|
|||
|
+ bool alloc_kmap)
|
|||
|
+{
|
|||
|
+ struct starfive_drm_gem_obj *starfive_obj;
|
|||
|
+ int ret;
|
|||
|
+
|
|||
|
+ starfive_obj = starfive_drm_gem_alloc_object(drm, size);
|
|||
|
+ if (IS_ERR(starfive_obj))
|
|||
|
+ return starfive_obj;
|
|||
|
+
|
|||
|
+ ret = starfive_drm_gem_alloc_buf(starfive_obj, alloc_kmap);
|
|||
|
+ if (ret)
|
|||
|
+ goto err_free_obj;
|
|||
|
+
|
|||
|
+ starfive_obj->base.funcs = &starfive_gem_object_funcs;
|
|||
|
+
|
|||
|
+ return starfive_obj;
|
|||
|
+
|
|||
|
+err_free_obj:
|
|||
|
+ starfive_drm_gem_release_object(starfive_obj);
|
|||
|
+ return ERR_PTR(ret);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static struct starfive_drm_gem_obj *
|
|||
|
+starfive_drm_gem_create_with_handle(struct drm_file *file_priv,
|
|||
|
+ struct drm_device *drm,
|
|||
|
+ unsigned int size,
|
|||
|
+ unsigned int *handle)
|
|||
|
+{
|
|||
|
+ struct starfive_drm_gem_obj *starfive_gem;
|
|||
|
+ struct drm_gem_object *gem;
|
|||
|
+ int ret;
|
|||
|
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE
|
|||
|
+ //config true, for console display
|
|||
|
+ starfive_gem = starfive_drm_gem_create_object(drm, size, true);
|
|||
|
+#else
|
|||
|
+ starfive_gem = starfive_drm_gem_create_object(drm, size, false);
|
|||
|
+#endif
|
|||
|
+ if (IS_ERR(starfive_gem))
|
|||
|
+ return ERR_CAST(starfive_gem);
|
|||
|
+
|
|||
|
+ gem = &starfive_gem->base;
|
|||
|
+
|
|||
|
+ /*
|
|||
|
+ * allocate a id of idr table where the obj is registered
|
|||
|
+ * and handle has the id what user can see.
|
|||
|
+ */
|
|||
|
+ ret = drm_gem_handle_create(file_priv, gem, handle);
|
|||
|
+ if (ret)
|
|||
|
+ goto err_handle_create;
|
|||
|
+
|
|||
|
+ /* drop reference from allocate - handle holds it now. */
|
|||
|
+ drm_gem_object_put(gem);
|
|||
|
+
|
|||
|
+ return starfive_gem;
|
|||
|
+
|
|||
|
+err_handle_create:
|
|||
|
+ starfive_drm_gem_free_object(gem);
|
|||
|
+
|
|||
|
+ return ERR_PTR(ret);
|
|||
|
+}
|
|||
|
+
|
|||
|
+int starfive_drm_gem_dumb_create(struct drm_file *file_priv,
|
|||
|
+ struct drm_device *dev,
|
|||
|
+ struct drm_mode_create_dumb *args)
|
|||
|
+{
|
|||
|
+ struct starfive_drm_gem_obj *starfive_gem;
|
|||
|
+
|
|||
|
+ args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
|
|||
|
+ args->size = args->pitch * args->height;
|
|||
|
+
|
|||
|
+ starfive_gem = starfive_drm_gem_create_with_handle(file_priv, dev,
|
|||
|
+ args->size,
|
|||
|
+ &args->handle);
|
|||
|
+
|
|||
|
+ return PTR_ERR_OR_ZERO(starfive_gem);
|
|||
|
+}
|
|||
|
+
|
|||
|
+struct sg_table *starfive_drm_gem_prime_get_sg_table(struct drm_gem_object *obj)
|
|||
|
+{
|
|||
|
+ struct starfive_drm_gem_obj *starfive_obj = to_starfive_gem_obj(obj);
|
|||
|
+ struct drm_device *drm = obj->dev;
|
|||
|
+ struct sg_table *sgt;
|
|||
|
+ int ret;
|
|||
|
+
|
|||
|
+ if (starfive_obj->pages)
|
|||
|
+ return drm_prime_pages_to_sg(obj->dev, starfive_obj->pages,
|
|||
|
+ starfive_obj->num_pages);
|
|||
|
+
|
|||
|
+ sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
|
|||
|
+ if (!sgt)
|
|||
|
+ return ERR_PTR(-ENOMEM);
|
|||
|
+
|
|||
|
+ ret = dma_get_sgtable_attrs(drm->dev, sgt, starfive_obj->kvaddr,
|
|||
|
+ starfive_obj->dma_addr, obj->size,
|
|||
|
+ starfive_obj->dma_attrs);
|
|||
|
+ if (ret) {
|
|||
|
+ DRM_ERROR("failed to allocate sgt, %d\n", ret);
|
|||
|
+ kfree(sgt);
|
|||
|
+ return ERR_PTR(ret);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return sgt;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+starfive_drm_gem_dma_map_sg(struct drm_device *drm,
|
|||
|
+ struct dma_buf_attachment *attach,
|
|||
|
+ struct sg_table *sg,
|
|||
|
+ struct starfive_drm_gem_obj *starfive_obj)
|
|||
|
+{
|
|||
|
+ int err;
|
|||
|
+
|
|||
|
+ err = dma_map_sgtable(drm->dev, sg, DMA_BIDIRECTIONAL, 0);
|
|||
|
+ if (err)
|
|||
|
+ return err;
|
|||
|
+
|
|||
|
+ if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) {
|
|||
|
+ DRM_ERROR("failed to map sg_table to contiguous linear address.\n");
|
|||
|
+ dma_unmap_sgtable(drm->dev, sg, DMA_BIDIRECTIONAL, 0);
|
|||
|
+ return -EINVAL;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ starfive_obj->dma_addr = sg_dma_address(sg->sgl);
|
|||
|
+ starfive_obj->sg = sg;
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+struct drm_gem_object *
|
|||
|
+starfive_drm_gem_prime_import_sg_table(struct drm_device *drm,
|
|||
|
+ struct dma_buf_attachment *attach,
|
|||
|
+ struct sg_table *sg)
|
|||
|
+{
|
|||
|
+ struct starfive_drm_gem_obj *starfive_obj;
|
|||
|
+ int ret;
|
|||
|
+
|
|||
|
+ starfive_obj = starfive_drm_gem_alloc_object(drm, attach->dmabuf->size);
|
|||
|
+ if (IS_ERR(starfive_obj))
|
|||
|
+ return ERR_CAST(starfive_obj);
|
|||
|
+
|
|||
|
+ ret = starfive_drm_gem_dma_map_sg(drm, attach, sg, starfive_obj);
|
|||
|
+ if (ret < 0) {
|
|||
|
+ DRM_ERROR("failed to import sg table: %d\n", ret);
|
|||
|
+ goto err_free_obj;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return &starfive_obj->base;
|
|||
|
+
|
|||
|
+err_free_obj:
|
|||
|
+ starfive_drm_gem_release_object(starfive_obj);
|
|||
|
+ return ERR_PTR(ret);
|
|||
|
+}
|
|||
|
+
|
|||
|
+int starfive_drm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
|
|||
|
+{
|
|||
|
+ struct starfive_drm_gem_obj *starfive_obj = to_starfive_gem_obj(obj);
|
|||
|
+
|
|||
|
+ if (starfive_obj->pages) {
|
|||
|
+ void *vaddr = vmap(starfive_obj->pages, starfive_obj->num_pages, VM_MAP,
|
|||
|
+ pgprot_writecombine(PAGE_KERNEL));
|
|||
|
+ if (!vaddr)
|
|||
|
+ return -ENOMEM;
|
|||
|
+ iosys_map_set_vaddr(map, vaddr);
|
|||
|
+ return 0;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if (starfive_obj->dma_attrs & DMA_ATTR_NO_KERNEL_MAPPING)
|
|||
|
+ return -ENOMEM;
|
|||
|
+
|
|||
|
+ iosys_map_set_vaddr(map, starfive_obj->kvaddr);
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void starfive_drm_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
|
|||
|
+{
|
|||
|
+ struct starfive_drm_gem_obj *starfive_obj = to_starfive_gem_obj(obj);
|
|||
|
+
|
|||
|
+ if (starfive_obj->pages) {
|
|||
|
+ vunmap(map->vaddr);
|
|||
|
+ return;
|
|||
|
+ }
|
|||
|
+ /* Nothing to do if allocated by DMA mapping API. */
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const struct drm_gem_object_funcs starfive_gem_object_funcs = {
|
|||
|
+ .free = starfive_drm_gem_free_object,
|
|||
|
+ .get_sg_table = starfive_drm_gem_prime_get_sg_table,
|
|||
|
+ .vmap = starfive_drm_gem_prime_vmap,
|
|||
|
+ .vunmap = starfive_drm_gem_prime_vunmap,
|
|||
|
+ .vm_ops = &drm_gem_dma_vm_ops,
|
|||
|
+};
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_gem.h b/drivers/gpu/drm/starfive/starfive_drm_gem.h
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..13a222a26e17
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_gem.h
|
|||
|
@@ -0,0 +1,40 @@
|
|||
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#ifndef _STARFIVE_DRM_GEM_H
|
|||
|
+#define _STARFIVE_DRM_GEM_H
|
|||
|
+
|
|||
|
+#include <drm/drm_gem.h>
|
|||
|
+
|
|||
|
+struct starfive_drm_gem_obj {
|
|||
|
+ struct drm_gem_object base;
|
|||
|
+ //void *cookie; //mtk
|
|||
|
+ void *kvaddr;
|
|||
|
+ dma_addr_t dma_addr;
|
|||
|
+ unsigned long dma_attrs;
|
|||
|
+
|
|||
|
+ /* Used when IOMMU is enabled */
|
|||
|
+ unsigned long num_pages;
|
|||
|
+ struct sg_table *sg;
|
|||
|
+ struct page **pages;
|
|||
|
+};
|
|||
|
+
|
|||
|
+#define to_starfive_gem_obj(x) container_of(x, struct starfive_drm_gem_obj, base)
|
|||
|
+
|
|||
|
+void starfive_drm_gem_free_object(struct drm_gem_object *obj);
|
|||
|
+int starfive_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
|
|||
|
+int starfive_drm_gem_mmap_buf(struct drm_gem_object *obj,
|
|||
|
+ struct vm_area_struct *vma);
|
|||
|
+int starfive_drm_gem_dumb_create(struct drm_file *file_priv,
|
|||
|
+ struct drm_device *dev,
|
|||
|
+ struct drm_mode_create_dumb *args);
|
|||
|
+struct sg_table *starfive_drm_gem_prime_get_sg_table(struct drm_gem_object *obj);
|
|||
|
+struct drm_gem_object *
|
|||
|
+starfive_drm_gem_prime_import_sg_table(struct drm_device *dev,
|
|||
|
+ struct dma_buf_attachment *attach,
|
|||
|
+ struct sg_table *sg);
|
|||
|
+int starfive_drm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map);
|
|||
|
+void starfive_drm_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map);
|
|||
|
+
|
|||
|
+#endif /* _STARFIVE_DRM_GEM_H */
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_lcdc.c b/drivers/gpu/drm/starfive/starfive_drm_lcdc.c
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..7e9bcbde3092
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_lcdc.c
|
|||
|
@@ -0,0 +1,512 @@
|
|||
|
+// SPDX-License-Identifier: GPL-2.0
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#include <linux/clk.h>
|
|||
|
+#include <linux/module.h>
|
|||
|
+#include <linux/units.h>
|
|||
|
+#include <drm/drm_crtc.h>
|
|||
|
+#include "starfive_drm_lcdc.h"
|
|||
|
+#include "starfive_drm_vpp.h"
|
|||
|
+
|
|||
|
+static u32 sf_fb_clkread32(struct starfive_crtc *sf_crtc, u32 reg)
|
|||
|
+{
|
|||
|
+ return ioread32(sf_crtc->base_clk + reg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void sf_fb_clkwrite32(struct starfive_crtc *sf_crtc, u32 reg, u32 val)
|
|||
|
+{
|
|||
|
+ iowrite32(val, sf_crtc->base_clk + reg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static u32 sf_fb_lcdcread32(struct starfive_crtc *sf_crtc, u32 reg)
|
|||
|
+{
|
|||
|
+ return ioread32(sf_crtc->base_lcdc + reg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void sf_fb_lcdcwrite32(struct starfive_crtc *sf_crtc, u32 reg, u32 val)
|
|||
|
+{
|
|||
|
+ iowrite32(val, sf_crtc->base_lcdc + reg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static u32 starfive_lcdc_rstread32(struct starfive_crtc *sf_crtc, u32 reg)
|
|||
|
+{
|
|||
|
+ return ioread32(sf_crtc->base_rst + reg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_lcdc_rstwrite32(struct starfive_crtc *sf_crtc, u32 reg, u32 val)
|
|||
|
+{
|
|||
|
+ iowrite32(val, sf_crtc->base_rst + reg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void lcdc_mode_cfg(struct starfive_crtc *sf_crtc, u32 work_mode, int dot_edge,
|
|||
|
+ int sync_edge, int r2y_bypass, int src_sel, int int_src, int int_freq)
|
|||
|
+{
|
|||
|
+ u32 lcdc_en = 0x1;
|
|||
|
+ u32 cfg = lcdc_en |
|
|||
|
+ work_mode << LCDC_WORK_MODE |
|
|||
|
+ dot_edge << LCDC_DOTCLK_P |
|
|||
|
+ sync_edge << LCDC_HSYNC_P |
|
|||
|
+ sync_edge << LCDC_VSYNC_P |
|
|||
|
+ 0x0 << LCDC_DITHER_EN |
|
|||
|
+ r2y_bypass << LCDC_R2Y_BPS |
|
|||
|
+ src_sel << LCDC_TV_LCD_PATHSEL |
|
|||
|
+ int_src << LCDC_INT_SEL |
|
|||
|
+ int_freq << LCDC_INT_FREQ;
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_GCTRL, cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "LCDC WorkMode: 0x%x, LCDC Path: %d\n", work_mode, src_sel);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void lcdc_timing_cfg(struct starfive_crtc *sf_crtc,
|
|||
|
+ struct drm_crtc_state *state, int vunit)
|
|||
|
+{
|
|||
|
+ int hpw, hbk, hfp, vpw, vbk, vfp;
|
|||
|
+ u32 htiming, vtiming, hvwid;
|
|||
|
+
|
|||
|
+ //h-sync
|
|||
|
+ int hsync_len = state->adjusted_mode.crtc_hsync_end -
|
|||
|
+ state->adjusted_mode.crtc_hsync_start;
|
|||
|
+ //h-bp
|
|||
|
+ int left_margin = state->adjusted_mode.crtc_htotal -
|
|||
|
+ state->adjusted_mode.crtc_hsync_end;
|
|||
|
+ //h-fp
|
|||
|
+ int right_margin = state->adjusted_mode.crtc_hsync_start -
|
|||
|
+ state->adjusted_mode.crtc_hdisplay;
|
|||
|
+ //v-sync
|
|||
|
+ int vsync_len = state->adjusted_mode.crtc_vsync_end -
|
|||
|
+ state->adjusted_mode.crtc_vsync_start;
|
|||
|
+ //v-bp
|
|||
|
+ int upper_margin = state->adjusted_mode.crtc_vtotal -
|
|||
|
+ state->adjusted_mode.crtc_vsync_end;
|
|||
|
+ //v-fp
|
|||
|
+ int lower_margin = state->adjusted_mode.crtc_vsync_start -
|
|||
|
+ state->adjusted_mode.crtc_vdisplay;
|
|||
|
+
|
|||
|
+ hpw = hsync_len - 1;
|
|||
|
+ hbk = hsync_len + left_margin;
|
|||
|
+ hfp = right_margin;
|
|||
|
+ vpw = vsync_len - 1;
|
|||
|
+ vbk = vsync_len + upper_margin;
|
|||
|
+ vfp = lower_margin;
|
|||
|
+
|
|||
|
+ dev_dbg(sf_crtc->dev, "%s: h-sync = %d, h-bp = %d, h-fp = %d", __func__,
|
|||
|
+ hsync_len, left_margin, right_margin);
|
|||
|
+ dev_dbg(sf_crtc->dev, "%s: v-sync = %d, v-bp = %d, v-fp = %d", __func__,
|
|||
|
+ vsync_len, upper_margin, lower_margin);
|
|||
|
+
|
|||
|
+ htiming = hbk | hfp << LCDC_RGB_HFP;
|
|||
|
+ vtiming = vbk | vfp << LCDC_RGB_VFP;
|
|||
|
+ hvwid = hpw | vpw << LCDC_RGB_VPW | vunit << LCDC_RGB_UNIT;
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_RGB_H_TMG, htiming);
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_RGB_V_TMG, vtiming);
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_RGB_W_TMG, hvwid);
|
|||
|
+ dev_dbg(sf_crtc->dev, "LCDC HPW: %d, HBK: %d, HFP: %d\n", hpw, hbk, hfp);
|
|||
|
+ dev_dbg(sf_crtc->dev, "LCDC VPW: %d, VBK: %d, VFP: %d\n", vpw, vbk, vfp);
|
|||
|
+ dev_dbg(sf_crtc->dev, "LCDC V-Unit: %d, 0-HSYNC and 1-dotClk period\n", vunit);
|
|||
|
+}
|
|||
|
+
|
|||
|
+//? background size
|
|||
|
+//lcdc_desize_cfg(sf_dev, sf_dev->display_info.xres-1, sf_dev->display_info.yres-1);
|
|||
|
+static void lcdc_desize_cfg(struct starfive_crtc *sf_crtc, struct drm_crtc_state *state)
|
|||
|
+{
|
|||
|
+ int hsize = state->adjusted_mode.crtc_hdisplay - 1;
|
|||
|
+ int vsize = state->adjusted_mode.crtc_vdisplay - 1;
|
|||
|
+ u32 sizecfg = hsize | vsize << LCDC_BG_VSIZE;
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_BACKGROUND, sizecfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "LCDC Dest H-Size: %d, V-Size: %d\n", hsize, vsize);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void lcdc_rgb_dclk_cfg(struct starfive_crtc *sf_crtc, int dot_clk_sel)
|
|||
|
+{
|
|||
|
+ u32 cfg = dot_clk_sel << 16;
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_RGB_DCLK, cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "LCDC Dot_clock_output_sel: 0x%x\n", cfg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+// color table
|
|||
|
+//win0, no lock transfer
|
|||
|
+//win3, no src_sel and addr_mode, 0 assigned to them
|
|||
|
+//lcdc_win_cfgA(sf_dev, win_num, sf_dev->display_info.xres-1, sf_dev->display_info.yres-1,
|
|||
|
+// 0x1, 0x0, 0x0, 0x1, 0x0, 0x0);
|
|||
|
+static void lcdc_win_cfgA(struct starfive_crtc *sf_crtc, struct drm_crtc_state *state,
|
|||
|
+ int win_num, int lay_en, int clor_tab,
|
|||
|
+ int color_en, int addr_mode, int lock)
|
|||
|
+{
|
|||
|
+ int hsize = state->adjusted_mode.crtc_hdisplay - 1;
|
|||
|
+ int vsize = state->adjusted_mode.crtc_vdisplay - 1;
|
|||
|
+ int src_sel_v = 1;
|
|||
|
+ u32 cfg;
|
|||
|
+
|
|||
|
+ if (sf_crtc->pp_conn_lcdc < 0)
|
|||
|
+ src_sel_v = 0;
|
|||
|
+
|
|||
|
+ cfg = hsize | vsize << LCDC_WIN_VSIZE | lay_en << LCDC_WIN_EN |
|
|||
|
+ clor_tab << LCDC_CC_EN | color_en << LCDC_CK_EN |
|
|||
|
+ src_sel_v << LCDC_WIN_ISSEL | addr_mode << LCDC_WIN_PM |
|
|||
|
+ lock << LCDC_WIN_CLK;
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_WIN0_CFG_A + win_num * 0xC, cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev,
|
|||
|
+ "LCDC Win%d H-Size: %d, V-Size: %d, lay_en: %d, Src: %d, AddrMode: %d\n",
|
|||
|
+ win_num, hsize, vsize, lay_en, src_sel_v, addr_mode);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void lcdc_win_cfgB(struct starfive_crtc *sf_crtc,
|
|||
|
+ int win_num, int xpos, int ypos, int argb_ord)
|
|||
|
+{
|
|||
|
+ int win_format = sf_crtc->lcdcfmt;
|
|||
|
+ u32 cfg;
|
|||
|
+
|
|||
|
+#ifdef CONFIG_DRM_STARFIVE_MIPI_DSI
|
|||
|
+ argb_ord = 0;
|
|||
|
+#else
|
|||
|
+ argb_ord = 1;
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+ cfg = xpos |
|
|||
|
+ ypos << LCDC_WIN_VPOS |
|
|||
|
+ win_format << LCDC_WIN_FMT |
|
|||
|
+ argb_ord << LCDC_WIN_ARGB_ORDER;
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_WIN0_CFG_B + win_num * 0xC, cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev,
|
|||
|
+ "LCDC Win%d Xpos: %d, Ypos: %d, win_format: 0x%x, ARGB Order: 0x%x\n",
|
|||
|
+ win_num, xpos, ypos, win_format, argb_ord);
|
|||
|
+}
|
|||
|
+
|
|||
|
+//? Color key
|
|||
|
+static void lcdc_win_cfgC(struct starfive_crtc *sf_crtc, int win_num, int color_key)
|
|||
|
+{
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_WIN0_CFG_C + win_num * 0xC, color_key);
|
|||
|
+ dev_dbg(sf_crtc->dev, "LCDC Win%d Color Key: 0x%6x\n", win_num, color_key);
|
|||
|
+}
|
|||
|
+
|
|||
|
+//? hsize
|
|||
|
+//lcdc_win_src_size(sf_dev, win_num, sf_dev->display_info.xres-1);
|
|||
|
+static void lcdc_win_src_size(struct starfive_crtc *sf_crtc,
|
|||
|
+ struct drm_crtc_state *state, int win_num)
|
|||
|
+{
|
|||
|
+ int addr, off, winsize, pre_cfg, cfg;
|
|||
|
+ int hsize = state->adjusted_mode.crtc_hdisplay - 1;
|
|||
|
+
|
|||
|
+ switch (win_num) {
|
|||
|
+ case 0:
|
|||
|
+ addr = LCDC_WIN01_HSIZE;
|
|||
|
+ off = 0xfffff000;
|
|||
|
+ winsize = hsize;
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ addr = LCDC_WIN01_HSIZE;
|
|||
|
+ off = 0xff000fff;
|
|||
|
+ winsize = hsize << LCDC_IMG_HSIZE;
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ addr = LCDC_WIN23_HSIZE;
|
|||
|
+ off = 0xfffff000;
|
|||
|
+ winsize = hsize;
|
|||
|
+ break;
|
|||
|
+ case 3:
|
|||
|
+ addr = LCDC_WIN23_HSIZE;
|
|||
|
+ off = 0xff000fff;
|
|||
|
+ winsize = hsize << LCDC_IMG_HSIZE;
|
|||
|
+ break;
|
|||
|
+ case 4:
|
|||
|
+ addr = LCDC_WIN45_HSIZE;
|
|||
|
+ off = 0xfffff000;
|
|||
|
+ winsize = hsize;
|
|||
|
+ break;
|
|||
|
+ case 5:
|
|||
|
+ addr = LCDC_WIN45_HSIZE;
|
|||
|
+ off = 0xff000fff;
|
|||
|
+ winsize = hsize << LCDC_IMG_HSIZE;
|
|||
|
+ break;
|
|||
|
+ case 6:
|
|||
|
+ addr = LCDC_WIN67_HSIZE;
|
|||
|
+ off = 0xfffff000;
|
|||
|
+ winsize = hsize;
|
|||
|
+ break;
|
|||
|
+ case 7:
|
|||
|
+ addr = LCDC_WIN67_HSIZE;
|
|||
|
+ off = 0xff000fff;
|
|||
|
+ winsize = hsize << LCDC_IMG_HSIZE;
|
|||
|
+ break;
|
|||
|
+ default:
|
|||
|
+ addr = LCDC_WIN01_HSIZE;
|
|||
|
+ off = 0xfffff000;
|
|||
|
+ winsize = hsize;
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ pre_cfg = sf_fb_lcdcread32(sf_crtc, addr) & off;
|
|||
|
+ cfg = winsize | pre_cfg;
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, addr, cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "LCDC Win%d Src Hsize: %d\n", win_num, hsize);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void lcdc_alpha_val_cfg(struct starfive_crtc *sf_crtc,
|
|||
|
+ int val1, int val2, int val3, int val4, int sel)
|
|||
|
+{
|
|||
|
+ u32 val = val1 |
|
|||
|
+ val2 << LCDC_ALPHA2 |
|
|||
|
+ val3 << LCDC_ALPHA3 |
|
|||
|
+ val4 << LCDC_ALPHA4 |
|
|||
|
+ sel << LCDC_01_ALPHA_SEL;
|
|||
|
+ u32 pre_val = sf_fb_lcdcread32(sf_crtc, LCDC_ALPHA_VALUE) & 0xfffb0000U;
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_ALPHA_VALUE, pre_val | val);
|
|||
|
+ dev_dbg(sf_crtc->dev, "LCDC Alpha 1: %x, 2: %x, 3: %x, 4: %x\n", val1, val2, val3, val4);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void lcdc_panel_cfg(struct starfive_crtc *sf_crtc,
|
|||
|
+ int buswid, int depth, int txcycle, int pixpcycle,
|
|||
|
+ int rgb565sel, int rgb888sel)
|
|||
|
+{
|
|||
|
+ u32 cfg = buswid |
|
|||
|
+ depth << LCDC_COLOR_DEP |
|
|||
|
+ txcycle << LCDC_TCYCLES |
|
|||
|
+ pixpcycle << LCDC_PIXELS |
|
|||
|
+ rgb565sel << LCDC_565RGB_SEL |
|
|||
|
+ rgb888sel << LCDC_888RGB_SEL;
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_PANELDATAFMT, cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "LCDC bus bit: :%d, pixDep: 0x%x, txCyle: %d, %dpix/cycle, RGB565 2cycle_%d, RGB888 3cycle_%d\n",
|
|||
|
+ buswid, depth, txcycle, pixpcycle, rgb565sel, rgb888sel);
|
|||
|
+}
|
|||
|
+
|
|||
|
+//win_num: 0-2
|
|||
|
+static void lcdc_win02_addr_cfg(struct starfive_crtc *sf_crtc, int addr0, int addr1)
|
|||
|
+{
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_WIN0STARTADDR0 + sf_crtc->win_num * 0x8, addr0);
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_WIN0STARTADDR1 + sf_crtc->win_num * 0x8, addr1);
|
|||
|
+ dev_dbg(sf_crtc->dev, "LCDC Win%d Start Addr0: 0x%8x, Addr1: 0x%8x\n",
|
|||
|
+ sf_crtc->win_num, addr0, addr1);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void starfive_set_win_addr(struct starfive_crtc *sf_crtc, int addr)
|
|||
|
+{
|
|||
|
+ lcdc_win02_addr_cfg(sf_crtc, addr, 0x0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void lcdc_enable_intr(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ u32 cfg = ~(1U << LCDC_OUT_FRAME_END);
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_INT_MSK, cfg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void lcdc_disable_intr(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_INT_MSK, 0xff);
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_INT_CLR, 0xff);
|
|||
|
+}
|
|||
|
+
|
|||
|
+int lcdc_win_sel(struct starfive_crtc *sf_crtc, enum lcdc_in_mode sel)
|
|||
|
+{
|
|||
|
+ int win_num;
|
|||
|
+
|
|||
|
+ switch (sel) {
|
|||
|
+ case LCDC_IN_LCD_AXI:
|
|||
|
+ win_num = LCDC_WIN_0;
|
|||
|
+ break;
|
|||
|
+ case LCDC_IN_VPP2:
|
|||
|
+ win_num = LCDC_WIN_0;
|
|||
|
+ break;
|
|||
|
+ case LCDC_IN_VPP1:
|
|||
|
+ win_num = LCDC_WIN_2;
|
|||
|
+ break;
|
|||
|
+ case LCDC_IN_VPP0:
|
|||
|
+ win_num = LCDC_WIN_1;
|
|||
|
+ //mapconv_pp0_sel(sf_dev, 0x0);
|
|||
|
+ break;
|
|||
|
+ case LCDC_IN_MAPCONVERT:
|
|||
|
+ win_num = LCDC_WIN_1;
|
|||
|
+ //mapconv_pp0_sel(sf_dev, 0x1);
|
|||
|
+ break;
|
|||
|
+ default:
|
|||
|
+ win_num = 2;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return win_num;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void lcdc_dsi_sel(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ int temp;
|
|||
|
+ u32 lcdc_en = 0x1;
|
|||
|
+ u32 work_mode = 0x1;
|
|||
|
+ u32 cfg = lcdc_en | work_mode << LCDC_WORK_MODE;
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_GCTRL, cfg);
|
|||
|
+ temp = starfive_lcdc_rstread32(sf_crtc, SRST_ASSERT0);
|
|||
|
+ temp &= ~(0x1 << BIT_RST_DSI_DPI_PIX);
|
|||
|
+ starfive_lcdc_rstwrite32(sf_crtc, SRST_ASSERT0, temp);
|
|||
|
+}
|
|||
|
+
|
|||
|
+irqreturn_t lcdc_isr_handler(int this_irq, void *dev_id)
|
|||
|
+{
|
|||
|
+ struct starfive_crtc *sf_crtc = dev_id;
|
|||
|
+ //u32 intr_status = sf_fb_lcdcread32(sf_crtc, LCDC_INT_STATUS);
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_INT_CLR, 0xffffffff);
|
|||
|
+
|
|||
|
+ return IRQ_HANDLED;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void lcdc_int_cfg(struct starfive_crtc *sf_crtc, int mask)
|
|||
|
+{
|
|||
|
+ u32 cfg;
|
|||
|
+
|
|||
|
+ if (mask == 0x1)
|
|||
|
+ cfg = 0xffffffff;
|
|||
|
+ else
|
|||
|
+ cfg = ~(1U << LCDC_OUT_FRAME_END); //only frame end interrupt mask
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_INT_MSK, cfg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void lcdc_config(struct starfive_crtc *sf_crtc, struct drm_crtc_state *state, int win_num)
|
|||
|
+{
|
|||
|
+ lcdc_mode_cfg(sf_crtc, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0);
|
|||
|
+ lcdc_timing_cfg(sf_crtc, state, 0);
|
|||
|
+ lcdc_desize_cfg(sf_crtc, state);
|
|||
|
+ lcdc_rgb_dclk_cfg(sf_crtc, 0x1);
|
|||
|
+
|
|||
|
+ if (sf_crtc->pp_conn_lcdc < 0) //ddr->lcdc
|
|||
|
+ lcdc_win02_addr_cfg(sf_crtc, sf_crtc->dma_addr, 0x0);
|
|||
|
+
|
|||
|
+ lcdc_win_cfgA(sf_crtc, state, win_num, 0x1, 0x0, 0x0, 0x0, 0x0);
|
|||
|
+ lcdc_win_cfgB(sf_crtc, win_num, 0x0, 0x0, 0x0);
|
|||
|
+ lcdc_win_cfgC(sf_crtc, win_num, 0xffffff);
|
|||
|
+
|
|||
|
+ lcdc_win_src_size(sf_crtc, state, win_num);
|
|||
|
+ lcdc_alpha_val_cfg(sf_crtc, 0xf, 0xf, 0xf, 0xf, 0x0);
|
|||
|
+ lcdc_panel_cfg(sf_crtc, 0x3, 0x4, 0x0, 0x0, 0x0, 0x1); //rgb888sel?
|
|||
|
+}
|
|||
|
+
|
|||
|
+void lcdc_run(struct starfive_crtc *sf_crtc, u32 win_mode, u32 lcd_trig)
|
|||
|
+{
|
|||
|
+ u32 runcfg = win_mode << LCDC_EN_CFG_MODE | lcd_trig;
|
|||
|
+
|
|||
|
+ sf_fb_lcdcwrite32(sf_crtc, LCDC_SWITCH, runcfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "Start run LCDC\n");
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int sf_fb_lcdc_clk_cfg(struct starfive_crtc *sf_crtc, struct drm_crtc_state *state)
|
|||
|
+{
|
|||
|
+ u32 reg_val = clk_get_rate(sf_crtc->clk_vout_src) / (state->mode.clock * HZ_PER_KHZ);
|
|||
|
+ u32 tmp_val;
|
|||
|
+
|
|||
|
+ dev_dbg(sf_crtc->dev, "%s: reg_val = %u\n", __func__, reg_val);
|
|||
|
+
|
|||
|
+ switch (state->adjusted_mode.crtc_hdisplay) {
|
|||
|
+ case 640:
|
|||
|
+ tmp_val = sf_fb_clkread32(sf_crtc, CLK_LCDC_OCLK_CTRL);
|
|||
|
+ tmp_val &= ~(0x3F);
|
|||
|
+ tmp_val |= (59 & 0x3F);
|
|||
|
+ sf_fb_clkwrite32(sf_crtc, CLK_LCDC_OCLK_CTRL, tmp_val);
|
|||
|
+ break;
|
|||
|
+ case 840:
|
|||
|
+ tmp_val = sf_fb_clkread32(sf_crtc, CLK_LCDC_OCLK_CTRL);
|
|||
|
+ tmp_val &= ~(0x3F);
|
|||
|
+ tmp_val |= (54 & 0x3F);
|
|||
|
+ sf_fb_clkwrite32(sf_crtc, CLK_LCDC_OCLK_CTRL, tmp_val);
|
|||
|
+ break;
|
|||
|
+ case 1024:
|
|||
|
+ tmp_val = sf_fb_clkread32(sf_crtc, CLK_LCDC_OCLK_CTRL);
|
|||
|
+ tmp_val &= ~(0x3F);
|
|||
|
+ tmp_val |= (30 & 0x3F);
|
|||
|
+ sf_fb_clkwrite32(sf_crtc, CLK_LCDC_OCLK_CTRL, tmp_val);
|
|||
|
+ break;
|
|||
|
+ case 1280:
|
|||
|
+ tmp_val = sf_fb_clkread32(sf_crtc, CLK_LCDC_OCLK_CTRL);
|
|||
|
+ tmp_val &= ~(0x3F);
|
|||
|
+ tmp_val |= (30 & 0x3F);
|
|||
|
+ sf_fb_clkwrite32(sf_crtc, CLK_LCDC_OCLK_CTRL, tmp_val);
|
|||
|
+ break;
|
|||
|
+ case 1440:
|
|||
|
+ tmp_val = sf_fb_clkread32(sf_crtc, CLK_LCDC_OCLK_CTRL);
|
|||
|
+ tmp_val &= ~(0x3F);
|
|||
|
+ tmp_val |= (30 & 0x3F);
|
|||
|
+ sf_fb_clkwrite32(sf_crtc, CLK_LCDC_OCLK_CTRL, tmp_val);
|
|||
|
+ break;
|
|||
|
+ case 1680:
|
|||
|
+ tmp_val = sf_fb_clkread32(sf_crtc, CLK_LCDC_OCLK_CTRL);
|
|||
|
+ tmp_val &= ~(0x3F);
|
|||
|
+ tmp_val |= (24 & 0x3F); //24 30MHZ
|
|||
|
+ sf_fb_clkwrite32(sf_crtc, CLK_LCDC_OCLK_CTRL, tmp_val);
|
|||
|
+ break;
|
|||
|
+ case 1920:
|
|||
|
+ tmp_val = sf_fb_clkread32(sf_crtc, CLK_LCDC_OCLK_CTRL);
|
|||
|
+ tmp_val &= ~(0x3F);
|
|||
|
+ tmp_val |= (10 & 0x3F); //20 30MHz , 15 40Mhz, 10 60Mhz
|
|||
|
+ sf_fb_clkwrite32(sf_crtc, CLK_LCDC_OCLK_CTRL, tmp_val);
|
|||
|
+ break;
|
|||
|
+ case 2048:
|
|||
|
+ tmp_val = sf_fb_clkread32(sf_crtc, CLK_LCDC_OCLK_CTRL);
|
|||
|
+ tmp_val &= ~(0x3F);
|
|||
|
+ tmp_val |= (10 & 0x3F);
|
|||
|
+ sf_fb_clkwrite32(sf_crtc, CLK_LCDC_OCLK_CTRL, tmp_val);
|
|||
|
+ break;
|
|||
|
+ default:
|
|||
|
+ tmp_val = sf_fb_clkread32(sf_crtc, CLK_LCDC_OCLK_CTRL);
|
|||
|
+ tmp_val &= ~(0x3F);
|
|||
|
+ tmp_val |= (reg_val & 0x3F);
|
|||
|
+ sf_fb_clkwrite32(sf_crtc, CLK_LCDC_OCLK_CTRL, tmp_val);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int sf_fb_lcdc_init(struct starfive_crtc *sf_crtc, struct drm_crtc_state *state)
|
|||
|
+{
|
|||
|
+ int pp_id;
|
|||
|
+ int lcd_in_pp;
|
|||
|
+ int win_num;
|
|||
|
+
|
|||
|
+ pp_id = sf_crtc->pp_conn_lcdc;
|
|||
|
+ if (pp_id < 0) {
|
|||
|
+ dev_dbg(sf_crtc->dev, "DDR to LCDC\n");
|
|||
|
+ lcd_in_pp = LCDC_IN_LCD_AXI;
|
|||
|
+ win_num = lcdc_win_sel(sf_crtc, lcd_in_pp);
|
|||
|
+ sf_crtc->win_num = win_num;
|
|||
|
+ lcdc_config(sf_crtc, state, win_num);
|
|||
|
+ } else {
|
|||
|
+ dev_dbg(sf_crtc->dev, "DDR to VPP to LCDC\n");
|
|||
|
+ lcd_in_pp = (pp_id == 0) ? LCDC_IN_VPP0 :
|
|||
|
+ ((pp_id == 1) ? LCDC_IN_VPP1 : LCDC_IN_VPP2);
|
|||
|
+ win_num = lcdc_win_sel(sf_crtc, lcd_in_pp);
|
|||
|
+ sf_crtc->win_num = win_num;
|
|||
|
+ lcdc_config(sf_crtc, state, win_num);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+int starfive_lcdc_enable(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ struct drm_crtc_state *state = sf_crtc->crtc.state;
|
|||
|
+
|
|||
|
+ lcdc_disable_intr(sf_crtc);
|
|||
|
+
|
|||
|
+ if (sf_fb_lcdc_clk_cfg(sf_crtc, state)) {
|
|||
|
+ dev_err(sf_crtc->dev, "lcdc clock configure fail\n");
|
|||
|
+ return -EINVAL;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if (sf_fb_lcdc_init(sf_crtc, state)) {
|
|||
|
+ dev_err(sf_crtc->dev, "lcdc init fail\n");
|
|||
|
+ return -EINVAL;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ lcdc_run(sf_crtc, sf_crtc->win_num, LCDC_RUN);
|
|||
|
+ lcdc_enable_intr(sf_crtc);
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+MODULE_AUTHOR("StarFive Technology Co., Ltd.");
|
|||
|
+MODULE_DESCRIPTION("loadable LCDC driver for StarFive");
|
|||
|
+MODULE_LICENSE("GPL");
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_lcdc.h b/drivers/gpu/drm/starfive/starfive_drm_lcdc.h
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..6d03ef82debe
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_lcdc.h
|
|||
|
@@ -0,0 +1,160 @@
|
|||
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#ifndef __SF_FB_LCDC_H__
|
|||
|
+#define __SF_FB_LCDC_H__
|
|||
|
+
|
|||
|
+#include "starfive_drm_crtc.h"
|
|||
|
+
|
|||
|
+enum lcdc_in_mode {
|
|||
|
+ LCDC_IN_LCD_AXI = 0,
|
|||
|
+ LCDC_IN_VPP2,
|
|||
|
+ LCDC_IN_VPP1,
|
|||
|
+ LCDC_IN_VPP0,
|
|||
|
+ LCDC_IN_MAPCONVERT,
|
|||
|
+};
|
|||
|
+
|
|||
|
+enum lcdc_win_num {
|
|||
|
+ LCDC_WIN_0 = 0,
|
|||
|
+ LCDC_WIN_1,
|
|||
|
+ LCDC_WIN_2,
|
|||
|
+ LCDC_WIN_3,
|
|||
|
+ LCDC_WIN_4,
|
|||
|
+ LCDC_WIN_5,
|
|||
|
+};
|
|||
|
+
|
|||
|
+enum WIN_FMT {
|
|||
|
+ WIN_FMT_RGB565 = 4,
|
|||
|
+ WIN_FMT_XRGB1555,
|
|||
|
+ WIN_FMT_XRGB4444,
|
|||
|
+ WIN_FMT_XRGB8888,
|
|||
|
+};
|
|||
|
+
|
|||
|
+#define LCDC_STOP 0
|
|||
|
+#define LCDC_RUN 1
|
|||
|
+
|
|||
|
+//lcdc registers
|
|||
|
+#define LCDC_SWITCH 0x0000
|
|||
|
+#define LCDC_GCTRL 0x0004
|
|||
|
+#define LCDC_INT_STATUS 0x0008
|
|||
|
+#define LCDC_INT_MSK 0x000C
|
|||
|
+#define LCDC_INT_CLR 0x0010
|
|||
|
+#define LCDC_RGB_H_TMG 0x0014
|
|||
|
+#define LCDC_RGB_V_TMG 0x0018
|
|||
|
+#define LCDC_RGB_W_TMG 0x001C
|
|||
|
+#define LCDC_RGB_DCLK 0x0020
|
|||
|
+#define LCDC_M_CS_CTRL 0x0024
|
|||
|
+#define LCDC_DeltaRGB_CFG 0x0028
|
|||
|
+#define LCDC_BACKGROUND 0x002C
|
|||
|
+#define LCDC_WIN0_CFG_A 0x0030
|
|||
|
+#define LCDC_WIN0_CFG_B 0x0034
|
|||
|
+#define LCDC_WIN0_CFG_C 0x0038
|
|||
|
+#define LCDC_WIN1_CFG_A 0x003C
|
|||
|
+#define LCDC_WIN1_CFG_B 0x0040
|
|||
|
+#define LCDC_WIN1_CFG_C 0x0044
|
|||
|
+#define LCDC_WIN2_CFG_A 0x0048
|
|||
|
+#define LCDC_WIN2_CFG_B 0x004C
|
|||
|
+#define LCDC_WIN2_CFG_C 0x0050
|
|||
|
+#define LCDC_WIN3_CFG_A 0x0054
|
|||
|
+#define LCDC_WIN3_CFG_B 0x0058
|
|||
|
+#define LCDC_WIN3_CFG_C 0x005C
|
|||
|
+#define LCDC_WIN01_HSIZE 0x0090
|
|||
|
+#define LCDC_WIN23_HSIZE 0x0094
|
|||
|
+#define LCDC_WIN45_HSIZE 0x0098
|
|||
|
+#define LCDC_WIN67_HSIZE 0x009C
|
|||
|
+#define LCDC_ALPHA_VALUE 0x00A0
|
|||
|
+#define LCDC_PANELDATAFMT 0x00A4
|
|||
|
+#define LCDC_WIN0STARTADDR0 0x00B8
|
|||
|
+#define LCDC_WIN0STARTADDR1 0x00BC
|
|||
|
+
|
|||
|
+/* Definition controller bit for LCDC registers */
|
|||
|
+//for LCDC_SWITCH
|
|||
|
+#define LCDC_DTRANS_SWITCH 0
|
|||
|
+#define LCDC_MPU_START 1
|
|||
|
+#define LCDC_EN_CFG_MODE 2
|
|||
|
+//for LCDC_GCTRL
|
|||
|
+#define LCDC_EN 0
|
|||
|
+#define LCDC_WORK_MODE 1
|
|||
|
+#define LCDC_A0_P 4
|
|||
|
+#define LCDC_ENABLE_P 5
|
|||
|
+#define LCDC_DOTCLK_P 6
|
|||
|
+#define LCDC_HSYNC_P 7
|
|||
|
+#define LCDC_VSYNC_P 8
|
|||
|
+#define LCDC_DITHER_EN 9
|
|||
|
+#define LCDC_R2Y_BPS 10
|
|||
|
+#define LCDC_MS_SEL 11
|
|||
|
+#define LCDC_TV_LCD_PATHSEL 12
|
|||
|
+#define LCDC_INTERLACE 13
|
|||
|
+#define LCDC_CBCR_ORDER 14
|
|||
|
+#define LCDC_INT_SEL 15
|
|||
|
+#define LCDC_INT_FREQ 24
|
|||
|
+//for LCDC_INT_MSK
|
|||
|
+#define LCDC_OUT_FRAME_END 5
|
|||
|
+//for RGB_H_TMG,RGB_V_TMG,RGB_W_TMG
|
|||
|
+#define LCDC_RGB_HBK 0
|
|||
|
+#define LCDC_RGB_HFP 16
|
|||
|
+#define LCDC_RGB_VBK 0
|
|||
|
+#define LCDC_RGB_VFP 16
|
|||
|
+#define LCDC_RGB_HPW 0
|
|||
|
+#define LCDC_RGB_VPW 8
|
|||
|
+#define LCDC_RGB_UNIT 16
|
|||
|
+//for BACKGROUND
|
|||
|
+#define LCDC_BG_HSIZE 0
|
|||
|
+#define LCDC_BG_VSIZE 12
|
|||
|
+//for WINx_CFG_A/B/C
|
|||
|
+#define LCDC_WIN_HSIZE 0
|
|||
|
+#define LCDC_WIN_VSIZE 12
|
|||
|
+#define LCDC_WIN_EN 24
|
|||
|
+#define LCDC_CC_EN 25
|
|||
|
+#define LCDC_CK_EN 26
|
|||
|
+#define LCDC_WIN_ISSEL 27
|
|||
|
+#define LCDC_WIN_PM 28
|
|||
|
+#define LCDC_WIN_CLK 30
|
|||
|
+#define LCDC_WIN_HPOS 0
|
|||
|
+#define LCDC_WIN_VPOS 12
|
|||
|
+#define LCDC_WIN_FMT 24
|
|||
|
+#define LCDC_WIN_ARGB_ORDER 27
|
|||
|
+#define LCDC_WIN_CC 0
|
|||
|
+//for WINxx_HSIZE
|
|||
|
+#define LCDC_IMG_HSIZE 12
|
|||
|
+//for LCDC_ALPHA_VALUE
|
|||
|
+#define LCDC_ALPHA1 0
|
|||
|
+#define LCDC_ALPHA2 4
|
|||
|
+#define LCDC_ALPHA3 8
|
|||
|
+#define LCDC_ALPHA4 12
|
|||
|
+#define LCDC_A_GLBL_ALPHA 16
|
|||
|
+#define LCDC_B_GLBL_ALPHA 17
|
|||
|
+#define LCDC_01_ALPHA_SEL 18
|
|||
|
+//for LCDC_PANELDATAFMT
|
|||
|
+#define LCDC_BUS_W 0
|
|||
|
+#define LCDC_TCYCLES 2
|
|||
|
+#define LCDC_COLOR_DEP 4
|
|||
|
+#define LCDC_PIXELS 7
|
|||
|
+#define LCDC_332RGB_SEL 8
|
|||
|
+#define LCDC_444RGB_SEL 9
|
|||
|
+#define LCDC_666RGB_SEL 12
|
|||
|
+#define LCDC_565RGB_SEL 16
|
|||
|
+#define LCDC_888RGB_SEL 18
|
|||
|
+
|
|||
|
+//sysrst registers
|
|||
|
+#define SRST_ASSERT0 0x00
|
|||
|
+#define SRST_STATUS0 0x04
|
|||
|
+/* Definition controller bit for syd rst registers */
|
|||
|
+#define BIT_RST_DSI_DPI_PIX 17
|
|||
|
+
|
|||
|
+void lcdc_enable_intr(struct starfive_crtc *sf_crtc);
|
|||
|
+void lcdc_disable_intr(struct starfive_crtc *sf_crtc);
|
|||
|
+irqreturn_t lcdc_isr_handler(int this_irq, void *dev_id);
|
|||
|
+void lcdc_int_cfg(struct starfive_crtc *sf_crtc, int mask);
|
|||
|
+void lcdc_config(struct starfive_crtc *sf_crtc,
|
|||
|
+ struct drm_crtc_state *old_state,
|
|||
|
+ int win_num);
|
|||
|
+int lcdc_win_sel(struct starfive_crtc *sf_crtc, enum lcdc_in_mode sel);
|
|||
|
+void lcdc_dsi_sel(struct starfive_crtc *sf_crtc);
|
|||
|
+void lcdc_run(struct starfive_crtc *sf_crtc,
|
|||
|
+ u32 win_mode, u32 lcd_trig);
|
|||
|
+void starfive_set_win_addr(struct starfive_crtc *sf_crtc, int addr);
|
|||
|
+int starfive_lcdc_enable(struct starfive_crtc *sf_crtc);
|
|||
|
+
|
|||
|
+#endif
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_plane.c b/drivers/gpu/drm/starfive/starfive_drm_plane.c
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..119a9fe32769
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_plane.c
|
|||
|
@@ -0,0 +1,227 @@
|
|||
|
+// SPDX-License-Identifier: GPL-2.0
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#include <drm/drm.h>
|
|||
|
+#include <drm/drm_atomic.h>
|
|||
|
+#include <drm/drm_atomic_helper.h>
|
|||
|
+#include <drm/drm_fourcc.h>
|
|||
|
+#include <drm/drm_atomic_uapi.h>
|
|||
|
+#include <drm/drm_framebuffer.h>
|
|||
|
+#include <drm/drm_plane_helper.h>
|
|||
|
+#include <drm/drm_gem_framebuffer_helper.h>
|
|||
|
+#include <drm/drm_gem_atomic_helper.h>
|
|||
|
+#include "starfive_drm_crtc.h"
|
|||
|
+#include "starfive_drm_plane.h"
|
|||
|
+#include "starfive_drm_gem.h"
|
|||
|
+#include "starfive_drm_lcdc.h"
|
|||
|
+#include "starfive_drm_vpp.h"
|
|||
|
+
|
|||
|
+static const u32 formats[] = {
|
|||
|
+ DRM_FORMAT_RGB565,
|
|||
|
+ DRM_FORMAT_UYVY,
|
|||
|
+ DRM_FORMAT_VYUY,
|
|||
|
+ DRM_FORMAT_YUYV,
|
|||
|
+ DRM_FORMAT_YVYU,
|
|||
|
+
|
|||
|
+ DRM_FORMAT_YUV420,
|
|||
|
+ DRM_FORMAT_NV21,
|
|||
|
+ DRM_FORMAT_NV12,
|
|||
|
+
|
|||
|
+ DRM_FORMAT_ARGB8888,
|
|||
|
+ DRM_FORMAT_ABGR8888,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static void starfive_plane_destroy(struct drm_plane *plane)
|
|||
|
+{
|
|||
|
+ drm_plane_cleanup(plane);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const struct drm_plane_funcs starfive_plane_funcs = {
|
|||
|
+ .update_plane = drm_atomic_helper_update_plane,
|
|||
|
+ .disable_plane = drm_atomic_helper_disable_plane,
|
|||
|
+ .destroy = starfive_plane_destroy,
|
|||
|
+ .set_property = NULL,
|
|||
|
+ .reset = drm_atomic_helper_plane_reset,
|
|||
|
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
|||
|
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static void starfive_plane_atomic_disable(struct drm_plane *plane,
|
|||
|
+ struct drm_atomic_state *old_state)
|
|||
|
+{
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_plane_atomic_check(struct drm_plane *plane,
|
|||
|
+ struct drm_atomic_state *state)
|
|||
|
+{
|
|||
|
+ struct drm_plane_state *new_plane_state =
|
|||
|
+ drm_atomic_get_new_plane_state(state, plane);
|
|||
|
+ struct drm_framebuffer *fb = new_plane_state->fb;
|
|||
|
+ struct drm_crtc_state *crtc_state;
|
|||
|
+
|
|||
|
+ if (!fb)
|
|||
|
+ return 0;
|
|||
|
+
|
|||
|
+ if (WARN_ON(!new_plane_state->crtc))
|
|||
|
+ return 0;
|
|||
|
+
|
|||
|
+ /*
|
|||
|
+ ret = starfive_drm_plane_check(state->crtc, plane,
|
|||
|
+ to_starfive_plane_state(state));
|
|||
|
+ if (ret)
|
|||
|
+ return ret;
|
|||
|
+ */
|
|||
|
+
|
|||
|
+ //crtc_state = drm_atomic_get_crtc_state(new_plane_state->state, new_plane_state->crtc);
|
|||
|
+ crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc);
|
|||
|
+ if (IS_ERR(crtc_state))
|
|||
|
+ return PTR_ERR(crtc_state);
|
|||
|
+
|
|||
|
+ return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
|
|||
|
+ DRM_PLANE_NO_SCALING,
|
|||
|
+ DRM_PLANE_NO_SCALING,
|
|||
|
+ true, true);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_plane_atomic_update(struct drm_plane *plane,
|
|||
|
+ struct drm_atomic_state *old_state)
|
|||
|
+{
|
|||
|
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(old_state,
|
|||
|
+ plane);
|
|||
|
+ struct drm_crtc *crtc = new_state->crtc;
|
|||
|
+ struct drm_framebuffer *fb = new_state->fb;
|
|||
|
+ //struct drm_plane_state *state = plane->state;
|
|||
|
+ //struct drm_crtc *crtc = state->crtc;
|
|||
|
+ //struct drm_framebuffer *fb = state->fb;
|
|||
|
+
|
|||
|
+ dma_addr_t dma_addr;
|
|||
|
+ struct drm_gem_object *obj;
|
|||
|
+ struct starfive_drm_gem_obj *starfive_obj;
|
|||
|
+ unsigned int pitch, format;
|
|||
|
+
|
|||
|
+ struct starfive_crtc *sf_crtc = to_starfive_crtc(crtc);
|
|||
|
+
|
|||
|
+ if (!crtc || WARN_ON(!fb))
|
|||
|
+ return;
|
|||
|
+
|
|||
|
+ //if (!plane->state->visible) {
|
|||
|
+ if (!new_state->visible) {
|
|||
|
+ starfive_plane_atomic_disable(plane, old_state);
|
|||
|
+ return;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ obj = fb->obj[0];
|
|||
|
+ starfive_obj = to_starfive_gem_obj(obj);
|
|||
|
+ dma_addr = starfive_obj->dma_addr;
|
|||
|
+ pitch = fb->pitches[0];
|
|||
|
+ format = fb->format->format;
|
|||
|
+
|
|||
|
+ //dma_addr += (plane->state->src.x1 >> 16) * fb->format->cpp[0];
|
|||
|
+ //dma_addr += (plane->state->src.y1 >> 16) * pitch;
|
|||
|
+ dma_addr += (new_state->src.x1 >> 16) * fb->format->cpp[0];
|
|||
|
+ dma_addr += (new_state->src.y1 >> 16) * pitch;
|
|||
|
+ if (sf_crtc->ddr_format != format) {
|
|||
|
+ sf_crtc->ddr_format = format;
|
|||
|
+ sf_crtc->ddr_format_change = true;
|
|||
|
+ } else {
|
|||
|
+ sf_crtc->ddr_format_change = false;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if (sf_crtc->dma_addr != dma_addr) {
|
|||
|
+ sf_crtc->dma_addr = dma_addr;
|
|||
|
+ sf_crtc->dma_addr_change = true;
|
|||
|
+ } else {
|
|||
|
+ sf_crtc->dma_addr_change = false;
|
|||
|
+ }
|
|||
|
+ sf_crtc->size = obj->size;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_plane_atomic_async_check(struct drm_plane *plane,
|
|||
|
+ struct drm_atomic_state *state)
|
|||
|
+{
|
|||
|
+ struct drm_crtc_state *crtc_state;
|
|||
|
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
|
|||
|
+ plane);
|
|||
|
+
|
|||
|
+ if (plane != new_plane_state->crtc->cursor)
|
|||
|
+ return -EINVAL;
|
|||
|
+
|
|||
|
+ if (!plane->state)
|
|||
|
+ return -EINVAL;
|
|||
|
+
|
|||
|
+ if (!plane->state->fb)
|
|||
|
+ return -EINVAL;
|
|||
|
+
|
|||
|
+ //if (new_plane_state->state)
|
|||
|
+ // crtc_state = drm_atomic_get_existing_crtc_state(new_plane_state->state,
|
|||
|
+ // new_plane_state->crtc);
|
|||
|
+ //else /* Special case for asynchronous cursor updates. */
|
|||
|
+ // crtc_state = new_plane_state->crtc->state;
|
|||
|
+
|
|||
|
+ if (state)
|
|||
|
+ crtc_state = drm_atomic_get_existing_crtc_state(state,
|
|||
|
+ new_plane_state->crtc);
|
|||
|
+ else /* Special case for asynchronous cursor updates. */
|
|||
|
+ //crtc_state = plane->crtc->state;
|
|||
|
+ crtc_state = new_plane_state->crtc->state;
|
|||
|
+
|
|||
|
+ return drm_atomic_helper_check_plane_state(plane->state, crtc_state,
|
|||
|
+ DRM_PLANE_NO_SCALING,
|
|||
|
+ DRM_PLANE_NO_SCALING,
|
|||
|
+ true, true);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_plane_atomic_async_update(struct drm_plane *plane,
|
|||
|
+ struct drm_atomic_state *new_state)
|
|||
|
+{
|
|||
|
+ struct drm_plane_state *new_plane_state =
|
|||
|
+ drm_atomic_get_new_plane_state(new_state, plane);
|
|||
|
+ struct starfive_crtc *crtcp = to_starfive_crtc(plane->state->crtc);
|
|||
|
+
|
|||
|
+ plane->state->crtc_x = new_plane_state->crtc_x;
|
|||
|
+ plane->state->crtc_y = new_plane_state->crtc_y;
|
|||
|
+ plane->state->crtc_h = new_plane_state->crtc_h;
|
|||
|
+ plane->state->crtc_w = new_plane_state->crtc_w;
|
|||
|
+ plane->state->src_x = new_plane_state->src_x;
|
|||
|
+ plane->state->src_y = new_plane_state->src_y;
|
|||
|
+ plane->state->src_h = new_plane_state->src_h;
|
|||
|
+ plane->state->src_w = new_plane_state->src_w;
|
|||
|
+ swap(plane->state->fb, new_plane_state->fb);
|
|||
|
+
|
|||
|
+ if (crtcp->is_enabled) {
|
|||
|
+ starfive_plane_atomic_update(plane, new_state);
|
|||
|
+ spin_lock(&crtcp->reg_lock);
|
|||
|
+ starfive_crtc_hw_config_simple(crtcp);
|
|||
|
+ spin_unlock(&crtcp->reg_lock);
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const struct drm_plane_helper_funcs starfive_plane_helper_funcs = {
|
|||
|
+ .atomic_check = starfive_plane_atomic_check,
|
|||
|
+ .atomic_update = starfive_plane_atomic_update,
|
|||
|
+ //.prepare_fb = drm_gem_fb_prepare_fb,
|
|||
|
+ .prepare_fb = drm_gem_plane_helper_prepare_fb,
|
|||
|
+ .atomic_disable = starfive_plane_atomic_disable,
|
|||
|
+ .atomic_async_check = starfive_plane_atomic_async_check,
|
|||
|
+ .atomic_async_update = starfive_plane_atomic_async_update,
|
|||
|
+};
|
|||
|
+
|
|||
|
+int starfive_plane_init(struct drm_device *dev,
|
|||
|
+ struct starfive_crtc *starfive_crtc,
|
|||
|
+ enum drm_plane_type type)
|
|||
|
+{
|
|||
|
+ int ret;
|
|||
|
+
|
|||
|
+ ret = drm_universal_plane_init(dev, starfive_crtc->planes, 0,
|
|||
|
+ &starfive_plane_funcs, formats,
|
|||
|
+ ARRAY_SIZE(formats), NULL, type, NULL);
|
|||
|
+ if (ret) {
|
|||
|
+ dev_err(dev->dev, "failed to initialize plane\n");
|
|||
|
+ return ret;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ drm_plane_helper_add(starfive_crtc->planes, &starfive_plane_helper_funcs);
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_plane.h b/drivers/gpu/drm/starfive/starfive_drm_plane.h
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..04c3637d4fa6
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_plane.h
|
|||
|
@@ -0,0 +1,12 @@
|
|||
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#ifndef _STARFIVE_DRM_PLANE_H
|
|||
|
+#define _STARFIVE_DRM_PLANE_H
|
|||
|
+
|
|||
|
+int starfive_plane_init(struct drm_device *dev,
|
|||
|
+ struct starfive_crtc *starfive_crtc,
|
|||
|
+ enum drm_plane_type type);
|
|||
|
+
|
|||
|
+#endif /* _STARFIVE_DRM_PLANE_H */
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_vpp.c b/drivers/gpu/drm/starfive/starfive_drm_vpp.c
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..5cada21d2651
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_vpp.c
|
|||
|
@@ -0,0 +1,806 @@
|
|||
|
+// SPDX-License-Identifier: GPL-2.0
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#include <linux/clk.h>
|
|||
|
+#include <linux/module.h>
|
|||
|
+#include <linux/reset.h>
|
|||
|
+#include <linux/delay.h>
|
|||
|
+#include "starfive_drm_vpp.h"
|
|||
|
+#include "starfive_drm_crtc.h"
|
|||
|
+#include <soc/sifive/sifive_ccache.h>
|
|||
|
+
|
|||
|
+static inline void sf_set_clear(void __iomem *addr, u32 reg, u32 set, u32 clear)
|
|||
|
+{
|
|||
|
+ u32 value = ioread32(addr + reg);
|
|||
|
+
|
|||
|
+ value &= ~clear;
|
|||
|
+ value |= set;
|
|||
|
+ iowrite32(value, addr + reg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static u32 sf_fb_sysread32(struct starfive_crtc *sf_crtc, u32 reg)
|
|||
|
+{
|
|||
|
+ return ioread32(sf_crtc->base_syscfg + reg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void sf_fb_syswrite32(struct starfive_crtc *sf_crtc, u32 reg, u32 val)
|
|||
|
+{
|
|||
|
+ iowrite32(val, sf_crtc->base_syscfg + reg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static u32 sf_fb_vppread32(struct starfive_crtc *sf_crtc, int pp_num, u32 reg)
|
|||
|
+{
|
|||
|
+ void __iomem *base_vpp;
|
|||
|
+
|
|||
|
+ switch (pp_num) {
|
|||
|
+ case 0:
|
|||
|
+ base_vpp = sf_crtc->base_vpp0;
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ base_vpp = sf_crtc->base_vpp1;
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ base_vpp = sf_crtc->base_vpp2;
|
|||
|
+ break;
|
|||
|
+ default:
|
|||
|
+ dev_err(sf_crtc->dev, "Err:invalid vpp Number!\n");
|
|||
|
+ return 0;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return ioread32(base_vpp + reg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void sf_fb_vppwrite32(struct starfive_crtc *sf_crtc, int pp_num, u32 reg, u32 val)
|
|||
|
+{
|
|||
|
+ void __iomem *base_vpp;
|
|||
|
+
|
|||
|
+ switch (pp_num) {
|
|||
|
+ case 0:
|
|||
|
+ base_vpp = sf_crtc->base_vpp0;
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ base_vpp = sf_crtc->base_vpp1;
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ base_vpp = sf_crtc->base_vpp2;
|
|||
|
+ break;
|
|||
|
+ default:
|
|||
|
+ dev_err(sf_crtc->dev, "Err:invalid vpp Number!\n");
|
|||
|
+ return;
|
|||
|
+ }
|
|||
|
+ iowrite32(val, base_vpp + reg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void mapconv_pp0_sel(struct starfive_crtc *sf_crtc, int sel)
|
|||
|
+{
|
|||
|
+ u32 temp;
|
|||
|
+
|
|||
|
+ temp = sf_fb_sysread32(sf_crtc, SYS_MAP_CONV);
|
|||
|
+ temp &= ~(0x1);
|
|||
|
+ temp |= (sel & 0x1);
|
|||
|
+ sf_fb_syswrite32(sf_crtc, SYS_MAP_CONV, temp);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_output_cfg(struct starfive_crtc *sf_crtc,
|
|||
|
+ int pp_num, int out_sel, int prog_inter, int desformat,
|
|||
|
+ int pt_mode)
|
|||
|
+{
|
|||
|
+ int cfg = out_sel | prog_inter << PP_INTERLACE |
|
|||
|
+ desformat << PP_DES_FORMAT |
|
|||
|
+ pt_mode << PP_POINTER_MODE;
|
|||
|
+ int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL1) & 0xffff8f0U;
|
|||
|
+
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL1, cfg | pre_cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d out_sel: %d, outFormat: 0x%x, Out Interlace: %d, pt_mode: %d\n",
|
|||
|
+ pp_num, out_sel, desformat, prog_inter, pt_mode);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_srcfmt_cfg(struct starfive_crtc *sf_crtc, int pp_num, int srcformat,
|
|||
|
+ int yuv420_inter, int yuv422_mode, int yuv420_mode, int argb_ord)
|
|||
|
+{
|
|||
|
+ int cfg = srcformat << PP_SRC_FORMAT_N |
|
|||
|
+ yuv420_inter << PP_420_ITLC |
|
|||
|
+ yuv422_mode << PP_SRC_422_YUV_POS |
|
|||
|
+ yuv420_mode << PP_SRC_420_YUV_POS |
|
|||
|
+ argb_ord << PP_SRC_ARGB_ORDER;
|
|||
|
+ int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL1) & 0x83ffff0fU;
|
|||
|
+
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL1, cfg | pre_cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d Src Format: 0x%x, YUV420 Interlace: %d, YUV422: %d, YUV420: %d, ARGB Order: %d\n",
|
|||
|
+ pp_num, srcformat, yuv420_inter, yuv422_mode, yuv420_mode, argb_ord);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_r2yscal_bypass(struct starfive_crtc *sf_crtc,
|
|||
|
+ int pp_num, int r2y_byp, int scal_byp, int y2r_byp)
|
|||
|
+{
|
|||
|
+ int bypass = (r2y_byp | scal_byp << 1 | y2r_byp << 2) << PP_R2Y_BPS;
|
|||
|
+ int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL1) & 0xffff8fffU;
|
|||
|
+
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL1, bypass | pre_cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d Bypass R2Y: %d, Y2R: %d, MainSacle: %d\n",
|
|||
|
+ pp_num, r2y_byp, y2r_byp, scal_byp);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_argb_alpha(struct starfive_crtc *sf_crtc, int pp_num, int alpha)
|
|||
|
+{
|
|||
|
+ int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL1) & 0xff00ffffU;
|
|||
|
+
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL1, alpha << PP_ARGB_ALPHA | pre_cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d Alpha: 0x%4x\n", pp_num, alpha);
|
|||
|
+}
|
|||
|
+
|
|||
|
+//rgbNum: 1-3
|
|||
|
+static void pp_r2y_coeff(struct starfive_crtc *sf_crtc,
|
|||
|
+ int pp_num, int coef_num, int rcoef, int gcoef, int bcoef, int off)
|
|||
|
+{
|
|||
|
+ int rgcoeff = rcoef | gcoef << PP_COEF_G1;
|
|||
|
+ int bcoefoff = bcoef | off << PP_OFFSET_1;
|
|||
|
+ u32 addr1 = (coef_num - 1) * 0x8 + PP_R2Y_COEF1;
|
|||
|
+ u32 addr2 = (coef_num - 1) * 0x8 + PP_R2Y_COEF2;
|
|||
|
+
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, addr1, rgcoeff);
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, addr2, bcoefoff);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d coef_num: %d, rCoef: 0x%4x, gCoef: 0x%4x, bCoef: 0x%4x, off: 0x%4x\n",
|
|||
|
+ pp_num, coef_num, rcoef, gcoef, bcoef, off);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_output_fmt_cfg(struct starfive_crtc *sf_crtc,
|
|||
|
+ int pp_num, int yuv420_inter, int yuv422_mode)
|
|||
|
+{
|
|||
|
+ int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL2) & 0xfffffffeU;
|
|||
|
+
|
|||
|
+ pre_cfg = pre_cfg |
|
|||
|
+ yuv420_inter << PP_DES_420_ORDER |
|
|||
|
+ yuv422_mode << PP_DES_422_ORDER;
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL2, pre_cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d Lock Transfer: %d\n", pp_num, yuv422_mode);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_lock_trans_cfg(struct starfive_crtc *sf_crtc, int pp_num, int lock_trans)
|
|||
|
+{
|
|||
|
+ int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL2) & 0xfffffffeU;
|
|||
|
+
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL2, lock_trans | pre_cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d Lock Transfer: %d\n", pp_num, lock_trans);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_int_interval_cfg(struct starfive_crtc *sf_crtc, int pp_num, int interval)
|
|||
|
+{
|
|||
|
+ int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL2) & 0xffff00ffU;
|
|||
|
+
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL2, interval << PP_INT_INTERVAL | pre_cfg);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d Frame Interrupt interval: %d Frames\n", pp_num, interval);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_src_size_cfg(struct starfive_crtc *sf_crtc, int pp_num, int hsize, int vsize)
|
|||
|
+{
|
|||
|
+ int size = hsize | vsize << PP_SRC_VSIZE;
|
|||
|
+
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_SIZE, size);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d HSize: %d, VSize: %d\n", pp_num, hsize, vsize);
|
|||
|
+}
|
|||
|
+
|
|||
|
+//0-no drop, 1-1/2, 2-1/4, down to 1/32
|
|||
|
+static void pp_drop_cfg(struct starfive_crtc *sf_crtc, int pp_num, int hdrop, int vdrop)
|
|||
|
+{
|
|||
|
+ int drop = hdrop | vdrop << PP_DROP_VRATION;
|
|||
|
+
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_DROP_CTRL, drop);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d HDrop: %d, VDrop: %d\n", pp_num, hdrop, vdrop);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_des_size_cfg(struct starfive_crtc *sf_crtc, int pp_num, int hsize, int vsize)
|
|||
|
+{
|
|||
|
+ int size = hsize | vsize << PP_DES_VSIZE;
|
|||
|
+
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_SIZE, size);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d HSize: %d, VSize: %d\n", pp_num, hsize, vsize);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_des_addr_cfg(struct starfive_crtc *sf_crtc,
|
|||
|
+ int pp_num, int yaddr, int uaddr, int vaddr)
|
|||
|
+{
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_Y_SA, yaddr);
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_U_SA, uaddr);
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_V_SA, vaddr);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d des-Addr Y: 0x%8x, U: 0x%8x, V: 0x%8x\n",
|
|||
|
+ pp_num, yaddr, uaddr, vaddr);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_des_offset_cfg(struct starfive_crtc *sf_crtc,
|
|||
|
+ int pp_num, int yoff, int uoff, int voff)
|
|||
|
+{
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_Y_OFS, yoff);
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_U_OFS, uoff);
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_V_OFS, voff);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d des-Offset Y: 0x%4x, U: 0x%4x, V: 0x%4x\n",
|
|||
|
+ pp_num, yoff, uoff, voff);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void pp_intcfg(struct starfive_crtc *sf_crtc, int pp_num, int int_mask)
|
|||
|
+{
|
|||
|
+ int intcfg = ~(0x1 << 0);
|
|||
|
+
|
|||
|
+ if (int_mask)
|
|||
|
+ intcfg = 0xf;
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_INT_MASK, intcfg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+//next source frame Y/RGB start address, ?
|
|||
|
+void pp_src_addr_next(struct starfive_crtc *sf_crtc, int pp_num, int ysa, int usa, int vsa)
|
|||
|
+{
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_Y_SA_NXT, ysa);
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_U_SA_NXT, usa);
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_V_SA_NXT, vsa);
|
|||
|
+ dev_dbg(sf_crtc->dev,
|
|||
|
+ "PP%d next Y startAddr: 0x%8x, U startAddr: 0x%8x, V startAddr: 0x%8x\n",
|
|||
|
+ pp_num, ysa, usa, vsa);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void pp_src_offset_cfg(struct starfive_crtc *sf_crtc, int pp_num, int yoff, int uoff, int voff)
|
|||
|
+{
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_Y_OFS, yoff);
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_U_OFS, uoff);
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_V_OFS, voff);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d src-Offset Y: 0x%4x, U: 0x%4x, V: 0x%4x\n",
|
|||
|
+ pp_num, yoff, uoff, voff);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void pp_nxt_addr_load(struct starfive_crtc *sf_crtc, int pp_num, int nxt_par, int nxt_pos)
|
|||
|
+{
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_LOAD_NXT_PAR, nxt_par | nxt_pos);
|
|||
|
+ dev_dbg(sf_crtc->dev, "PP%d next addrPointer: %d, %d set Regs\n", pp_num, nxt_par, nxt_pos);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void pp_run(struct starfive_crtc *sf_crtc, int pp_num, int start)
|
|||
|
+{
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_SWITCH, start);
|
|||
|
+ //if (start)
|
|||
|
+ // dev_dbg(sf_crtc->dev, "Now start the PP%d\n\n", pp_num);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void pp1_enable_intr(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, 1, PP_INT_MASK, 0x0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void pp_enable_intr(struct starfive_crtc *sf_crtc, int pp_num)
|
|||
|
+{
|
|||
|
+ u32 cfg = 0xfffe;
|
|||
|
+
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_INT_MASK, cfg);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void pp_disable_intr(struct starfive_crtc *sf_crtc, int pp_num)
|
|||
|
+{
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_INT_MASK, 0xf);
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, pp_num, PP_INT_CLR, 0xf);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_srcfmt_set(struct starfive_crtc *sf_crtc, int pp_num, struct pp_video_mode *src)
|
|||
|
+{
|
|||
|
+ switch (src->format) {
|
|||
|
+ case COLOR_YUV422_YVYU:
|
|||
|
+ pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV422, 0x0, COLOR_YUV422_YVYU, 0x0, 0x0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_YUV422_VYUY:
|
|||
|
+ pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV422, 0x0, COLOR_YUV422_VYUY, 0x0, 0x0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_YUV422_YUYV:
|
|||
|
+ pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV422, 0x0, COLOR_YUV422_YUYV, 0x0, 0x0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_YUV422_UYVY:
|
|||
|
+ pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV422, 0x0, COLOR_YUV422_UYVY, 0x0, 0x0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_YUV420P:
|
|||
|
+ pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV420P, 0x0, 0, 0x0, 0x0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_YUV420_NV21:
|
|||
|
+ pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV420I, 0x1, 0,
|
|||
|
+ COLOR_YUV420_NV21 - COLOR_YUV420_NV21, 0x0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_YUV420_NV12:
|
|||
|
+ pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV420I, 0x1, 0,
|
|||
|
+ COLOR_YUV420_NV12 - COLOR_YUV420_NV21, 0x0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_RGB888_ARGB:
|
|||
|
+ pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_GRB888, 0x0, 0x0,
|
|||
|
+ 0x0, COLOR_RGB888_ARGB - COLOR_RGB888_ARGB);
|
|||
|
+ break;
|
|||
|
+ case COLOR_RGB888_ABGR:
|
|||
|
+ pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_GRB888, 0x0, 0x0,
|
|||
|
+ 0x0, COLOR_RGB888_ABGR - COLOR_RGB888_ARGB);
|
|||
|
+ break;
|
|||
|
+ case COLOR_RGB888_RGBA:
|
|||
|
+ pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_GRB888, 0x0, 0x0,
|
|||
|
+ 0x0, COLOR_RGB888_RGBA - COLOR_RGB888_ARGB);
|
|||
|
+ break;
|
|||
|
+ case COLOR_RGB888_BGRA:
|
|||
|
+ pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_GRB888, 0x0, 0x0,
|
|||
|
+ 0x0, COLOR_RGB888_BGRA - COLOR_RGB888_ARGB);
|
|||
|
+ break;
|
|||
|
+ case COLOR_RGB565:
|
|||
|
+ pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_RGB565, 0x0, 0x0, 0x0, 0x0);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_dstfmt_set(struct starfive_crtc *sf_crtc, int pp_num, struct pp_video_mode *dst)
|
|||
|
+{
|
|||
|
+ unsigned int outsel = 1;
|
|||
|
+
|
|||
|
+ if (dst->addr)
|
|||
|
+ outsel = 0;
|
|||
|
+
|
|||
|
+ switch (dst->format) {
|
|||
|
+ case COLOR_YUV422_YVYU:
|
|||
|
+ pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV422, 0x0);
|
|||
|
+ pp_output_fmt_cfg(sf_crtc, pp_num, 0, COLOR_YUV422_UYVY - COLOR_YUV422_YVYU);
|
|||
|
+ break;
|
|||
|
+ case COLOR_YUV422_VYUY:
|
|||
|
+ pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV422, 0x0);
|
|||
|
+ pp_output_fmt_cfg(sf_crtc, pp_num, 0, COLOR_YUV422_UYVY - COLOR_YUV422_VYUY);
|
|||
|
+ break;
|
|||
|
+ case COLOR_YUV422_YUYV:
|
|||
|
+ pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV422, 0x0);
|
|||
|
+ pp_output_fmt_cfg(sf_crtc, pp_num, 0, COLOR_YUV422_UYVY - COLOR_YUV422_YUYV);
|
|||
|
+ break;
|
|||
|
+ case COLOR_YUV422_UYVY:
|
|||
|
+ pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV422, 0x0);
|
|||
|
+ pp_output_fmt_cfg(sf_crtc, pp_num, 0, COLOR_YUV422_UYVY - COLOR_YUV422_YVYU);
|
|||
|
+ break;
|
|||
|
+ case COLOR_YUV420P:
|
|||
|
+ pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV420P, 0x0);
|
|||
|
+ pp_output_fmt_cfg(sf_crtc, pp_num, 0, 0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_YUV420_NV21:
|
|||
|
+ pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV420I, 0x0);
|
|||
|
+ pp_output_fmt_cfg(sf_crtc, pp_num, COLOR_YUV420_NV21 - COLOR_YUV420_NV21, 0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_YUV420_NV12:
|
|||
|
+ pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV420I, 0x0);///0x2, 0x0);
|
|||
|
+ //pp_output_fmt_cfg(pp_num, COLOR_YUV420_NV12 - COLOR_YUV420_NV21, 0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_RGB888_ARGB:
|
|||
|
+ pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_ARGB888, 0x0);
|
|||
|
+ //pp_output_fmt_cfg(pp_num, 0, 0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_RGB888_ABGR:
|
|||
|
+ pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_ABGR888, 0x0);
|
|||
|
+ pp_output_fmt_cfg(sf_crtc, pp_num, 0, 0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_RGB888_RGBA:
|
|||
|
+ pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_RGBA888, 0x0);
|
|||
|
+ pp_output_fmt_cfg(sf_crtc, pp_num, 0, 0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_RGB888_BGRA:
|
|||
|
+ pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_BGRA888, 0x0);
|
|||
|
+ pp_output_fmt_cfg(sf_crtc, pp_num, 0, 0);
|
|||
|
+ break;
|
|||
|
+ case COLOR_RGB565:
|
|||
|
+ pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_RGB565, 0x0);
|
|||
|
+ pp_output_fmt_cfg(sf_crtc, pp_num, 0, 0);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_format_set(struct starfive_crtc *sf_crtc, int pp_num,
|
|||
|
+ struct pp_video_mode *src, struct pp_video_mode *dst)
|
|||
|
+{
|
|||
|
+ /* 1:bypass, 0:not bypass */
|
|||
|
+ unsigned int scale_byp = 1;
|
|||
|
+
|
|||
|
+ pp_srcfmt_set(sf_crtc, pp_num, src);
|
|||
|
+ pp_dstfmt_set(sf_crtc, pp_num, dst);
|
|||
|
+
|
|||
|
+ if (src->height != dst->height || src->width != dst->width)
|
|||
|
+ scale_byp = 0;
|
|||
|
+
|
|||
|
+ if (src->format >= COLOR_RGB888_ARGB && dst->format <= COLOR_YUV420_NV12) {
|
|||
|
+ /* rgb -> yuv-420 */
|
|||
|
+ pp_r2yscal_bypass(sf_crtc, pp_num, NOT_BYPASS, scale_byp, BYPASS);
|
|||
|
+ pp_r2y_coeff(sf_crtc, pp_num, 1, R2Y_COEF_R1, R2Y_COEF_G1,
|
|||
|
+ R2Y_COEF_B1, R2Y_OFFSET1);
|
|||
|
+ pp_r2y_coeff(sf_crtc, pp_num, 2, R2Y_COEF_R2, R2Y_COEF_G2,
|
|||
|
+ R2Y_COEF_B2, R2Y_OFFSET2);
|
|||
|
+ pp_r2y_coeff(sf_crtc, pp_num, 3, R2Y_COEF_R3, R2Y_COEF_G3,
|
|||
|
+ R2Y_COEF_B3, R2Y_OFFSET3);
|
|||
|
+ } else if (src->format <= COLOR_YUV420_NV12 && dst->format >= COLOR_RGB888_ARGB) {
|
|||
|
+ /* yuv-420 -> rgb */
|
|||
|
+ pp_r2yscal_bypass(sf_crtc, pp_num, BYPASS, scale_byp, NOT_BYPASS);
|
|||
|
+ } else if (src->format <= COLOR_YUV422_YVYU && dst->format <= COLOR_YUV420_NV12) {
|
|||
|
+ /* yuv422 -> yuv420 */
|
|||
|
+ pp_r2yscal_bypass(sf_crtc, pp_num, BYPASS, scale_byp, BYPASS);
|
|||
|
+ } else {
|
|||
|
+ /* rgb565->argb888 */
|
|||
|
+ pp_r2yscal_bypass(sf_crtc, pp_num, BYPASS, scale_byp, BYPASS);
|
|||
|
+ } //else if ((src->format >= COLOR_RGB888_ARGB) && (dst->format >= COLOR_RGB888_ARGB)) {
|
|||
|
+ /* rgb -> rgb */
|
|||
|
+ // pp_r2yscal_bypass(pp_num, BYPASS, scale_byp, BYPASS);
|
|||
|
+ //}
|
|||
|
+ pp_argb_alpha(sf_crtc, pp_num, 0xff);
|
|||
|
+
|
|||
|
+ if (dst->addr)
|
|||
|
+ pp_lock_trans_cfg(sf_crtc, pp_num, SYS_BUS_OUTPUT);
|
|||
|
+ else
|
|||
|
+ pp_lock_trans_cfg(sf_crtc, pp_num, FIFO_OUTPUT);
|
|||
|
+
|
|||
|
+ pp_int_interval_cfg(sf_crtc, pp_num, 0x1);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_size_set(struct starfive_crtc *sf_crtc, int pp_num,
|
|||
|
+ struct pp_video_mode *src, struct pp_video_mode *dst)
|
|||
|
+{
|
|||
|
+ u32 src_addr, dstaddr;
|
|||
|
+ unsigned int size, y_rgb_ofst, uofst;
|
|||
|
+ unsigned int v_uvofst = 0, next_y_rgb_addr = 0, next_u_addr = 0, next_v_addr = 0;
|
|||
|
+ unsigned int i = 0;
|
|||
|
+
|
|||
|
+ pp_src_size_cfg(sf_crtc, pp_num, src->width - 1, src->height - 1);
|
|||
|
+ pp_drop_cfg(sf_crtc, pp_num, 0x0, 0x0);///0:no drop
|
|||
|
+ pp_des_size_cfg(sf_crtc, pp_num, dst->width - 1, dst->height - 1);
|
|||
|
+
|
|||
|
+ src_addr = src->addr + (i << 30); //PP_SRC_BASE_ADDR + (i << 30);
|
|||
|
+ size = src->width * src->height;
|
|||
|
+
|
|||
|
+ if (src->format >= COLOR_RGB888_ARGB) {
|
|||
|
+ next_y_rgb_addr = src_addr;
|
|||
|
+ next_u_addr = 0;
|
|||
|
+ next_v_addr = 0;
|
|||
|
+
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ //pp_src_addr_next(pp_num, src_addr, 0, 0);
|
|||
|
+ //pp_src_offset_cfg(pp_num, 0x0, 0x0, 0x0);
|
|||
|
+ } else {
|
|||
|
+ if (src->format == COLOR_YUV420_NV21) { //ok
|
|||
|
+ next_y_rgb_addr = src_addr;
|
|||
|
+ next_u_addr = src_addr + size + 1;
|
|||
|
+ next_v_addr = src_addr + size;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = size;
|
|||
|
+ } else if (src->format == COLOR_YUV420_NV12) {
|
|||
|
+ next_y_rgb_addr = src_addr;
|
|||
|
+ next_u_addr = src_addr + size;
|
|||
|
+ next_v_addr = src_addr + size + 1;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = size;
|
|||
|
+ } else if (src->format == COLOR_YUV420P) {
|
|||
|
+ next_y_rgb_addr = src_addr;
|
|||
|
+ next_u_addr = src_addr + size;
|
|||
|
+ next_v_addr = src_addr + size * 5 / 4;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ } else if (src->format == COLOR_YUV422_YVYU) { //ok
|
|||
|
+ next_y_rgb_addr = src_addr;
|
|||
|
+ next_u_addr = src_addr + 1;
|
|||
|
+ next_v_addr = src_addr + 3;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ } else if (src->format == COLOR_YUV422_VYUY) { //ok
|
|||
|
+ next_y_rgb_addr = src_addr + 1;
|
|||
|
+ next_u_addr = src_addr + 2;
|
|||
|
+ next_v_addr = src_addr;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ } else if (src->format == COLOR_YUV422_YUYV) { //ok
|
|||
|
+ next_y_rgb_addr = src_addr;
|
|||
|
+ next_u_addr = src_addr + 1;
|
|||
|
+ next_v_addr = src_addr + 2;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ } else if (src->format == COLOR_YUV422_UYVY) { //ok
|
|||
|
+ next_y_rgb_addr = src_addr + 1;
|
|||
|
+ next_u_addr = src_addr;
|
|||
|
+ next_v_addr = src_addr + 2;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+ pp_src_addr_next(sf_crtc, pp_num, next_y_rgb_addr, next_u_addr, next_v_addr);
|
|||
|
+ pp_src_offset_cfg(sf_crtc, pp_num, y_rgb_ofst, uofst, v_uvofst);
|
|||
|
+ /* source addr not change */
|
|||
|
+ pp_nxt_addr_load(sf_crtc, pp_num, 0x1, (i & 0x1));
|
|||
|
+
|
|||
|
+ if (dst->addr) {
|
|||
|
+ dstaddr = dst->addr;
|
|||
|
+ size = dst->height * dst->width;
|
|||
|
+ if (dst->format >= COLOR_RGB888_ARGB) {
|
|||
|
+ next_y_rgb_addr = dstaddr;
|
|||
|
+ next_u_addr = 0;
|
|||
|
+ next_v_addr = 0;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ } else {
|
|||
|
+ if (dst->format == COLOR_YUV420_NV21) {
|
|||
|
+ /* yyyyvuvuvu */
|
|||
|
+ next_y_rgb_addr = dstaddr;
|
|||
|
+ next_u_addr = dstaddr + size;
|
|||
|
+ next_v_addr = 0;//dstaddr + size;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ } else if (dst->format == COLOR_YUV420_NV12) {
|
|||
|
+ /* yyyyuvuvuv */
|
|||
|
+ next_y_rgb_addr = dstaddr;
|
|||
|
+ next_u_addr = dstaddr + size;
|
|||
|
+ next_v_addr = dstaddr + size + 1;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = size;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ } else if (dst->format == COLOR_YUV420P) {
|
|||
|
+ next_y_rgb_addr = dstaddr;
|
|||
|
+ next_u_addr = dstaddr + size;
|
|||
|
+ next_v_addr = dstaddr + size * 5 / 4;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ } else if (dst->format == COLOR_YUV422_YVYU) {
|
|||
|
+ next_y_rgb_addr = dstaddr;
|
|||
|
+ next_u_addr = dstaddr + 1;
|
|||
|
+ next_v_addr = dstaddr + 3;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ } else if (dst->format == COLOR_YUV422_VYUY) {
|
|||
|
+ next_y_rgb_addr = dstaddr + 1;
|
|||
|
+ next_u_addr = dstaddr + 2;
|
|||
|
+ next_v_addr = dstaddr;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ } else if (dst->format == COLOR_YUV422_YUYV) {
|
|||
|
+ next_y_rgb_addr = dstaddr;
|
|||
|
+ next_u_addr = dstaddr + 1;
|
|||
|
+ next_v_addr = dstaddr + 2;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ } else if (dst->format == COLOR_YUV422_UYVY) {
|
|||
|
+ next_y_rgb_addr = dstaddr + 1;
|
|||
|
+ next_u_addr = dstaddr;
|
|||
|
+ next_v_addr = dstaddr + 2;
|
|||
|
+ y_rgb_ofst = 0;
|
|||
|
+ uofst = 0;
|
|||
|
+ v_uvofst = 0;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+ pp_des_addr_cfg(sf_crtc, pp_num, next_y_rgb_addr, next_u_addr, next_v_addr);
|
|||
|
+ pp_des_offset_cfg(sf_crtc, pp_num, y_rgb_ofst, uofst, v_uvofst);
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void pp_config(struct starfive_crtc *sf_crtc, int pp_num,
|
|||
|
+ struct pp_video_mode *src, struct pp_video_mode *dst)
|
|||
|
+{
|
|||
|
+ //pp_disable_intr(sf_dev, pp_num);
|
|||
|
+ pp_format_set(sf_crtc, pp_num, src, dst);
|
|||
|
+ pp_size_set(sf_crtc, pp_num, src, dst);
|
|||
|
+}
|
|||
|
+
|
|||
|
+irqreturn_t vpp1_isr_handler(int this_irq, void *dev_id)
|
|||
|
+{
|
|||
|
+ struct starfive_crtc *sf_crtc = dev_id;
|
|||
|
+
|
|||
|
+ sf_fb_vppread32(sf_crtc, 1, PP_INT_STATUS);
|
|||
|
+ sf_fb_vppwrite32(sf_crtc, 1, PP_INT_CLR, 0xf);
|
|||
|
+ sifive_ccache_flush_range(sf_crtc->dma_addr, sf_crtc->size);
|
|||
|
+
|
|||
|
+ return IRQ_HANDLED;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void starfive_pp_enable_intr(struct starfive_crtc *sf_crtc, int enable)
|
|||
|
+{
|
|||
|
+ int pp_id;
|
|||
|
+
|
|||
|
+ for (pp_id = 0; pp_id < PP_NUM; pp_id++) {
|
|||
|
+ if (sf_crtc->pp[pp_id].inited == 1) {
|
|||
|
+ if (enable)
|
|||
|
+ pp_enable_intr(sf_crtc, pp_id);
|
|||
|
+ else
|
|||
|
+ pp_disable_intr(sf_crtc, pp_id);
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_pp_video_mode_init(struct starfive_crtc *sf_crtc,
|
|||
|
+ struct pp_video_mode *src,
|
|||
|
+ struct pp_video_mode *dst,
|
|||
|
+ int pp_id)
|
|||
|
+{
|
|||
|
+ if (!src || !dst) {
|
|||
|
+ dev_err(sf_crtc->dev, "Invalid argument!\n");
|
|||
|
+ return -EINVAL;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if (pp_id < PP_NUM && pp_id >= 0) {
|
|||
|
+ src->format = sf_crtc->vpp_format;
|
|||
|
+ src->width = sf_crtc->crtc.state->adjusted_mode.hdisplay;
|
|||
|
+ src->height = sf_crtc->crtc.state->adjusted_mode.vdisplay;
|
|||
|
+ src->addr = sf_crtc->dma_addr;
|
|||
|
+ //src->addr = 0xa0000000;
|
|||
|
+ dst->format = sf_crtc->pp[pp_id].dst.format;
|
|||
|
+ dst->width = sf_crtc->crtc.state->adjusted_mode.hdisplay;
|
|||
|
+ dst->height = sf_crtc->crtc.state->adjusted_mode.vdisplay;
|
|||
|
+ if (sf_crtc->pp[pp_id].bus_out) /*out to ddr*/
|
|||
|
+ dst->addr = 0xfc000000;
|
|||
|
+ else if (sf_crtc->pp[pp_id].fifo_out) /*out to lcdc*/
|
|||
|
+ dst->addr = 0;
|
|||
|
+ } else {
|
|||
|
+ dev_err(sf_crtc->dev, "pp_id %d is not support\n", pp_id);
|
|||
|
+ return -EINVAL;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_pp_init(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ int pp_id;
|
|||
|
+ int ret = 0;
|
|||
|
+ struct pp_video_mode src, dst;
|
|||
|
+
|
|||
|
+ for (pp_id = 0; pp_id < PP_NUM; pp_id++) {
|
|||
|
+ if (sf_crtc->pp[pp_id].inited == 1) {
|
|||
|
+ ret = starfive_pp_video_mode_init(sf_crtc, &src, &dst, pp_id);
|
|||
|
+ if (!ret)
|
|||
|
+ pp_config(sf_crtc, pp_id, &src, &dst);
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return ret;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int starfive_pp_run(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ int pp_id;
|
|||
|
+ int ret = 0;
|
|||
|
+
|
|||
|
+ for (pp_id = 0; pp_id < PP_NUM; pp_id++) {
|
|||
|
+ if (sf_crtc->pp[pp_id].inited == 1)
|
|||
|
+ pp_run(sf_crtc, pp_id, PP_RUN);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return ret;
|
|||
|
+}
|
|||
|
+
|
|||
|
+int starfive_pp_enable(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ starfive_pp_enable_intr(sf_crtc, PP_INTR_DISABLE);
|
|||
|
+
|
|||
|
+ if (starfive_pp_init(sf_crtc))
|
|||
|
+ return -ENODEV;
|
|||
|
+
|
|||
|
+ starfive_pp_run(sf_crtc);
|
|||
|
+ starfive_pp_enable_intr(sf_crtc, PP_INTR_ENABLE);
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+int starfive_pp_update(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ int pp_id;
|
|||
|
+ int ret = 0;
|
|||
|
+ struct pp_video_mode src, dst;
|
|||
|
+
|
|||
|
+ for (pp_id = 0; pp_id < PP_NUM; pp_id++) {
|
|||
|
+ if (sf_crtc->pp[pp_id].inited == 1) {
|
|||
|
+ ret = starfive_pp_video_mode_init(sf_crtc, &src, &dst, pp_id);
|
|||
|
+ if (!ret) {
|
|||
|
+ if (sf_crtc->ddr_format_change)
|
|||
|
+ pp_format_set(sf_crtc, pp_id, &src, &dst);
|
|||
|
+
|
|||
|
+ if (sf_crtc->dma_addr_change)
|
|||
|
+ pp_size_set(sf_crtc, pp_id, &src, &dst);
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+int starfive_pp_get_2lcdc_id(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ int pp_id;
|
|||
|
+
|
|||
|
+ for (pp_id = 0; pp_id < PP_NUM; pp_id++) {
|
|||
|
+ if (sf_crtc->pp[pp_id].inited == 1) {
|
|||
|
+ if (sf_crtc->pp[pp_id].fifo_out == 1 && !sf_crtc->pp[pp_id].bus_out)
|
|||
|
+ return pp_id;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if (pp_id == PP_NUM - 1)
|
|||
|
+ dev_warn(sf_crtc->dev, "NO pp connect to LCDC\n");
|
|||
|
+
|
|||
|
+ return -ENODEV;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void dsitx_vout_init(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ u32 temp;
|
|||
|
+
|
|||
|
+ reset_control_assert(sf_crtc->rst_vout_src);
|
|||
|
+ reset_control_assert(sf_crtc->rst_disp_axi);
|
|||
|
+ clk_prepare_enable(sf_crtc->clk_disp_axi);
|
|||
|
+ clk_prepare_enable(sf_crtc->clk_vout_src);
|
|||
|
+ reset_control_deassert(sf_crtc->rst_vout_src);
|
|||
|
+ reset_control_deassert(sf_crtc->rst_disp_axi);
|
|||
|
+
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_disp0_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_disp1_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_lcdc_oclk_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_lcdc_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_vpp0_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_vpp1_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_vpp2_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_ppi_tx_esc_clk_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_dsi_apb_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_dsi_sys_clk_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+
|
|||
|
+ sf_set_clear(sf_crtc->base_rst, vout_rstgen_assert0_REG, ~0x1981ec, 0x1981ec);
|
|||
|
+
|
|||
|
+ do {
|
|||
|
+ temp = ioread32(sf_crtc->base_rst + vout_rstgen_status0_REG);
|
|||
|
+ temp &= 0x1981ec;
|
|||
|
+ } while (temp != 0x1981ec);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void vout_reset(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ u32 temp;
|
|||
|
+
|
|||
|
+ iowrite32(0xFFFFFFFF, sf_crtc->base_rst);
|
|||
|
+
|
|||
|
+ clk_prepare_enable(sf_crtc->clk_disp_axi);
|
|||
|
+ clk_prepare_enable(sf_crtc->clk_vout_src);
|
|||
|
+ reset_control_deassert(sf_crtc->rst_vout_src);
|
|||
|
+ reset_control_deassert(sf_crtc->rst_disp_axi);
|
|||
|
+
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_disp0_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_disp1_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_lcdc_oclk_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_lcdc_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_vpp0_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_vpp1_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_vpp2_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_mapconv_apb_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_mapconv_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_pixrawout_apb_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_pixrawout_axi_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_csi2tx_strm0_apb_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_csi2tx_strm0_pixclk_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_ppi_tx_esc_clk_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_dsi_apb_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+ sf_set_clear(sf_crtc->base_clk, clk_dsi_sys_clk_ctrl_REG, BIT(31), BIT(31));
|
|||
|
+
|
|||
|
+ sf_set_clear(sf_crtc->base_rst, vout_rstgen_assert0_REG, ~0x19bfff, 0x19bfff);
|
|||
|
+ do {
|
|||
|
+ temp = ioread32(sf_crtc->base_rst + vout_rstgen_status0_REG);
|
|||
|
+ temp &= 0x19bfff;
|
|||
|
+ } while (temp != 0x19bfff);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void vout_disable(struct starfive_crtc *sf_crtc)
|
|||
|
+{
|
|||
|
+ iowrite32(0xFFFFFFFF, sf_crtc->base_rst);
|
|||
|
+
|
|||
|
+ clk_disable_unprepare(sf_crtc->clk_disp_axi);
|
|||
|
+ clk_disable_unprepare(sf_crtc->clk_vout_src);
|
|||
|
+ reset_control_assert(sf_crtc->rst_vout_src);
|
|||
|
+ reset_control_assert(sf_crtc->rst_disp_axi);
|
|||
|
+}
|
|||
|
+
|
|||
|
+MODULE_AUTHOR("StarFive Technology Co., Ltd.");
|
|||
|
+MODULE_DESCRIPTION("loadable VPP driver for StarFive");
|
|||
|
+MODULE_LICENSE("GPL");
|
|||
|
diff --git a/drivers/gpu/drm/starfive/starfive_drm_vpp.h b/drivers/gpu/drm/starfive/starfive_drm_vpp.h
|
|||
|
new file mode 100644
|
|||
|
index 000000000000..12a1928987c3
|
|||
|
--- /dev/null
|
|||
|
+++ b/drivers/gpu/drm/starfive/starfive_drm_vpp.h
|
|||
|
@@ -0,0 +1,201 @@
|
|||
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|||
|
+/*
|
|||
|
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
|
|||
|
+ */
|
|||
|
+#ifndef __SF_FB_VPP_H__
|
|||
|
+#define __SF_FB_VPP_H__
|
|||
|
+
|
|||
|
+#include "starfive_drm_crtc.h"
|
|||
|
+
|
|||
|
+#define PP_ID_0 0
|
|||
|
+#define PP_ID_1 1
|
|||
|
+#define PP_ID_2 2
|
|||
|
+
|
|||
|
+#define PP_NUM 3
|
|||
|
+
|
|||
|
+#define PP_STOP 0
|
|||
|
+#define PP_RUN 1
|
|||
|
+
|
|||
|
+#define PP_INTR_ENABLE 1
|
|||
|
+#define PP_INTR_DISABLE 0
|
|||
|
+//PP coefficients
|
|||
|
+#define R2Y_COEF_R1 77
|
|||
|
+#define R2Y_COEF_G1 150
|
|||
|
+#define R2Y_COEF_B1 29
|
|||
|
+#define R2Y_OFFSET1 0
|
|||
|
+#define R2Y_COEF_R2 (0x400 | 43)
|
|||
|
+#define R2Y_COEF_G2 (0x400 | 85)
|
|||
|
+#define R2Y_COEF_B2 128
|
|||
|
+#define R2Y_OFFSET2 128
|
|||
|
+#define R2Y_COEF_R3 128
|
|||
|
+#define R2Y_COEF_G3 (0x400 | 107)
|
|||
|
+#define R2Y_COEF_B3 (0x400 | 21)
|
|||
|
+#define R2Y_OFFSET3 128
|
|||
|
+
|
|||
|
+//sys registers
|
|||
|
+#define SYS_CONF_LCDC 0x00
|
|||
|
+#define SYS_CONF_PP 0x04
|
|||
|
+#define SYS_MAP_CONV 0x08
|
|||
|
+
|
|||
|
+//vout clk registers
|
|||
|
+#define CLK_LCDC_OCLK_CTRL 0x14
|
|||
|
+
|
|||
|
+enum PP_LCD_PATH {
|
|||
|
+ SYS_BUS_OUTPUT = 0,
|
|||
|
+ FIFO_OUTPUT = 1,
|
|||
|
+};
|
|||
|
+
|
|||
|
+enum PP_COLOR_CONVERT_SCALE {
|
|||
|
+ NOT_BYPASS = 0,
|
|||
|
+ BYPASS,
|
|||
|
+};
|
|||
|
+
|
|||
|
+enum PP_SRC_FORMAT {
|
|||
|
+ PP_SRC_YUV420P = 0,
|
|||
|
+ PP_SRC_YUV422,
|
|||
|
+ PP_SRC_YUV420I,
|
|||
|
+ PP_RESERVED,
|
|||
|
+ PP_SRC_GRB888,
|
|||
|
+ PP_SRC_RGB565,
|
|||
|
+};
|
|||
|
+
|
|||
|
+enum PP_DST_FORMAT {
|
|||
|
+ PP_DST_YUV420P = 0,
|
|||
|
+ PP_DST_YUV422,
|
|||
|
+ PP_DST_YUV420I,
|
|||
|
+ PP_DST_RGBA888,
|
|||
|
+ PP_DST_ARGB888,
|
|||
|
+ PP_DST_RGB565,
|
|||
|
+ PP_DST_ABGR888,
|
|||
|
+ PP_DST_BGRA888,
|
|||
|
+};
|
|||
|
+
|
|||
|
+struct pp_video_mode {
|
|||
|
+ enum COLOR_FORMAT format;
|
|||
|
+ unsigned int height;
|
|||
|
+ unsigned int width;
|
|||
|
+ unsigned int addr;
|
|||
|
+};
|
|||
|
+
|
|||
|
+struct pp_mode {
|
|||
|
+ char pp_id;
|
|||
|
+ bool bus_out; /*out to ddr*/
|
|||
|
+ bool fifo_out; /*out to lcdc*/
|
|||
|
+ bool inited;
|
|||
|
+ struct pp_video_mode src;
|
|||
|
+ struct pp_video_mode dst;
|
|||
|
+};
|
|||
|
+
|
|||
|
+//vpp registers
|
|||
|
+#define PP_SWITCH 0x0000
|
|||
|
+#define PP_CTRL1 0x0004
|
|||
|
+#define PP_CTRL2 0x0008
|
|||
|
+#define PP_SRC_SIZE 0x000C
|
|||
|
+#define PP_DROP_CTRL 0x0010
|
|||
|
+#define PP_DES_SIZE 0x0014
|
|||
|
+#define PP_Scale_Hratio 0x0018
|
|||
|
+#define PP_Scale_Vratio 0x001C
|
|||
|
+#define PP_Scale_limit 0x0020
|
|||
|
+#define PP_SRC_Y_SA_NXT 0x0024
|
|||
|
+#define PP_SRC_U_SA_NXT 0x0028
|
|||
|
+#define PP_SRC_V_SA_NXT 0x002c
|
|||
|
+#define PP_LOAD_NXT_PAR 0x0030
|
|||
|
+#define PP_SRC_Y_SA0 0x0034
|
|||
|
+#define PP_SRC_U_SA0 0x0038
|
|||
|
+#define PP_SRC_V_SA0 0x003c
|
|||
|
+#define PP_SRC_Y_OFS 0x0040
|
|||
|
+#define PP_SRC_U_OFS 0x0044
|
|||
|
+#define PP_SRC_V_OFS 0x0048
|
|||
|
+#define PP_SRC_Y_SA1 0x004C
|
|||
|
+#define PP_SRC_U_SA1 0x0050
|
|||
|
+#define PP_SRC_V_SA1 0x0054
|
|||
|
+#define PP_DES_Y_SA 0x0058
|
|||
|
+#define PP_DES_U_SA 0x005C
|
|||
|
+#define PP_DES_V_SA 0x0060
|
|||
|
+#define PP_DES_Y_OFS 0x0064
|
|||
|
+#define PP_DES_U_OFS 0x0068
|
|||
|
+#define PP_DES_V_OFS 0x006C
|
|||
|
+#define PP_INT_STATUS 0x0070
|
|||
|
+#define PP_INT_MASK 0x0074
|
|||
|
+#define PP_INT_CLR 0x0078
|
|||
|
+#define PP_R2Y_COEF1 0x007C
|
|||
|
+#define PP_R2Y_COEF2 0x0080
|
|||
|
+
|
|||
|
+/* Definition controller bit for LCDC registers */
|
|||
|
+//for PP_SWITCH
|
|||
|
+#define PP_TRIG 0
|
|||
|
+//for PP_CTRL1
|
|||
|
+#define PP_LCDPATH_EN 0
|
|||
|
+#define PP_INTERLACE 1
|
|||
|
+#define PP_POINTER_MODE 2
|
|||
|
+#define PP_SRC_FORMAT_N 4
|
|||
|
+#define PP_420_ITLC 7
|
|||
|
+#define PP_DES_FORMAT 8
|
|||
|
+#define PP_R2Y_BPS 12
|
|||
|
+#define PP_MSCALE_BPS 13
|
|||
|
+#define PP_Y2R_BPS 14
|
|||
|
+#define PP_ARGB_ALPHA 16
|
|||
|
+#define PP_UV_IN_ADD_128 24
|
|||
|
+#define PP_UV_OUT_ADD_128 25
|
|||
|
+#define PP_SRC_422_YUV_POS 26
|
|||
|
+#define PP_SRC_420_YUV_POS 28
|
|||
|
+#define PP_SRC_ARGB_ORDER 29
|
|||
|
+//for PP_CTRL2
|
|||
|
+#define PP_LOCK_EN 0
|
|||
|
+#define PP_INT_INTERVAL 8
|
|||
|
+#define PP_DES_422_ORDER 16
|
|||
|
+#define PP_DES_420_ORDER 18
|
|||
|
+//for PP_SRC_SIZE
|
|||
|
+#define PP_SRC_HSIZE 0
|
|||
|
+#define PP_SRC_VSIZE 16
|
|||
|
+//for PP_DROP_CTRL
|
|||
|
+#define PP_DROP_HRATION 0
|
|||
|
+#define PP_DROP_VRATION 4
|
|||
|
+//for PP_DES_SIZE
|
|||
|
+#define PP_DES_HSIZE 0
|
|||
|
+#define PP_DES_VSIZE 16
|
|||
|
+//for PP_R2Y_COEF1
|
|||
|
+#define PP_COEF_R1 0
|
|||
|
+#define PP_COEF_G1 16
|
|||
|
+//for PP_R2Y_COEF2
|
|||
|
+#define PP_COEF_B1 0
|
|||
|
+#define PP_OFFSET_1 16
|
|||
|
+
|
|||
|
+#define vout_rstgen_assert0_REG 0x0
|
|||
|
+#define vout_rstgen_status0_REG 0x4
|
|||
|
+#define clk_vout_apb_ctrl_REG 0x0
|
|||
|
+#define clk_mapconv_apb_ctrl_REG 0x4
|
|||
|
+#define clk_mapconv_axi_ctrl_REG 0x8
|
|||
|
+#define clk_disp0_axi_ctrl_REG 0xC
|
|||
|
+#define clk_disp1_axi_ctrl_REG 0x10
|
|||
|
+#define clk_lcdc_oclk_ctrl_REG 0x14
|
|||
|
+#define clk_lcdc_axi_ctrl_REG 0x18
|
|||
|
+#define clk_vpp0_axi_ctrl_REG 0x1C
|
|||
|
+#define clk_vpp1_axi_ctrl_REG 0x20
|
|||
|
+#define clk_vpp2_axi_ctrl_REG 0x24
|
|||
|
+#define clk_pixrawout_apb_ctrl_REG 0x28
|
|||
|
+#define clk_pixrawout_axi_ctrl_REG 0x2C
|
|||
|
+#define clk_csi2tx_strm0_pixclk_ctrl_REG 0x30
|
|||
|
+#define clk_csi2tx_strm0_apb_ctrl_REG 0x34
|
|||
|
+#define clk_dsi_sys_clk_ctrl_REG 0x38
|
|||
|
+#define clk_dsi_apb_ctrl_REG 0x3C
|
|||
|
+#define clk_ppi_tx_esc_clk_ctrl_REG 0x40
|
|||
|
+
|
|||
|
+void mapconv_pp0_sel(struct starfive_crtc *sf_crtc, int sel);
|
|||
|
+void pp_src_addr_next(struct starfive_crtc *sf_crtc, int pp_num, int ysa, int usa, int vsa);
|
|||
|
+void pp_src_offset_cfg(struct starfive_crtc *sf_crtc, int pp_num, int yoff, int uoff, int voff);
|
|||
|
+void pp_nxt_addr_load(struct starfive_crtc *sf_crtc, int pp_num, int nxt_par, int nxt_pos);
|
|||
|
+void pp_intcfg(struct starfive_crtc *sf_crtc, int pp_num, int int_mask);
|
|||
|
+irqreturn_t vpp1_isr_handler(int this_irq, void *dev_id);
|
|||
|
+void pp1_enable_intr(struct starfive_crtc *sf_crtc);
|
|||
|
+void pp_enable_intr(struct starfive_crtc *sf_crtc, int pp_num);
|
|||
|
+void pp_disable_intr(struct starfive_crtc *sf_crtc, int pp_num);
|
|||
|
+void pp_run(struct starfive_crtc *sf_crtc, int pp_num, int start);
|
|||
|
+int starfive_pp_enable(struct starfive_crtc *sf_crtc);
|
|||
|
+int starfive_pp_get_2lcdc_id(struct starfive_crtc *sf_crtc);
|
|||
|
+int starfive_pp_update(struct starfive_crtc *sf_crtc);
|
|||
|
+void vout_disable(struct starfive_crtc *sf_crtc);
|
|||
|
+void vout_reset(struct starfive_crtc *sf_crtc);
|
|||
|
+void dsitx_vout_init(struct starfive_crtc *sf_crtc);
|
|||
|
+
|
|||
|
+#endif
|
|||
|
--
|
|||
|
Armbian
|
|||
|
|