192 lines
6.3 KiB
Diff
192 lines
6.3 KiB
Diff
From 4dd1101f3e16e6202132ae34a8da2a7d78043d56 Mon Sep 17 00:00:00 2001
|
|
From: Maxime Ripard <maxime@cerno.tech>
|
|
Date: Thu, 3 Dec 2020 14:25:39 +0100
|
|
Subject: [PATCH] drm/vc4: dsi: Introduce a variant structure
|
|
|
|
Commit d1d195ce26a14ec0a87816c09ae514e1c40e97f7 upstream.
|
|
|
|
Most of the differences between DSI0 and DSI1 are handled through the
|
|
ID. However, the BCM2711 DSI is going to introduce one more variable to
|
|
the mix and will break some expectations of the earlier, simpler, test.
|
|
|
|
Let's add a variant structure that will address most of the differences
|
|
between those three controllers.
|
|
|
|
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
|
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
|
Link: https://patchwork.freedesktop.org/patch/msgid/20201203132543.861591-5-maxime@cerno.tech
|
|
---
|
|
drivers/gpu/drm/vc4/vc4_dsi.c | 63 ++++++++++++++++++++---------------
|
|
1 file changed, 37 insertions(+), 26 deletions(-)
|
|
|
|
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
|
|
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
|
|
@@ -493,6 +493,18 @@
|
|
*/
|
|
#define DSI1_ID 0x8c
|
|
|
|
+struct vc4_dsi_variant {
|
|
+ /* Whether we're on bcm2835's DSI0 or DSI1. */
|
|
+ unsigned int port;
|
|
+
|
|
+ bool broken_axi_workaround;
|
|
+
|
|
+ const char *debugfs_name;
|
|
+ const struct debugfs_reg32 *regs;
|
|
+ size_t nregs;
|
|
+
|
|
+};
|
|
+
|
|
/* General DSI hardware state. */
|
|
struct vc4_dsi {
|
|
struct platform_device *pdev;
|
|
@@ -509,8 +521,7 @@ struct vc4_dsi {
|
|
u32 *reg_dma_mem;
|
|
dma_addr_t reg_paddr;
|
|
|
|
- /* Whether we're on bcm2835's DSI0 or DSI1. */
|
|
- int port;
|
|
+ const struct vc4_dsi_variant *variant;
|
|
|
|
/* DSI channel for the panel we're connected to. */
|
|
u32 channel;
|
|
@@ -586,10 +597,10 @@ dsi_dma_workaround_write(struct vc4_dsi
|
|
#define DSI_READ(offset) readl(dsi->regs + (offset))
|
|
#define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val)
|
|
#define DSI_PORT_READ(offset) \
|
|
- DSI_READ(dsi->port ? DSI1_##offset : DSI0_##offset)
|
|
+ DSI_READ(dsi->variant->port ? DSI1_##offset : DSI0_##offset)
|
|
#define DSI_PORT_WRITE(offset, val) \
|
|
- DSI_WRITE(dsi->port ? DSI1_##offset : DSI0_##offset, val)
|
|
-#define DSI_PORT_BIT(bit) (dsi->port ? DSI1_##bit : DSI0_##bit)
|
|
+ DSI_WRITE(dsi->variant->port ? DSI1_##offset : DSI0_##offset, val)
|
|
+#define DSI_PORT_BIT(bit) (dsi->variant->port ? DSI1_##bit : DSI0_##bit)
|
|
|
|
/* VC4 DSI encoder KMS struct */
|
|
struct vc4_dsi_encoder {
|
|
@@ -837,7 +848,7 @@ static void vc4_dsi_encoder_enable(struc
|
|
|
|
ret = pm_runtime_get_sync(dev);
|
|
if (ret) {
|
|
- DRM_ERROR("Failed to runtime PM enable on DSI%d\n", dsi->port);
|
|
+ DRM_ERROR("Failed to runtime PM enable on DSI%d\n", dsi->variant->port);
|
|
return;
|
|
}
|
|
|
|
@@ -871,7 +882,7 @@ static void vc4_dsi_encoder_enable(struc
|
|
DSI_PORT_WRITE(STAT, DSI_PORT_READ(STAT));
|
|
|
|
/* Set AFE CTR00/CTR1 to release powerdown of analog. */
|
|
- if (dsi->port == 0) {
|
|
+ if (dsi->variant->port == 0) {
|
|
u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) |
|
|
VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ));
|
|
|
|
@@ -1017,7 +1028,7 @@ static void vc4_dsi_encoder_enable(struc
|
|
DSI_PORT_BIT(PHYC_CLANE_ENABLE) |
|
|
((dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ?
|
|
0 : DSI_PORT_BIT(PHYC_HS_CLK_CONTINUOUS)) |
|
|
- (dsi->port == 0 ?
|
|
+ (dsi->variant->port == 0 ?
|
|
VC4_SET_FIELD(lpx - 1, DSI0_PHYC_ESC_CLK_LPDT) :
|
|
VC4_SET_FIELD(lpx - 1, DSI1_PHYC_ESC_CLK_LPDT)));
|
|
|
|
@@ -1043,13 +1054,13 @@ static void vc4_dsi_encoder_enable(struc
|
|
DSI_DISP1_ENABLE);
|
|
|
|
/* Ungate the block. */
|
|
- if (dsi->port == 0)
|
|
+ if (dsi->variant->port == 0)
|
|
DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI0_CTRL_CTRL0);
|
|
else
|
|
DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI1_CTRL_EN);
|
|
|
|
/* Bring AFE out of reset. */
|
|
- if (dsi->port == 0) {
|
|
+ if (dsi->variant->port == 0) {
|
|
} else {
|
|
DSI_PORT_WRITE(PHY_AFEC0,
|
|
DSI_PORT_READ(PHY_AFEC0) &
|
|
@@ -1305,8 +1316,16 @@ static const struct drm_encoder_helper_f
|
|
.mode_fixup = vc4_dsi_encoder_mode_fixup,
|
|
};
|
|
|
|
+static const struct vc4_dsi_variant bcm2835_dsi1_variant = {
|
|
+ .port = 1,
|
|
+ .broken_axi_workaround = true,
|
|
+ .debugfs_name = "dsi1_regs",
|
|
+ .regs = dsi1_regs,
|
|
+ .nregs = ARRAY_SIZE(dsi1_regs),
|
|
+};
|
|
+
|
|
static const struct of_device_id vc4_dsi_dt_match[] = {
|
|
- { .compatible = "brcm,bcm2835-dsi1", (void *)(uintptr_t)1 },
|
|
+ { .compatible = "brcm,bcm2835-dsi1", &bcm2835_dsi1_variant },
|
|
{}
|
|
};
|
|
|
|
@@ -1317,7 +1336,7 @@ static void dsi_handle_error(struct vc4_
|
|
if (!(stat & bit))
|
|
return;
|
|
|
|
- DRM_ERROR("DSI%d: %s error\n", dsi->port, type);
|
|
+ DRM_ERROR("DSI%d: %s error\n", dsi->variant->port, type);
|
|
*ret = IRQ_HANDLED;
|
|
}
|
|
|
|
@@ -1415,7 +1434,7 @@ vc4_dsi_init_phy_clocks(struct vc4_dsi *
|
|
int ret;
|
|
|
|
snprintf(clk_name, sizeof(clk_name),
|
|
- "dsi%u_%s", dsi->port, phy_clocks[i].name);
|
|
+ "dsi%u_%s", dsi->variant->port, phy_clocks[i].name);
|
|
|
|
/* We just use core fixed factor clock ops for the PHY
|
|
* clocks. The clocks are actually gated by the
|
|
@@ -1463,7 +1482,7 @@ static int vc4_dsi_bind(struct device *d
|
|
if (!match)
|
|
return -ENODEV;
|
|
|
|
- dsi->port = (uintptr_t)match->data;
|
|
+ dsi->variant = match->data;
|
|
|
|
vc4_dsi_encoder = devm_kzalloc(dev, sizeof(*vc4_dsi_encoder),
|
|
GFP_KERNEL);
|
|
@@ -1480,13 +1499,8 @@ static int vc4_dsi_bind(struct device *d
|
|
return PTR_ERR(dsi->regs);
|
|
|
|
dsi->regset.base = dsi->regs;
|
|
- if (dsi->port == 0) {
|
|
- dsi->regset.regs = dsi0_regs;
|
|
- dsi->regset.nregs = ARRAY_SIZE(dsi0_regs);
|
|
- } else {
|
|
- dsi->regset.regs = dsi1_regs;
|
|
- dsi->regset.nregs = ARRAY_SIZE(dsi1_regs);
|
|
- }
|
|
+ dsi->regset.regs = dsi->variant->regs;
|
|
+ dsi->regset.nregs = dsi->variant->nregs;
|
|
|
|
if (DSI_PORT_READ(ID) != DSI_ID_VALUE) {
|
|
dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n",
|
|
@@ -1498,7 +1512,7 @@ static int vc4_dsi_bind(struct device *d
|
|
* from the ARM. It does handle writes from the DMA engine,
|
|
* so set up a channel for talking to it.
|
|
*/
|
|
- if (dsi->port == 1) {
|
|
+ if (dsi->variant->broken_axi_workaround) {
|
|
dsi->reg_dma_mem = dma_alloc_coherent(dev, 4,
|
|
&dsi->reg_dma_paddr,
|
|
GFP_KERNEL);
|
|
@@ -1619,10 +1633,7 @@ static int vc4_dsi_bind(struct device *d
|
|
*/
|
|
list_splice_init(&dsi->encoder->bridge_chain, &dsi->bridge_chain);
|
|
|
|
- if (dsi->port == 0)
|
|
- vc4_debugfs_add_regset32(drm, "dsi0_regs", &dsi->regset);
|
|
- else
|
|
- vc4_debugfs_add_regset32(drm, "dsi1_regs", &dsi->regset);
|
|
+ vc4_debugfs_add_regset32(drm, dsi->variant->debugfs_name, &dsi->regset);
|
|
|
|
pm_runtime_enable(dev);
|
|
|