// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 Marek Vasut <marex@denx.de> * * This code is based on drivers/video/fbdev/mxsfb.c : * Copyright (C) 2010 Juergen Beisert, Pengutronix * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
*/
/* * Setup the MXSFB registers for decoding the pixels out of the framebuffer and * outputting them on the bus.
*/ staticvoid mxsfb_set_formats(struct mxsfb_drm_private *mxsfb, const u32 bus_format)
{ struct drm_device *drm = mxsfb->drm; const u32 format = mxsfb->crtc.primary->state->fb->format->format;
u32 ctrl, ctrl1;
switch (format) { case DRM_FORMAT_RGB565:
dev_dbg(drm->dev, "Setting up RGB565 mode\n");
ctrl |= CTRL_WORD_LENGTH_16;
ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf); break; case DRM_FORMAT_XRGB8888:
dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
ctrl |= CTRL_WORD_LENGTH_24; /* Do not use packed pixels = one pixel per word instead. */
ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7); break;
}
switch (bus_format) { case MEDIA_BUS_FMT_RGB565_1X16:
ctrl |= CTRL_BUS_WIDTH_16; break; case MEDIA_BUS_FMT_RGB666_1X18:
ctrl |= CTRL_BUS_WIDTH_18; break; case MEDIA_BUS_FMT_RGB888_1X24:
ctrl |= CTRL_BUS_WIDTH_24; break; default:
dev_err(drm->dev, "Unknown media bus format 0x%x\n", bus_format); break;
}
vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* Always in DOTCLOCK mode */
VDCTRL0_VSYNC_PERIOD_UNIT |
VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len); if (m->flags & DRM_MODE_FLAG_PHSYNC)
vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH; if (m->flags & DRM_MODE_FLAG_PVSYNC)
vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH; /* Make sure Data Enable is high active by default */ if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH; /* * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric, * controllers VDCTRL0_DOTCLK is display centric. * Drive on positive edge -> display samples on falling edge * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
*/ if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
/* Frame length in lines. */
writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
/* Line length in units of clocks or pixels. */
hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
mxsfb->base + LCDC_VDCTRL2);
if (mxsfb->clk_disp_axi)
clk_prepare_enable(mxsfb->clk_disp_axi);
clk_prepare_enable(mxsfb->clk);
/* Increase number of outstanding requests on all supported IPs */ if (mxsfb->devdata->has_ctrl2) {
reg = readl(mxsfb->base + LCDC_V4_CTRL2);
reg &= ~CTRL2_SET_OUTSTANDING_REQS_MASK;
reg |= CTRL2_SET_OUTSTANDING_REQS_16;
writel(reg, mxsfb->base + LCDC_V4_CTRL2);
}
/* If it was disabled, re-enable the mode again */
writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
/* Enable the SYNC signals first, then the DMA engine */
reg = readl(mxsfb->base + LCDC_VDCTRL4);
reg |= VDCTRL4_SYNC_SIGNALS_ON;
writel(reg, mxsfb->base + LCDC_VDCTRL4);
/* * Enable recovery on underflow. * * There is some sort of corner case behavior of the controller, * which could rarely be triggered at least on i.MX6SX connected * to 800x480 DPI panel and i.MX8MM connected to DPI->DSI->LVDS * bridged 1920x1080 panel (and likely on other setups too), where * the image on the panel shifts to the right and wraps around. * This happens either when the controller is enabled on boot or * even later during run time. The condition does not correct * itself automatically, i.e. the display image remains shifted. * * It seems this problem is known and is due to sporadic underflows * of the LCDIF FIFO. While the LCDIF IP does have underflow/overflow * IRQs, neither of the IRQs trigger and neither IRQ status bit is * asserted when this condition occurs. * * All known revisions of the LCDIF IP have CTRL1 RECOVER_ON_UNDERFLOW * bit, which is described in the reference manual since i.MX23 as * " * Set this bit to enable the LCDIF block to recover in the next * field/frame if there was an underflow in the current field/frame. * " * Enable this bit to mitigate the sporadic underflows.
*/
reg = readl(mxsfb->base + LCDC_CTRL1);
reg |= CTRL1_RECOVER_ON_UNDERFLOW;
writel(reg, mxsfb->base + LCDC_CTRL1);
/* * Even if we disable the controller here, it will still continue * until its FIFOs are running out of data
*/
writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
clk_disable_unprepare(mxsfb->clk); if (mxsfb->clk_disp_axi)
clk_disable_unprepare(mxsfb->clk_disp_axi);
}
/* * Clear the bit and poll it cleared. This is usually called with * a reset address and mask being either SFTRST(bit 31) or CLKGATE * (bit 30).
*/ staticint clear_poll_bit(void __iomem *addr, u32 mask)
{
u32 reg;
staticint mxsfb_reset_block(struct mxsfb_drm_private *mxsfb)
{ int ret;
/* * It seems, you can't re-program the controller if it is still * running. This may lead to shifted pictures (FIFO issue?), so * first stop the controller and drain its FIFOs.
*/
ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST); if (ret) return ret;
/* If there is a bridge attached to the LCDIF, use its bus format */ if (mxsfb->bridge) {
bridge_state =
drm_atomic_get_new_bridge_state(state,
mxsfb->bridge); if (!bridge_state)
bus_format = MEDIA_BUS_FMT_FIXED; else
bus_format = bridge_state->input_bus_cfg.format;
if (bus_format == MEDIA_BUS_FMT_FIXED) {
dev_warn_once(drm->dev, "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n" "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n");
bus_format = MEDIA_BUS_FMT_RGB888_1X24;
}
}
/* If there is no bridge, use bus format from connector */ if (!bus_format && mxsfb->connector->display_info.num_bus_formats)
bus_format = mxsfb->connector->display_info.bus_formats[0];
/* If all else fails, default to RGB888_1X24 */ if (!bus_format)
bus_format = MEDIA_BUS_FMT_RGB888_1X24;
/* * HACK: The hardware seems to output 64 bytes of data of unknown * origin, and then to proceed with the framebuffer. Until the reason * is understood, live with the 16 initial invalid pixels on the first * line and start 64 bytes within the framebuffer.
*/
dma_addr += 64;
writel(dma_addr, mxsfb->base + LCDC_AS_NEXT_BUF);
/* * If the plane was previously disabled, write LCDC_AS_BUF as well to * provide the first buffer.
*/ if (!old_pstate->fb)
writel(dma_addr, mxsfb->base + LCDC_AS_BUF);
ctrl = AS_CTRL_AS_ENABLE | AS_CTRL_ALPHA(255);
switch (new_pstate->fb->format->format) { case DRM_FORMAT_XRGB4444:
ctrl |= AS_CTRL_FORMAT_RGB444 | AS_CTRL_ALPHA_CTRL_OVERRIDE; break; case DRM_FORMAT_ARGB4444:
ctrl |= AS_CTRL_FORMAT_ARGB4444 | AS_CTRL_ALPHA_CTRL_EMBEDDED; break; case DRM_FORMAT_XRGB1555:
ctrl |= AS_CTRL_FORMAT_RGB555 | AS_CTRL_ALPHA_CTRL_OVERRIDE; break; case DRM_FORMAT_ARGB1555:
ctrl |= AS_CTRL_FORMAT_ARGB1555 | AS_CTRL_ALPHA_CTRL_EMBEDDED; break; case DRM_FORMAT_RGB565:
ctrl |= AS_CTRL_FORMAT_RGB565 | AS_CTRL_ALPHA_CTRL_OVERRIDE; break; case DRM_FORMAT_XRGB8888:
ctrl |= AS_CTRL_FORMAT_RGB888 | AS_CTRL_ALPHA_CTRL_OVERRIDE; break; case DRM_FORMAT_ARGB8888:
ctrl |= AS_CTRL_FORMAT_ARGB8888 | AS_CTRL_ALPHA_CTRL_EMBEDDED; break;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.