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

1 // SPDX-License-Identifier: GPL-2.0-only
2 // SPDX-FileCopyrightText: 2020 Marian Cichy <[email protected]>
22 #include <linux/dma-mapping.h>
27 #define IMX21LCDC_LSSAR 0x0000 /* LCDC Screen Start Address Register */
28 #define IMX21LCDC_LSR 0x0004 /* LCDC Size Register */
29 #define IMX21LCDC_LVPWR 0x0008 /* LCDC Virtual Page Width Register */
30 #define IMX21LCDC_LCPR 0x000C /* LCDC Cursor Position Register */
31 #define IMX21LCDC_LCWHB 0x0010 /* LCDC Cursor Width Height and Blink Register*/
32 #define IMX21LCDC_LCCMR 0x0014 /* LCDC Color Cursor Mapping Register */
33 #define IMX21LCDC_LPCR 0x0018 /* LCDC Panel Configuration Register */
34 #define IMX21LCDC_LHCR 0x001C /* LCDC Horizontal Configuration Register */
35 #define IMX21LCDC_LVCR 0x0020 /* LCDC Vertical Configuration Register */
36 #define IMX21LCDC_LPOR 0x0024 /* LCDC Panning Offset Register */
37 #define IMX21LCDC_LSCR 0x0028 /* LCDC Sharp Configuration Register */
38 #define IMX21LCDC_LPCCR 0x002C /* LCDC PWM Contrast Control Register */
39 #define IMX21LCDC_LDCR 0x0030 /* LCDC DMA Control Register */
40 #define IMX21LCDC_LRMCR 0x0034 /* LCDC Refresh Mode Control Register */
41 #define IMX21LCDC_LICR 0x0038 /* LCDC Interrupt Configuration Register */
42 #define IMX21LCDC_LIER 0x003C /* LCDC Interrupt Enable Register */
43 #define IMX21LCDC_LISR 0x0040 /* LCDC Interrupt Status Register */
44 #define IMX21LCDC_LGWSAR 0x0050 /* LCDC Graphic Window Start Address Register */
45 #define IMX21LCDC_LGWSR 0x0054 /* LCDC Graph Window Size Register */
46 #define IMX21LCDC_LGWVPWR 0x0058 /* LCDC Graphic Window Virtual Page Width Register */
47 #define IMX21LCDC_LGWPOR 0x005C /* LCDC Graphic Window Panning Offset Register */
48 #define IMX21LCDC_LGWPR 0x0060 /* LCDC Graphic Window Position Register */
49 #define IMX21LCDC_LGWCR 0x0064 /* LCDC Graphic Window Control Register */
50 #define IMX21LCDC_LGWDCR 0x0068 /* LCDC Graphic Window DMA Control Register */
51 #define IMX21LCDC_LAUSCR 0x0080 /* LCDC AUS Mode Control Register */
52 #define IMX21LCDC_LAUSCCR 0x0084 /* LCDC AUS Mode Cursor Control Register */
126 DRM_WARN("Format not supported - fallback to XRGB8888\n"); in imx_lcdc_get_format()
141 struct drm_crtc *crtc = &pipe->crtc; in imx_lcdc_update_hw_registers()
142 struct drm_plane_state *new_state = pipe->plane.state; in imx_lcdc_update_hw_registers()
143 struct drm_framebuffer *fb = new_state->fb; in imx_lcdc_update_hw_registers()
144 struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev); in imx_lcdc_update_hw_registers() local
151 writel(addr, lcdc->base + IMX21LCDC_LSSAR); in imx_lcdc_update_hw_registers()
157 if (old_state && old_state->crtc && old_state->crtc->enabled) in imx_lcdc_update_hw_registers()
158 clk_disable_unprepare(lcdc->clk_per); in imx_lcdc_update_hw_registers()
161 framesize = FIELD_PREP(IMX21LCDC_LSR_XMAX, crtc->mode.hdisplay >> 4) | in imx_lcdc_update_hw_registers()
162 FIELD_PREP(IMX21LCDC_LSR_YMAX, crtc->mode.vdisplay); in imx_lcdc_update_hw_registers()
163 writel(framesize, lcdc->base + IMX21LCDC_LSR); in imx_lcdc_update_hw_registers()
166 lhcr = FIELD_PREP(IMX21LCDC_LHCR_HFPORCH, crtc->mode.hsync_start - crtc->mode.hdisplay - 1) | in imx_lcdc_update_hw_registers()
167 FIELD_PREP(IMX21LCDC_LHCR_HWIDTH, crtc->mode.hsync_end - crtc->mode.hsync_start - 1) | in imx_lcdc_update_hw_registers()
168 FIELD_PREP(IMX21LCDC_LHCR_HBPORCH, crtc->mode.htotal - crtc->mode.hsync_end - 3); in imx_lcdc_update_hw_registers()
169 writel(lhcr, lcdc->base + IMX21LCDC_LHCR); in imx_lcdc_update_hw_registers()
172 lvcr = FIELD_PREP(IMX21LCDC_LVCR_VFPORCH, crtc->mode.vsync_start - crtc->mode.vdisplay) | in imx_lcdc_update_hw_registers()
173 FIELD_PREP(IMX21LCDC_LVCR_VWIDTH, crtc->mode.vsync_end - crtc->mode.vsync_start) | in imx_lcdc_update_hw_registers()
174 FIELD_PREP(IMX21LCDC_LVCR_VBPORCH, crtc->mode.vtotal - crtc->mode.vsync_end); in imx_lcdc_update_hw_registers()
175 writel(lvcr, lcdc->base + IMX21LCDC_LVCR); in imx_lcdc_update_hw_registers()
177 lpcr = readl(lcdc->base + IMX21LCDC_LPCR); in imx_lcdc_update_hw_registers()
179 lpcr |= FIELD_PREP(IMX21LCDC_LPCR_BPIX, imx_lcdc_get_format(fb->format->format)); in imx_lcdc_update_hw_registers()
180 writel(lpcr, lcdc->base + IMX21LCDC_LPCR); in imx_lcdc_update_hw_registers()
183 writel(new_state->fb->pitches[0] / 4, lcdc->base + IMX21LCDC_LVPWR); in imx_lcdc_update_hw_registers()
186 if (new_state->crtc->enabled) in imx_lcdc_update_hw_registers()
187 clk_prepare_enable(lcdc->clk_per); in imx_lcdc_update_hw_registers()
197 struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev); in imx_lcdc_pipe_enable() local
198 struct drm_display_mode *mode = &pipe->crtc.mode; in imx_lcdc_pipe_enable()
199 struct drm_display_info *disp_info = &lcdc->connector->display_info; in imx_lcdc_pipe_enable()
200 const int hsync_pol = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : 1; in imx_lcdc_pipe_enable()
201 const int vsync_pol = (mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : 1; in imx_lcdc_pipe_enable()
203 (disp_info->bus_flags & DRM_BUS_FLAG_DE_HIGH) ? 0 : 1; in imx_lcdc_pipe_enable()
205 (disp_info->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE) ? 0 : 1; in imx_lcdc_pipe_enable()
207 clk_div = DIV_ROUND_CLOSEST_ULL(clk_get_rate(lcdc->clk_per), in imx_lcdc_pipe_enable()
208 mode->clock * 1000); in imx_lcdc_pipe_enable()
209 bpp = imx_lcdc_get_format(plane_state->fb->format->format); in imx_lcdc_pipe_enable()
211 writel(FIELD_PREP(IMX21LCDC_LPCR_PCD, clk_div - 1) | in imx_lcdc_pipe_enable()
222 lcdc->base + IMX21LCDC_LPCR); in imx_lcdc_pipe_enable()
225 writel(0x00000000, lcdc->base + IMX21LCDC_LPOR); in imx_lcdc_pipe_enable()
228 writel(readl(lcdc->base + IMX21LCDC_LCPR) & ~(IMX21LCDC_LCPR_CC0 | IMX21LCDC_LCPR_CC1), in imx_lcdc_pipe_enable()
229 lcdc->base + IMX21LCDC_LCPR); in imx_lcdc_pipe_enable()
231 ret = clk_prepare_enable(lcdc->clk_ipg); in imx_lcdc_pipe_enable()
233 dev_err(pipe->crtc.dev->dev, "Cannot enable ipg clock: %pe\n", ERR_PTR(ret)); in imx_lcdc_pipe_enable()
236 ret = clk_prepare_enable(lcdc->clk_ahb); in imx_lcdc_pipe_enable()
238 dev_err(pipe->crtc.dev->dev, "Cannot enable ahb clock: %pe\n", ERR_PTR(ret)); in imx_lcdc_pipe_enable()
240 clk_disable_unprepare(lcdc->clk_ipg); in imx_lcdc_pipe_enable()
248 writel(INTR_EOF, lcdc->base + IMX21LCDC_LIER); in imx_lcdc_pipe_enable()
253 struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev); in imx_lcdc_pipe_disable() local
254 struct drm_crtc *crtc = &lcdc->pipe.crtc; in imx_lcdc_pipe_disable()
257 clk_disable_unprepare(lcdc->clk_ahb); in imx_lcdc_pipe_disable()
258 clk_disable_unprepare(lcdc->clk_ipg); in imx_lcdc_pipe_disable()
260 if (pipe->crtc.enabled) in imx_lcdc_pipe_disable()
261 clk_disable_unprepare(lcdc->clk_per); in imx_lcdc_pipe_disable()
263 spin_lock_irq(&lcdc->drm.event_lock); in imx_lcdc_pipe_disable()
264 event = crtc->state->event; in imx_lcdc_pipe_disable()
266 crtc->state->event = NULL; in imx_lcdc_pipe_disable()
269 spin_unlock_irq(&lcdc->drm.event_lock); in imx_lcdc_pipe_disable()
272 writel(0, lcdc->base + IMX21LCDC_LIER); in imx_lcdc_pipe_disable()
279 const struct drm_display_mode *mode = &crtc_state->mode; in imx_lcdc_pipe_check()
280 const struct drm_display_mode *old_mode = &pipe->crtc.state->mode; in imx_lcdc_pipe_check()
282 if (mode->hdisplay < LCDC_MIN_XRES || mode->hdisplay > LCDC_MAX_XRES || in imx_lcdc_pipe_check()
283 mode->vdisplay < LCDC_MIN_YRES || mode->vdisplay > LCDC_MAX_YRES || in imx_lcdc_pipe_check()
284 mode->hdisplay % 0x10) { /* must be multiple of 16 */ in imx_lcdc_pipe_check()
285 drm_err(pipe->crtc.dev, "unsupported display mode (%u x %u)\n", in imx_lcdc_pipe_check()
286 mode->hdisplay, mode->vdisplay); in imx_lcdc_pipe_check()
287 return -EINVAL; in imx_lcdc_pipe_check()
290 crtc_state->mode_changed = in imx_lcdc_pipe_check()
291 old_mode->hdisplay != mode->hdisplay || in imx_lcdc_pipe_check()
292 old_mode->vdisplay != mode->vdisplay; in imx_lcdc_pipe_check()
300 struct drm_crtc *crtc = &pipe->crtc; in imx_lcdc_pipe_update()
301 struct drm_pending_vblank_event *event = crtc->state->event; in imx_lcdc_pipe_update()
302 struct drm_plane_state *new_state = pipe->plane.state; in imx_lcdc_pipe_update()
303 struct drm_framebuffer *fb = new_state->fb; in imx_lcdc_pipe_update()
304 struct drm_framebuffer *old_fb = old_state->fb; in imx_lcdc_pipe_update()
305 struct drm_crtc *old_crtc = old_state->crtc; in imx_lcdc_pipe_update()
308 if (old_fb && old_fb->format != fb->format) in imx_lcdc_pipe_update()
316 crtc->state->event = NULL; in imx_lcdc_pipe_update()
318 spin_lock_irq(&crtc->dev->event_lock); in imx_lcdc_pipe_update()
320 if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0) in imx_lcdc_pipe_update()
325 spin_unlock_irq(&crtc->dev->event_lock); in imx_lcdc_pipe_update()
353 .name = "imx-lcdc",
354 .desc = "i.MX LCDC driver",
359 .compatible = "fsl,imx21-lcdc",
362 .compatible = "fsl,imx25-lcdc",
370 struct imx_lcdc *lcdc = arg; in imx_lcdc_irq_handler() local
371 struct drm_crtc *crtc = &lcdc->pipe.crtc; in imx_lcdc_irq_handler()
374 status = readl(lcdc->base + IMX21LCDC_LISR); in imx_lcdc_irq_handler()
386 struct imx_lcdc *lcdc; in imx_lcdc_probe() local
391 struct device *dev = &pdev->dev; in imx_lcdc_probe()
393 lcdc = devm_drm_dev_alloc(dev, &imx_lcdc_drm_driver, in imx_lcdc_probe()
395 if (IS_ERR(lcdc)) in imx_lcdc_probe()
396 return PTR_ERR(lcdc); in imx_lcdc_probe()
398 drm = &lcdc->drm; in imx_lcdc_probe()
400 lcdc->base = devm_platform_ioremap_resource(pdev, 0); in imx_lcdc_probe()
401 if (IS_ERR(lcdc->base)) in imx_lcdc_probe()
402 return dev_err_probe(dev, PTR_ERR(lcdc->base), "Cannot get IO memory\n"); in imx_lcdc_probe()
404 bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); in imx_lcdc_probe()
409 lcdc->clk_ipg = devm_clk_get(dev, "ipg"); in imx_lcdc_probe()
410 if (IS_ERR(lcdc->clk_ipg)) in imx_lcdc_probe()
411 return dev_err_probe(dev, PTR_ERR(lcdc->clk_ipg), "Failed to get %s clk\n", "ipg"); in imx_lcdc_probe()
413 lcdc->clk_ahb = devm_clk_get(dev, "ahb"); in imx_lcdc_probe()
414 if (IS_ERR(lcdc->clk_ahb)) in imx_lcdc_probe()
415 return dev_err_probe(dev, PTR_ERR(lcdc->clk_ahb), "Failed to get %s clk\n", "ahb"); in imx_lcdc_probe()
417 lcdc->clk_per = devm_clk_get(dev, "per"); in imx_lcdc_probe()
418 if (IS_ERR(lcdc->clk_per)) in imx_lcdc_probe()
419 return dev_err_probe(dev, PTR_ERR(lcdc->clk_per), "Failed to get %s clk\n", "per"); in imx_lcdc_probe()
421 ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32)); in imx_lcdc_probe()
431 ret = drm_simple_display_pipe_init(drm, &lcdc->pipe, in imx_lcdc_probe()
436 return dev_err_probe(drm->dev, ret, "Cannot setup simple display pipe\n"); in imx_lcdc_probe()
438 ret = drm_vblank_init(drm, drm->mode_config.num_crtc); in imx_lcdc_probe()
440 return dev_err_probe(drm->dev, ret, "Failed to initialize vblank\n"); in imx_lcdc_probe()
442 ret = drm_bridge_attach(&lcdc->pipe.encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); in imx_lcdc_probe()
444 return dev_err_probe(drm->dev, ret, "Cannot attach bridge\n"); in imx_lcdc_probe()
446 lcdc->connector = drm_bridge_connector_init(drm, &lcdc->pipe.encoder); in imx_lcdc_probe()
447 if (IS_ERR(lcdc->connector)) in imx_lcdc_probe()
448 return dev_err_probe(drm->dev, PTR_ERR(lcdc->connector), "Cannot init bridge connector\n"); in imx_lcdc_probe()
450 drm_connector_attach_encoder(lcdc->connector, &lcdc->pipe.encoder); in imx_lcdc_probe()
453 * The LCDC controller does not have an enable bit. The in imx_lcdc_probe()
459 * To avoid this issue, let's enable and disable LCDC IPG, in imx_lcdc_probe()
461 * to the LCDC block. in imx_lcdc_probe()
464 ret = clk_prepare_enable(lcdc->clk_ipg); in imx_lcdc_probe()
467 clk_disable_unprepare(lcdc->clk_ipg); in imx_lcdc_probe()
469 ret = clk_prepare_enable(lcdc->clk_per); in imx_lcdc_probe()
472 clk_disable_unprepare(lcdc->clk_per); in imx_lcdc_probe()
474 ret = clk_prepare_enable(lcdc->clk_ahb); in imx_lcdc_probe()
477 clk_disable_unprepare(lcdc->clk_ahb); in imx_lcdc_probe()
479 drm->mode_config.min_width = LCDC_MIN_XRES; in imx_lcdc_probe()
480 drm->mode_config.max_width = LCDC_MAX_XRES; in imx_lcdc_probe()
481 drm->mode_config.min_height = LCDC_MIN_YRES; in imx_lcdc_probe()
482 drm->mode_config.max_height = LCDC_MAX_YRES; in imx_lcdc_probe()
483 drm->mode_config.preferred_depth = 16; in imx_lcdc_probe()
484 drm->mode_config.funcs = &imx_lcdc_mode_config_funcs; in imx_lcdc_probe()
485 drm->mode_config.helper_private = &imx_lcdc_mode_config_helpers; in imx_lcdc_probe()
495 ret = devm_request_irq(dev, irq, imx_lcdc_irq_handler, 0, "imx-lcdc", lcdc); in imx_lcdc_probe()
497 return dev_err_probe(drm->dev, ret, "Failed to install IRQ handler\n"); in imx_lcdc_probe()
501 ret = drm_dev_register(&lcdc->drm, 0); in imx_lcdc_probe()
525 .name = "imx-lcdc",
535 MODULE_DESCRIPTION("Freescale i.MX LCDC driver");