drivers/gpu/drm/imx/lcdc/imx-lcdc.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/imx/lcdc/imx-lcdc.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/imx/lcdc/imx-lcdc.c
Extension
.c
Size
17931 bytes
Lines
536
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct imx_lcdc {
	struct drm_device drm;
	struct drm_simple_display_pipe pipe;
	struct drm_connector *connector;
	void __iomem *base;

	struct clk *clk_ipg;
	struct clk *clk_ahb;
	struct clk *clk_per;
};

static const u32 imx_lcdc_formats[] = {
	DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
};

static inline struct imx_lcdc *imx_lcdc_from_drmdev(struct drm_device *drm)
{
	return container_of(drm, struct imx_lcdc, drm);
}

static unsigned int imx_lcdc_get_format(unsigned int drm_format)
{
	switch (drm_format) {
	default:
		DRM_WARN("Format not supported - fallback to XRGB8888\n");
		fallthrough;

	case DRM_FORMAT_XRGB8888:
		return BPP_XRGB8888;

	case DRM_FORMAT_RGB565:
		return BPP_RGB565;
	}
}

static void imx_lcdc_update_hw_registers(struct drm_simple_display_pipe *pipe,
					 struct drm_plane_state *old_state,
					 bool mode_set)
{
	struct drm_crtc *crtc = &pipe->crtc;
	struct drm_plane_state *new_state = pipe->plane.state;
	struct drm_framebuffer *fb = new_state->fb;
	struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev);
	u32 lpcr, lvcr, lhcr;
	u32 framesize;
	dma_addr_t addr;

	addr = drm_fb_dma_get_gem_addr(fb, new_state, 0);
	/* The LSSAR register specifies the LCD screen start address (SSA). */
	writel(addr, lcdc->base + IMX21LCDC_LSSAR);

	if (!mode_set)
		return;

	/* Disable PER clock to make register write possible */
	if (old_state && old_state->crtc && old_state->crtc->enabled)
		clk_disable_unprepare(lcdc->clk_per);

	/* Framesize */
	framesize = FIELD_PREP(IMX21LCDC_LSR_XMAX, crtc->mode.hdisplay >> 4) |
		FIELD_PREP(IMX21LCDC_LSR_YMAX, crtc->mode.vdisplay);
	writel(framesize, lcdc->base + IMX21LCDC_LSR);

	/* HSYNC */
	lhcr = FIELD_PREP(IMX21LCDC_LHCR_HFPORCH, crtc->mode.hsync_start - crtc->mode.hdisplay - 1) |
		FIELD_PREP(IMX21LCDC_LHCR_HWIDTH, crtc->mode.hsync_end - crtc->mode.hsync_start - 1) |
		FIELD_PREP(IMX21LCDC_LHCR_HBPORCH, crtc->mode.htotal - crtc->mode.hsync_end - 3);
	writel(lhcr, lcdc->base + IMX21LCDC_LHCR);

	/* VSYNC */
	lvcr = FIELD_PREP(IMX21LCDC_LVCR_VFPORCH, crtc->mode.vsync_start - crtc->mode.vdisplay) |
		FIELD_PREP(IMX21LCDC_LVCR_VWIDTH, crtc->mode.vsync_end - crtc->mode.vsync_start) |
		FIELD_PREP(IMX21LCDC_LVCR_VBPORCH, crtc->mode.vtotal - crtc->mode.vsync_end);
	writel(lvcr, lcdc->base + IMX21LCDC_LVCR);

	lpcr = readl(lcdc->base + IMX21LCDC_LPCR);
	lpcr &= ~IMX21LCDC_LPCR_BPIX;
	lpcr |= FIELD_PREP(IMX21LCDC_LPCR_BPIX, imx_lcdc_get_format(fb->format->format));
	writel(lpcr, lcdc->base + IMX21LCDC_LPCR);

	/* Virtual Page Width */
	writel(new_state->fb->pitches[0] / 4, lcdc->base + IMX21LCDC_LVPWR);

	/* Enable PER clock */
	if (new_state->crtc->enabled)
		clk_prepare_enable(lcdc->clk_per);
}

static void imx_lcdc_pipe_enable(struct drm_simple_display_pipe *pipe,
				 struct drm_crtc_state *crtc_state,

Annotation

Implementation Notes