Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1640080 > unrolled thread
| Started by | Eric Anholt <eric@anholt.net> |
|---|---|
| First post | 2017-05-12 02:00 +0200 |
| Last post | 2017-05-12 13:10 +0200 |
| Articles | 3 — 3 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[PATCH 1/4] drm/vc4: Adjust modes in DSI to work around the integer PLL divider. Eric Anholt <eric@anholt.net> - 2017-05-12 02:00 +0200
Re: [PATCH 1/4] drm/vc4: Adjust modes in DSI to work around the integer PLL divider. Daniel Vetter <daniel@ffwll.ch> - 2017-05-12 10:00 +0200
Re: [PATCH 1/4] drm/vc4: Adjust modes in DSI to work around the integer PLL divider. Noralf Trønnes <noralf@tronnes.org> - 2017-05-12 13:10 +0200
| From | Eric Anholt <eric@anholt.net> |
|---|---|
| Date | 2017-05-12 02:00 +0200 |
| Subject | [PATCH 1/4] drm/vc4: Adjust modes in DSI to work around the integer PLL divider. |
| Message-ID | <tG69Y-4C8-11@gated-at.bofh.it> |
BCM2835's PLLD_DSI1 divider doesn't give us many choices for our pixel
clocks, so to support panels on the Raspberry Pi we need to set a
higher pixel clock rate than requested and adjust the mode we program
to extend out the HFP so that the refresh rate matches.
Signed-off-by: Eric Anholt <eric@anholt.net>
---
drivers/gpu/drm/vc4/vc4_dsi.c | 112 ++++++++++++++++++++++++++++++++----------
1 file changed, 86 insertions(+), 26 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index fb54a9d10360..62cb3b0d0345 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -519,7 +519,8 @@ struct vc4_dsi {
/* DSI channel for the panel we're connected to. */
u32 channel;
u32 lanes;
- enum mipi_dsi_pixel_format format;
+ u32 format;
+ u32 divider;
u32 mode_flags;
/* Input clock from CPRMAN to the digital PHY, for the DSI
@@ -817,13 +818,67 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder)
pm_runtime_put(dev);
}
+/* Extends the mode's blank intervals to handle BCM2835's integer-only
+ * DSI PLL divider.
+ *
+ * On 2835, PLLD is set to 2Ghz, and may not be changed by the display
+ * driver since most peripherals are hanging off of the PLLD_PER
+ * divider. PLLD_DSI1, which drives our DSI bit clock (and therefore
+ * the pixel clock), only has an integer divider off of DSI.
+ *
+ * To get our panel mode to refresh at the expected 60Hz, we need to
+ * extend the horizontal blank time. This means we drive a
+ * higher-than-expected clock rate to the panel, but that's what the
+ * firmware (which ) does too.
+ */
+static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
+ struct vc4_dsi *dsi = vc4_encoder->dsi;
+ struct clk *phy_parent = clk_get_parent(dsi->pll_phy_clock);
+ unsigned long parent_rate = clk_get_rate(phy_parent);
+ unsigned long pixel_clock_hz = mode->clock * 1000;
+ unsigned long pll_clock = pixel_clock_hz * dsi->divider;
+ int divider;
+
+ /* Find what divider gets us a faster clock than the requested
+ * pixel clock.
+ */
+ for (divider = 1; divider < 8; divider++) {
+ if (parent_rate / divider < pll_clock) {
+ divider--;
+ break;
+ }
+ }
+
+ /* Now that we've picked a PLL divider, calculate back to its
+ * pixel clock.
+ */
+ pll_clock = parent_rate / divider;
+ pixel_clock_hz = pll_clock / dsi->divider;
+
+ /* Round up the clk_set_rate() request slightly, since
+ * PLLD_DSI1 is an integer divider and its rate selection will
+ * never round up.
+ */
+ adjusted_mode->clock = pixel_clock_hz / 1000 + 1;
+
+ /* Given the new pixel clock, adjust HFP to keep vrefresh the same. */
+ adjusted_mode->htotal = pixel_clock_hz / (mode->vrefresh * mode->vtotal);
+ adjusted_mode->hsync_end += adjusted_mode->htotal - mode->htotal;
+ adjusted_mode->hsync_start += adjusted_mode->htotal - mode->htotal;
+
+ return true;
+}
+
static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
{
- struct drm_display_mode *mode = &encoder->crtc->mode;
+ struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
struct vc4_dsi *dsi = vc4_encoder->dsi;
struct device *dev = &dsi->pdev->dev;
- u32 format = 0, divider = 0;
bool debug_dump_regs = false;
unsigned long hs_clock;
u32 ui_ns;
@@ -845,26 +900,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
vc4_dsi_dump_regs(dsi);
}
- switch (dsi->format) {
- case MIPI_DSI_FMT_RGB888:
- format = DSI_PFORMAT_RGB888;
- divider = 24 / dsi->lanes;
- break;
- case MIPI_DSI_FMT_RGB666:
- format = DSI_PFORMAT_RGB666;
- divider = 24 / dsi->lanes;
- break;
- case MIPI_DSI_FMT_RGB666_PACKED:
- format = DSI_PFORMAT_RGB666_PACKED;
- divider = 18 / dsi->lanes;
- break;
- case MIPI_DSI_FMT_RGB565:
- format = DSI_PFORMAT_RGB565;
- divider = 16 / dsi->lanes;
- break;
- }
-
- phy_clock = pixel_clock_hz * divider;
+ phy_clock = pixel_clock_hz * dsi->divider;
ret = clk_set_rate(dsi->pll_phy_clock, phy_clock);
if (ret) {
dev_err(&dsi->pdev->dev,
@@ -1049,8 +1085,9 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
DSI_PORT_WRITE(DISP0_CTRL,
- VC4_SET_FIELD(divider, DSI_DISP0_PIX_CLK_DIV) |
- VC4_SET_FIELD(format, DSI_DISP0_PFORMAT) |
+ VC4_SET_FIELD(dsi->divider,
+ DSI_DISP0_PIX_CLK_DIV) |
+ VC4_SET_FIELD(dsi->format, DSI_DISP0_PFORMAT) |
VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME,
DSI_DISP0_LP_STOP_CTRL) |
DSI_DISP0_ST_END |
@@ -1255,9 +1292,31 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
dsi->lanes = device->lanes;
dsi->channel = device->channel;
- dsi->format = device->format;
dsi->mode_flags = device->mode_flags;
+ switch (device->format) {
+ case MIPI_DSI_FMT_RGB888:
+ dsi->format = DSI_PFORMAT_RGB888;
+ dsi->divider = 24 / dsi->lanes;
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ dsi->format = DSI_PFORMAT_RGB666;
+ dsi->divider = 24 / dsi->lanes;
+ break;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ dsi->format = DSI_PFORMAT_RGB666_PACKED;
+ dsi->divider = 18 / dsi->lanes;
+ break;
+ case MIPI_DSI_FMT_RGB565:
+ dsi->format = DSI_PFORMAT_RGB565;
+ dsi->divider = 16 / dsi->lanes;
+ break;
+ default:
+ dev_err(&dsi->pdev->dev, "Unknown DSI format: %d.\n",
+ dsi->format);
+ return 0;
+ }
+
if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) {
dev_err(&dsi->pdev->dev,
"Only VIDEO mode panels supported currently.\n");
@@ -1304,6 +1363,7 @@ static const struct mipi_dsi_host_ops vc4_dsi_host_ops = {
static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = {
.disable = vc4_dsi_encoder_disable,
.enable = vc4_dsi_encoder_enable,
+ .mode_fixup = vc4_dsi_encoder_mode_fixup,
};
static const struct of_device_id vc4_dsi_dt_match[] = {
--
2.11.0
[toc] | [next] | [standalone]
| From | Daniel Vetter <daniel@ffwll.ch> |
|---|---|
| Date | 2017-05-12 10:00 +0200 |
| Subject | Re: [PATCH 1/4] drm/vc4: Adjust modes in DSI to work around the integer PLL divider. |
| Message-ID | <tGdEu-1eG-13@gated-at.bofh.it> |
| In reply to | #1640080 |
On Thu, May 11, 2017 at 04:56:22PM -0700, Eric Anholt wrote:
> BCM2835's PLLD_DSI1 divider doesn't give us many choices for our pixel
> clocks, so to support panels on the Raspberry Pi we need to set a
> higher pixel clock rate than requested and adjust the mode we program
> to extend out the HFP so that the refresh rate matches.
>
> Signed-off-by: Eric Anholt <eric@anholt.net>
Yeah, this is what mode_fixup is for (or the fancier atomic_check, but no
benefit with using that one here).
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
> drivers/gpu/drm/vc4/vc4_dsi.c | 112 ++++++++++++++++++++++++++++++++----------
> 1 file changed, 86 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> index fb54a9d10360..62cb3b0d0345 100644
> --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> @@ -519,7 +519,8 @@ struct vc4_dsi {
> /* DSI channel for the panel we're connected to. */
> u32 channel;
> u32 lanes;
> - enum mipi_dsi_pixel_format format;
> + u32 format;
> + u32 divider;
> u32 mode_flags;
>
> /* Input clock from CPRMAN to the digital PHY, for the DSI
> @@ -817,13 +818,67 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder)
> pm_runtime_put(dev);
> }
>
> +/* Extends the mode's blank intervals to handle BCM2835's integer-only
> + * DSI PLL divider.
> + *
> + * On 2835, PLLD is set to 2Ghz, and may not be changed by the display
> + * driver since most peripherals are hanging off of the PLLD_PER
> + * divider. PLLD_DSI1, which drives our DSI bit clock (and therefore
> + * the pixel clock), only has an integer divider off of DSI.
> + *
> + * To get our panel mode to refresh at the expected 60Hz, we need to
> + * extend the horizontal blank time. This means we drive a
> + * higher-than-expected clock rate to the panel, but that's what the
> + * firmware (which ) does too.
> + */
> +static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
> + const struct drm_display_mode *mode,
> + struct drm_display_mode *adjusted_mode)
> +{
> + struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
> + struct vc4_dsi *dsi = vc4_encoder->dsi;
> + struct clk *phy_parent = clk_get_parent(dsi->pll_phy_clock);
> + unsigned long parent_rate = clk_get_rate(phy_parent);
> + unsigned long pixel_clock_hz = mode->clock * 1000;
> + unsigned long pll_clock = pixel_clock_hz * dsi->divider;
> + int divider;
> +
> + /* Find what divider gets us a faster clock than the requested
> + * pixel clock.
> + */
> + for (divider = 1; divider < 8; divider++) {
> + if (parent_rate / divider < pll_clock) {
> + divider--;
> + break;
> + }
> + }
> +
> + /* Now that we've picked a PLL divider, calculate back to its
> + * pixel clock.
> + */
> + pll_clock = parent_rate / divider;
> + pixel_clock_hz = pll_clock / dsi->divider;
> +
> + /* Round up the clk_set_rate() request slightly, since
> + * PLLD_DSI1 is an integer divider and its rate selection will
> + * never round up.
> + */
> + adjusted_mode->clock = pixel_clock_hz / 1000 + 1;
> +
> + /* Given the new pixel clock, adjust HFP to keep vrefresh the same. */
> + adjusted_mode->htotal = pixel_clock_hz / (mode->vrefresh * mode->vtotal);
> + adjusted_mode->hsync_end += adjusted_mode->htotal - mode->htotal;
> + adjusted_mode->hsync_start += adjusted_mode->htotal - mode->htotal;
> +
> + return true;
> +}
> +
> static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
> {
> - struct drm_display_mode *mode = &encoder->crtc->mode;
> + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
> struct vc4_dsi *dsi = vc4_encoder->dsi;
> struct device *dev = &dsi->pdev->dev;
> - u32 format = 0, divider = 0;
> bool debug_dump_regs = false;
> unsigned long hs_clock;
> u32 ui_ns;
> @@ -845,26 +900,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
> vc4_dsi_dump_regs(dsi);
> }
>
> - switch (dsi->format) {
> - case MIPI_DSI_FMT_RGB888:
> - format = DSI_PFORMAT_RGB888;
> - divider = 24 / dsi->lanes;
> - break;
> - case MIPI_DSI_FMT_RGB666:
> - format = DSI_PFORMAT_RGB666;
> - divider = 24 / dsi->lanes;
> - break;
> - case MIPI_DSI_FMT_RGB666_PACKED:
> - format = DSI_PFORMAT_RGB666_PACKED;
> - divider = 18 / dsi->lanes;
> - break;
> - case MIPI_DSI_FMT_RGB565:
> - format = DSI_PFORMAT_RGB565;
> - divider = 16 / dsi->lanes;
> - break;
> - }
> -
> - phy_clock = pixel_clock_hz * divider;
> + phy_clock = pixel_clock_hz * dsi->divider;
> ret = clk_set_rate(dsi->pll_phy_clock, phy_clock);
> if (ret) {
> dev_err(&dsi->pdev->dev,
> @@ -1049,8 +1085,9 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
>
> if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
> DSI_PORT_WRITE(DISP0_CTRL,
> - VC4_SET_FIELD(divider, DSI_DISP0_PIX_CLK_DIV) |
> - VC4_SET_FIELD(format, DSI_DISP0_PFORMAT) |
> + VC4_SET_FIELD(dsi->divider,
> + DSI_DISP0_PIX_CLK_DIV) |
> + VC4_SET_FIELD(dsi->format, DSI_DISP0_PFORMAT) |
> VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME,
> DSI_DISP0_LP_STOP_CTRL) |
> DSI_DISP0_ST_END |
> @@ -1255,9 +1292,31 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
>
> dsi->lanes = device->lanes;
> dsi->channel = device->channel;
> - dsi->format = device->format;
> dsi->mode_flags = device->mode_flags;
>
> + switch (device->format) {
> + case MIPI_DSI_FMT_RGB888:
> + dsi->format = DSI_PFORMAT_RGB888;
> + dsi->divider = 24 / dsi->lanes;
> + break;
> + case MIPI_DSI_FMT_RGB666:
> + dsi->format = DSI_PFORMAT_RGB666;
> + dsi->divider = 24 / dsi->lanes;
> + break;
> + case MIPI_DSI_FMT_RGB666_PACKED:
> + dsi->format = DSI_PFORMAT_RGB666_PACKED;
> + dsi->divider = 18 / dsi->lanes;
> + break;
> + case MIPI_DSI_FMT_RGB565:
> + dsi->format = DSI_PFORMAT_RGB565;
> + dsi->divider = 16 / dsi->lanes;
> + break;
> + default:
> + dev_err(&dsi->pdev->dev, "Unknown DSI format: %d.\n",
> + dsi->format);
> + return 0;
> + }
> +
> if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) {
> dev_err(&dsi->pdev->dev,
> "Only VIDEO mode panels supported currently.\n");
> @@ -1304,6 +1363,7 @@ static const struct mipi_dsi_host_ops vc4_dsi_host_ops = {
> static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = {
> .disable = vc4_dsi_encoder_disable,
> .enable = vc4_dsi_encoder_enable,
> + .mode_fixup = vc4_dsi_encoder_mode_fixup,
> };
>
> static const struct of_device_id vc4_dsi_dt_match[] = {
> --
> 2.11.0
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
[toc] | [prev] | [next] | [standalone]
| From | Noralf Trønnes <noralf@tronnes.org> |
|---|---|
| Date | 2017-05-12 13:10 +0200 |
| Subject | Re: [PATCH 1/4] drm/vc4: Adjust modes in DSI to work around the integer PLL divider. |
| Message-ID | <tGgCm-3yS-21@gated-at.bofh.it> |
| In reply to | #1640080 |
Den 12.05.2017 01.56, skrev Eric Anholt:
> BCM2835's PLLD_DSI1 divider doesn't give us many choices for our pixel
> clocks, so to support panels on the Raspberry Pi we need to set a
> higher pixel clock rate than requested and adjust the mode we program
> to extend out the HFP so that the refresh rate matches.
>
> Signed-off-by: Eric Anholt <eric@anholt.net>
> ---
> drivers/gpu/drm/vc4/vc4_dsi.c | 112 ++++++++++++++++++++++++++++++++----------
> 1 file changed, 86 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> index fb54a9d10360..62cb3b0d0345 100644
> --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> @@ -519,7 +519,8 @@ struct vc4_dsi {
> /* DSI channel for the panel we're connected to. */
> u32 channel;
> u32 lanes;
> - enum mipi_dsi_pixel_format format;
> + u32 format;
> + u32 divider;
> u32 mode_flags;
>
> /* Input clock from CPRMAN to the digital PHY, for the DSI
> @@ -817,13 +818,67 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder)
> pm_runtime_put(dev);
> }
>
> +/* Extends the mode's blank intervals to handle BCM2835's integer-only
> + * DSI PLL divider.
> + *
> + * On 2835, PLLD is set to 2Ghz, and may not be changed by the display
> + * driver since most peripherals are hanging off of the PLLD_PER
> + * divider. PLLD_DSI1, which drives our DSI bit clock (and therefore
> + * the pixel clock), only has an integer divider off of DSI.
> + *
> + * To get our panel mode to refresh at the expected 60Hz, we need to
> + * extend the horizontal blank time. This means we drive a
> + * higher-than-expected clock rate to the panel, but that's what the
> + * firmware (which ) does too.
Something missing in the comment here.
Noralf.
> + */
> +static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
> + const struct drm_display_mode *mode,
> + struct drm_display_mode *adjusted_mode)
> +{
> + struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
> + struct vc4_dsi *dsi = vc4_encoder->dsi;
> + struct clk *phy_parent = clk_get_parent(dsi->pll_phy_clock);
> + unsigned long parent_rate = clk_get_rate(phy_parent);
> + unsigned long pixel_clock_hz = mode->clock * 1000;
> + unsigned long pll_clock = pixel_clock_hz * dsi->divider;
> + int divider;
> +
> + /* Find what divider gets us a faster clock than the requested
> + * pixel clock.
> + */
> + for (divider = 1; divider < 8; divider++) {
> + if (parent_rate / divider < pll_clock) {
> + divider--;
> + break;
> + }
> + }
> +
> + /* Now that we've picked a PLL divider, calculate back to its
> + * pixel clock.
> + */
> + pll_clock = parent_rate / divider;
> + pixel_clock_hz = pll_clock / dsi->divider;
> +
> + /* Round up the clk_set_rate() request slightly, since
> + * PLLD_DSI1 is an integer divider and its rate selection will
> + * never round up.
> + */
> + adjusted_mode->clock = pixel_clock_hz / 1000 + 1;
> +
> + /* Given the new pixel clock, adjust HFP to keep vrefresh the same. */
> + adjusted_mode->htotal = pixel_clock_hz / (mode->vrefresh * mode->vtotal);
> + adjusted_mode->hsync_end += adjusted_mode->htotal - mode->htotal;
> + adjusted_mode->hsync_start += adjusted_mode->htotal - mode->htotal;
> +
> + return true;
> +}
> +
> static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
> {
> - struct drm_display_mode *mode = &encoder->crtc->mode;
> + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
> struct vc4_dsi *dsi = vc4_encoder->dsi;
> struct device *dev = &dsi->pdev->dev;
> - u32 format = 0, divider = 0;
> bool debug_dump_regs = false;
> unsigned long hs_clock;
> u32 ui_ns;
> @@ -845,26 +900,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
> vc4_dsi_dump_regs(dsi);
> }
>
> - switch (dsi->format) {
> - case MIPI_DSI_FMT_RGB888:
> - format = DSI_PFORMAT_RGB888;
> - divider = 24 / dsi->lanes;
> - break;
> - case MIPI_DSI_FMT_RGB666:
> - format = DSI_PFORMAT_RGB666;
> - divider = 24 / dsi->lanes;
> - break;
> - case MIPI_DSI_FMT_RGB666_PACKED:
> - format = DSI_PFORMAT_RGB666_PACKED;
> - divider = 18 / dsi->lanes;
> - break;
> - case MIPI_DSI_FMT_RGB565:
> - format = DSI_PFORMAT_RGB565;
> - divider = 16 / dsi->lanes;
> - break;
> - }
> -
> - phy_clock = pixel_clock_hz * divider;
> + phy_clock = pixel_clock_hz * dsi->divider;
> ret = clk_set_rate(dsi->pll_phy_clock, phy_clock);
> if (ret) {
> dev_err(&dsi->pdev->dev,
> @@ -1049,8 +1085,9 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
>
> if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
> DSI_PORT_WRITE(DISP0_CTRL,
> - VC4_SET_FIELD(divider, DSI_DISP0_PIX_CLK_DIV) |
> - VC4_SET_FIELD(format, DSI_DISP0_PFORMAT) |
> + VC4_SET_FIELD(dsi->divider,
> + DSI_DISP0_PIX_CLK_DIV) |
> + VC4_SET_FIELD(dsi->format, DSI_DISP0_PFORMAT) |
> VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME,
> DSI_DISP0_LP_STOP_CTRL) |
> DSI_DISP0_ST_END |
> @@ -1255,9 +1292,31 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
>
> dsi->lanes = device->lanes;
> dsi->channel = device->channel;
> - dsi->format = device->format;
> dsi->mode_flags = device->mode_flags;
>
> + switch (device->format) {
> + case MIPI_DSI_FMT_RGB888:
> + dsi->format = DSI_PFORMAT_RGB888;
> + dsi->divider = 24 / dsi->lanes;
> + break;
> + case MIPI_DSI_FMT_RGB666:
> + dsi->format = DSI_PFORMAT_RGB666;
> + dsi->divider = 24 / dsi->lanes;
> + break;
> + case MIPI_DSI_FMT_RGB666_PACKED:
> + dsi->format = DSI_PFORMAT_RGB666_PACKED;
> + dsi->divider = 18 / dsi->lanes;
> + break;
> + case MIPI_DSI_FMT_RGB565:
> + dsi->format = DSI_PFORMAT_RGB565;
> + dsi->divider = 16 / dsi->lanes;
> + break;
> + default:
> + dev_err(&dsi->pdev->dev, "Unknown DSI format: %d.\n",
> + dsi->format);
> + return 0;
> + }
> +
> if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) {
> dev_err(&dsi->pdev->dev,
> "Only VIDEO mode panels supported currently.\n");
> @@ -1304,6 +1363,7 @@ static const struct mipi_dsi_host_ops vc4_dsi_host_ops = {
> static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = {
> .disable = vc4_dsi_encoder_disable,
> .enable = vc4_dsi_encoder_enable,
> + .mode_fixup = vc4_dsi_encoder_mode_fixup,
> };
>
> static const struct of_device_id vc4_dsi_dt_match[] = {
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web