Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DSI0 colour swap fixes #6094

Merged
merged 13 commits into from
Apr 30, 2024
Merged
2 changes: 1 addition & 1 deletion arch/arm/boot/dts/broadcom/bcm283x.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@
#size-cells = <0>;
#clock-cells = <1>;

clocks = <&clocks BCM2835_PLLA_DSI0>,
clocks = <&clocks BCM2835_PLLD_DSI0>,
<&clocks BCM2835_CLOCK_DSI0E>,
<&clocks BCM2835_CLOCK_DSI0P>;
clock-names = "phy", "escape", "pixel";
Expand Down
4 changes: 4 additions & 0 deletions drivers/clk/bcm/clk-bcm2835.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
#define CM_UARTDIV 0x0f4
#define CM_VECCTL 0x0f8
#define CM_VECDIV 0x0fc
#define CM_DSI0HSCK 0x120
#define CM_PULSECTL 0x190
#define CM_PULSEDIV 0x194
#define CM_SDCCTL 0x1a8
Expand Down Expand Up @@ -2352,6 +2353,9 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
if (IS_ERR(cprman->regs))
return PTR_ERR(cprman->regs);

/* Mux DSI0 clock to PLLD */
cprman_write(cprman, CM_DSI0HSCK, 1);

fw_node = of_parse_phandle(dev->of_node, "firmware", 0);
if (fw_node) {
struct rpi_firmware *fw = rpi_firmware_get(fw_node);
Expand Down
24 changes: 15 additions & 9 deletions drivers/gpu/drm/bridge/tc358762.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
#define LCDCTRL_VSPOL BIT(19) /* Polarity of VSYNC signal */
#define LCDCTRL_VSDELAY(v) (((v) & 0xfff) << 20) /* VSYNC delay */

/* First parameter is in the 16bits, second is in the top 16bits */
#define LCD_HS_HBP 0x0424
#define LCD_HDISP_HFP 0x0428
#define LCD_VS_VBP 0x042c
#define LCD_VDISP_VFP 0x0430

/* SPI Master Registers */
#define SPICMR 0x0450
#define SPITCR 0x0454
Expand Down Expand Up @@ -139,6 +145,15 @@ static int tc358762_init(struct tc358762 *ctx)
tc358762_write(ctx, LCDCTRL, lcdctrl);

tc358762_write(ctx, SYSCTRL, 0x040f);

tc358762_write(ctx, LCD_HS_HBP, (ctx->mode.hsync_end - ctx->mode.hsync_start) |
((ctx->mode.htotal - ctx->mode.hsync_end) << 16));
tc358762_write(ctx, LCD_HDISP_HFP, ctx->mode.hdisplay |
((ctx->mode.hsync_start - ctx->mode.hdisplay) << 16));
tc358762_write(ctx, LCD_VS_VBP, (ctx->mode.vsync_end - ctx->mode.vsync_start) |
((ctx->mode.vtotal - ctx->mode.vsync_end) << 16));
tc358762_write(ctx, LCD_VDISP_VFP, ctx->mode.vdisplay |
((ctx->mode.vsync_start - ctx->mode.vdisplay) << 16));
msleep(100);

tc358762_write(ctx, PPI_STARTPPI, PPI_START_FUNCTION);
Expand Down Expand Up @@ -185,14 +200,6 @@ static void tc358762_pre_enable(struct drm_bridge *bridge, struct drm_bridge_sta
usleep_range(5000, 10000);
}

ctx->pre_enabled = true;
}

static void tc358762_enable(struct drm_bridge *bridge, struct drm_bridge_state *state)
{
struct tc358762 *ctx = bridge_to_tc358762(bridge);
int ret;

ret = tc358762_init(ctx);
if (ret < 0)
dev_err(ctx->dev, "error initializing bridge (%d)\n", ret);
Expand All @@ -219,7 +226,6 @@ static void tc358762_bridge_mode_set(struct drm_bridge *bridge,
static const struct drm_bridge_funcs tc358762_bridge_funcs = {
.atomic_post_disable = tc358762_post_disable,
.atomic_pre_enable = tc358762_pre_enable,
.atomic_enable = tc358762_enable,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
Expand Down
10 changes: 5 additions & 5 deletions drivers/gpu/drm/panel/panel-simple.c
Original file line number Diff line number Diff line change
Expand Up @@ -3413,15 +3413,15 @@ static const struct panel_desc rocktech_rk043fn48h = {
};

static const struct drm_display_mode raspberrypi_7inch_mode = {
.clock = 27777,
.clock = 30000,
.hdisplay = 800,
.hsync_start = 800 + 59,
.hsync_end = 800 + 59 + 2,
.htotal = 800 + 59 + 2 + 46,
.hsync_start = 800 + 131,
.hsync_end = 800 + 131 + 2,
.htotal = 800 + 131 + 2 + 45,
.vdisplay = 480,
.vsync_start = 480 + 7,
.vsync_end = 480 + 7 + 2,
.vtotal = 480 + 7 + 2 + 21,
.vtotal = 480 + 7 + 2 + 22,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};

Expand Down
12 changes: 11 additions & 1 deletion drivers/gpu/drm/vc4/vc4_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -827,12 +827,15 @@ static void vc4_disable_vblank(struct drm_crtc *crtc)
{
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, crtc->state);
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
int idx;

if (!drm_dev_enter(dev, &idx))
return;

CRTC_WRITE(PV_INTEN, 0);
if (vc4_encoder->type != VC4_ENCODER_TYPE_DSI0)
CRTC_WRITE(PV_INTEN, 0);

drm_dev_exit(idx);
}
Expand Down Expand Up @@ -877,7 +880,14 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)

void vc4_crtc_handle_vblank(struct vc4_crtc *crtc)
{
struct drm_encoder *encoder = vc4_get_crtc_encoder(&crtc->base, crtc->base.state);
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);

crtc->t_vblank = ktime_get();

if (vc4_encoder && vc4_encoder->vblank)
vc4_encoder->vblank(encoder);

drm_crtc_handle_vblank(&crtc->base);
vc4_crtc_handle_page_flip(crtc);
}
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/vc4/vc4_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ struct vc4_encoder {

void (*post_crtc_disable)(struct drm_encoder *encoder, struct drm_atomic_state *state);
void (*post_crtc_powerdown)(struct drm_encoder *encoder, struct drm_atomic_state *state);
void (*vblank)(struct drm_encoder *encoder);
};

#define to_vc4_encoder(_encoder) \
Expand Down
98 changes: 73 additions & 25 deletions drivers/gpu/drm/vc4/vc4_dsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,16 @@
# define DSI_PHY_AFEC0_CTATADJ_MASK VC4_MASK(3, 0)
# define DSI_PHY_AFEC0_CTATADJ_SHIFT 0

# define DSI0_AFEC0_PD_ALL_LANES (DSI0_PHY_AFEC0_PD | \
DSI0_PHY_AFEC0_PD_BG | \
DSI0_PHY_AFEC0_PD_DLANE1)

# define DSI1_AFEC0_PD_ALL_LANES (DSI1_PHY_AFEC0_PD | \
DSI1_PHY_AFEC0_PD_BG | \
DSI1_PHY_AFEC0_PD_DLANE3 | \
DSI1_PHY_AFEC0_PD_DLANE2 | \
DSI1_PHY_AFEC0_PD_DLANE1)

#define DSI0_PHY_AFEC1 0x68
# define DSI0_PHY_AFEC1_IDR_DLANE1_MASK VC4_MASK(10, 8)
# define DSI0_PHY_AFEC1_IDR_DLANE1_SHIFT 8
Expand Down Expand Up @@ -398,7 +408,8 @@
# define DSI1_CTRL_DISABLE_DISP_ECCC BIT(1)
# define DSI0_CTRL_CTRL0 BIT(0)
# define DSI1_CTRL_EN BIT(0)
# define DSI0_CTRL_RESET_FIFOS (DSI_CTRL_CLR_LDF | \
# define DSI0_CTRL_RESET_FIFOS (DSI0_CTRL_CTRL0 | \
DSI_CTRL_CLR_LDF | \
DSI0_CTRL_CLR_PBCF | \
DSI0_CTRL_CLR_CPBCF | \
DSI0_CTRL_CLR_PDF | \
Expand Down Expand Up @@ -807,6 +818,16 @@ static void vc4_dsi_bridge_disable(struct drm_bridge *bridge,
disp0_ctrl = DSI_PORT_READ(DISP0_CTRL);
disp0_ctrl &= ~DSI_DISP0_ENABLE;
DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl);

/* Reset the DSI and all its fifos. */
DSI_PORT_WRITE(CTRL, DSI_CTRL_SOFT_RESET_CFG |
DSI_PORT_BIT(CTRL_RESET_FIFOS));

/* Power down the analogue front end. */
DSI_PORT_WRITE(PHY_AFEC0, DSI_PORT_BIT(PHY_AFEC0_RESET) |
DSI_PORT_BIT(PHY_AFEC0_PD) |
DSI_PORT_BIT(AFEC0_PD_ALL_LANES));

}

static void vc4_dsi_bridge_post_disable(struct drm_bridge *bridge,
Expand Down Expand Up @@ -845,6 +866,7 @@ static bool vc4_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
unsigned long pixel_clock_hz = mode->clock * 1000;
unsigned long pll_clock = pixel_clock_hz * dsi->divider;
int divider;
u16 htotal;

/* Find what divider gets us a faster clock than the requested
* pixel clock.
Expand All @@ -861,12 +883,27 @@ static bool vc4_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
pixel_clock_hz = pll_clock / dsi->divider;

adjusted_mode->clock = pixel_clock_hz / 1000;
htotal = mode->htotal;

if (dsi->variant->port == 0 && mode->clock == 30000 &&
mode->hdisplay == 800 && mode->htotal == (800 + 59 + 2 + 45) &&
mode->vdisplay == 480 && mode->vtotal == (480 + 7 + 2 + 22)) {
/*
* Raspberry Pi 7" panel via TC358762 seems to have an issue on
* DSI0 that it doesn't actually follow the vertical timing that
* is otherwise identical to that produced on DSI1.
* Fixup the mode.
*/
htotal = 800 + 59 + 2 + 47;
adjusted_mode->vtotal = 480 + 7 + 2 + 45;
adjusted_mode->crtc_vtotal = 480 + 7 + 2 + 45;
}

/* Given the new pixel clock, adjust HFP to keep vrefresh the same. */
adjusted_mode->htotal = adjusted_mode->clock * mode->htotal /
adjusted_mode->htotal = adjusted_mode->clock * htotal /
mode->clock;
adjusted_mode->hsync_end += adjusted_mode->htotal - mode->htotal;
adjusted_mode->hsync_start += adjusted_mode->htotal - mode->htotal;
adjusted_mode->hsync_end += adjusted_mode->htotal - htotal;
adjusted_mode->hsync_start += adjusted_mode->htotal - htotal;

return true;
}
Expand Down Expand Up @@ -926,12 +963,31 @@ static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge,
"Failed to set phy clock to %ld: %d\n", phy_clock, ret);
}

/* Reset the DSI and all its fifos. */
ret = clk_prepare_enable(dsi->escape_clock);
if (ret) {
DRM_ERROR("Failed to turn on DSI escape clock: %d\n", ret);
return;
}

ret = clk_prepare_enable(dsi->pll_phy_clock);
if (ret) {
DRM_ERROR("Failed to turn on DSI PLL: %d\n", ret);
return;
}

hs_clock = clk_get_rate(dsi->pll_phy_clock);

/*
* Reset the DSI and all its fifos. The block must be enabled for the
* FIFO resets to trigger.
*/
DSI_PORT_WRITE(CTRL,
DSI_CTRL_SOFT_RESET_CFG |
DSI_PORT_BIT(CTRL_RESET_FIFOS));

DSI_PORT_WRITE(CTRL,
((dsi->variant->port == 0) ?
DSI0_CTRL_CTRL0 : DSI1_CTRL_EN) |
DSI_CTRL_HSDT_EOT_DISABLE |
DSI_CTRL_RX_LPDT_EOT_DISABLE);

Expand Down Expand Up @@ -984,20 +1040,6 @@ static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge,
mdelay(1);
}

ret = clk_prepare_enable(dsi->escape_clock);
if (ret) {
DRM_ERROR("Failed to turn on DSI escape clock: %d\n", ret);
return;
}

ret = clk_prepare_enable(dsi->pll_phy_clock);
if (ret) {
DRM_ERROR("Failed to turn on DSI PLL: %d\n", ret);
return;
}

hs_clock = clk_get_rate(dsi->pll_phy_clock);

/* Yes, we set the DSI0P/DSI1P pixel clock to the byte rate,
* not the pixel clock rate. DSIxP take from the APHY's byte,
* DDR2, or DDR4 clock (we use byte) and feed into the PV at
Expand Down Expand Up @@ -1113,12 +1155,6 @@ static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge,
DSI_DISP1_PFORMAT) |
DSI_DISP1_ENABLE);

/* Ungate the block. */
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. */
DSI_PORT_WRITE(PHY_AFEC0,
DSI_PORT_READ(PHY_AFEC0) &
Expand Down Expand Up @@ -1418,6 +1454,15 @@ static const struct drm_bridge_funcs vc4_dsi_bridge_funcs = {
.mode_fixup = vc4_dsi_bridge_mode_fixup,
};

static void vc4_dsi_reset_fifo(struct drm_encoder *encoder)
{
struct vc4_dsi *dsi = to_vc4_dsi(encoder);
u32 val;

val = DSI_PORT_READ(CTRL);
DSI_PORT_WRITE(CTRL, val | DSI0_CTRL_CLR_PBCF);
}

static int vc4_dsi_late_register(struct drm_encoder *encoder)
{
struct drm_device *drm = encoder->dev;
Expand Down Expand Up @@ -1662,6 +1707,9 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
dsi->encoder.type = dsi->variant->port ?
VC4_ENCODER_TYPE_DSI1 : VC4_ENCODER_TYPE_DSI0;

if (dsi->encoder.type == VC4_ENCODER_TYPE_DSI0)
dsi->encoder.vblank = vc4_dsi_reset_fifo;

dsi->regs = vc4_ioremap_regs(pdev, 0);
if (IS_ERR(dsi->regs))
return PTR_ERR(dsi->regs);
Expand Down
9 changes: 9 additions & 0 deletions drivers/regulator/rpi-panel-attiny-regulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,14 @@ static void attiny_i2c_remove(struct i2c_client *client)
mutex_destroy(&state->lock);
}

static void attiny_i2c_shutdown(struct i2c_client *client)
{
struct attiny_lcd *state = i2c_get_clientdata(client);

regmap_write(state->regmap, REG_PWM, 0);
regmap_write(state->regmap, REG_POWERON, 0);
}

static const struct of_device_id attiny_dt_ids[] = {
{ .compatible = "raspberrypi,7inch-touchscreen-panel-regulator" },
{},
Expand All @@ -384,6 +392,7 @@ static struct i2c_driver attiny_regulator_driver = {
},
.probe = attiny_i2c_probe,
.remove = attiny_i2c_remove,
.shutdown = attiny_i2c_shutdown,
};

module_i2c_driver(attiny_regulator_driver);
Expand Down