Commit d1d195ce authored by Maxime Ripard's avatar Maxime Ripard

drm/vc4: dsi: Introduce a variant structure

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: default avatarDave Stevenson <dave.stevenson@raspberrypi.com>
Signed-off-by: default avatarMaxime Ripard <maxime@cerno.tech>
Link: https://patchwork.freedesktop.org/patch/msgid/20201203132543.861591-5-maxime@cerno.tech
parent dc0bf364
...@@ -493,6 +493,18 @@ ...@@ -493,6 +493,18 @@
*/ */
#define DSI1_ID 0x8c #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. */ /* General DSI hardware state. */
struct vc4_dsi { struct vc4_dsi {
struct platform_device *pdev; struct platform_device *pdev;
...@@ -509,8 +521,7 @@ struct vc4_dsi { ...@@ -509,8 +521,7 @@ struct vc4_dsi {
u32 *reg_dma_mem; u32 *reg_dma_mem;
dma_addr_t reg_paddr; dma_addr_t reg_paddr;
/* Whether we're on bcm2835's DSI0 or DSI1. */ const struct vc4_dsi_variant *variant;
int port;
/* DSI channel for the panel we're connected to. */ /* DSI channel for the panel we're connected to. */
u32 channel; u32 channel;
...@@ -586,10 +597,10 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val) ...@@ -586,10 +597,10 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
#define DSI_READ(offset) readl(dsi->regs + (offset)) #define DSI_READ(offset) readl(dsi->regs + (offset))
#define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val) #define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val)
#define DSI_PORT_READ(offset) \ #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) \ #define DSI_PORT_WRITE(offset, val) \
DSI_WRITE(dsi->port ? DSI1_##offset : DSI0_##offset, val) DSI_WRITE(dsi->variant->port ? DSI1_##offset : DSI0_##offset, val)
#define DSI_PORT_BIT(bit) (dsi->port ? DSI1_##bit : DSI0_##bit) #define DSI_PORT_BIT(bit) (dsi->variant->port ? DSI1_##bit : DSI0_##bit)
/* VC4 DSI encoder KMS struct */ /* VC4 DSI encoder KMS struct */
struct vc4_dsi_encoder { struct vc4_dsi_encoder {
...@@ -837,7 +848,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) ...@@ -837,7 +848,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
ret = pm_runtime_get_sync(dev); ret = pm_runtime_get_sync(dev);
if (ret) { 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; return;
} }
...@@ -871,7 +882,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) ...@@ -871,7 +882,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
DSI_PORT_WRITE(STAT, DSI_PORT_READ(STAT)); DSI_PORT_WRITE(STAT, DSI_PORT_READ(STAT));
/* Set AFE CTR00/CTR1 to release powerdown of analog. */ /* 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) | u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) |
VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ)); VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ));
...@@ -1017,7 +1028,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) ...@@ -1017,7 +1028,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
DSI_PORT_BIT(PHYC_CLANE_ENABLE) | DSI_PORT_BIT(PHYC_CLANE_ENABLE) |
((dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? ((dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ?
0 : DSI_PORT_BIT(PHYC_HS_CLK_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, DSI0_PHYC_ESC_CLK_LPDT) :
VC4_SET_FIELD(lpx - 1, DSI1_PHYC_ESC_CLK_LPDT))); VC4_SET_FIELD(lpx - 1, DSI1_PHYC_ESC_CLK_LPDT)));
...@@ -1043,13 +1054,13 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) ...@@ -1043,13 +1054,13 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
DSI_DISP1_ENABLE); DSI_DISP1_ENABLE);
/* Ungate the block. */ /* Ungate the block. */
if (dsi->port == 0) if (dsi->variant->port == 0)
DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI0_CTRL_CTRL0); DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI0_CTRL_CTRL0);
else else
DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI1_CTRL_EN); DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI1_CTRL_EN);
/* Bring AFE out of reset. */ /* Bring AFE out of reset. */
if (dsi->port == 0) { if (dsi->variant->port == 0) {
} else { } else {
DSI_PORT_WRITE(PHY_AFEC0, DSI_PORT_WRITE(PHY_AFEC0,
DSI_PORT_READ(PHY_AFEC0) & DSI_PORT_READ(PHY_AFEC0) &
...@@ -1313,8 +1324,16 @@ static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = { ...@@ -1313,8 +1324,16 @@ static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = {
.mode_fixup = vc4_dsi_encoder_mode_fixup, .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[] = { 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 },
{} {}
}; };
...@@ -1325,7 +1344,7 @@ static void dsi_handle_error(struct vc4_dsi *dsi, ...@@ -1325,7 +1344,7 @@ static void dsi_handle_error(struct vc4_dsi *dsi,
if (!(stat & bit)) if (!(stat & bit))
return; 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; *ret = IRQ_HANDLED;
} }
...@@ -1423,7 +1442,7 @@ vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi) ...@@ -1423,7 +1442,7 @@ vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi)
int ret; int ret;
snprintf(clk_name, sizeof(clk_name), 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 /* We just use core fixed factor clock ops for the PHY
* clocks. The clocks are actually gated by the * clocks. The clocks are actually gated by the
...@@ -1471,7 +1490,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) ...@@ -1471,7 +1490,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
if (!match) if (!match)
return -ENODEV; return -ENODEV;
dsi->port = (uintptr_t)match->data; dsi->variant = match->data;
vc4_dsi_encoder = devm_kzalloc(dev, sizeof(*vc4_dsi_encoder), vc4_dsi_encoder = devm_kzalloc(dev, sizeof(*vc4_dsi_encoder),
GFP_KERNEL); GFP_KERNEL);
...@@ -1488,13 +1507,8 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) ...@@ -1488,13 +1507,8 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
return PTR_ERR(dsi->regs); return PTR_ERR(dsi->regs);
dsi->regset.base = dsi->regs; dsi->regset.base = dsi->regs;
if (dsi->port == 0) { dsi->regset.regs = dsi->variant->regs;
dsi->regset.regs = dsi0_regs; dsi->regset.nregs = dsi->variant->nregs;
dsi->regset.nregs = ARRAY_SIZE(dsi0_regs);
} else {
dsi->regset.regs = dsi1_regs;
dsi->regset.nregs = ARRAY_SIZE(dsi1_regs);
}
if (DSI_PORT_READ(ID) != DSI_ID_VALUE) { if (DSI_PORT_READ(ID) != DSI_ID_VALUE) {
dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n", dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n",
...@@ -1506,7 +1520,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) ...@@ -1506,7 +1520,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
* from the ARM. It does handle writes from the DMA engine, * from the ARM. It does handle writes from the DMA engine,
* so set up a channel for talking to it. * 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_mem = dma_alloc_coherent(dev, 4,
&dsi->reg_dma_paddr, &dsi->reg_dma_paddr,
GFP_KERNEL); GFP_KERNEL);
...@@ -1627,10 +1641,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) ...@@ -1627,10 +1641,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
*/ */
list_splice_init(&dsi->encoder->bridge_chain, &dsi->bridge_chain); list_splice_init(&dsi->encoder->bridge_chain, &dsi->bridge_chain);
if (dsi->port == 0) vc4_debugfs_add_regset32(drm, dsi->variant->debugfs_name, &dsi->regset);
vc4_debugfs_add_regset32(drm, "dsi0_regs", &dsi->regset);
else
vc4_debugfs_add_regset32(drm, "dsi1_regs", &dsi->regset);
pm_runtime_enable(dev); pm_runtime_enable(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment