Lines Matching +full:jz4740 +full:- +full:lcd

1 // SPDX-License-Identifier: GPL-2.0
7 #include "ingenic-drm.h"
11 #include <linux/dma-mapping.h>
56 * f0 (aka. foreground0) can be overlayed. Z-order is fixed in
143 mutex_lock(&priv->clk_mutex); in ingenic_drm_update_pixclk()
144 priv->update_clk_rate = true; in ingenic_drm_update_pixclk()
145 drm_crtc_wait_one_vblank(&priv->crtc); in ingenic_drm_update_pixclk()
148 mutex_unlock(&priv->clk_mutex); in ingenic_drm_update_pixclk()
158 regmap_write(priv->map, JZ_REG_LCD_STATE, 0); in ingenic_drm_crtc_atomic_enable()
160 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_crtc_atomic_enable()
175 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_crtc_atomic_disable()
178 regmap_read_poll_timeout(priv->map, JZ_REG_LCD_STATE, var, in ingenic_drm_crtc_atomic_disable()
188 vpe = mode->vsync_end - mode->vsync_start; in ingenic_drm_crtc_update_timings()
189 vds = mode->vtotal - mode->vsync_start; in ingenic_drm_crtc_update_timings()
190 vde = vds + mode->vdisplay; in ingenic_drm_crtc_update_timings()
191 vt = vde + mode->vsync_start - mode->vdisplay; in ingenic_drm_crtc_update_timings()
193 hpe = mode->hsync_end - mode->hsync_start; in ingenic_drm_crtc_update_timings()
194 hds = mode->htotal - mode->hsync_start; in ingenic_drm_crtc_update_timings()
195 hde = hds + mode->hdisplay; in ingenic_drm_crtc_update_timings()
196 ht = hde + mode->hsync_start - mode->hdisplay; in ingenic_drm_crtc_update_timings()
198 regmap_write(priv->map, JZ_REG_LCD_VSYNC, in ingenic_drm_crtc_update_timings()
202 regmap_write(priv->map, JZ_REG_LCD_HSYNC, in ingenic_drm_crtc_update_timings()
206 regmap_write(priv->map, JZ_REG_LCD_VAT, in ingenic_drm_crtc_update_timings()
210 regmap_write(priv->map, JZ_REG_LCD_DAH, in ingenic_drm_crtc_update_timings()
213 regmap_write(priv->map, JZ_REG_LCD_DAV, in ingenic_drm_crtc_update_timings()
217 if (priv->panel_is_sharp) { in ingenic_drm_crtc_update_timings()
218 regmap_write(priv->map, JZ_REG_LCD_PS, hde << 16 | (hde + 1)); in ingenic_drm_crtc_update_timings()
219 regmap_write(priv->map, JZ_REG_LCD_CLS, hde << 16 | (hde + 1)); in ingenic_drm_crtc_update_timings()
220 regmap_write(priv->map, JZ_REG_LCD_SPL, hpe << 16 | (hpe + 1)); in ingenic_drm_crtc_update_timings()
221 regmap_write(priv->map, JZ_REG_LCD_REV, mode->htotal << 16); in ingenic_drm_crtc_update_timings()
224 regmap_set_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_crtc_update_timings()
228 * IPU restart - specify how much time the LCDC will wait before in ingenic_drm_crtc_update_timings()
232 regmap_write(priv->map, JZ_REG_LCD_IPUR, JZ_LCD_IPUR_IPUREN | in ingenic_drm_crtc_update_timings()
242 if (drm_atomic_crtc_needs_modeset(state) && priv->soc_info->has_osd) { in ingenic_drm_crtc_atomic_check()
243 f1_state = drm_atomic_get_plane_state(state->state, &priv->f1); in ingenic_drm_crtc_atomic_check()
247 f0_state = drm_atomic_get_plane_state(state->state, &priv->f0); in ingenic_drm_crtc_atomic_check()
251 if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && priv->ipu_plane) { in ingenic_drm_crtc_atomic_check()
252 ipu_state = drm_atomic_get_plane_state(state->state, priv->ipu_plane); in ingenic_drm_crtc_atomic_check()
257 if (f1_state->fb && ipu_state->fb) { in ingenic_drm_crtc_atomic_check()
258 dev_dbg(priv->dev, "Cannot enable both F1 and IPU\n"); in ingenic_drm_crtc_atomic_check()
259 return -EINVAL; in ingenic_drm_crtc_atomic_check()
264 priv->no_vblank = !f1_state->fb && !f0_state->fb && in ingenic_drm_crtc_atomic_check()
265 !(ipu_state && ipu_state->fb); in ingenic_drm_crtc_atomic_check()
277 if (mode->hdisplay > priv->soc_info->max_width) in ingenic_drm_crtc_mode_valid()
279 if (mode->vdisplay > priv->soc_info->max_height) in ingenic_drm_crtc_mode_valid()
282 rate = clk_round_rate(priv->pix_clk, mode->clock * 1000); in ingenic_drm_crtc_mode_valid()
295 if (priv->soc_info->has_osd && in ingenic_drm_crtc_atomic_begin()
296 drm_atomic_crtc_needs_modeset(crtc->state)) { in ingenic_drm_crtc_atomic_begin()
301 if (priv->ipu_plane && priv->ipu_plane->state->fb) in ingenic_drm_crtc_atomic_begin()
304 regmap_update_bits(priv->map, JZ_REG_LCD_OSDCTRL, in ingenic_drm_crtc_atomic_begin()
313 struct drm_crtc_state *state = crtc->state; in ingenic_drm_crtc_atomic_flush()
314 struct drm_pending_vblank_event *event = state->event; in ingenic_drm_crtc_atomic_flush()
317 ingenic_drm_crtc_update_timings(priv, &state->mode); in ingenic_drm_crtc_atomic_flush()
318 priv->update_clk_rate = true; in ingenic_drm_crtc_atomic_flush()
321 if (priv->update_clk_rate) { in ingenic_drm_crtc_atomic_flush()
322 mutex_lock(&priv->clk_mutex); in ingenic_drm_crtc_atomic_flush()
323 clk_set_rate(priv->pix_clk, state->adjusted_mode.clock * 1000); in ingenic_drm_crtc_atomic_flush()
324 priv->update_clk_rate = false; in ingenic_drm_crtc_atomic_flush()
325 mutex_unlock(&priv->clk_mutex); in ingenic_drm_crtc_atomic_flush()
329 state->event = NULL; in ingenic_drm_crtc_atomic_flush()
331 spin_lock_irq(&crtc->dev->event_lock); in ingenic_drm_crtc_atomic_flush()
336 spin_unlock_irq(&crtc->dev->event_lock); in ingenic_drm_crtc_atomic_flush()
343 struct ingenic_drm *priv = drm_device_get_priv(plane->dev); in ingenic_drm_plane_atomic_check()
345 struct drm_crtc *crtc = state->crtc ?: plane->state->crtc; in ingenic_drm_plane_atomic_check()
351 crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); in ingenic_drm_plane_atomic_check()
353 return -EINVAL; in ingenic_drm_plane_atomic_check()
358 priv->soc_info->has_osd, in ingenic_drm_plane_atomic_check()
365 * Note that state->src_* are in 16.16 fixed-point format. in ingenic_drm_plane_atomic_check()
367 if (!priv->soc_info->has_osd && in ingenic_drm_plane_atomic_check()
368 (state->src_x != 0 || in ingenic_drm_plane_atomic_check()
369 (state->src_w >> 16) != state->crtc_w || in ingenic_drm_plane_atomic_check()
370 (state->src_h >> 16) != state->crtc_h)) in ingenic_drm_plane_atomic_check()
371 return -EINVAL; in ingenic_drm_plane_atomic_check()
377 if (priv->soc_info->has_osd && in ingenic_drm_plane_atomic_check()
378 (!plane->state->fb || !state->fb || in ingenic_drm_plane_atomic_check()
379 plane->state->crtc_x != state->crtc_x || in ingenic_drm_plane_atomic_check()
380 plane->state->crtc_y != state->crtc_y || in ingenic_drm_plane_atomic_check()
381 plane->state->crtc_w != state->crtc_w || in ingenic_drm_plane_atomic_check()
382 plane->state->crtc_h != state->crtc_h || in ingenic_drm_plane_atomic_check()
383 plane->state->fb->format->format != state->fb->format->format)) in ingenic_drm_plane_atomic_check()
384 crtc_state->mode_changed = true; in ingenic_drm_plane_atomic_check()
394 if (priv->soc_info->has_osd) { in ingenic_drm_plane_enable()
395 if (plane != &priv->f0) in ingenic_drm_plane_enable()
400 regmap_set_bits(priv->map, JZ_REG_LCD_OSDC, en_bit); in ingenic_drm_plane_enable()
409 if (priv->soc_info->has_osd) { in ingenic_drm_plane_disable()
410 if (plane != &priv->f0) in ingenic_drm_plane_disable()
415 regmap_clear_bits(priv->map, JZ_REG_LCD_OSDC, en_bit); in ingenic_drm_plane_disable()
422 struct ingenic_drm *priv = drm_device_get_priv(plane->dev); in ingenic_drm_plane_atomic_disable()
424 ingenic_drm_plane_disable(priv->dev, plane); in ingenic_drm_plane_atomic_disable()
431 struct drm_plane_state *state = plane->state; in ingenic_drm_plane_config()
437 if (priv->soc_info->has_osd && plane != &priv->f0) { in ingenic_drm_plane_config()
450 regmap_update_bits(priv->map, JZ_REG_LCD_OSDCTRL, in ingenic_drm_plane_config()
465 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_plane_config()
469 if (priv->soc_info->has_osd) { in ingenic_drm_plane_config()
470 if (plane != &priv->f0) { in ingenic_drm_plane_config()
478 regmap_write(priv->map, xy_reg, in ingenic_drm_plane_config()
479 state->crtc_x << JZ_LCD_XYP01_XPOS_LSB | in ingenic_drm_plane_config()
480 state->crtc_y << JZ_LCD_XYP01_YPOS_LSB); in ingenic_drm_plane_config()
481 regmap_write(priv->map, size_reg, in ingenic_drm_plane_config()
482 state->crtc_w << JZ_LCD_SIZE01_WIDTH_LSB | in ingenic_drm_plane_config()
483 state->crtc_h << JZ_LCD_SIZE01_HEIGHT_LSB); in ingenic_drm_plane_config()
490 struct ingenic_drm *priv = drm_device_get_priv(plane->dev); in ingenic_drm_plane_atomic_update()
491 struct drm_plane_state *state = plane->state; in ingenic_drm_plane_atomic_update()
496 if (state && state->fb) { in ingenic_drm_plane_atomic_update()
497 addr = drm_fb_cma_get_gem_addr(state->fb, state, 0); in ingenic_drm_plane_atomic_update()
498 width = state->src_w >> 16; in ingenic_drm_plane_atomic_update()
499 height = state->src_h >> 16; in ingenic_drm_plane_atomic_update()
500 cpp = state->fb->format->cpp[0]; in ingenic_drm_plane_atomic_update()
502 if (!priv->soc_info->has_osd || plane == &priv->f0) in ingenic_drm_plane_atomic_update()
503 hwdesc = priv->dma_hwdesc_f0; in ingenic_drm_plane_atomic_update()
505 hwdesc = priv->dma_hwdesc_f1; in ingenic_drm_plane_atomic_update()
507 hwdesc->addr = addr; in ingenic_drm_plane_atomic_update()
508 hwdesc->cmd = JZ_LCD_CMD_EOF_IRQ | (width * height * cpp / 4); in ingenic_drm_plane_atomic_update()
510 if (drm_atomic_crtc_needs_modeset(state->crtc->state)) in ingenic_drm_plane_atomic_update()
511 ingenic_drm_plane_config(priv->dev, plane, in ingenic_drm_plane_atomic_update()
512 state->fb->format->format); in ingenic_drm_plane_atomic_update()
520 struct ingenic_drm *priv = drm_device_get_priv(encoder->dev); in ingenic_drm_encoder_atomic_mode_set()
521 struct drm_display_mode *mode = &crtc_state->adjusted_mode; in ingenic_drm_encoder_atomic_mode_set()
522 struct drm_connector *conn = conn_state->connector; in ingenic_drm_encoder_atomic_mode_set()
523 struct drm_display_info *info = &conn->display_info; in ingenic_drm_encoder_atomic_mode_set()
526 priv->panel_is_sharp = info->bus_flags & DRM_BUS_FLAG_SHARP_SIGNALS; in ingenic_drm_encoder_atomic_mode_set()
528 if (priv->panel_is_sharp) { in ingenic_drm_encoder_atomic_mode_set()
535 if (mode->flags & DRM_MODE_FLAG_NHSYNC) in ingenic_drm_encoder_atomic_mode_set()
537 if (mode->flags & DRM_MODE_FLAG_NVSYNC) in ingenic_drm_encoder_atomic_mode_set()
539 if (info->bus_flags & DRM_BUS_FLAG_DE_LOW) in ingenic_drm_encoder_atomic_mode_set()
541 if (info->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) in ingenic_drm_encoder_atomic_mode_set()
544 if (!priv->panel_is_sharp) { in ingenic_drm_encoder_atomic_mode_set()
545 if (conn->connector_type == DRM_MODE_CONNECTOR_TV) { in ingenic_drm_encoder_atomic_mode_set()
546 if (mode->flags & DRM_MODE_FLAG_INTERLACE) in ingenic_drm_encoder_atomic_mode_set()
551 switch (*info->bus_formats) { in ingenic_drm_encoder_atomic_mode_set()
570 regmap_write(priv->map, JZ_REG_LCD_CFG, cfg); in ingenic_drm_encoder_atomic_mode_set()
577 struct drm_display_info *info = &conn_state->connector->display_info; in ingenic_drm_encoder_atomic_check()
579 if (info->num_bus_formats != 1) in ingenic_drm_encoder_atomic_check()
580 return -EINVAL; in ingenic_drm_encoder_atomic_check()
582 if (conn_state->connector->connector_type == DRM_MODE_CONNECTOR_TV) in ingenic_drm_encoder_atomic_check()
585 switch (*info->bus_formats) { in ingenic_drm_encoder_atomic_check()
592 return -EINVAL; in ingenic_drm_encoder_atomic_check()
600 * drm_atomic_helper_wait_for_vblanks() if priv->no_vblank. in ingenic_drm_atomic_helper_commit_tail()
602 struct drm_device *dev = old_state->dev; in ingenic_drm_atomic_helper_commit_tail()
613 if (!priv->no_vblank) in ingenic_drm_atomic_helper_commit_tail()
624 regmap_read(priv->map, JZ_REG_LCD_STATE, &state); in ingenic_drm_irq_handler()
626 regmap_update_bits(priv->map, JZ_REG_LCD_STATE, in ingenic_drm_irq_handler()
630 drm_crtc_handle_vblank(&priv->crtc); in ingenic_drm_irq_handler()
639 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_enable_vblank()
649 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, JZ_LCD_CTRL_EOF_IRQ, 0); in ingenic_drm_disable_vblank()
656 .name = "ingenic-drm",
730 component_unbind_all(priv->dev, &priv->drm); in ingenic_drm_unbind_all()
752 return -EINVAL; in ingenic_drm_bind()
760 priv->soc_info = soc_info; in ingenic_drm_bind()
761 priv->dev = dev; in ingenic_drm_bind()
762 drm = &priv->drm; in ingenic_drm_bind()
770 drm->mode_config.min_width = 0; in ingenic_drm_bind()
771 drm->mode_config.min_height = 0; in ingenic_drm_bind()
772 drm->mode_config.max_width = soc_info->max_width; in ingenic_drm_bind()
773 drm->mode_config.max_height = 4095; in ingenic_drm_bind()
774 drm->mode_config.funcs = &ingenic_drm_mode_config_funcs; in ingenic_drm_bind()
775 drm->mode_config.helper_private = &ingenic_drm_mode_config_helpers; in ingenic_drm_bind()
783 priv->map = devm_regmap_init_mmio(dev, base, in ingenic_drm_bind()
785 if (IS_ERR(priv->map)) { in ingenic_drm_bind()
787 return PTR_ERR(priv->map); in ingenic_drm_bind()
794 if (soc_info->needs_dev_clk) { in ingenic_drm_bind()
795 priv->lcd_clk = devm_clk_get(dev, "lcd"); in ingenic_drm_bind()
796 if (IS_ERR(priv->lcd_clk)) { in ingenic_drm_bind()
797 dev_err(dev, "Failed to get lcd clock\n"); in ingenic_drm_bind()
798 return PTR_ERR(priv->lcd_clk); in ingenic_drm_bind()
802 priv->pix_clk = devm_clk_get(dev, "lcd_pclk"); in ingenic_drm_bind()
803 if (IS_ERR(priv->pix_clk)) { in ingenic_drm_bind()
805 return PTR_ERR(priv->pix_clk); in ingenic_drm_bind()
808 priv->dma_hwdesc_f1 = dmam_alloc_coherent(dev, sizeof(*priv->dma_hwdesc_f1), in ingenic_drm_bind()
809 &priv->dma_hwdesc_phys_f1, in ingenic_drm_bind()
811 if (!priv->dma_hwdesc_f1) in ingenic_drm_bind()
812 return -ENOMEM; in ingenic_drm_bind()
814 priv->dma_hwdesc_f1->next = priv->dma_hwdesc_phys_f1; in ingenic_drm_bind()
815 priv->dma_hwdesc_f1->id = 0xf1; in ingenic_drm_bind()
817 if (priv->soc_info->has_osd) { in ingenic_drm_bind()
818 priv->dma_hwdesc_f0 = dmam_alloc_coherent(dev, in ingenic_drm_bind()
819 sizeof(*priv->dma_hwdesc_f0), in ingenic_drm_bind()
820 &priv->dma_hwdesc_phys_f0, in ingenic_drm_bind()
822 if (!priv->dma_hwdesc_f0) in ingenic_drm_bind()
823 return -ENOMEM; in ingenic_drm_bind()
825 priv->dma_hwdesc_f0->next = priv->dma_hwdesc_phys_f0; in ingenic_drm_bind()
826 priv->dma_hwdesc_f0->id = 0xf0; in ingenic_drm_bind()
829 if (soc_info->has_osd) in ingenic_drm_bind()
830 priv->ipu_plane = drm_plane_from_index(drm, 0); in ingenic_drm_bind()
832 primary = priv->soc_info->has_osd ? &priv->f1 : &priv->f0; in ingenic_drm_bind()
846 drm_crtc_helper_add(&priv->crtc, &ingenic_drm_crtc_helper_funcs); in ingenic_drm_bind()
848 ret = drm_crtc_init_with_planes(drm, &priv->crtc, primary, in ingenic_drm_bind()
855 if (soc_info->has_osd) { in ingenic_drm_bind()
856 drm_plane_helper_add(&priv->f0, in ingenic_drm_bind()
859 ret = drm_universal_plane_init(drm, &priv->f0, 1, in ingenic_drm_bind()
874 if (ret != -EPROBE_DEFER) in ingenic_drm_bind()
883 priv->ipu_plane = drm_plane_from_index(drm, 2); in ingenic_drm_bind()
884 if (!priv->ipu_plane) { in ingenic_drm_bind()
886 return -EINVAL; in ingenic_drm_bind()
892 ret = drm_of_find_panel_or_bridge(dev->of_node, 0, i, &panel, &bridge); in ingenic_drm_bind()
894 if (ret == -ENODEV) in ingenic_drm_bind()
896 if (ret != -EPROBE_DEFER) in ingenic_drm_bind()
907 return -ENOMEM; in ingenic_drm_bind()
909 encoder->possible_crtcs = 1; in ingenic_drm_bind()
931 encoder->possible_clones = clone_mask; in ingenic_drm_bind()
948 ret = clk_prepare_enable(priv->pix_clk); in ingenic_drm_bind()
954 if (priv->lcd_clk) { in ingenic_drm_bind()
955 parent_clk = clk_get_parent(priv->lcd_clk); in ingenic_drm_bind()
958 /* LCD Device clock must be 3x the pixel clock for STN panels, in ingenic_drm_bind()
960 * check for the LCD device clock everytime we do a mode change, in ingenic_drm_bind()
961 * we set the LCD device clock to the highest rate possible. in ingenic_drm_bind()
963 ret = clk_set_rate(priv->lcd_clk, parent_rate); in ingenic_drm_bind()
965 dev_err(dev, "Unable to set LCD clock rate\n"); in ingenic_drm_bind()
969 ret = clk_prepare_enable(priv->lcd_clk); in ingenic_drm_bind()
971 dev_err(dev, "Unable to start lcd clock\n"); in ingenic_drm_bind()
977 regmap_write(priv->map, JZ_REG_LCD_DA0, priv->dma_hwdesc_phys_f0); in ingenic_drm_bind()
978 regmap_write(priv->map, JZ_REG_LCD_DA1, priv->dma_hwdesc_phys_f1); in ingenic_drm_bind()
981 if (soc_info->has_osd) in ingenic_drm_bind()
982 regmap_write(priv->map, JZ_REG_LCD_OSDC, JZ_LCD_OSDC_OSDEN); in ingenic_drm_bind()
984 mutex_init(&priv->clk_mutex); in ingenic_drm_bind()
985 priv->clock_nb.notifier_call = ingenic_drm_update_pixclk; in ingenic_drm_bind()
987 parent_clk = clk_get_parent(priv->pix_clk); in ingenic_drm_bind()
988 ret = clk_notifier_register(parent_clk, &priv->clock_nb); in ingenic_drm_bind()
1005 clk_notifier_unregister(parent_clk, &priv->clock_nb); in ingenic_drm_bind()
1007 if (priv->lcd_clk) in ingenic_drm_bind()
1008 clk_disable_unprepare(priv->lcd_clk); in ingenic_drm_bind()
1010 clk_disable_unprepare(priv->pix_clk); in ingenic_drm_bind()
1021 return dev->of_node == data; in compare_of()
1027 struct clk *parent_clk = clk_get_parent(priv->pix_clk); in ingenic_drm_unbind()
1029 clk_notifier_unregister(parent_clk, &priv->clock_nb); in ingenic_drm_unbind()
1030 if (priv->lcd_clk) in ingenic_drm_unbind()
1031 clk_disable_unprepare(priv->lcd_clk); in ingenic_drm_unbind()
1032 clk_disable_unprepare(priv->pix_clk); in ingenic_drm_unbind()
1034 drm_dev_unregister(&priv->drm); in ingenic_drm_unbind()
1035 drm_atomic_helper_shutdown(&priv->drm); in ingenic_drm_unbind()
1045 struct device *dev = &pdev->dev; in ingenic_drm_probe()
1053 np = of_graph_get_remote_node(dev->of_node, 8, 0); in ingenic_drm_probe()
1065 struct device *dev = &pdev->dev; in ingenic_drm_remove()
1097 { .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info },
1098 { .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info },
1099 { .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info },
1106 .name = "ingenic-drm",