Lines Matching +full:imx25 +full:- +full:lcdc

1 // SPDX-License-Identifier: GPL-2.0-only
2 // SPDX-FileCopyrightText: 2020 Marian Cichy <M.Cichy@pengutronix.de>
21 #include <linux/dma-mapping.h>
26 #define IMX21LCDC_LSSAR 0x0000 /* LCDC Screen Start Address Register */
27 #define IMX21LCDC_LSR 0x0004 /* LCDC Size Register */
28 #define IMX21LCDC_LVPWR 0x0008 /* LCDC Virtual Page Width Register */
29 #define IMX21LCDC_LCPR 0x000C /* LCDC Cursor Position Register */
30 #define IMX21LCDC_LCWHB 0x0010 /* LCDC Cursor Width Height and Blink Register*/
31 #define IMX21LCDC_LCCMR 0x0014 /* LCDC Color Cursor Mapping Register */
32 #define IMX21LCDC_LPCR 0x0018 /* LCDC Panel Configuration Register */
33 #define IMX21LCDC_LHCR 0x001C /* LCDC Horizontal Configuration Register */
34 #define IMX21LCDC_LVCR 0x0020 /* LCDC Vertical Configuration Register */
35 #define IMX21LCDC_LPOR 0x0024 /* LCDC Panning Offset Register */
36 #define IMX21LCDC_LSCR 0x0028 /* LCDC Sharp Configuration Register */
37 #define IMX21LCDC_LPCCR 0x002C /* LCDC PWM Contrast Control Register */
38 #define IMX21LCDC_LDCR 0x0030 /* LCDC DMA Control Register */
39 #define IMX21LCDC_LRMCR 0x0034 /* LCDC Refresh Mode Control Register */
40 #define IMX21LCDC_LICR 0x0038 /* LCDC Interrupt Configuration Register */
41 #define IMX21LCDC_LIER 0x003C /* LCDC Interrupt Enable Register */
42 #define IMX21LCDC_LISR 0x0040 /* LCDC Interrupt Status Register */
43 #define IMX21LCDC_LGWSAR 0x0050 /* LCDC Graphic Window Start Address Register */
44 #define IMX21LCDC_LGWSR 0x0054 /* LCDC Graph Window Size Register */
45 #define IMX21LCDC_LGWVPWR 0x0058 /* LCDC Graphic Window Virtual Page Width Register */
46 #define IMX21LCDC_LGWPOR 0x005C /* LCDC Graphic Window Panning Offset Register */
47 #define IMX21LCDC_LGWPR 0x0060 /* LCDC Graphic Window Position Register */
48 #define IMX21LCDC_LGWCR 0x0064 /* LCDC Graphic Window Control Register */
49 #define IMX21LCDC_LGWDCR 0x0068 /* LCDC Graphic Window DMA Control Register */
50 #define IMX21LCDC_LAUSCR 0x0080 /* LCDC AUS Mode Control Register */
51 #define IMX21LCDC_LAUSCCR 0x0084 /* LCDC AUS Mode Cursor Control Register */
125 DRM_WARN("Format not supported - fallback to XRGB8888\n"); in imx_lcdc_get_format()
140 struct drm_crtc *crtc = &pipe->crtc; in imx_lcdc_update_hw_registers()
141 struct drm_plane_state *new_state = pipe->plane.state; in imx_lcdc_update_hw_registers()
142 struct drm_framebuffer *fb = new_state->fb; in imx_lcdc_update_hw_registers()
143 struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev); in imx_lcdc_update_hw_registers() local
150 writel(addr, lcdc->base + IMX21LCDC_LSSAR); in imx_lcdc_update_hw_registers()
156 if (old_state && old_state->crtc && old_state->crtc->enabled) in imx_lcdc_update_hw_registers()
157 clk_disable_unprepare(lcdc->clk_per); in imx_lcdc_update_hw_registers()
160 framesize = FIELD_PREP(IMX21LCDC_LSR_XMAX, crtc->mode.hdisplay >> 4) | in imx_lcdc_update_hw_registers()
161 FIELD_PREP(IMX21LCDC_LSR_YMAX, crtc->mode.vdisplay); in imx_lcdc_update_hw_registers()
162 writel(framesize, lcdc->base + IMX21LCDC_LSR); in imx_lcdc_update_hw_registers()
165 lhcr = FIELD_PREP(IMX21LCDC_LHCR_HFPORCH, crtc->mode.hsync_start - crtc->mode.hdisplay - 1) | in imx_lcdc_update_hw_registers()
166 FIELD_PREP(IMX21LCDC_LHCR_HWIDTH, crtc->mode.hsync_end - crtc->mode.hsync_start - 1) | in imx_lcdc_update_hw_registers()
167 FIELD_PREP(IMX21LCDC_LHCR_HBPORCH, crtc->mode.htotal - crtc->mode.hsync_end - 3); in imx_lcdc_update_hw_registers()
168 writel(lhcr, lcdc->base + IMX21LCDC_LHCR); in imx_lcdc_update_hw_registers()
171 lvcr = FIELD_PREP(IMX21LCDC_LVCR_VFPORCH, crtc->mode.vsync_start - crtc->mode.vdisplay) | in imx_lcdc_update_hw_registers()
172 FIELD_PREP(IMX21LCDC_LVCR_VWIDTH, crtc->mode.vsync_end - crtc->mode.vsync_start) | in imx_lcdc_update_hw_registers()
173 FIELD_PREP(IMX21LCDC_LVCR_VBPORCH, crtc->mode.vtotal - crtc->mode.vsync_end); in imx_lcdc_update_hw_registers()
174 writel(lvcr, lcdc->base + IMX21LCDC_LVCR); in imx_lcdc_update_hw_registers()
176 lpcr = readl(lcdc->base + IMX21LCDC_LPCR); in imx_lcdc_update_hw_registers()
178 lpcr |= FIELD_PREP(IMX21LCDC_LPCR_BPIX, imx_lcdc_get_format(fb->format->format)); in imx_lcdc_update_hw_registers()
179 writel(lpcr, lcdc->base + IMX21LCDC_LPCR); in imx_lcdc_update_hw_registers()
182 writel(new_state->fb->pitches[0] / 4, lcdc->base + IMX21LCDC_LVPWR); in imx_lcdc_update_hw_registers()
185 if (new_state->crtc->enabled) in imx_lcdc_update_hw_registers()
186 clk_prepare_enable(lcdc->clk_per); in imx_lcdc_update_hw_registers()
196 struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev); in imx_lcdc_pipe_enable() local
197 struct drm_display_mode *mode = &pipe->crtc.mode; in imx_lcdc_pipe_enable()
198 struct drm_display_info *disp_info = &lcdc->connector->display_info; in imx_lcdc_pipe_enable()
199 const int hsync_pol = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : 1; in imx_lcdc_pipe_enable()
200 const int vsync_pol = (mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : 1; in imx_lcdc_pipe_enable()
202 (disp_info->bus_flags & DRM_BUS_FLAG_DE_HIGH) ? 0 : 1; in imx_lcdc_pipe_enable()
204 (disp_info->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE) ? 0 : 1; in imx_lcdc_pipe_enable()
206 clk_div = DIV_ROUND_CLOSEST_ULL(clk_get_rate(lcdc->clk_per), in imx_lcdc_pipe_enable()
207 mode->clock * 1000); in imx_lcdc_pipe_enable()
208 bpp = imx_lcdc_get_format(plane_state->fb->format->format); in imx_lcdc_pipe_enable()
210 writel(FIELD_PREP(IMX21LCDC_LPCR_PCD, clk_div - 1) | in imx_lcdc_pipe_enable()
221 lcdc->base + IMX21LCDC_LPCR); in imx_lcdc_pipe_enable()
224 writel(0x00000000, lcdc->base + IMX21LCDC_LPOR); in imx_lcdc_pipe_enable()
227 writel(readl(lcdc->base + IMX21LCDC_LCPR) & ~(IMX21LCDC_LCPR_CC0 | IMX21LCDC_LCPR_CC1), in imx_lcdc_pipe_enable()
228 lcdc->base + IMX21LCDC_LCPR); in imx_lcdc_pipe_enable()
230 ret = clk_prepare_enable(lcdc->clk_ipg); in imx_lcdc_pipe_enable()
232 dev_err(pipe->crtc.dev->dev, "Cannot enable ipg clock: %pe\n", ERR_PTR(ret)); in imx_lcdc_pipe_enable()
235 ret = clk_prepare_enable(lcdc->clk_ahb); in imx_lcdc_pipe_enable()
237 dev_err(pipe->crtc.dev->dev, "Cannot enable ahb clock: %pe\n", ERR_PTR(ret)); in imx_lcdc_pipe_enable()
239 clk_disable_unprepare(lcdc->clk_ipg); in imx_lcdc_pipe_enable()
247 writel(INTR_EOF, lcdc->base + IMX21LCDC_LIER); in imx_lcdc_pipe_enable()
252 struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev); in imx_lcdc_pipe_disable() local
253 struct drm_crtc *crtc = &lcdc->pipe.crtc; in imx_lcdc_pipe_disable()
256 clk_disable_unprepare(lcdc->clk_ahb); in imx_lcdc_pipe_disable()
257 clk_disable_unprepare(lcdc->clk_ipg); in imx_lcdc_pipe_disable()
259 if (pipe->crtc.enabled) in imx_lcdc_pipe_disable()
260 clk_disable_unprepare(lcdc->clk_per); in imx_lcdc_pipe_disable()
262 spin_lock_irq(&lcdc->drm.event_lock); in imx_lcdc_pipe_disable()
263 event = crtc->state->event; in imx_lcdc_pipe_disable()
265 crtc->state->event = NULL; in imx_lcdc_pipe_disable()
268 spin_unlock_irq(&lcdc->drm.event_lock); in imx_lcdc_pipe_disable()
271 writel(0, lcdc->base + IMX21LCDC_LIER); in imx_lcdc_pipe_disable()
278 const struct drm_display_mode *mode = &crtc_state->mode; in imx_lcdc_pipe_check()
279 const struct drm_display_mode *old_mode = &pipe->crtc.state->mode; in imx_lcdc_pipe_check()
281 if (mode->hdisplay < LCDC_MIN_XRES || mode->hdisplay > LCDC_MAX_XRES || in imx_lcdc_pipe_check()
282 mode->vdisplay < LCDC_MIN_YRES || mode->vdisplay > LCDC_MAX_YRES || in imx_lcdc_pipe_check()
283 mode->hdisplay % 0x10) { /* must be multiple of 16 */ in imx_lcdc_pipe_check()
284 drm_err(pipe->crtc.dev, "unsupported display mode (%u x %u)\n", in imx_lcdc_pipe_check()
285 mode->hdisplay, mode->vdisplay); in imx_lcdc_pipe_check()
286 return -EINVAL; in imx_lcdc_pipe_check()
289 crtc_state->mode_changed = in imx_lcdc_pipe_check()
290 old_mode->hdisplay != mode->hdisplay || in imx_lcdc_pipe_check()
291 old_mode->vdisplay != mode->vdisplay; in imx_lcdc_pipe_check()
299 struct drm_crtc *crtc = &pipe->crtc; in imx_lcdc_pipe_update()
300 struct drm_pending_vblank_event *event = crtc->state->event; in imx_lcdc_pipe_update()
301 struct drm_plane_state *new_state = pipe->plane.state; in imx_lcdc_pipe_update()
302 struct drm_framebuffer *fb = new_state->fb; in imx_lcdc_pipe_update()
303 struct drm_framebuffer *old_fb = old_state->fb; in imx_lcdc_pipe_update()
304 struct drm_crtc *old_crtc = old_state->crtc; in imx_lcdc_pipe_update()
307 if (old_fb && old_fb->format != fb->format) in imx_lcdc_pipe_update()
315 crtc->state->event = NULL; in imx_lcdc_pipe_update()
317 spin_lock_irq(&crtc->dev->event_lock); in imx_lcdc_pipe_update()
319 if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0) in imx_lcdc_pipe_update()
324 spin_unlock_irq(&crtc->dev->event_lock); in imx_lcdc_pipe_update()
351 .name = "imx-lcdc",
352 .desc = "i.MX LCDC driver",
358 .compatible = "fsl,imx21-lcdc",
361 .compatible = "fsl,imx25-lcdc",
369 struct imx_lcdc *lcdc = arg; in imx_lcdc_irq_handler() local
370 struct drm_crtc *crtc = &lcdc->pipe.crtc; in imx_lcdc_irq_handler()
373 status = readl(lcdc->base + IMX21LCDC_LISR); in imx_lcdc_irq_handler()
385 struct imx_lcdc *lcdc; in imx_lcdc_probe() local
390 struct device *dev = &pdev->dev; in imx_lcdc_probe()
392 lcdc = devm_drm_dev_alloc(dev, &imx_lcdc_drm_driver, in imx_lcdc_probe()
394 if (IS_ERR(lcdc)) in imx_lcdc_probe()
395 return PTR_ERR(lcdc); in imx_lcdc_probe()
397 drm = &lcdc->drm; in imx_lcdc_probe()
399 lcdc->base = devm_platform_ioremap_resource(pdev, 0); in imx_lcdc_probe()
400 if (IS_ERR(lcdc->base)) in imx_lcdc_probe()
401 return dev_err_probe(dev, PTR_ERR(lcdc->base), "Cannot get IO memory\n"); in imx_lcdc_probe()
403 bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); in imx_lcdc_probe()
408 lcdc->clk_ipg = devm_clk_get(dev, "ipg"); in imx_lcdc_probe()
409 if (IS_ERR(lcdc->clk_ipg)) in imx_lcdc_probe()
410 return dev_err_probe(dev, PTR_ERR(lcdc->clk_ipg), "Failed to get %s clk\n", "ipg"); in imx_lcdc_probe()
412 lcdc->clk_ahb = devm_clk_get(dev, "ahb"); in imx_lcdc_probe()
413 if (IS_ERR(lcdc->clk_ahb)) in imx_lcdc_probe()
414 return dev_err_probe(dev, PTR_ERR(lcdc->clk_ahb), "Failed to get %s clk\n", "ahb"); in imx_lcdc_probe()
416 lcdc->clk_per = devm_clk_get(dev, "per"); in imx_lcdc_probe()
417 if (IS_ERR(lcdc->clk_per)) in imx_lcdc_probe()
418 return dev_err_probe(dev, PTR_ERR(lcdc->clk_per), "Failed to get %s clk\n", "per"); in imx_lcdc_probe()
420 ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32)); in imx_lcdc_probe()
430 ret = drm_simple_display_pipe_init(drm, &lcdc->pipe, in imx_lcdc_probe()
435 return dev_err_probe(drm->dev, ret, "Cannot setup simple display pipe\n"); in imx_lcdc_probe()
437 ret = drm_vblank_init(drm, drm->mode_config.num_crtc); in imx_lcdc_probe()
439 return dev_err_probe(drm->dev, ret, "Failed to initialize vblank\n"); in imx_lcdc_probe()
441 ret = drm_bridge_attach(&lcdc->pipe.encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); in imx_lcdc_probe()
443 return dev_err_probe(drm->dev, ret, "Cannot attach bridge\n"); in imx_lcdc_probe()
445 lcdc->connector = drm_bridge_connector_init(drm, &lcdc->pipe.encoder); in imx_lcdc_probe()
446 if (IS_ERR(lcdc->connector)) in imx_lcdc_probe()
447 return dev_err_probe(drm->dev, PTR_ERR(lcdc->connector), "Cannot init bridge connector\n"); in imx_lcdc_probe()
449 drm_connector_attach_encoder(lcdc->connector, &lcdc->pipe.encoder); in imx_lcdc_probe()
452 * The LCDC controller does not have an enable bit. The in imx_lcdc_probe()
458 * To avoid this issue, let's enable and disable LCDC IPG, in imx_lcdc_probe()
460 * to the LCDC block. in imx_lcdc_probe()
463 ret = clk_prepare_enable(lcdc->clk_ipg); in imx_lcdc_probe()
466 clk_disable_unprepare(lcdc->clk_ipg); in imx_lcdc_probe()
468 ret = clk_prepare_enable(lcdc->clk_per); in imx_lcdc_probe()
471 clk_disable_unprepare(lcdc->clk_per); in imx_lcdc_probe()
473 ret = clk_prepare_enable(lcdc->clk_ahb); in imx_lcdc_probe()
476 clk_disable_unprepare(lcdc->clk_ahb); in imx_lcdc_probe()
478 drm->mode_config.min_width = LCDC_MIN_XRES; in imx_lcdc_probe()
479 drm->mode_config.max_width = LCDC_MAX_XRES; in imx_lcdc_probe()
480 drm->mode_config.min_height = LCDC_MIN_YRES; in imx_lcdc_probe()
481 drm->mode_config.max_height = LCDC_MAX_YRES; in imx_lcdc_probe()
482 drm->mode_config.preferred_depth = 16; in imx_lcdc_probe()
483 drm->mode_config.funcs = &imx_lcdc_mode_config_funcs; in imx_lcdc_probe()
484 drm->mode_config.helper_private = &imx_lcdc_mode_config_helpers; in imx_lcdc_probe()
494 ret = devm_request_irq(dev, irq, imx_lcdc_irq_handler, 0, "imx-lcdc", lcdc); in imx_lcdc_probe()
496 return dev_err_probe(drm->dev, ret, "Failed to install IRQ handler\n"); in imx_lcdc_probe()
500 ret = drm_dev_register(&lcdc->drm, 0); in imx_lcdc_probe()
524 .name = "imx-lcdc",
534 MODULE_DESCRIPTION("Freescale i.MX LCDC driver");