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

1 // SPDX-License-Identifier: GPL-2.0
7 #include "ingenic-drm.h"
12 #include <linux/dma-mapping.h>
14 #include <linux/media-bus-format.h>
87 * f0 (aka. foreground0) can be overlayed. Z-order is fixed in
146 priv_state = drm_atomic_get_private_obj_state(state, &priv->private_obj); in ingenic_drm_get_priv_state()
158 priv_state = drm_atomic_get_new_private_obj_state(state, &priv->private_obj); in ingenic_drm_get_new_priv_state()
209 return priv->dma_hwdescs_phys + offset; in dma_hwdesc_addr()
220 mutex_lock(&priv->clk_mutex); in ingenic_drm_update_pixclk()
221 priv->update_clk_rate = true; in ingenic_drm_update_pixclk()
222 drm_crtc_wait_one_vblank(&priv->crtc); in ingenic_drm_update_pixclk()
225 mutex_unlock(&priv->clk_mutex); in ingenic_drm_update_pixclk()
233 struct ingenic_drm *priv = drm_device_get_priv(bridge->dev); in ingenic_drm_bridge_atomic_enable()
235 regmap_write(priv->map, JZ_REG_LCD_STATE, 0); in ingenic_drm_bridge_atomic_enable()
237 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_bridge_atomic_enable()
254 next_id = priv_state->use_palette ? HWDESC_PALETTE : 0; in ingenic_drm_crtc_atomic_enable()
255 regmap_write(priv->map, JZ_REG_LCD_DA0, dma_hwdesc_addr(priv, next_id)); in ingenic_drm_crtc_atomic_enable()
256 regmap_write(priv->map, JZ_REG_LCD_DA1, dma_hwdesc_addr(priv, 1)); in ingenic_drm_crtc_atomic_enable()
264 struct ingenic_drm *priv = drm_device_get_priv(bridge->dev); in ingenic_drm_bridge_atomic_disable()
267 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_bridge_atomic_disable()
270 regmap_read_poll_timeout(priv->map, JZ_REG_LCD_STATE, var, in ingenic_drm_bridge_atomic_disable()
286 vpe = mode->crtc_vsync_end - mode->crtc_vsync_start; in ingenic_drm_crtc_update_timings()
287 vds = mode->crtc_vtotal - mode->crtc_vsync_start; in ingenic_drm_crtc_update_timings()
288 vde = vds + mode->crtc_vdisplay; in ingenic_drm_crtc_update_timings()
289 vt = vde + mode->crtc_vsync_start - mode->crtc_vdisplay; in ingenic_drm_crtc_update_timings()
291 hpe = mode->crtc_hsync_end - mode->crtc_hsync_start; in ingenic_drm_crtc_update_timings()
292 hds = mode->crtc_htotal - mode->crtc_hsync_start; in ingenic_drm_crtc_update_timings()
293 hde = hds + mode->crtc_hdisplay; in ingenic_drm_crtc_update_timings()
294 ht = hde + mode->crtc_hsync_start - mode->crtc_hdisplay; in ingenic_drm_crtc_update_timings()
296 regmap_write(priv->map, JZ_REG_LCD_VSYNC, in ingenic_drm_crtc_update_timings()
300 regmap_write(priv->map, JZ_REG_LCD_HSYNC, in ingenic_drm_crtc_update_timings()
304 regmap_write(priv->map, JZ_REG_LCD_VAT, in ingenic_drm_crtc_update_timings()
308 regmap_write(priv->map, JZ_REG_LCD_DAH, in ingenic_drm_crtc_update_timings()
311 regmap_write(priv->map, JZ_REG_LCD_DAV, in ingenic_drm_crtc_update_timings()
315 if (priv->panel_is_sharp) { in ingenic_drm_crtc_update_timings()
316 regmap_write(priv->map, JZ_REG_LCD_PS, hde << 16 | (hde + 1)); in ingenic_drm_crtc_update_timings()
317 regmap_write(priv->map, JZ_REG_LCD_CLS, hde << 16 | (hde + 1)); in ingenic_drm_crtc_update_timings()
318 regmap_write(priv->map, JZ_REG_LCD_SPL, hpe << 16 | (hpe + 1)); in ingenic_drm_crtc_update_timings()
319 regmap_write(priv->map, JZ_REG_LCD_REV, mode->htotal << 16); in ingenic_drm_crtc_update_timings()
322 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_crtc_update_timings()
324 JZ_LCD_CTRL_OFUP | priv->soc_info->max_burst); in ingenic_drm_crtc_update_timings()
327 * IPU restart - specify how much time the LCDC will wait before in ingenic_drm_crtc_update_timings()
331 regmap_write(priv->map, JZ_REG_LCD_IPUR, JZ_LCD_IPUR_IPUREN | in ingenic_drm_crtc_update_timings()
343 if (crtc_state->gamma_lut && in ingenic_drm_crtc_atomic_check()
344 drm_color_lut_size(crtc_state->gamma_lut) != ARRAY_SIZE(priv->dma_hwdescs->palette)) { in ingenic_drm_crtc_atomic_check()
345 dev_dbg(priv->dev, "Invalid palette size\n"); in ingenic_drm_crtc_atomic_check()
346 return -EINVAL; in ingenic_drm_crtc_atomic_check()
349 if (drm_atomic_crtc_needs_modeset(crtc_state) && priv->soc_info->has_osd) { in ingenic_drm_crtc_atomic_check()
350 f1_state = drm_atomic_get_plane_state(crtc_state->state, in ingenic_drm_crtc_atomic_check()
351 &priv->f1); in ingenic_drm_crtc_atomic_check()
355 f0_state = drm_atomic_get_plane_state(crtc_state->state, in ingenic_drm_crtc_atomic_check()
356 &priv->f0); in ingenic_drm_crtc_atomic_check()
360 if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && priv->ipu_plane) { in ingenic_drm_crtc_atomic_check()
361 ipu_state = drm_atomic_get_plane_state(crtc_state->state, in ingenic_drm_crtc_atomic_check()
362 priv->ipu_plane); in ingenic_drm_crtc_atomic_check()
367 if (f1_state->fb && ipu_state->fb) { in ingenic_drm_crtc_atomic_check()
368 dev_dbg(priv->dev, "Cannot enable both F1 and IPU\n"); in ingenic_drm_crtc_atomic_check()
369 return -EINVAL; in ingenic_drm_crtc_atomic_check()
374 priv->no_vblank = !f1_state->fb && !f0_state->fb && in ingenic_drm_crtc_atomic_check()
375 !(ipu_state && ipu_state->fb); in ingenic_drm_crtc_atomic_check()
387 if (mode->hdisplay > priv->soc_info->max_width) in ingenic_drm_crtc_mode_valid()
389 if (mode->vdisplay > priv->soc_info->max_height) in ingenic_drm_crtc_mode_valid()
392 rate = clk_round_rate(priv->pix_clk, mode->clock * 1000); in ingenic_drm_crtc_mode_valid()
407 if (priv->soc_info->has_osd && in ingenic_drm_crtc_atomic_begin()
413 if (priv->ipu_plane && priv->ipu_plane->state->fb) in ingenic_drm_crtc_atomic_begin()
416 regmap_update_bits(priv->map, JZ_REG_LCD_OSDCTRL, in ingenic_drm_crtc_atomic_begin()
427 struct drm_pending_vblank_event *event = crtc_state->event; in ingenic_drm_crtc_atomic_flush()
430 ingenic_drm_crtc_update_timings(priv, &crtc_state->adjusted_mode); in ingenic_drm_crtc_atomic_flush()
431 priv->update_clk_rate = true; in ingenic_drm_crtc_atomic_flush()
434 if (priv->update_clk_rate) { in ingenic_drm_crtc_atomic_flush()
435 mutex_lock(&priv->clk_mutex); in ingenic_drm_crtc_atomic_flush()
436 clk_set_rate(priv->pix_clk, in ingenic_drm_crtc_atomic_flush()
437 crtc_state->adjusted_mode.crtc_clock * 1000); in ingenic_drm_crtc_atomic_flush()
438 priv->update_clk_rate = false; in ingenic_drm_crtc_atomic_flush()
439 mutex_unlock(&priv->clk_mutex); in ingenic_drm_crtc_atomic_flush()
443 crtc_state->event = NULL; in ingenic_drm_crtc_atomic_flush()
445 spin_lock_irq(&crtc->dev->event_lock); in ingenic_drm_crtc_atomic_flush()
450 spin_unlock_irq(&crtc->dev->event_lock); in ingenic_drm_crtc_atomic_flush()
461 struct ingenic_drm *priv = drm_device_get_priv(plane->dev); in ingenic_drm_plane_atomic_check()
464 struct drm_crtc *crtc = new_plane_state->crtc ?: old_plane_state->crtc; in ingenic_drm_plane_atomic_check()
470 if (priv->soc_info->plane_f0_not_working && plane == &priv->f0) in ingenic_drm_plane_atomic_check()
471 return -EINVAL; in ingenic_drm_plane_atomic_check()
476 return -EINVAL; in ingenic_drm_plane_atomic_check()
485 priv->soc_info->has_osd, in ingenic_drm_plane_atomic_check()
492 * Note that state->src_* are in 16.16 fixed-point format. in ingenic_drm_plane_atomic_check()
494 if (!priv->soc_info->has_osd && in ingenic_drm_plane_atomic_check()
495 (new_plane_state->src_x != 0 || in ingenic_drm_plane_atomic_check()
496 (new_plane_state->src_w >> 16) != new_plane_state->crtc_w || in ingenic_drm_plane_atomic_check()
497 (new_plane_state->src_h >> 16) != new_plane_state->crtc_h)) in ingenic_drm_plane_atomic_check()
498 return -EINVAL; in ingenic_drm_plane_atomic_check()
500 priv_state->use_palette = new_plane_state->fb && in ingenic_drm_plane_atomic_check()
501 new_plane_state->fb->format->format == DRM_FORMAT_C8; in ingenic_drm_plane_atomic_check()
507 if (priv->soc_info->has_osd && in ingenic_drm_plane_atomic_check()
508 (!old_plane_state->fb || !new_plane_state->fb || in ingenic_drm_plane_atomic_check()
509 old_plane_state->crtc_x != new_plane_state->crtc_x || in ingenic_drm_plane_atomic_check()
510 old_plane_state->crtc_y != new_plane_state->crtc_y || in ingenic_drm_plane_atomic_check()
511 old_plane_state->crtc_w != new_plane_state->crtc_w || in ingenic_drm_plane_atomic_check()
512 old_plane_state->crtc_h != new_plane_state->crtc_h || in ingenic_drm_plane_atomic_check()
513 old_plane_state->fb->format->format != new_plane_state->fb->format->format)) in ingenic_drm_plane_atomic_check()
514 crtc_state->mode_changed = true; in ingenic_drm_plane_atomic_check()
516 if (priv->soc_info->map_noncoherent) in ingenic_drm_plane_atomic_check()
527 if (priv->soc_info->has_osd) { in ingenic_drm_plane_enable()
528 if (plane != &priv->f0) in ingenic_drm_plane_enable()
533 regmap_set_bits(priv->map, JZ_REG_LCD_OSDC, en_bit); in ingenic_drm_plane_enable()
542 if (priv->soc_info->has_osd) { in ingenic_drm_plane_disable()
543 if (plane != &priv->f0) in ingenic_drm_plane_disable()
548 regmap_clear_bits(priv->map, JZ_REG_LCD_OSDC, en_bit); in ingenic_drm_plane_disable()
555 struct ingenic_drm *priv = drm_device_get_priv(plane->dev); in ingenic_drm_plane_atomic_disable()
557 ingenic_drm_plane_disable(priv->dev, plane); in ingenic_drm_plane_atomic_disable()
564 struct drm_plane_state *state = plane->state; in ingenic_drm_plane_config()
570 if (priv->soc_info->has_osd && plane != &priv->f0) { in ingenic_drm_plane_config()
589 regmap_update_bits(priv->map, JZ_REG_LCD_OSDCTRL, in ingenic_drm_plane_config()
613 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_plane_config()
617 if (priv->soc_info->has_osd) { in ingenic_drm_plane_config()
618 if (plane != &priv->f0) { in ingenic_drm_plane_config()
626 regmap_write(priv->map, xy_reg, in ingenic_drm_plane_config()
627 state->crtc_x << JZ_LCD_XYP01_XPOS_LSB | in ingenic_drm_plane_config()
628 state->crtc_y << JZ_LCD_XYP01_YPOS_LSB); in ingenic_drm_plane_config()
629 regmap_write(priv->map, size_reg, in ingenic_drm_plane_config()
630 state->crtc_w << JZ_LCD_SIZE01_WIDTH_LSB | in ingenic_drm_plane_config()
631 state->crtc_h << JZ_LCD_SIZE01_HEIGHT_LSB); in ingenic_drm_plane_config()
639 return priv->soc_info->map_noncoherent; in ingenic_drm_map_noncoherent()
647 for (i = 0; i < ARRAY_SIZE(priv->dma_hwdescs->palette); i++) { in ingenic_drm_update_palette()
652 priv->dma_hwdescs->palette[i] = color; in ingenic_drm_update_palette()
659 struct ingenic_drm *priv = drm_device_get_priv(plane->dev); in ingenic_drm_plane_atomic_update()
669 if (newstate && newstate->fb) { in ingenic_drm_plane_atomic_update()
670 if (priv->soc_info->map_noncoherent) in ingenic_drm_plane_atomic_update()
671 drm_fb_dma_sync_non_coherent(&priv->drm, oldstate, newstate); in ingenic_drm_plane_atomic_update()
673 crtc_state = newstate->crtc->state; in ingenic_drm_plane_atomic_update()
674 plane_id = !!(priv->soc_info->has_osd && plane != &priv->f0); in ingenic_drm_plane_atomic_update()
676 addr = drm_fb_dma_get_gem_addr(newstate->fb, newstate, 0); in ingenic_drm_plane_atomic_update()
677 width = newstate->src_w >> 16; in ingenic_drm_plane_atomic_update()
678 height = newstate->src_h >> 16; in ingenic_drm_plane_atomic_update()
679 cpp = newstate->fb->format->cpp[0]; in ingenic_drm_plane_atomic_update()
682 next_id = (priv_state && priv_state->use_palette) ? HWDESC_PALETTE : plane_id; in ingenic_drm_plane_atomic_update()
684 hwdesc = &priv->dma_hwdescs->hwdesc[plane_id]; in ingenic_drm_plane_atomic_update()
685 hwdesc->addr = addr; in ingenic_drm_plane_atomic_update()
686 hwdesc->cmd = JZ_LCD_CMD_EOF_IRQ | (width * height * cpp / 4); in ingenic_drm_plane_atomic_update()
687 hwdesc->next = dma_hwdesc_addr(priv, next_id); in ingenic_drm_plane_atomic_update()
689 if (priv->soc_info->use_extended_hwdesc) { in ingenic_drm_plane_atomic_update()
690 hwdesc->cmd |= JZ_LCD_CMD_FRM_ENABLE; in ingenic_drm_plane_atomic_update()
692 /* Extended 8-byte descriptor */ in ingenic_drm_plane_atomic_update()
693 hwdesc->cpos = 0; in ingenic_drm_plane_atomic_update()
694 hwdesc->offsize = 0; in ingenic_drm_plane_atomic_update()
695 hwdesc->pagewidth = 0; in ingenic_drm_plane_atomic_update()
697 switch (newstate->fb->format->format) { in ingenic_drm_plane_atomic_update()
699 hwdesc->cpos |= JZ_LCD_CPOS_RGB555; in ingenic_drm_plane_atomic_update()
702 hwdesc->cpos |= JZ_LCD_CPOS_BPP_15_16; in ingenic_drm_plane_atomic_update()
705 hwdesc->cpos |= JZ_LCD_CPOS_BPP_18_24; in ingenic_drm_plane_atomic_update()
708 hwdesc->cpos |= (JZ_LCD_CPOS_COEFFICIENT_1 << in ingenic_drm_plane_atomic_update()
710 hwdesc->dessize = in ingenic_drm_plane_atomic_update()
712 FIELD_PREP(JZ_LCD_DESSIZE_HEIGHT_MASK, height - 1) | in ingenic_drm_plane_atomic_update()
713 FIELD_PREP(JZ_LCD_DESSIZE_WIDTH_MASK, width - 1); in ingenic_drm_plane_atomic_update()
717 fourcc = newstate->fb->format->format; in ingenic_drm_plane_atomic_update()
719 ingenic_drm_plane_config(priv->dev, plane, fourcc); in ingenic_drm_plane_atomic_update()
721 crtc_state->color_mgmt_changed = fourcc == DRM_FORMAT_C8; in ingenic_drm_plane_atomic_update()
724 if (crtc_state->color_mgmt_changed) in ingenic_drm_plane_atomic_update()
725 ingenic_drm_update_palette(priv, crtc_state->gamma_lut->data); in ingenic_drm_plane_atomic_update()
733 struct ingenic_drm *priv = drm_device_get_priv(encoder->dev); in ingenic_drm_encoder_atomic_mode_set()
734 struct drm_display_mode *mode = &crtc_state->adjusted_mode; in ingenic_drm_encoder_atomic_mode_set()
738 priv->panel_is_sharp = bridge->bus_cfg.flags & DRM_BUS_FLAG_SHARP_SIGNALS; in ingenic_drm_encoder_atomic_mode_set()
740 if (priv->panel_is_sharp) { in ingenic_drm_encoder_atomic_mode_set()
747 if (priv->soc_info->use_extended_hwdesc) in ingenic_drm_encoder_atomic_mode_set()
750 if (mode->flags & DRM_MODE_FLAG_NHSYNC) in ingenic_drm_encoder_atomic_mode_set()
752 if (mode->flags & DRM_MODE_FLAG_NVSYNC) in ingenic_drm_encoder_atomic_mode_set()
754 if (bridge->bus_cfg.flags & DRM_BUS_FLAG_DE_LOW) in ingenic_drm_encoder_atomic_mode_set()
756 if (bridge->bus_cfg.flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) in ingenic_drm_encoder_atomic_mode_set()
759 if (!priv->panel_is_sharp) { in ingenic_drm_encoder_atomic_mode_set()
760 if (conn_state->connector->connector_type == DRM_MODE_CONNECTOR_TV) { in ingenic_drm_encoder_atomic_mode_set()
761 if (mode->flags & DRM_MODE_FLAG_INTERLACE) in ingenic_drm_encoder_atomic_mode_set()
766 switch (bridge->bus_cfg.format) { in ingenic_drm_encoder_atomic_mode_set()
788 regmap_write(priv->map, JZ_REG_LCD_CFG, cfg); in ingenic_drm_encoder_atomic_mode_set()
789 regmap_write(priv->map, JZ_REG_LCD_RGBC, rgbcfg); in ingenic_drm_encoder_atomic_mode_set()
795 struct ingenic_drm_bridge *ib = to_ingenic_drm_bridge(bridge->encoder); in ingenic_drm_bridge_attach()
797 return drm_bridge_attach(bridge->encoder, ib->next_bridge, in ingenic_drm_bridge_attach()
798 &ib->bridge, flags); in ingenic_drm_bridge_attach()
806 struct drm_display_mode *mode = &crtc_state->adjusted_mode; in ingenic_drm_bridge_atomic_check()
807 struct ingenic_drm_bridge *ib = to_ingenic_drm_bridge(bridge->encoder); in ingenic_drm_bridge_atomic_check()
809 ib->bus_cfg = bridge_state->output_bus_cfg; in ingenic_drm_bridge_atomic_check()
811 if (conn_state->connector->connector_type == DRM_MODE_CONNECTOR_TV) in ingenic_drm_bridge_atomic_check()
814 switch (bridge_state->output_bus_cfg.format) { in ingenic_drm_bridge_atomic_check()
818 * The LCD controller expects timing values in dot-clock ticks, in ingenic_drm_bridge_atomic_check()
819 * which is 3x the timing values in pixels when using a 3x8-bit in ingenic_drm_bridge_atomic_check()
823 mode->crtc_clock = mode->clock * 3; in ingenic_drm_bridge_atomic_check()
824 mode->crtc_hsync_start = mode->hsync_start * 3 - mode->hdisplay * 2; in ingenic_drm_bridge_atomic_check()
825 mode->crtc_hsync_end = mode->hsync_end * 3 - mode->hdisplay * 2; in ingenic_drm_bridge_atomic_check()
826 mode->crtc_hdisplay = mode->hdisplay; in ingenic_drm_bridge_atomic_check()
827 mode->crtc_htotal = mode->htotal * 3 - mode->hdisplay * 2; in ingenic_drm_bridge_atomic_check()
834 return -EINVAL; in ingenic_drm_bridge_atomic_check()
869 regmap_read(priv->map, JZ_REG_LCD_STATE, &state); in ingenic_drm_irq_handler()
871 regmap_update_bits(priv->map, JZ_REG_LCD_STATE, in ingenic_drm_irq_handler()
875 drm_crtc_handle_vblank(&priv->crtc); in ingenic_drm_irq_handler()
884 if (priv->no_vblank) in ingenic_drm_enable_vblank()
885 return -EINVAL; in ingenic_drm_enable_vblank()
887 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, in ingenic_drm_enable_vblank()
897 regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, JZ_LCD_CTRL_EOF_IRQ, 0); in ingenic_drm_disable_vblank()
906 if (priv->soc_info->map_noncoherent) in ingenic_drm_gem_fb_create()
920 return ERR_PTR(-ENOMEM); in ingenic_drm_gem_create_object()
922 obj->map_noncoherent = priv->soc_info->map_noncoherent; in ingenic_drm_gem_create_object()
924 return &obj->base; in ingenic_drm_gem_create_object()
930 struct ingenic_drm_private_state *state = to_ingenic_drm_priv_state(obj->state); in ingenic_drm_duplicate_state()
936 __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); in ingenic_drm_duplicate_state()
938 return &state->base; in ingenic_drm_duplicate_state()
953 .name = "ingenic-drm",
1037 component_unbind_all(priv->dev, &priv->drm); in ingenic_drm_unbind_all()
1049 struct ingenic_dma_hwdesc *desc = &priv->dma_hwdescs->hwdesc[hwdesc]; in ingenic_drm_configure_hwdesc()
1051 desc->next = dma_hwdesc_addr(priv, next_hwdesc); in ingenic_drm_configure_hwdesc()
1052 desc->id = id; in ingenic_drm_configure_hwdesc()
1061 desc = &priv->dma_hwdescs->hwdesc[HWDESC_PALETTE]; in ingenic_drm_configure_hwdesc_palette()
1062 desc->addr = priv->dma_hwdescs_phys in ingenic_drm_configure_hwdesc_palette()
1064 desc->cmd = JZ_LCD_CMD_ENABLE_PAL in ingenic_drm_configure_hwdesc_palette()
1065 | (sizeof(priv->dma_hwdescs->palette) / 4); in ingenic_drm_configure_hwdesc_palette()
1104 return -EINVAL; in ingenic_drm_bind()
1110 if (ret && ret != -ENODEV) in ingenic_drm_bind()
1125 priv->soc_info = soc_info; in ingenic_drm_bind()
1126 priv->dev = dev; in ingenic_drm_bind()
1127 drm = &priv->drm; in ingenic_drm_bind()
1135 drm->mode_config.min_width = 0; in ingenic_drm_bind()
1136 drm->mode_config.min_height = 0; in ingenic_drm_bind()
1137 drm->mode_config.max_width = soc_info->max_width; in ingenic_drm_bind()
1138 drm->mode_config.max_height = 4095; in ingenic_drm_bind()
1139 drm->mode_config.funcs = &ingenic_drm_mode_config_funcs; in ingenic_drm_bind()
1140 drm->mode_config.helper_private = &ingenic_drm_mode_config_helpers; in ingenic_drm_bind()
1150 regmap_config.max_register = res->end - res->start; in ingenic_drm_bind()
1151 priv->map = devm_regmap_init_mmio(dev, base, in ingenic_drm_bind()
1153 if (IS_ERR(priv->map)) { in ingenic_drm_bind()
1155 ret = PTR_ERR(priv->map); in ingenic_drm_bind()
1165 if (soc_info->needs_dev_clk) { in ingenic_drm_bind()
1166 priv->lcd_clk = devm_clk_get(dev, "lcd"); in ingenic_drm_bind()
1167 if (IS_ERR(priv->lcd_clk)) { in ingenic_drm_bind()
1168 dev_err(dev, "Failed to get lcd clock\n"); in ingenic_drm_bind()
1169 ret = PTR_ERR(priv->lcd_clk); in ingenic_drm_bind()
1174 priv->pix_clk = devm_clk_get(dev, "lcd_pclk"); in ingenic_drm_bind()
1175 if (IS_ERR(priv->pix_clk)) { in ingenic_drm_bind()
1177 ret = PTR_ERR(priv->pix_clk); in ingenic_drm_bind()
1181 priv->dma_hwdescs = dmam_alloc_coherent(dev, in ingenic_drm_bind()
1182 sizeof(*priv->dma_hwdescs), in ingenic_drm_bind()
1183 &priv->dma_hwdescs_phys, in ingenic_drm_bind()
1185 if (!priv->dma_hwdescs) { in ingenic_drm_bind()
1186 ret = -ENOMEM; in ingenic_drm_bind()
1199 primary = priv->soc_info->has_osd ? &priv->f1 : &priv->f0; in ingenic_drm_bind()
1205 priv->soc_info->formats_f1, in ingenic_drm_bind()
1206 priv->soc_info->num_formats_f1, in ingenic_drm_bind()
1213 if (soc_info->map_noncoherent) in ingenic_drm_bind()
1214 drm_plane_enable_fb_damage_clips(&priv->f1); in ingenic_drm_bind()
1216 drm_crtc_helper_add(&priv->crtc, &ingenic_drm_crtc_helper_funcs); in ingenic_drm_bind()
1218 ret = drm_crtc_init_with_planes(drm, &priv->crtc, primary, in ingenic_drm_bind()
1225 drm_crtc_enable_color_mgmt(&priv->crtc, 0, false, in ingenic_drm_bind()
1226 ARRAY_SIZE(priv->dma_hwdescs->palette)); in ingenic_drm_bind()
1228 if (soc_info->has_osd) { in ingenic_drm_bind()
1229 drm_plane_helper_add(&priv->f0, in ingenic_drm_bind()
1232 ret = drm_universal_plane_init(drm, &priv->f0, 1, in ingenic_drm_bind()
1234 priv->soc_info->formats_f0, in ingenic_drm_bind()
1235 priv->soc_info->num_formats_f0, in ingenic_drm_bind()
1244 if (soc_info->map_noncoherent) in ingenic_drm_bind()
1245 drm_plane_enable_fb_damage_clips(&priv->f0); in ingenic_drm_bind()
1250 if (ret != -EPROBE_DEFER) in ingenic_drm_bind()
1259 priv->ipu_plane = drm_plane_from_index(drm, 2); in ingenic_drm_bind()
1260 if (!priv->ipu_plane) { in ingenic_drm_bind()
1262 ret = -EINVAL; in ingenic_drm_bind()
1269 ret = drm_of_find_panel_or_bridge(dev->of_node, 0, i, &panel, &bridge); in ingenic_drm_bind()
1271 if (ret == -ENODEV) in ingenic_drm_bind()
1273 if (ret != -EPROBE_DEFER) in ingenic_drm_bind()
1290 encoder = &ib->encoder; in ingenic_drm_bind()
1291 encoder->possible_crtcs = drm_crtc_mask(&priv->crtc); in ingenic_drm_bind()
1295 ib->bridge.funcs = &ingenic_drm_bridge_funcs; in ingenic_drm_bind()
1296 ib->next_bridge = bridge; in ingenic_drm_bind()
1298 ret = drm_bridge_attach(encoder, &ib->bridge, NULL, in ingenic_drm_bind()
1320 encoder->possible_clones = clone_mask; in ingenic_drm_bind()
1323 ret = devm_request_irq(dev, irq, ingenic_drm_irq_handler, 0, drm->driver->name, drm); in ingenic_drm_bind()
1337 ret = clk_prepare_enable(priv->pix_clk); in ingenic_drm_bind()
1343 if (priv->lcd_clk) { in ingenic_drm_bind()
1344 parent_clk = clk_get_parent(priv->lcd_clk); in ingenic_drm_bind()
1347 /* LCD Device clock must be 3x the pixel clock for STN panels, in ingenic_drm_bind()
1349 * check for the LCD device clock everytime we do a mode change, in ingenic_drm_bind()
1350 * we set the LCD device clock to the highest rate possible. in ingenic_drm_bind()
1352 ret = clk_set_rate(priv->lcd_clk, parent_rate); in ingenic_drm_bind()
1354 dev_err(dev, "Unable to set LCD clock rate\n"); in ingenic_drm_bind()
1358 ret = clk_prepare_enable(priv->lcd_clk); in ingenic_drm_bind()
1360 dev_err(dev, "Unable to start lcd clock\n"); in ingenic_drm_bind()
1366 if (soc_info->has_osd) in ingenic_drm_bind()
1368 if (soc_info->has_alpha) in ingenic_drm_bind()
1370 regmap_write(priv->map, JZ_REG_LCD_OSDC, osdc); in ingenic_drm_bind()
1372 mutex_init(&priv->clk_mutex); in ingenic_drm_bind()
1373 priv->clock_nb.notifier_call = ingenic_drm_update_pixclk; in ingenic_drm_bind()
1375 parent_clk = clk_get_parent(priv->pix_clk); in ingenic_drm_bind()
1376 ret = clk_notifier_register(parent_clk, &priv->clock_nb); in ingenic_drm_bind()
1384 ret = -ENOMEM; in ingenic_drm_bind()
1388 drm_atomic_private_obj_init(drm, &priv->private_obj, &private_state->base, in ingenic_drm_bind()
1392 &priv->private_obj); in ingenic_drm_bind()
1409 clk_notifier_unregister(parent_clk, &priv->clock_nb); in ingenic_drm_bind()
1411 if (priv->lcd_clk) in ingenic_drm_bind()
1412 clk_disable_unprepare(priv->lcd_clk); in ingenic_drm_bind()
1414 clk_disable_unprepare(priv->pix_clk); in ingenic_drm_bind()
1428 struct clk *parent_clk = clk_get_parent(priv->pix_clk); in ingenic_drm_unbind()
1430 clk_notifier_unregister(parent_clk, &priv->clock_nb); in ingenic_drm_unbind()
1431 if (priv->lcd_clk) in ingenic_drm_unbind()
1432 clk_disable_unprepare(priv->lcd_clk); in ingenic_drm_unbind()
1433 clk_disable_unprepare(priv->pix_clk); in ingenic_drm_unbind()
1435 drm_dev_unregister(&priv->drm); in ingenic_drm_unbind()
1436 drm_atomic_helper_shutdown(&priv->drm); in ingenic_drm_unbind()
1447 struct device *dev = &pdev->dev; in ingenic_drm_probe()
1455 np = of_graph_get_remote_node(dev->of_node, 8, 0); in ingenic_drm_probe()
1467 struct device *dev = &pdev->dev; in ingenic_drm_remove()
1480 drm_atomic_helper_shutdown(&priv->drm); in ingenic_drm_shutdown()
1487 return drm_mode_config_helper_suspend(&priv->drm); in ingenic_drm_suspend()
1494 return drm_mode_config_helper_resume(&priv->drm); in ingenic_drm_resume()
1545 /* JZ4740 has only one plane */
1616 { .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info },
1617 { .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info },
1618 { .compatible = "ingenic,jz4760-lcd", .data = &jz4760_soc_info },
1619 { .compatible = "ingenic,jz4760b-lcd", .data = &jz4760b_soc_info },
1620 { .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info },
1621 { .compatible = "ingenic,jz4780-lcd", .data = &jz4780_soc_info },
1628 .name = "ingenic-drm",
1642 return -ENODEV; in ingenic_drm_init()