diff options
Diffstat (limited to 'drivers/gpu/drm/vc4/vc4_crtc.c')
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_crtc.c | 495 |
1 files changed, 95 insertions, 400 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 1208258ad3b2..6d8fa6118fc1 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -44,26 +44,7 @@ #include "vc4_drv.h" #include "vc4_regs.h" -struct vc4_crtc_state { - struct drm_crtc_state base; - /* Dlist area for this CRTC configuration. */ - struct drm_mm_node mm; - bool feed_txp; - bool txp_armed; - - struct { - unsigned int left; - unsigned int right; - unsigned int top; - unsigned int bottom; - } margins; -}; - -static inline struct vc4_crtc_state * -to_vc4_crtc_state(struct drm_crtc_state *crtc_state) -{ - return (struct vc4_crtc_state *)crtc_state; -} +#define HVS_FIFO_LATENCY_PIX 6 #define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset)) #define CRTC_READ(offset) readl(vc4_crtc->regs + (offset)) @@ -203,67 +184,25 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc, return ret; } -static void vc4_crtc_destroy(struct drm_crtc *crtc) +void vc4_crtc_destroy(struct drm_crtc *crtc) { drm_crtc_cleanup(crtc); } -static void -vc4_crtc_lut_load(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - u32 i; - - /* The LUT memory is laid out with each HVS channel in order, - * each of which takes 256 writes for R, 256 for G, then 256 - * for B. - */ - HVS_WRITE(SCALER_GAMADDR, - SCALER_GAMADDR_AUTOINC | - (vc4_crtc->channel * 3 * crtc->gamma_size)); - - for (i = 0; i < crtc->gamma_size; i++) - HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_r[i]); - for (i = 0; i < crtc->gamma_size; i++) - HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_g[i]); - for (i = 0; i < crtc->gamma_size; i++) - HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_b[i]); -} - -static void -vc4_crtc_update_gamma_lut(struct drm_crtc *crtc) -{ - struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - struct drm_color_lut *lut = crtc->state->gamma_lut->data; - u32 length = drm_color_lut_size(crtc->state->gamma_lut); - u32 i; - - for (i = 0; i < length; i++) { - vc4_crtc->lut_r[i] = drm_color_lut_extract(lut[i].red, 8); - vc4_crtc->lut_g[i] = drm_color_lut_extract(lut[i].green, 8); - vc4_crtc->lut_b[i] = drm_color_lut_extract(lut[i].blue, 8); - } - - vc4_crtc_lut_load(crtc); -} - static u32 vc4_get_fifo_full_level(u32 format) { static const u32 fifo_len_bytes = 64; - static const u32 hvs_latency_pix = 6; switch (format) { case PV_CONTROL_FORMAT_DSIV_16: case PV_CONTROL_FORMAT_DSIC_16: - return fifo_len_bytes - 2 * hvs_latency_pix; + return fifo_len_bytes - 2 * HVS_FIFO_LATENCY_PIX; case PV_CONTROL_FORMAT_DSIV_18: return fifo_len_bytes - 14; case PV_CONTROL_FORMAT_24: case PV_CONTROL_FORMAT_DSIV_24: default: - return fifo_len_bytes - 3 * hvs_latency_pix; + return fifo_len_bytes - 3 * HVS_FIFO_LATENCY_PIX; } } @@ -364,7 +303,8 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc) (is_dsi ? PV_VCONTROL_DSI : 0)); } - CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); + if (is_dsi) + CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); CRTC_WRITE(PV_CONTROL, VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | @@ -382,12 +322,7 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc) static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); - struct drm_display_mode *mode = &crtc->state->adjusted_mode; - bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; bool debug_dump_regs = false; if (debug_dump_regs) { @@ -397,42 +332,9 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) drm_print_regset32(&p, &vc4_crtc->regset); } - if (vc4_crtc->channel == 2) { - u32 dispctrl; - u32 dsp3_mux; + vc4_crtc_config_pv(crtc); - /* - * SCALER_DISPCTRL_DSP3 = X, where X < 2 means 'connect DSP3 to - * FIFO X'. - * SCALER_DISPCTRL_DSP3 = 3 means 'disable DSP 3'. - * - * DSP3 is connected to FIFO2 unless the transposer is - * enabled. In this case, FIFO 2 is directly accessed by the - * TXP IP, and we need to disable the FIFO2 -> pixelvalve1 - * route. - */ - if (vc4_state->feed_txp) - dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX); - else - dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); - - dispctrl = HVS_READ(SCALER_DISPCTRL) & - ~SCALER_DISPCTRL_DSP3_MUX_MASK; - HVS_WRITE(SCALER_DISPCTRL, dispctrl | dsp3_mux); - } - - if (!vc4_state->feed_txp) - vc4_crtc_config_pv(crtc); - - HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), - SCALER_DISPBKGND_AUTOHS | - SCALER_DISPBKGND_GAMMA | - (interlace ? SCALER_DISPBKGND_INTERLACE : 0)); - - /* Reload the LUT, since the SRAMs would have been disabled if - * all CRTCs had SCALER_DISPBKGND_GAMMA unset at once. - */ - vc4_crtc_lut_load(crtc); + vc4_hvs_mode_set_nofb(crtc); if (debug_dump_regs) { struct drm_printer p = drm_info_printer(&vc4_crtc->pdev->dev); @@ -454,10 +356,9 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct drm_device *dev = crtc->dev; - struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - u32 chan = vc4_crtc->channel; int ret; + require_hvs_enabled(dev); /* Disable vblank irq handling before crtc is disabled. */ @@ -468,28 +369,7 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1); WARN_ONCE(ret, "Timeout waiting for !PV_VCONTROL_VIDEN\n"); - if (HVS_READ(SCALER_DISPCTRLX(chan)) & - SCALER_DISPCTRLX_ENABLE) { - HVS_WRITE(SCALER_DISPCTRLX(chan), - SCALER_DISPCTRLX_RESET); - - /* While the docs say that reset is self-clearing, it - * seems it doesn't actually. - */ - HVS_WRITE(SCALER_DISPCTRLX(chan), 0); - } - - /* Once we leave, the scaler should be disabled and its fifo empty. */ - - WARN_ON_ONCE(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_RESET); - - WARN_ON_ONCE(VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)), - SCALER_DISPSTATX_MODE) != - SCALER_DISPSTATX_MODE_DISABLED); - - WARN_ON_ONCE((HVS_READ(SCALER_DISPSTATX(chan)) & - (SCALER_DISPSTATX_FULL | SCALER_DISPSTATX_EMPTY)) != - SCALER_DISPSTATX_EMPTY); + vc4_hvs_atomic_disable(crtc, old_state); /* * Make sure we issue a vblank event after disabling the CRTC if @@ -505,52 +385,11 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, } } -void vc4_crtc_txp_armed(struct drm_crtc_state *state) -{ - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state); - - vc4_state->txp_armed = true; -} - -static void vc4_crtc_update_dlist(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); - - if (crtc->state->event) { - unsigned long flags; - - crtc->state->event->pipe = drm_crtc_index(crtc); - - WARN_ON(drm_crtc_vblank_get(crtc) != 0); - - spin_lock_irqsave(&dev->event_lock, flags); - - if (!vc4_state->feed_txp || vc4_state->txp_armed) { - vc4_crtc->event = crtc->state->event; - crtc->state->event = NULL; - } - - HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), - vc4_state->mm.start); - - spin_unlock_irqrestore(&dev->event_lock, flags); - } else { - HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), - vc4_state->mm.start); - } -} - static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct drm_device *dev = crtc->dev; - struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); - struct drm_display_mode *mode = &crtc->state->adjusted_mode; require_hvs_enabled(dev); @@ -558,25 +397,14 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, * drm_crtc_get_vblank() fails in vc4_crtc_update_dlist(). */ drm_crtc_vblank_on(crtc); - vc4_crtc_update_dlist(crtc); - /* Turn on the scaler, which will wait for vstart to start - * compositing. - * When feeding the transposer, we should operate in oneshot - * mode. - */ - HVS_WRITE(SCALER_DISPCTRLX(vc4_crtc->channel), - VC4_SET_FIELD(mode->hdisplay, SCALER_DISPCTRLX_WIDTH) | - VC4_SET_FIELD(mode->vdisplay, SCALER_DISPCTRLX_HEIGHT) | - SCALER_DISPCTRLX_ENABLE | - (vc4_state->feed_txp ? SCALER_DISPCTRLX_ONESHOT : 0)); + vc4_hvs_atomic_enable(crtc, old_state); /* When feeding the transposer block the pixelvalve is unneeded and * should not be enabled. */ - if (!vc4_state->feed_txp) - CRTC_WRITE(PV_V_CONTROL, - CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); + CRTC_WRITE(PV_V_CONTROL, + CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); } static enum drm_mode_status vc4_crtc_mode_valid(struct drm_crtc *crtc, @@ -627,31 +455,11 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state); - struct drm_device *dev = crtc->dev; - struct vc4_dev *vc4 = to_vc4_dev(dev); - struct drm_plane *plane; - unsigned long flags; - const struct drm_plane_state *plane_state; struct drm_connector *conn; struct drm_connector_state *conn_state; - u32 dlist_count = 0; int ret, i; - /* The pixelvalve can only feed one encoder (and encoders are - * 1:1 with connectors.) - */ - if (hweight32(state->connector_mask) > 1) - return -EINVAL; - - drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, state) - dlist_count += vc4_plane_dlist_size(plane_state); - - dlist_count++; /* Account for SCALER_CTL0_END. */ - - spin_lock_irqsave(&vc4->hvs->mm_lock, flags); - ret = drm_mm_insert_node(&vc4->hvs->dlist_mm, &vc4_state->mm, - dlist_count); - spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags); + ret = vc4_hvs_atomic_check(crtc, state); if (ret) return ret; @@ -659,17 +467,6 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc, if (conn_state->crtc != crtc) continue; - /* The writeback connector is implemented using the transposer - * block which is directly taking its data from the HVS FIFO. - */ - if (conn->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) { - state->no_vblank = true; - vc4_state->feed_txp = true; - } else { - state->no_vblank = false; - vc4_state->feed_txp = false; - } - vc4_state->margins.left = conn_state->tv.margins.left; vc4_state->margins.right = conn_state->tv.margins.right; vc4_state->margins.top = conn_state->tv.margins.top; @@ -680,89 +477,6 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc, return 0; } -static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) -{ - struct drm_device *dev = crtc->dev; - struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); - struct drm_plane *plane; - struct vc4_plane_state *vc4_plane_state; - bool debug_dump_regs = false; - bool enable_bg_fill = false; - u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start; - u32 __iomem *dlist_next = dlist_start; - - if (debug_dump_regs) { - DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc)); - vc4_hvs_dump_state(dev); - } - - /* Copy all the active planes' dlist contents to the hardware dlist. */ - drm_atomic_crtc_for_each_plane(plane, crtc) { - /* Is this the first active plane? */ - if (dlist_next == dlist_start) { - /* We need to enable background fill when a plane - * could be alpha blending from the background, i.e. - * where no other plane is underneath. It suffices to - * consider the first active plane here since we set - * needs_bg_fill such that either the first plane - * already needs it or all planes on top blend from - * the first or a lower plane. - */ - vc4_plane_state = to_vc4_plane_state(plane->state); - enable_bg_fill = vc4_plane_state->needs_bg_fill; - } - - dlist_next += vc4_plane_write_dlist(plane, dlist_next); - } - - writel(SCALER_CTL0_END, dlist_next); - dlist_next++; - - WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size); - - if (enable_bg_fill) - /* This sets a black background color fill, as is the case - * with other DRM drivers. - */ - HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), - HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel)) | - SCALER_DISPBKGND_FILL); - - /* Only update DISPLIST if the CRTC was already running and is not - * being disabled. - * vc4_crtc_enable() takes care of updating the dlist just after - * re-enabling VBLANK interrupts and before enabling the engine. - * If the CRTC is being disabled, there's no point in updating this - * information. - */ - if (crtc->state->active && old_state->active) - vc4_crtc_update_dlist(crtc); - - if (crtc->state->color_mgmt_changed) { - u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel)); - - if (crtc->state->gamma_lut) { - vc4_crtc_update_gamma_lut(crtc); - dispbkgndx |= SCALER_DISPBKGND_GAMMA; - } else { - /* Unsetting DISPBKGND_GAMMA skips the gamma lut step - * in hardware, which is the same as a linear lut that - * DRM expects us to use in absence of a user lut. - */ - dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; - } - HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), dispbkgndx); - } - - if (debug_dump_regs) { - DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc)); - vc4_hvs_dump_state(dev); - } -} - static int vc4_enable_vblank(struct drm_crtc *crtc) { struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); @@ -961,11 +675,11 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, return 0; } -static int vc4_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, - uint32_t flags, - struct drm_modeset_acquire_ctx *ctx) +int vc4_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx) { if (flags & DRM_MODE_PAGE_FLIP_ASYNC) return vc4_async_page_flip(crtc, fb, event, flags); @@ -973,7 +687,7 @@ static int vc4_page_flip(struct drm_crtc *crtc, return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx); } -static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc) +struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc) { struct vc4_crtc_state *vc4_state, *old_vc4_state; @@ -989,8 +703,8 @@ static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc) return &vc4_state->base; } -static void vc4_crtc_destroy_state(struct drm_crtc *crtc, - struct drm_crtc_state *state) +void vc4_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) { struct vc4_dev *vc4 = to_vc4_dev(crtc->dev); struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state); @@ -1007,15 +721,13 @@ static void vc4_crtc_destroy_state(struct drm_crtc *crtc, drm_atomic_helper_crtc_destroy_state(crtc, state); } -static void -vc4_crtc_reset(struct drm_crtc *crtc) +void vc4_crtc_reset(struct drm_crtc *crtc) { if (crtc->state) vc4_crtc_destroy_state(crtc, crtc->state); - crtc->state = kzalloc(sizeof(struct vc4_crtc_state), GFP_KERNEL); if (crtc->state) - crtc->state->crtc = crtc; + __drm_atomic_helper_crtc_reset(crtc, crtc->state); } static const struct drm_crtc_funcs vc4_crtc_funcs = { @@ -1038,14 +750,16 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { .mode_set_nofb = vc4_crtc_mode_set_nofb, .mode_valid = vc4_crtc_mode_valid, .atomic_check = vc4_crtc_atomic_check, - .atomic_flush = vc4_crtc_atomic_flush, + .atomic_flush = vc4_hvs_atomic_flush, .atomic_enable = vc4_crtc_atomic_enable, .atomic_disable = vc4_crtc_atomic_disable, .get_scanout_position = vc4_crtc_get_scanout_position, }; -static const struct vc4_crtc_data pv0_data = { - .hvs_channel = 0, +static const struct vc4_pv_data bcm2835_pv0_data = { + .base = { + .hvs_channel = 0, + }, .debugfs_name = "crtc0_regs", .encoder_types = { [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0, @@ -1053,8 +767,10 @@ static const struct vc4_crtc_data pv0_data = { }, }; -static const struct vc4_crtc_data pv1_data = { - .hvs_channel = 2, +static const struct vc4_pv_data bcm2835_pv1_data = { + .base = { + .hvs_channel = 2, + }, .debugfs_name = "crtc1_regs", .encoder_types = { [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1, @@ -1062,8 +778,10 @@ static const struct vc4_crtc_data pv1_data = { }, }; -static const struct vc4_crtc_data pv2_data = { - .hvs_channel = 1, +static const struct vc4_pv_data bcm2835_pv2_data = { + .base = { + .hvs_channel = 1, + }, .debugfs_name = "crtc2_regs", .encoder_types = { [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI, @@ -1072,9 +790,9 @@ static const struct vc4_crtc_data pv2_data = { }; static const struct of_device_id vc4_crtc_dt_match[] = { - { .compatible = "brcm,bcm2835-pixelvalve0", .data = &pv0_data }, - { .compatible = "brcm,bcm2835-pixelvalve1", .data = &pv1_data }, - { .compatible = "brcm,bcm2835-pixelvalve2", .data = &pv2_data }, + { .compatible = "brcm,bcm2835-pixelvalve0", .data = &bcm2835_pv0_data }, + { .compatible = "brcm,bcm2835-pixelvalve1", .data = &bcm2835_pv1_data }, + { .compatible = "brcm,bcm2835-pixelvalve2", .data = &bcm2835_pv2_data }, {} }; @@ -1082,23 +800,16 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm, struct drm_crtc *crtc) { struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - const struct vc4_crtc_data *crtc_data = vc4_crtc->data; - const enum vc4_encoder_type *encoder_types = crtc_data->encoder_types; + const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc); + const enum vc4_encoder_type *encoder_types = pv_data->encoder_types; struct drm_encoder *encoder; drm_for_each_encoder(encoder, drm) { struct vc4_encoder *vc4_encoder; int i; - /* HVS FIFO2 can feed the TXP IP. */ - if (crtc_data->hvs_channel == 2 && - encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) { - encoder->possible_crtcs |= drm_crtc_mask(crtc); - continue; - } - vc4_encoder = to_vc4_encoder(encoder); - for (i = 0; i < ARRAY_SIZE(crtc_data->encoder_types); i++) { + for (i = 0; i < ARRAY_SIZE(pv_data->encoder_types); i++) { if (vc4_encoder->type == encoder_types[i]) { vc4_encoder->clock_select = i; encoder->possible_crtcs |= drm_crtc_mask(crtc); @@ -1124,34 +835,13 @@ vc4_crtc_get_cob_allocation(struct vc4_crtc *vc4_crtc) vc4_crtc->cob_size = top - base + 4; } -static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) +int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc, + const struct drm_crtc_funcs *crtc_funcs, + const struct drm_crtc_helper_funcs *crtc_helper_funcs) { - struct platform_device *pdev = to_platform_device(dev); - struct drm_device *drm = dev_get_drvdata(master); - struct vc4_crtc *vc4_crtc; - struct drm_crtc *crtc; - struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp; - const struct of_device_id *match; - int ret, i; - - vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); - if (!vc4_crtc) - return -ENOMEM; - crtc = &vc4_crtc->base; - - match = of_match_device(vc4_crtc_dt_match, dev); - if (!match) - return -ENODEV; - vc4_crtc->data = match->data; - vc4_crtc->pdev = pdev; - - vc4_crtc->regs = vc4_ioremap_regs(pdev, 0); - if (IS_ERR(vc4_crtc->regs)) - return PTR_ERR(vc4_crtc->regs); - - vc4_crtc->regset.base = vc4_crtc->regs; - vc4_crtc->regset.regs = crtc_regs; - vc4_crtc->regset.nregs = ARRAY_SIZE(crtc_regs); + struct drm_crtc *crtc = &vc4_crtc->base; + struct drm_plane *primary_plane; + unsigned int i; /* For now, we create just the primary and the legacy cursor * planes. We should be able to stack more planes on easily, @@ -1161,14 +851,13 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) */ primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY); if (IS_ERR(primary_plane)) { - dev_err(dev, "failed to construct primary plane\n"); - ret = PTR_ERR(primary_plane); - goto err; + dev_err(drm->dev, "failed to construct primary plane\n"); + return PTR_ERR(primary_plane); } drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, - &vc4_crtc_funcs, NULL); - drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs); + crtc_funcs, NULL); + drm_crtc_helper_add(crtc, crtc_helper_funcs); vc4_crtc->channel = vc4_crtc->data->hvs_channel; drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); @@ -1177,37 +866,51 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) * implemented as private driver state in vc4_kms, not here. */ drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size); + vc4_crtc_get_cob_allocation(vc4_crtc); - /* Set up some arbitrary number of planes. We're not limited - * by a set number of physical registers, just the space in - * the HVS (16k) and how small an plane can be (28 bytes). - * However, each plane we set up takes up some memory, and - * increases the cost of looping over planes, which atomic - * modesetting does quite a bit. As a result, we pick a - * modest number of planes to expose, that should hopefully - * still cover any sane usecase. - */ - for (i = 0; i < 8; i++) { - struct drm_plane *plane = - vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY); + for (i = 0; i < crtc->gamma_size; i++) { + vc4_crtc->lut_r[i] = i; + vc4_crtc->lut_g[i] = i; + vc4_crtc->lut_b[i] = i; + } - if (IS_ERR(plane)) - continue; + return 0; +} - plane->possible_crtcs = drm_crtc_mask(crtc); - } +static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); + const struct vc4_pv_data *pv_data; + struct vc4_crtc *vc4_crtc; + struct drm_crtc *crtc; + struct drm_plane *destroy_plane, *temp; + int ret; - /* Set up the legacy cursor after overlay initialization, - * since we overlay planes on the CRTC in the order they were - * initialized. - */ - cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); - if (!IS_ERR(cursor_plane)) { - cursor_plane->possible_crtcs = drm_crtc_mask(crtc); - crtc->cursor = cursor_plane; - } + vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); + if (!vc4_crtc) + return -ENOMEM; + crtc = &vc4_crtc->base; - vc4_crtc_get_cob_allocation(vc4_crtc); + pv_data = of_device_get_match_data(dev); + if (!pv_data) + return -ENODEV; + vc4_crtc->data = &pv_data->base; + vc4_crtc->pdev = pdev; + + vc4_crtc->regs = vc4_ioremap_regs(pdev, 0); + if (IS_ERR(vc4_crtc->regs)) + return PTR_ERR(vc4_crtc->regs); + + vc4_crtc->regset.base = vc4_crtc->regs; + vc4_crtc->regset.regs = crtc_regs; + vc4_crtc->regset.nregs = ARRAY_SIZE(crtc_regs); + + ret = vc4_crtc_init(drm, vc4_crtc, + &vc4_crtc_funcs, &vc4_crtc_helper_funcs); + if (ret) + return ret; + vc4_set_crtc_possible_masks(drm, crtc); CRTC_WRITE(PV_INTEN, 0); CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START); @@ -1216,17 +919,9 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) if (ret) goto err_destroy_planes; - vc4_set_crtc_possible_masks(drm, crtc); - - for (i = 0; i < crtc->gamma_size; i++) { - vc4_crtc->lut_r[i] = i; - vc4_crtc->lut_g[i] = i; - vc4_crtc->lut_b[i] = i; - } - platform_set_drvdata(pdev, vc4_crtc); - vc4_debugfs_add_regset32(drm, vc4_crtc->data->debugfs_name, + vc4_debugfs_add_regset32(drm, pv_data->debugfs_name, &vc4_crtc->regset); return 0; @@ -1237,7 +932,7 @@ err_destroy_planes: if (destroy_plane->possible_crtcs == drm_crtc_mask(crtc)) destroy_plane->funcs->destroy(destroy_plane); } -err: + return ret; } |