[PATCH 8/8] drm/loongson: Add support for the display subsystem in LS2K2000

From: Sui Jingfeng
Date: Sun Oct 29 2023 - 15:46:43 EST


Before apply this patch, drm/loongson is basically works on LS2K2000.
Because majority of hardware features of the DC are same with LS7A2000's
counterpart. Despite LS2K2000 is a SoC, it don't has a dedicated VRAM.
But the firmware will carve out part of system RAM as VRAM, and write the
base address and size of this reserved RAM to the PCI Bar 2 of the GPU.
So this kind of reserved RAM is nearly same with the dedicated video RAM.

In short, the display subsystem in LS2K2000 are nearly compatible with the
display subsystem in LS7A2000. But LS2K2000 has only one built-in HDMI
encoder, which is connected with the CRTC-0 (display pipe 0). Display pipe
1 exports a generic DVO interface. So there still need a trivial fix.

Before apply this patch:

$ dmesg | grep 0000:00:06.1

pci 0000:00:06.1: [0014:7a36] type 00 class 0x030000
pci 0000:00:06.1: reg 0x10: [mem 0x51250000-0x5125ffff 64bit]
pci 0000:00:06.1: reg 0x18: [mem 0x512b6000-0x512b60ff]
pci 0000:00:06.1: BAR 0: assigned [mem 0x51250000-0x5125ffff 64bit]
pci 0000:00:06.1: BAR 2: assigned [mem 0x512b7f00-0x512b7fff]
pci 0000:00:06.1: vgaarb: setting as boot VGA device
loongson 0000:00:06.1: Found LS7A2000 bridge chipset, revision: 16
loongson 0000:00:06.1: [drm] dc: 400MHz, gmc: 800MHz, gpu: 533MHz
loongson 0000:00:06.1: [drm] Dedicated vram start: 0x40000000, size: 256MiB
loongson 0000:00:06.1: [drm] Loongson VBIOS version: 2.1
loongson 0000:00:06.1: [drm] Loongson VBIOS: has 8 DCBs
loongson 0000:00:06.1: [drm] VRAM: 16384 pages ready
loongson 0000:00:06.1: [drm] GTT: 32768 pages ready
loongson 0000:00:06.1: [drm] lsdc-i2c0(sda pin mask=1, scl pin mask=2) created
loongson 0000:00:06.1: [drm] lsdc-i2c1(sda pin mask=4, scl pin mask=8) created
loongson 0000:00:06.1: [drm] DisplayPipe-0 has HDMI-0
loongson 0000:00:06.1: [drm] DisplayPipe-1 has HDMI-1
loongson 0000:00:06.1: [drm] Total 2 outputs
loongson 0000:00:06.1: [drm] registered irq: 42
[drm] Initialized loongson 1.0.0 20220701 for 0000:00:06.1 on minor 0
loongson 0000:00:06.1: [drm] *ERROR* Setting HDMI-1 PLL failed
loongson 0000:00:06.1: [drm] fb0: loongsondrmfb frame buffer device

After apply this patch, the error "*ERROR* Setting HDMI-1 PLL failed" got
fixed.

$ dmesg | grep 0000:00:06.1

pci 0000:00:06.1: [0014:7a36] type 00 class 0x030000
pci 0000:00:06.1: reg 0x10: [mem 0x51250000-0x5125ffff 64bit]
pci 0000:00:06.1: reg 0x18: [mem 0x512b6000-0x512b60ff]
pci 0000:00:06.1: BAR 0: assigned [mem 0x51250000-0x5125ffff 64bit]
pci 0000:00:06.1: BAR 2: assigned [mem 0x512b7f00-0x512b7fff]
pci 0000:00:06.1: vgaarb: setting as boot VGA device
loongson 0000:00:06.1: Found LS2K2000 SoC, revision: 16
loongson 0000:00:06.1: [drm] dc: 400MHz, gmc: 800MHz, gpu: 533MHz
loongson 0000:00:06.1: [drm] Dedicated vram start: 0x40000000, size: 256MiB
loongson 0000:00:06.1: [drm] Loongson VBIOS version: 2.1
loongson 0000:00:06.1: [drm] Loongson VBIOS: has 8 DCBs
loongson 0000:00:06.1: [drm] VRAM: 16384 pages ready
loongson 0000:00:06.1: [drm] GTT: 32768 pages ready
loongson 0000:00:06.1: [drm] lsdc-i2c0(sda pin mask=1, scl pin mask=2) created
loongson 0000:00:06.1: [drm] lsdc-i2c1(sda pin mask=4, scl pin mask=8) created
loongson 0000:00:06.1: [drm] DisplayPipe-0 has HDMI-0
loongson 0000:00:06.1: [drm] DisplayPipe-1 has DVO-1
loongson 0000:00:06.1: [drm] Total 2 outputs
loongson 0000:00:06.1: [drm] registered irq: 42
[drm] Initialized loongson 1.0.0 20220701 for 0000:00:06.1 on minor 0
loongson 0000:00:06.1: [drm] fb0: loongsondrmfb frame buffer device

Signed-off-by: Sui Jingfeng <suijingfeng@xxxxxxxxxxx>
---
drivers/gpu/drm/loongson/Makefile | 1 +
drivers/gpu/drm/loongson/loongson_device.c | 46 ++++++++++
drivers/gpu/drm/loongson/lsdc_output.h | 5 ++
drivers/gpu/drm/loongson/lsdc_output_2k2000.c | 84 +++++++++++++++++++
4 files changed, 136 insertions(+)
create mode 100644 drivers/gpu/drm/loongson/lsdc_output_2k2000.c

diff --git a/drivers/gpu/drm/loongson/Makefile b/drivers/gpu/drm/loongson/Makefile
index 393709e686aa..7d3d82ddd5ff 100644
--- a/drivers/gpu/drm/loongson/Makefile
+++ b/drivers/gpu/drm/loongson/Makefile
@@ -10,6 +10,7 @@ loongson-y := \
lsdc_i2c.o \
lsdc_irq.o \
lsdc_output.o \
+ lsdc_output_2k2000.o \
lsdc_output_7a1000.o \
lsdc_output_7a2000.o \
lsdc_plane.o \
diff --git a/drivers/gpu/drm/loongson/loongson_device.c b/drivers/gpu/drm/loongson/loongson_device.c
index 64096ad5466e..33aae403f0b0 100644
--- a/drivers/gpu/drm/loongson/loongson_device.c
+++ b/drivers/gpu/drm/loongson/loongson_device.c
@@ -6,6 +6,7 @@
#include <linux/pci.h>

#include "lsdc_drv.h"
+#include "lsdc_probe.h"

extern struct loongson_vbios __loongson_vbios;

@@ -27,6 +28,15 @@ static const struct lsdc_kms_funcs ls7a2000_kms_funcs = {
.crtc_init = ls7a2000_crtc_init,
};

+static const struct lsdc_kms_funcs ls2k2000_kms_funcs = {
+ .create_i2c = lsdc_create_i2c_chan,
+ .irq_handler = ls7a2000_dc_irq_handler,
+ .output_init = ls2k2000_output_init,
+ .cursor_plane_init = ls7a2000_cursor_plane_init,
+ .primary_plane_init = lsdc_primary_plane_init,
+ .crtc_init = ls7a2000_crtc_init,
+};
+
static const struct loongson_gfx_desc ls7a1000_gfx = {
.dc = {
.num_of_crtc = 2,
@@ -93,14 +103,50 @@ static const struct loongson_gfx_desc ls7a2000_gfx = {
.model = "LS7A2000 bridge chipset",
};

+static const struct loongson_gfx_desc ls2k2000_gfx = {
+ .dc = {
+ .num_of_crtc = 2,
+ .max_pixel_clk = 350000,
+ .max_width = 4096,
+ .max_height = 4096,
+ .num_of_hw_cursor = 2,
+ .hw_cursor_w = 64,
+ .hw_cursor_h = 64,
+ .pitch_align = 64,
+ .has_vblank_counter = true,
+ .funcs = &ls2k2000_kms_funcs,
+ },
+ .conf_reg_base = LS7A2000_CONF_REG_BASE,
+ .gfxpll = {
+ .reg_offset = LS7A2000_PLL_GFX_REG,
+ .reg_size = 8,
+ },
+ .pixpll = {
+ [0] = {
+ .reg_offset = LS7A2000_PIXPLL0_REG,
+ .reg_size = 8,
+ },
+ [1] = {
+ .reg_offset = LS7A2000_PIXPLL1_REG,
+ .reg_size = 8,
+ },
+ },
+ .vbios = &__loongson_vbios,
+ .chip_id = CHIP_LS2K2000,
+ .model = "LS2K2000 SoC",
+};
+
static const struct lsdc_desc *__chip_id_desc_table[] = {
[CHIP_LS7A1000] = &ls7a1000_gfx.dc,
[CHIP_LS7A2000] = &ls7a2000_gfx.dc,
+ [CHIP_LS2K2000] = &ls2k2000_gfx.dc,
[CHIP_LS_LAST] = NULL,
};

const struct lsdc_desc *
lsdc_device_probe(struct pci_dev *pdev, enum loongson_chip_id chip_id)
{
+ chip_id = loongson_chip_id_fixup(chip_id);
+
return __chip_id_desc_table[chip_id];
}
diff --git a/drivers/gpu/drm/loongson/lsdc_output.h b/drivers/gpu/drm/loongson/lsdc_output.h
index a37a72687bdf..463d59d680c2 100644
--- a/drivers/gpu/drm/loongson/lsdc_output.h
+++ b/drivers/gpu/drm/loongson/lsdc_output.h
@@ -61,6 +61,11 @@ int ls7a2000_output_init(struct drm_device *ddev,
struct i2c_adapter *ddc,
unsigned int index);

+int ls2k2000_output_init(struct drm_device *ddev,
+ struct lsdc_display_pipe *dispipe,
+ struct i2c_adapter *ddc,
+ unsigned int pipe);
+
int lsdc_output_init(struct drm_device *ddev,
struct lsdc_display_pipe *dispipe,
struct i2c_adapter *ddc,
diff --git a/drivers/gpu/drm/loongson/lsdc_output_2k2000.c b/drivers/gpu/drm/loongson/lsdc_output_2k2000.c
new file mode 100644
index 000000000000..350af51da541
--- /dev/null
+++ b/drivers/gpu/drm/loongson/lsdc_output_2k2000.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ */
+
+#include "lsdc_drv.h"
+#include "lsdc_output.h"
+
+/*
+ * The DC in LS2K2000 is nearly same with the DC in LS7A2000, except that
+ * LS2K2000 has only one built-in HDMI encoder which is connected with the
+ * display pipe 0. Display pipe 1 is a DVO output interface.
+ * ________________________
+ * | | ______________
+ * | +----------| | |
+ * | CRTC-0 ---> | HDMI phy ---> HDMI Connector --> | HDMI Monitor |<--+
+ * | +----------| |______________| |
+ * | +-------+ | |
+ * | | i2c-x | <------------------------------------------+
+ * | +-------+ |
+ * | |
+ * | DC in LS2K2000 |
+ * | |
+ * | +-------+ |
+ * | | i2c-y | <------------------------------------+
+ * | +-------+ | |
+ * | | ____|____
+ * | +-------| | |
+ * | CRTC-1 ------> | DVO --> Encoder1 --> Connector1 --> | Display |
+ * | +-------| |_________|
+ * |________________________|
+ */
+
+static void ls2k2000_pipe1_dvo_encoder_reset(struct drm_encoder *encoder)
+{
+ struct drm_device *ddev = encoder->dev;
+ struct lsdc_device *ldev = to_lsdc(ddev);
+ u32 val;
+
+ val = PHY_CLOCK_POL | PHY_CLOCK_EN | PHY_DATA_EN;
+ lsdc_wreg32(ldev, LSDC_CRTC1_DVO_CONF_REG, val);
+}
+
+const struct drm_encoder_funcs ls2k2000_pipe1_dvo_encoder_funcs = {
+ .reset = ls2k2000_pipe1_dvo_encoder_reset,
+ .destroy = drm_encoder_cleanup,
+};
+
+static const struct lsdc_output_desc ls2k2000_output_desc[2] = {
+ {
+ .pipe = 0,
+ .encoder_type = DRM_MODE_ENCODER_TMDS,
+ .connector_type = DRM_MODE_CONNECTOR_HDMIA,
+ .encoder_funcs = &lsdc_pipe0_hdmi_encoder_funcs,
+ .encoder_helper_funcs = &lsdc_pipe0_hdmi_encoder_helper_funcs,
+ .connector_funcs = &lsdc_pipe0_hdmi_connector_funcs,
+ .connector_helper_funcs = &lsdc_connector_helper_funcs,
+ .name = "HDMI-0",
+ },
+ {
+ .pipe = 1,
+ .encoder_type = DRM_MODE_ENCODER_DPI,
+ .connector_type = DRM_MODE_CONNECTOR_DPI,
+ .encoder_funcs = &ls2k2000_pipe1_dvo_encoder_funcs,
+ .encoder_helper_funcs = &lsdc_encoder_helper_funcs,
+ .connector_funcs = &lsdc_connector_funcs,
+ .connector_helper_funcs = &lsdc_connector_helper_funcs,
+ .name = "DVO-1",
+ },
+};
+
+int ls2k2000_output_init(struct drm_device *ddev,
+ struct lsdc_display_pipe *dispipe,
+ struct i2c_adapter *ddc,
+ unsigned int pipe)
+{
+ struct lsdc_output *output = &dispipe->output;
+
+ output->descp = &ls2k2000_output_desc[pipe];
+
+ lsdc_output_init(ddev, dispipe, ddc, pipe);
+
+ return 0;
+}
--
2.34.1