Lines Matching +full:bcm2835 +full:- +full:hdmi

1 // SPDX-License-Identifier: GPL-2.0-only
21 * image domain can feed either HDMI or the SDTV controller. The
22 * pixel valve chooses from the CPRMAN clocks (HSM for HDMI, VEC for
27 * output-specific clock. Since the encoders also directly consume
49 #define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset))
50 #define CRTC_READ(offset) readl(vc4_crtc->regs + (offset))
72 /* Top/base are supposed to be 4-pixel aligned, but the in vc4_crtc_get_cob_allocation()
79 return top - base + 4; in vc4_crtc_get_cob_allocation()
88 struct drm_device *dev = crtc->dev; in vc4_crtc_get_scanout_position()
91 struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state); in vc4_crtc_get_scanout_position()
108 val = HVS_READ(SCALER_DISPSTATX(vc4_crtc_state->assigned_channel)); in vc4_crtc_get_scanout_position()
120 if (mode->flags & DRM_MODE_FLAG_INTERLACE) { in vc4_crtc_get_scanout_position()
125 *hpos += mode->crtc_htotal / 2; in vc4_crtc_get_scanout_position()
128 cob_size = vc4_crtc_get_cob_allocation(vc4, vc4_crtc_state->assigned_channel); in vc4_crtc_get_scanout_position()
129 /* This is the offset we need for translating hvs -> pv scanout pos. */ in vc4_crtc_get_scanout_position()
130 fifo_lines = cob_size / mode->crtc_hdisplay; in vc4_crtc_get_scanout_position()
145 * incrementing vpos. Therefore we choose HVS read position - in vc4_crtc_get_scanout_position()
149 *vpos -= fifo_lines + 1; in vc4_crtc_get_scanout_position()
157 * fifo with new lines from the top-most lines of the new framebuffers. in vc4_crtc_get_scanout_position()
163 vblank_lines = mode->vtotal - mode->vdisplay; in vc4_crtc_get_scanout_position()
175 *vpos = -vblank_lines; in vc4_crtc_get_scanout_position()
178 *stime = vc4_crtc->t_vblank; in vc4_crtc_get_scanout_position()
180 *etime = vc4_crtc->t_vblank; in vc4_crtc_get_scanout_position()
213 u32 fifo_len_bytes = pv_data->fifo_depth; in vc4_get_fifo_full_level()
228 return fifo_len_bytes - 2 * HVS_FIFO_LATENCY_PIX; in vc4_get_fifo_full_level()
230 return fifo_len_bytes - 14; in vc4_get_fifo_full_level()
238 if (crtc_data->hvs_output == 5) in vc4_get_fifo_full_level()
241 return fifo_len_bytes - 3 * HVS_FIFO_LATENCY_PIX; in vc4_get_fifo_full_level()
270 drm_connector_list_iter_begin(crtc->dev, &conn_iter); in vc4_get_crtc_encoder()
272 if (connector->state->crtc == crtc) { in vc4_get_crtc_encoder()
274 return connector->encoder; in vc4_get_crtc_encoder()
293 struct drm_device *dev = crtc->dev; in vc4_crtc_config_pv()
299 struct drm_crtc_state *state = crtc->state; in vc4_crtc_config_pv()
300 struct drm_display_mode *mode = &state->adjusted_mode; in vc4_crtc_config_pv()
301 bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; in vc4_crtc_config_pv()
302 u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1; in vc4_crtc_config_pv()
303 bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 || in vc4_crtc_config_pv()
304 vc4_encoder->type == VC4_ENCODER_TYPE_DSI1); in vc4_crtc_config_pv()
306 u8 ppc = pv_data->pixels_per_clock; in vc4_crtc_config_pv()
310 struct drm_printer p = drm_info_printer(&vc4_crtc->pdev->dev); in vc4_crtc_config_pv()
311 dev_info(&vc4_crtc->pdev->dev, "CRTC %d regs before:\n", in vc4_crtc_config_pv()
313 drm_print_regset32(&p, &vc4_crtc->regset); in vc4_crtc_config_pv()
319 VC4_SET_FIELD((mode->htotal - mode->hsync_end) * pixel_rep / ppc, in vc4_crtc_config_pv()
321 VC4_SET_FIELD((mode->hsync_end - mode->hsync_start) * pixel_rep / ppc, in vc4_crtc_config_pv()
325 VC4_SET_FIELD((mode->hsync_start - mode->hdisplay) * pixel_rep / ppc, in vc4_crtc_config_pv()
327 VC4_SET_FIELD(mode->hdisplay * pixel_rep / ppc, in vc4_crtc_config_pv()
331 VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end, in vc4_crtc_config_pv()
333 VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start, in vc4_crtc_config_pv()
336 VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay, in vc4_crtc_config_pv()
338 VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE)); in vc4_crtc_config_pv()
342 VC4_SET_FIELD(mode->crtc_vtotal - in vc4_crtc_config_pv()
343 mode->crtc_vsync_end - 1, in vc4_crtc_config_pv()
345 VC4_SET_FIELD(mode->crtc_vsync_end - in vc4_crtc_config_pv()
346 mode->crtc_vsync_start, in vc4_crtc_config_pv()
349 VC4_SET_FIELD(mode->crtc_vsync_start - in vc4_crtc_config_pv()
350 mode->crtc_vdisplay, in vc4_crtc_config_pv()
352 VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE)); in vc4_crtc_config_pv()
354 /* We set up first field even mode for HDMI. VEC's in vc4_crtc_config_pv()
363 VC4_SET_FIELD(mode->htotal * pixel_rep / 2, in vc4_crtc_config_pv()
373 CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); in vc4_crtc_config_pv()
375 if (vc4->hvs->hvs5) in vc4_crtc_config_pv()
383 VC4_SET_FIELD(pixel_rep - 1, PV_CONTROL_PIXEL_REP) | in vc4_crtc_config_pv()
387 VC4_SET_FIELD(vc4_encoder->clock_select, in vc4_crtc_config_pv()
391 struct drm_printer p = drm_info_printer(&vc4_crtc->pdev->dev); in vc4_crtc_config_pv()
392 dev_info(&vc4_crtc->pdev->dev, "CRTC %d regs after:\n", in vc4_crtc_config_pv()
394 drm_print_regset32(&p, &vc4_crtc->regset); in vc4_crtc_config_pv()
411 struct drm_device *dev = crtc->dev; in vc4_crtc_disable()
421 * unflushable FIFO between the pixelvalve and the HDMI in vc4_crtc_disable()
437 if (vc4_encoder && vc4_encoder->post_crtc_disable) in vc4_crtc_disable()
438 vc4_encoder->post_crtc_disable(encoder); in vc4_crtc_disable()
443 if (vc4_encoder && vc4_encoder->post_crtc_powerdown) in vc4_crtc_disable()
444 vc4_encoder->post_crtc_powerdown(encoder); in vc4_crtc_disable()
451 struct drm_device *drm = crtc->dev; in vc4_crtc_disable_at_boot()
455 if (!(of_device_is_compatible(vc4_crtc->pdev->dev.of_node, in vc4_crtc_disable_at_boot()
456 "brcm,bcm2711-pixelvalve2") || in vc4_crtc_disable_at_boot()
457 of_device_is_compatible(vc4_crtc->pdev->dev.of_node, in vc4_crtc_disable_at_boot()
458 "brcm,bcm2711-pixelvalve4"))) in vc4_crtc_disable_at_boot()
467 channel = vc4_hvs_get_fifo_from_output(drm, vc4_crtc->data->hvs_output); in vc4_crtc_disable_at_boot()
478 struct drm_device *dev = crtc->dev; in vc4_crtc_atomic_disable()
485 vc4_crtc_disable(crtc, old_vc4_state->assigned_channel); in vc4_crtc_atomic_disable()
491 if (crtc->state->event) { in vc4_crtc_atomic_disable()
494 spin_lock_irqsave(&dev->event_lock, flags); in vc4_crtc_atomic_disable()
495 drm_crtc_send_vblank_event(crtc, crtc->state->event); in vc4_crtc_atomic_disable()
496 crtc->state->event = NULL; in vc4_crtc_atomic_disable()
497 spin_unlock_irqrestore(&dev->event_lock, flags); in vc4_crtc_atomic_disable()
504 struct drm_device *dev = crtc->dev; in vc4_crtc_atomic_enable()
518 if (vc4_encoder->pre_crtc_configure) in vc4_crtc_atomic_enable()
519 vc4_encoder->pre_crtc_configure(encoder); in vc4_crtc_atomic_enable()
525 if (vc4_encoder->pre_crtc_enable) in vc4_crtc_atomic_enable()
526 vc4_encoder->pre_crtc_enable(encoder); in vc4_crtc_atomic_enable()
534 if (vc4_encoder->post_crtc_enable) in vc4_crtc_atomic_enable()
535 vc4_encoder->post_crtc_enable(encoder); in vc4_crtc_atomic_enable()
542 if (mode->flags & DRM_MODE_FLAG_DBLSCAN) { in vc4_crtc_mode_valid()
544 crtc->base.id); in vc4_crtc_mode_valid()
560 *left = vc4_state->margins.left; in vc4_crtc_get_margins()
561 *right = vc4_state->margins.right; in vc4_crtc_get_margins()
562 *top = vc4_state->margins.top; in vc4_crtc_get_margins()
563 *bottom = vc4_state->margins.bottom; in vc4_crtc_get_margins()
570 for_each_new_connector_in_state(state->state, conn, conn_state, i) { in vc4_crtc_get_margins()
571 if (conn_state->crtc != state->crtc) in vc4_crtc_get_margins()
574 *left = conn_state->tv.margins.left; in vc4_crtc_get_margins()
575 *right = conn_state->tv.margins.right; in vc4_crtc_get_margins()
576 *top = conn_state->tv.margins.top; in vc4_crtc_get_margins()
577 *bottom = conn_state->tv.margins.bottom; in vc4_crtc_get_margins()
594 for_each_new_connector_in_state(state->state, conn, conn_state, i) { in vc4_crtc_atomic_check()
595 if (conn_state->crtc != crtc) in vc4_crtc_atomic_check()
598 vc4_state->margins.left = conn_state->tv.margins.left; in vc4_crtc_atomic_check()
599 vc4_state->margins.right = conn_state->tv.margins.right; in vc4_crtc_atomic_check()
600 vc4_state->margins.top = conn_state->tv.margins.top; in vc4_crtc_atomic_check()
601 vc4_state->margins.bottom = conn_state->tv.margins.bottom; in vc4_crtc_atomic_check()
626 struct drm_crtc *crtc = &vc4_crtc->base; in vc4_crtc_handle_page_flip()
627 struct drm_device *dev = crtc->dev; in vc4_crtc_handle_page_flip()
629 struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); in vc4_crtc_handle_page_flip()
630 u32 chan = vc4_state->assigned_channel; in vc4_crtc_handle_page_flip()
633 spin_lock_irqsave(&dev->event_lock, flags); in vc4_crtc_handle_page_flip()
634 if (vc4_crtc->event && in vc4_crtc_handle_page_flip()
635 (vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)) || in vc4_crtc_handle_page_flip()
636 vc4_state->feed_txp)) { in vc4_crtc_handle_page_flip()
637 drm_crtc_send_vblank_event(crtc, vc4_crtc->event); in vc4_crtc_handle_page_flip()
638 vc4_crtc->event = NULL; in vc4_crtc_handle_page_flip()
649 spin_unlock_irqrestore(&dev->event_lock, flags); in vc4_crtc_handle_page_flip()
654 crtc->t_vblank = ktime_get(); in vc4_crtc_handle_vblank()
655 drm_crtc_handle_vblank(&crtc->base); in vc4_crtc_handle_vblank()
691 struct drm_crtc *crtc = flip_state->crtc; in vc4_async_page_flip_complete()
692 struct drm_device *dev = crtc->dev; in vc4_async_page_flip_complete()
694 struct drm_plane *plane = crtc->primary; in vc4_async_page_flip_complete()
696 vc4_plane_async_set_fb(plane, flip_state->fb); in vc4_async_page_flip_complete()
697 if (flip_state->event) { in vc4_async_page_flip_complete()
700 spin_lock_irqsave(&dev->event_lock, flags); in vc4_async_page_flip_complete()
701 drm_crtc_send_vblank_event(crtc, flip_state->event); in vc4_async_page_flip_complete()
702 spin_unlock_irqrestore(&dev->event_lock, flags); in vc4_async_page_flip_complete()
706 drm_framebuffer_put(flip_state->fb); in vc4_async_page_flip_complete()
710 * FIXME: we should move to generic async-page-flip when it's in vc4_async_page_flip_complete()
711 * available, so that we can get rid of this hand-made cleanup_fb() in vc4_async_page_flip_complete()
714 if (flip_state->old_fb) { in vc4_async_page_flip_complete()
718 cma_bo = drm_fb_cma_get_gem_obj(flip_state->old_fb, 0); in vc4_async_page_flip_complete()
719 bo = to_vc4_bo(&cma_bo->base); in vc4_async_page_flip_complete()
721 drm_framebuffer_put(flip_state->old_fb); in vc4_async_page_flip_complete()
726 up(&vc4->async_modeset); in vc4_async_page_flip_complete()
729 /* Implements async (non-vblank-synced) page flips.
740 struct drm_device *dev = crtc->dev; in vc4_async_page_flip()
742 struct drm_plane *plane = crtc->primary; in vc4_async_page_flip()
746 struct vc4_bo *bo = to_vc4_bo(&cma_bo->base); in vc4_async_page_flip()
750 * plane is later updated through the non-async path. in vc4_async_page_flip()
751 * FIXME: we should move to generic async-page-flip when it's in vc4_async_page_flip()
752 * available, so that we can get rid of this hand-made prepare_fb() in vc4_async_page_flip()
762 return -ENOMEM; in vc4_async_page_flip()
766 flip_state->fb = fb; in vc4_async_page_flip()
767 flip_state->crtc = crtc; in vc4_async_page_flip()
768 flip_state->event = event; in vc4_async_page_flip()
771 ret = down_interruptible(&vc4->async_modeset); in vc4_async_page_flip()
783 * FIXME: we should move to generic async-page-flip when it's in vc4_async_page_flip()
784 * available, so that we can get rid of this hand-made cleanup_fb() in vc4_async_page_flip()
787 flip_state->old_fb = plane->state->fb; in vc4_async_page_flip()
788 if (flip_state->old_fb) in vc4_async_page_flip()
789 drm_framebuffer_get(flip_state->old_fb); in vc4_async_page_flip()
797 drm_atomic_set_fb_for_plane(plane->state, fb); in vc4_async_page_flip()
799 vc4_queue_seqno_cb(dev, &flip_state->cb, bo->seqno, in vc4_async_page_flip()
826 old_vc4_state = to_vc4_crtc_state(crtc->state); in vc4_crtc_duplicate_state()
827 vc4_state->feed_txp = old_vc4_state->feed_txp; in vc4_crtc_duplicate_state()
828 vc4_state->margins = old_vc4_state->margins; in vc4_crtc_duplicate_state()
829 vc4_state->assigned_channel = old_vc4_state->assigned_channel; in vc4_crtc_duplicate_state()
831 __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base); in vc4_crtc_duplicate_state()
832 return &vc4_state->base; in vc4_crtc_duplicate_state()
838 struct vc4_dev *vc4 = to_vc4_dev(crtc->dev); in vc4_crtc_destroy_state()
841 if (drm_mm_node_allocated(&vc4_state->mm)) { in vc4_crtc_destroy_state()
844 spin_lock_irqsave(&vc4->hvs->mm_lock, flags); in vc4_crtc_destroy_state()
845 drm_mm_remove_node(&vc4_state->mm); in vc4_crtc_destroy_state()
846 spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags); in vc4_crtc_destroy_state()
857 if (crtc->state) in vc4_crtc_reset()
858 vc4_crtc_destroy_state(crtc, crtc->state); in vc4_crtc_reset()
862 crtc->state = NULL; in vc4_crtc_reset()
866 vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED; in vc4_crtc_reset()
867 __drm_atomic_helper_crtc_reset(crtc, &vc4_crtc_state->base); in vc4_crtc_reset()
1005 { .compatible = "brcm,bcm2835-pixelvalve0", .data = &bcm2835_pv0_data },
1006 { .compatible = "brcm,bcm2835-pixelvalve1", .data = &bcm2835_pv1_data },
1007 { .compatible = "brcm,bcm2835-pixelvalve2", .data = &bcm2835_pv2_data },
1008 { .compatible = "brcm,bcm2711-pixelvalve0", .data = &bcm2711_pv0_data },
1009 { .compatible = "brcm,bcm2711-pixelvalve1", .data = &bcm2711_pv1_data },
1010 { .compatible = "brcm,bcm2711-pixelvalve2", .data = &bcm2711_pv2_data },
1011 { .compatible = "brcm,bcm2711-pixelvalve3", .data = &bcm2711_pv3_data },
1012 { .compatible = "brcm,bcm2711-pixelvalve4", .data = &bcm2711_pv4_data },
1021 const enum vc4_encoder_type *encoder_types = pv_data->encoder_types; in vc4_set_crtc_possible_masks()
1029 for (i = 0; i < ARRAY_SIZE(pv_data->encoder_types); i++) { in vc4_set_crtc_possible_masks()
1030 if (vc4_encoder->type == encoder_types[i]) { in vc4_set_crtc_possible_masks()
1031 vc4_encoder->clock_select = i; in vc4_set_crtc_possible_masks()
1032 encoder->possible_crtcs |= drm_crtc_mask(crtc); in vc4_set_crtc_possible_masks()
1044 struct drm_crtc *crtc = &vc4_crtc->base; in vc4_crtc_init()
1056 dev_err(drm->dev, "failed to construct primary plane\n"); in vc4_crtc_init()
1064 if (!vc4->hvs->hvs5) { in vc4_crtc_init()
1065 drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); in vc4_crtc_init()
1067 drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); in vc4_crtc_init()
1072 drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size); in vc4_crtc_init()
1075 for (i = 0; i < crtc->gamma_size; i++) { in vc4_crtc_init()
1076 vc4_crtc->lut_r[i] = i; in vc4_crtc_init()
1077 vc4_crtc->lut_g[i] = i; in vc4_crtc_init()
1078 vc4_crtc->lut_b[i] = i; in vc4_crtc_init()
1096 return -ENOMEM; in vc4_crtc_bind()
1097 crtc = &vc4_crtc->base; in vc4_crtc_bind()
1101 return -ENODEV; in vc4_crtc_bind()
1102 vc4_crtc->data = &pv_data->base; in vc4_crtc_bind()
1103 vc4_crtc->pdev = pdev; in vc4_crtc_bind()
1105 vc4_crtc->regs = vc4_ioremap_regs(pdev, 0); in vc4_crtc_bind()
1106 if (IS_ERR(vc4_crtc->regs)) in vc4_crtc_bind()
1107 return PTR_ERR(vc4_crtc->regs); in vc4_crtc_bind()
1109 vc4_crtc->regset.base = vc4_crtc->regs; in vc4_crtc_bind()
1110 vc4_crtc->regset.regs = crtc_regs; in vc4_crtc_bind()
1111 vc4_crtc->regset.nregs = ARRAY_SIZE(crtc_regs); in vc4_crtc_bind()
1130 vc4_debugfs_add_regset32(drm, pv_data->debugfs_name, in vc4_crtc_bind()
1131 &vc4_crtc->regset); in vc4_crtc_bind()
1137 &drm->mode_config.plane_list, head) { in vc4_crtc_bind()
1138 if (destroy_plane->possible_crtcs == drm_crtc_mask(crtc)) in vc4_crtc_bind()
1139 destroy_plane->funcs->destroy(destroy_plane); in vc4_crtc_bind()
1151 vc4_crtc_destroy(&vc4_crtc->base); in vc4_crtc_unbind()
1165 return component_add(&pdev->dev, &vc4_crtc_ops); in vc4_crtc_dev_probe()
1170 component_del(&pdev->dev, &vc4_crtc_ops); in vc4_crtc_dev_remove()