Lines Matching +full:jz4725b +full:- +full:lcd
1 // SPDX-License-Identifier: GPL-2.0
7 #include "ingenic-drm.h"
11 #include <linux/dma-mapping.h>
55 * f0 (aka. foreground0) can be overlayed. Z-order is fixed in
119 regmap_write(priv->map, JZ_REG_LCD_STATE, 0); in ingenic_drm_crtc_atomic_enable()
121 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_crtc_atomic_enable()
136 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_crtc_atomic_disable()
139 regmap_read_poll_timeout(priv->map, JZ_REG_LCD_STATE, var, in ingenic_drm_crtc_atomic_disable()
149 vpe = mode->vsync_end - mode->vsync_start; in ingenic_drm_crtc_update_timings()
150 vds = mode->vtotal - mode->vsync_start; in ingenic_drm_crtc_update_timings()
151 vde = vds + mode->vdisplay; in ingenic_drm_crtc_update_timings()
152 vt = vde + mode->vsync_start - mode->vdisplay; in ingenic_drm_crtc_update_timings()
154 hpe = mode->hsync_end - mode->hsync_start; in ingenic_drm_crtc_update_timings()
155 hds = mode->htotal - mode->hsync_start; in ingenic_drm_crtc_update_timings()
156 hde = hds + mode->hdisplay; in ingenic_drm_crtc_update_timings()
157 ht = hde + mode->hsync_start - mode->hdisplay; in ingenic_drm_crtc_update_timings()
159 regmap_write(priv->map, JZ_REG_LCD_VSYNC, in ingenic_drm_crtc_update_timings()
163 regmap_write(priv->map, JZ_REG_LCD_HSYNC, in ingenic_drm_crtc_update_timings()
167 regmap_write(priv->map, JZ_REG_LCD_VAT, in ingenic_drm_crtc_update_timings()
171 regmap_write(priv->map, JZ_REG_LCD_DAH, in ingenic_drm_crtc_update_timings()
174 regmap_write(priv->map, JZ_REG_LCD_DAV, in ingenic_drm_crtc_update_timings()
178 if (priv->panel_is_sharp) { in ingenic_drm_crtc_update_timings()
179 regmap_write(priv->map, JZ_REG_LCD_PS, hde << 16 | (hde + 1)); in ingenic_drm_crtc_update_timings()
180 regmap_write(priv->map, JZ_REG_LCD_CLS, hde << 16 | (hde + 1)); in ingenic_drm_crtc_update_timings()
181 regmap_write(priv->map, JZ_REG_LCD_SPL, hpe << 16 | (hpe + 1)); in ingenic_drm_crtc_update_timings()
182 regmap_write(priv->map, JZ_REG_LCD_REV, mode->htotal << 16); in ingenic_drm_crtc_update_timings()
185 regmap_set_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_crtc_update_timings()
189 * IPU restart - specify how much time the LCDC will wait before in ingenic_drm_crtc_update_timings()
193 regmap_write(priv->map, JZ_REG_LCD_IPUR, JZ_LCD_IPUR_IPUREN | in ingenic_drm_crtc_update_timings()
203 if (drm_atomic_crtc_needs_modeset(state) && priv->soc_info->has_osd) { in ingenic_drm_crtc_atomic_check()
204 f1_state = drm_atomic_get_plane_state(state->state, &priv->f1); in ingenic_drm_crtc_atomic_check()
208 f0_state = drm_atomic_get_plane_state(state->state, &priv->f0); in ingenic_drm_crtc_atomic_check()
212 if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && priv->ipu_plane) { in ingenic_drm_crtc_atomic_check()
213 ipu_state = drm_atomic_get_plane_state(state->state, priv->ipu_plane); in ingenic_drm_crtc_atomic_check()
218 if (f1_state->fb && ipu_state->fb) { in ingenic_drm_crtc_atomic_check()
219 dev_dbg(priv->dev, "Cannot enable both F1 and IPU\n"); in ingenic_drm_crtc_atomic_check()
220 return -EINVAL; in ingenic_drm_crtc_atomic_check()
225 priv->no_vblank = !f1_state->fb && !f0_state->fb && in ingenic_drm_crtc_atomic_check()
226 !(ipu_state && ipu_state->fb); in ingenic_drm_crtc_atomic_check()
238 if (mode->hdisplay > priv->soc_info->max_width) in ingenic_drm_crtc_mode_valid()
240 if (mode->vdisplay > priv->soc_info->max_height) in ingenic_drm_crtc_mode_valid()
243 rate = clk_round_rate(priv->pix_clk, mode->clock * 1000); in ingenic_drm_crtc_mode_valid()
256 if (priv->soc_info->has_osd && in ingenic_drm_crtc_atomic_begin()
257 drm_atomic_crtc_needs_modeset(crtc->state)) { in ingenic_drm_crtc_atomic_begin()
262 if (priv->ipu_plane && priv->ipu_plane->state->fb) in ingenic_drm_crtc_atomic_begin()
265 regmap_update_bits(priv->map, JZ_REG_LCD_OSDCTRL, in ingenic_drm_crtc_atomic_begin()
274 struct drm_crtc_state *state = crtc->state; in ingenic_drm_crtc_atomic_flush()
275 struct drm_pending_vblank_event *event = state->event; in ingenic_drm_crtc_atomic_flush()
278 ingenic_drm_crtc_update_timings(priv, &state->mode); in ingenic_drm_crtc_atomic_flush()
280 clk_set_rate(priv->pix_clk, state->adjusted_mode.clock * 1000); in ingenic_drm_crtc_atomic_flush()
284 state->event = NULL; in ingenic_drm_crtc_atomic_flush()
286 spin_lock_irq(&crtc->dev->event_lock); in ingenic_drm_crtc_atomic_flush()
291 spin_unlock_irq(&crtc->dev->event_lock); in ingenic_drm_crtc_atomic_flush()
298 struct ingenic_drm *priv = drm_device_get_priv(plane->dev); in ingenic_drm_plane_atomic_check()
300 struct drm_crtc *crtc = state->crtc ?: plane->state->crtc; in ingenic_drm_plane_atomic_check()
306 crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); in ingenic_drm_plane_atomic_check()
308 return -EINVAL; in ingenic_drm_plane_atomic_check()
313 priv->soc_info->has_osd, in ingenic_drm_plane_atomic_check()
320 * Note that state->src_* are in 16.16 fixed-point format. in ingenic_drm_plane_atomic_check()
322 if (!priv->soc_info->has_osd && in ingenic_drm_plane_atomic_check()
323 (state->src_x != 0 || in ingenic_drm_plane_atomic_check()
324 (state->src_w >> 16) != state->crtc_w || in ingenic_drm_plane_atomic_check()
325 (state->src_h >> 16) != state->crtc_h)) in ingenic_drm_plane_atomic_check()
326 return -EINVAL; in ingenic_drm_plane_atomic_check()
332 if (priv->soc_info->has_osd && in ingenic_drm_plane_atomic_check()
333 (!plane->state->fb || !state->fb || in ingenic_drm_plane_atomic_check()
334 plane->state->crtc_x != state->crtc_x || in ingenic_drm_plane_atomic_check()
335 plane->state->crtc_y != state->crtc_y || in ingenic_drm_plane_atomic_check()
336 plane->state->crtc_w != state->crtc_w || in ingenic_drm_plane_atomic_check()
337 plane->state->crtc_h != state->crtc_h || in ingenic_drm_plane_atomic_check()
338 plane->state->fb->format->format != state->fb->format->format)) in ingenic_drm_plane_atomic_check()
339 crtc_state->mode_changed = true; in ingenic_drm_plane_atomic_check()
349 if (priv->soc_info->has_osd) { in ingenic_drm_plane_enable()
350 if (plane->type == DRM_PLANE_TYPE_PRIMARY) in ingenic_drm_plane_enable()
355 regmap_set_bits(priv->map, JZ_REG_LCD_OSDC, en_bit); in ingenic_drm_plane_enable()
364 if (priv->soc_info->has_osd) { in ingenic_drm_plane_disable()
365 if (plane->type == DRM_PLANE_TYPE_PRIMARY) in ingenic_drm_plane_disable()
370 regmap_clear_bits(priv->map, JZ_REG_LCD_OSDC, en_bit); in ingenic_drm_plane_disable()
377 struct ingenic_drm *priv = drm_device_get_priv(plane->dev); in ingenic_drm_plane_atomic_disable()
379 ingenic_drm_plane_disable(priv->dev, plane); in ingenic_drm_plane_atomic_disable()
386 struct drm_plane_state *state = plane->state; in ingenic_drm_plane_config()
392 if (priv->soc_info->has_osd && in ingenic_drm_plane_config()
393 plane->type == DRM_PLANE_TYPE_PRIMARY) { in ingenic_drm_plane_config()
406 regmap_update_bits(priv->map, JZ_REG_LCD_OSDCTRL, in ingenic_drm_plane_config()
421 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_plane_config()
425 if (priv->soc_info->has_osd) { in ingenic_drm_plane_config()
426 if (plane->type == DRM_PLANE_TYPE_PRIMARY) { in ingenic_drm_plane_config()
434 regmap_write(priv->map, xy_reg, in ingenic_drm_plane_config()
435 state->crtc_x << JZ_LCD_XYP01_XPOS_LSB | in ingenic_drm_plane_config()
436 state->crtc_y << JZ_LCD_XYP01_YPOS_LSB); in ingenic_drm_plane_config()
437 regmap_write(priv->map, size_reg, in ingenic_drm_plane_config()
438 state->crtc_w << JZ_LCD_SIZE01_WIDTH_LSB | in ingenic_drm_plane_config()
439 state->crtc_h << JZ_LCD_SIZE01_HEIGHT_LSB); in ingenic_drm_plane_config()
446 struct ingenic_drm *priv = drm_device_get_priv(plane->dev); in ingenic_drm_plane_atomic_update()
447 struct drm_plane_state *state = plane->state; in ingenic_drm_plane_atomic_update()
452 if (state && state->fb) { in ingenic_drm_plane_atomic_update()
453 addr = drm_fb_cma_get_gem_addr(state->fb, state, 0); in ingenic_drm_plane_atomic_update()
454 width = state->src_w >> 16; in ingenic_drm_plane_atomic_update()
455 height = state->src_h >> 16; in ingenic_drm_plane_atomic_update()
456 cpp = state->fb->format->cpp[0]; in ingenic_drm_plane_atomic_update()
458 if (priv->soc_info->has_osd && plane->type == DRM_PLANE_TYPE_OVERLAY) in ingenic_drm_plane_atomic_update()
459 hwdesc = priv->dma_hwdesc_f0; in ingenic_drm_plane_atomic_update()
461 hwdesc = priv->dma_hwdesc_f1; in ingenic_drm_plane_atomic_update()
463 hwdesc->addr = addr; in ingenic_drm_plane_atomic_update()
464 hwdesc->cmd = JZ_LCD_CMD_EOF_IRQ | (width * height * cpp / 4); in ingenic_drm_plane_atomic_update()
466 if (drm_atomic_crtc_needs_modeset(state->crtc->state)) in ingenic_drm_plane_atomic_update()
467 ingenic_drm_plane_config(priv->dev, plane, in ingenic_drm_plane_atomic_update()
468 state->fb->format->format); in ingenic_drm_plane_atomic_update()
476 struct ingenic_drm *priv = drm_device_get_priv(encoder->dev); in ingenic_drm_encoder_atomic_mode_set()
477 struct drm_display_mode *mode = &crtc_state->adjusted_mode; in ingenic_drm_encoder_atomic_mode_set()
478 struct drm_connector *conn = conn_state->connector; in ingenic_drm_encoder_atomic_mode_set()
479 struct drm_display_info *info = &conn->display_info; in ingenic_drm_encoder_atomic_mode_set()
482 priv->panel_is_sharp = info->bus_flags & DRM_BUS_FLAG_SHARP_SIGNALS; in ingenic_drm_encoder_atomic_mode_set()
484 if (priv->panel_is_sharp) { in ingenic_drm_encoder_atomic_mode_set()
491 if (mode->flags & DRM_MODE_FLAG_NHSYNC) in ingenic_drm_encoder_atomic_mode_set()
493 if (mode->flags & DRM_MODE_FLAG_NVSYNC) in ingenic_drm_encoder_atomic_mode_set()
495 if (info->bus_flags & DRM_BUS_FLAG_DE_LOW) in ingenic_drm_encoder_atomic_mode_set()
497 if (info->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) in ingenic_drm_encoder_atomic_mode_set()
500 if (!priv->panel_is_sharp) { in ingenic_drm_encoder_atomic_mode_set()
501 if (conn->connector_type == DRM_MODE_CONNECTOR_TV) { in ingenic_drm_encoder_atomic_mode_set()
502 if (mode->flags & DRM_MODE_FLAG_INTERLACE) in ingenic_drm_encoder_atomic_mode_set()
507 switch (*info->bus_formats) { in ingenic_drm_encoder_atomic_mode_set()
526 regmap_write(priv->map, JZ_REG_LCD_CFG, cfg); in ingenic_drm_encoder_atomic_mode_set()
533 struct drm_display_info *info = &conn_state->connector->display_info; in ingenic_drm_encoder_atomic_check()
535 if (info->num_bus_formats != 1) in ingenic_drm_encoder_atomic_check()
536 return -EINVAL; in ingenic_drm_encoder_atomic_check()
538 if (conn_state->connector->connector_type == DRM_MODE_CONNECTOR_TV) in ingenic_drm_encoder_atomic_check()
541 switch (*info->bus_formats) { in ingenic_drm_encoder_atomic_check()
548 return -EINVAL; in ingenic_drm_encoder_atomic_check()
556 * drm_atomic_helper_wait_for_vblanks() if priv->no_vblank. in ingenic_drm_atomic_helper_commit_tail()
558 struct drm_device *dev = old_state->dev; in ingenic_drm_atomic_helper_commit_tail()
569 if (!priv->no_vblank) in ingenic_drm_atomic_helper_commit_tail()
580 regmap_read(priv->map, JZ_REG_LCD_STATE, &state); in ingenic_drm_irq_handler()
582 regmap_update_bits(priv->map, JZ_REG_LCD_STATE, in ingenic_drm_irq_handler()
586 drm_crtc_handle_vblank(&priv->crtc); in ingenic_drm_irq_handler()
595 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_enable_vblank()
605 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, JZ_LCD_CTRL_EOF_IRQ, 0); in ingenic_drm_disable_vblank()
612 .name = "ingenic-drm",
686 component_unbind_all(priv->dev, &priv->drm); in ingenic_drm_unbind_all()
707 return -EINVAL; in ingenic_drm_bind()
715 priv->soc_info = soc_info; in ingenic_drm_bind()
716 priv->dev = dev; in ingenic_drm_bind()
717 drm = &priv->drm; in ingenic_drm_bind()
725 drm->mode_config.min_width = 0; in ingenic_drm_bind()
726 drm->mode_config.min_height = 0; in ingenic_drm_bind()
727 drm->mode_config.max_width = soc_info->max_width; in ingenic_drm_bind()
728 drm->mode_config.max_height = 4095; in ingenic_drm_bind()
729 drm->mode_config.funcs = &ingenic_drm_mode_config_funcs; in ingenic_drm_bind()
730 drm->mode_config.helper_private = &ingenic_drm_mode_config_helpers; in ingenic_drm_bind()
738 priv->map = devm_regmap_init_mmio(dev, base, in ingenic_drm_bind()
740 if (IS_ERR(priv->map)) { in ingenic_drm_bind()
742 return PTR_ERR(priv->map); in ingenic_drm_bind()
749 if (soc_info->needs_dev_clk) { in ingenic_drm_bind()
750 priv->lcd_clk = devm_clk_get(dev, "lcd"); in ingenic_drm_bind()
751 if (IS_ERR(priv->lcd_clk)) { in ingenic_drm_bind()
752 dev_err(dev, "Failed to get lcd clock\n"); in ingenic_drm_bind()
753 return PTR_ERR(priv->lcd_clk); in ingenic_drm_bind()
757 priv->pix_clk = devm_clk_get(dev, "lcd_pclk"); in ingenic_drm_bind()
758 if (IS_ERR(priv->pix_clk)) { in ingenic_drm_bind()
760 return PTR_ERR(priv->pix_clk); in ingenic_drm_bind()
763 priv->dma_hwdesc_f1 = dmam_alloc_coherent(dev, sizeof(*priv->dma_hwdesc_f1), in ingenic_drm_bind()
764 &priv->dma_hwdesc_phys_f1, in ingenic_drm_bind()
766 if (!priv->dma_hwdesc_f1) in ingenic_drm_bind()
767 return -ENOMEM; in ingenic_drm_bind()
769 priv->dma_hwdesc_f1->next = priv->dma_hwdesc_phys_f1; in ingenic_drm_bind()
770 priv->dma_hwdesc_f1->id = 0xf1; in ingenic_drm_bind()
772 if (priv->soc_info->has_osd) { in ingenic_drm_bind()
773 priv->dma_hwdesc_f0 = dmam_alloc_coherent(dev, in ingenic_drm_bind()
774 sizeof(*priv->dma_hwdesc_f0), in ingenic_drm_bind()
775 &priv->dma_hwdesc_phys_f0, in ingenic_drm_bind()
777 if (!priv->dma_hwdesc_f0) in ingenic_drm_bind()
778 return -ENOMEM; in ingenic_drm_bind()
780 priv->dma_hwdesc_f0->next = priv->dma_hwdesc_phys_f0; in ingenic_drm_bind()
781 priv->dma_hwdesc_f0->id = 0xf0; in ingenic_drm_bind()
784 if (soc_info->has_osd) in ingenic_drm_bind()
785 priv->ipu_plane = drm_plane_from_index(drm, 0); in ingenic_drm_bind()
787 drm_plane_helper_add(&priv->f1, &ingenic_drm_plane_helper_funcs); in ingenic_drm_bind()
789 ret = drm_universal_plane_init(drm, &priv->f1, 1, in ingenic_drm_bind()
799 drm_crtc_helper_add(&priv->crtc, &ingenic_drm_crtc_helper_funcs); in ingenic_drm_bind()
801 ret = drm_crtc_init_with_planes(drm, &priv->crtc, &priv->f1, in ingenic_drm_bind()
808 if (soc_info->has_osd) { in ingenic_drm_bind()
809 drm_plane_helper_add(&priv->f0, in ingenic_drm_bind()
812 ret = drm_universal_plane_init(drm, &priv->f0, 1, in ingenic_drm_bind()
827 if (ret != -EPROBE_DEFER) in ingenic_drm_bind()
836 priv->ipu_plane = drm_plane_from_index(drm, 2); in ingenic_drm_bind()
837 if (!priv->ipu_plane) { in ingenic_drm_bind()
839 return -EINVAL; in ingenic_drm_bind()
845 ret = drm_of_find_panel_or_bridge(dev->of_node, 0, i, &panel, &bridge); in ingenic_drm_bind()
847 if (ret == -ENODEV) in ingenic_drm_bind()
849 if (ret != -EPROBE_DEFER) in ingenic_drm_bind()
860 return -ENOMEM; in ingenic_drm_bind()
862 encoder->possible_crtcs = 1; in ingenic_drm_bind()
884 encoder->possible_clones = clone_mask; in ingenic_drm_bind()
901 ret = clk_prepare_enable(priv->pix_clk); in ingenic_drm_bind()
907 if (priv->lcd_clk) { in ingenic_drm_bind()
908 parent_clk = clk_get_parent(priv->lcd_clk); in ingenic_drm_bind()
911 /* LCD Device clock must be 3x the pixel clock for STN panels, in ingenic_drm_bind()
913 * check for the LCD device clock everytime we do a mode change, in ingenic_drm_bind()
914 * we set the LCD device clock to the highest rate possible. in ingenic_drm_bind()
916 ret = clk_set_rate(priv->lcd_clk, parent_rate); in ingenic_drm_bind()
918 dev_err(dev, "Unable to set LCD clock rate\n"); in ingenic_drm_bind()
922 ret = clk_prepare_enable(priv->lcd_clk); in ingenic_drm_bind()
924 dev_err(dev, "Unable to start lcd clock\n"); in ingenic_drm_bind()
930 regmap_write(priv->map, JZ_REG_LCD_DA0, priv->dma_hwdesc_phys_f0); in ingenic_drm_bind()
931 regmap_write(priv->map, JZ_REG_LCD_DA1, priv->dma_hwdesc_phys_f1); in ingenic_drm_bind()
934 if (soc_info->has_osd) in ingenic_drm_bind()
935 regmap_write(priv->map, JZ_REG_LCD_OSDC, JZ_LCD_OSDC_OSDEN); in ingenic_drm_bind()
948 if (priv->lcd_clk) in ingenic_drm_bind()
949 clk_disable_unprepare(priv->lcd_clk); in ingenic_drm_bind()
951 clk_disable_unprepare(priv->pix_clk); in ingenic_drm_bind()
962 return dev->of_node == data; in compare_of()
969 if (priv->lcd_clk) in ingenic_drm_unbind()
970 clk_disable_unprepare(priv->lcd_clk); in ingenic_drm_unbind()
971 clk_disable_unprepare(priv->pix_clk); in ingenic_drm_unbind()
973 drm_dev_unregister(&priv->drm); in ingenic_drm_unbind()
974 drm_atomic_helper_shutdown(&priv->drm); in ingenic_drm_unbind()
984 struct device *dev = &pdev->dev; in ingenic_drm_probe()
992 np = of_graph_get_remote_node(dev->of_node, 8, 0); in ingenic_drm_probe()
1004 struct device *dev = &pdev->dev; in ingenic_drm_remove()
1036 { .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info },
1037 { .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info },
1038 { .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info },
1045 .name = "ingenic-drm",