diff options
Diffstat (limited to 'drivers/gpu/drm/sun4i/sun8i_ui_layer.c')
| -rw-r--r-- | drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 315 |
1 files changed, 98 insertions, 217 deletions
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c index e779855bcd6e..f08f6da55dd0 100644 --- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c @@ -11,103 +11,64 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_blend.h> #include <drm/drm_crtc.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> +#include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include "sun8i_mixer.h" #include "sun8i_ui_layer.h" #include "sun8i_ui_scaler.h" +#include "sun8i_vi_scaler.h" -static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel, - int overlay, bool enable, unsigned int zpos, - unsigned int old_zpos) +static void sun8i_ui_layer_disable(struct sun8i_layer *layer) { - u32 val, bld_base, ch_base; + u32 ch_base = sun8i_channel_base(layer); - bld_base = sun8i_blender_base(mixer); - ch_base = sun8i_channel_base(mixer, channel); - - DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n", - enable ? "En" : "Dis", channel, overlay); - - if (enable) - val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN; - else - val = 0; - - regmap_update_bits(mixer->engine.regs, - SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay), - SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val); - - if (!enable || zpos != old_zpos) { - regmap_update_bits(mixer->engine.regs, - SUN8I_MIXER_BLEND_PIPE_CTL(bld_base), - SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos), - 0); - - regmap_update_bits(mixer->engine.regs, - SUN8I_MIXER_BLEND_ROUTE(bld_base), - SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos), - 0); - } - - if (enable) { - val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); - - regmap_update_bits(mixer->engine.regs, - SUN8I_MIXER_BLEND_PIPE_CTL(bld_base), - val, val); - - val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos); - - regmap_update_bits(mixer->engine.regs, - SUN8I_MIXER_BLEND_ROUTE(bld_base), - SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos), - val); - } + regmap_write(layer->regs, + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, layer->overlay), 0); } -static void sun8i_ui_layer_update_alpha(struct sun8i_mixer *mixer, int channel, - int overlay, struct drm_plane *plane) +static void sun8i_ui_layer_update_attributes(struct sun8i_layer *layer, + struct drm_plane *plane) { - u32 mask, val, ch_base; - - ch_base = sun8i_channel_base(mixer, channel); - - mask = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK | - SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK; + struct drm_plane_state *state = plane->state; + const struct drm_format_info *fmt; + u32 val, ch_base, hw_fmt; - val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA(plane->state->alpha >> 8); + ch_base = sun8i_channel_base(layer); + fmt = state->fb->format; + sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt); - val |= (plane->state->alpha == DRM_BLEND_ALPHA_OPAQUE) ? + val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA(state->alpha >> 8); + val |= (state->alpha == DRM_BLEND_ALPHA_OPAQUE) ? SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_PIXEL : SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_COMBINED; + val |= hw_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET; + val |= SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN; - regmap_update_bits(mixer->engine.regs, - SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay), - mask, val); + regmap_write(layer->regs, + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, layer->overlay), val); } -static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel, - int overlay, struct drm_plane *plane, - unsigned int zpos) +static void sun8i_ui_layer_update_coord(struct sun8i_layer *layer, + struct drm_plane *plane) { struct drm_plane_state *state = plane->state; u32 src_w, src_h, dst_w, dst_h; - u32 bld_base, ch_base; u32 outsize, insize; u32 hphase, vphase; + u32 ch_base; DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n", - channel, overlay); + layer->channel, layer->overlay); - bld_base = sun8i_blender_base(mixer); - ch_base = sun8i_channel_base(mixer, channel); + ch_base = sun8i_channel_base(layer); src_w = drm_rect_width(&state->src) >> 16; src_h = drm_rect_height(&state->src) >> 16; @@ -120,44 +81,14 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel, insize = SUN8I_MIXER_SIZE(src_w, src_h); outsize = SUN8I_MIXER_SIZE(dst_w, dst_h); - if (plane->type == DRM_PLANE_TYPE_PRIMARY) { - bool interlaced = false; - u32 val; - - DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n", - dst_w, dst_h); - regmap_write(mixer->engine.regs, - SUN8I_MIXER_GLOBAL_SIZE, - outsize); - regmap_write(mixer->engine.regs, - SUN8I_MIXER_BLEND_OUTSIZE(bld_base), outsize); - - if (state->crtc) - interlaced = state->crtc->state->adjusted_mode.flags - & DRM_MODE_FLAG_INTERLACE; - - if (interlaced) - val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED; - else - val = 0; - - regmap_update_bits(mixer->engine.regs, - SUN8I_MIXER_BLEND_OUTCTL(bld_base), - SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, - val); - - DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n", - interlaced ? "on" : "off"); - } - /* Set height and width */ DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n", state->src.x1 >> 16, state->src.y1 >> 16); DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h); - regmap_write(mixer->engine.regs, - SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch_base, overlay), + regmap_write(layer->regs, + SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch_base, layer->overlay), insize); - regmap_write(mixer->engine.regs, + regmap_write(layer->regs, SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch_base), insize); @@ -169,91 +100,61 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel, hscale = state->src_w / state->crtc_w; vscale = state->src_h / state->crtc_h; - sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w, - dst_h, hscale, vscale, hphase, vphase); - sun8i_ui_scaler_enable(mixer, channel, true); + if (layer->cfg->de_type == SUN8I_MIXER_DE33) { + sun8i_vi_scaler_setup(layer, src_w, src_h, dst_w, dst_h, + hscale, vscale, hphase, vphase, + state->fb->format); + sun8i_vi_scaler_enable(layer, true); + } else { + sun8i_ui_scaler_setup(layer, src_w, src_h, dst_w, dst_h, + hscale, vscale, hphase, vphase); + sun8i_ui_scaler_enable(layer, true); + } } else { DRM_DEBUG_DRIVER("HW scaling is not needed\n"); - sun8i_ui_scaler_enable(mixer, channel, false); - } - - /* Set base coordinates */ - DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n", - state->dst.x1, state->dst.y1); - DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h); - regmap_write(mixer->engine.regs, - SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos), - SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1)); - regmap_write(mixer->engine.regs, - SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos), - outsize); - - return 0; -} - -static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel, - int overlay, struct drm_plane *plane) -{ - struct drm_plane_state *state = plane->state; - const struct drm_format_info *fmt; - u32 val, ch_base, hw_fmt; - int ret; - - ch_base = sun8i_channel_base(mixer, channel); - - fmt = state->fb->format; - ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt); - if (ret || fmt->is_yuv) { - DRM_DEBUG_DRIVER("Invalid format\n"); - return -EINVAL; + if (layer->cfg->de_type == SUN8I_MIXER_DE33) + sun8i_vi_scaler_enable(layer, false); + else + sun8i_ui_scaler_enable(layer, false); } - - val = hw_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET; - regmap_update_bits(mixer->engine.regs, - SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay), - SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val); - - return 0; } -static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel, - int overlay, struct drm_plane *plane) +static void sun8i_ui_layer_update_buffer(struct sun8i_layer *layer, + struct drm_plane *plane) { struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; - struct drm_gem_cma_object *gem; - dma_addr_t paddr; + struct drm_gem_dma_object *gem; + dma_addr_t dma_addr; u32 ch_base; int bpp; - ch_base = sun8i_channel_base(mixer, channel); + ch_base = sun8i_channel_base(layer); /* Get the physical address of the buffer in memory */ - gem = drm_fb_cma_get_gem_obj(fb, 0); + gem = drm_fb_dma_get_gem_obj(fb, 0); - DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr); + DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->dma_addr); /* Compute the start of the displayed memory */ bpp = fb->format->cpp[0]; - paddr = gem->paddr + fb->offsets[0]; + dma_addr = gem->dma_addr + fb->offsets[0]; /* Fixup framebuffer address for src coordinates */ - paddr += (state->src.x1 >> 16) * bpp; - paddr += (state->src.y1 >> 16) * fb->pitches[0]; + dma_addr += (state->src.x1 >> 16) * bpp; + dma_addr += (state->src.y1 >> 16) * fb->pitches[0]; /* Set the line width */ DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]); - regmap_write(mixer->engine.regs, - SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch_base, overlay), + regmap_write(layer->regs, + SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch_base, layer->overlay), fb->pitches[0]); - DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); - - regmap_write(mixer->engine.regs, - SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch_base, overlay), - lower_32_bits(paddr)); + DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &dma_addr); - return 0; + regmap_write(layer->regs, + SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch_base, layer->overlay), + lower_32_bits(dma_addr)); } static int sun8i_ui_layer_atomic_check(struct drm_plane *plane, @@ -261,23 +162,31 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane, { struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); - struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); + struct sun8i_layer *layer = plane_to_sun8i_layer(plane); struct drm_crtc *crtc = new_plane_state->crtc; struct drm_crtc_state *crtc_state; - int min_scale, max_scale; + const struct drm_format_info *fmt; + int min_scale, max_scale, ret; + u32 hw_fmt; if (!crtc) return 0; - crtc_state = drm_atomic_get_existing_crtc_state(state, - crtc); + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); if (WARN_ON(!crtc_state)) return -EINVAL; - min_scale = DRM_PLANE_HELPER_NO_SCALING; - max_scale = DRM_PLANE_HELPER_NO_SCALING; + fmt = new_plane_state->fb->format; + ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt); + if (ret || fmt->is_yuv) { + DRM_DEBUG_DRIVER("Invalid plane format\n"); + return -EINVAL; + } + + min_scale = DRM_PLANE_NO_SCALING; + max_scale = DRM_PLANE_NO_SCALING; - if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) { + if (layer->cfg->scaler_mask & BIT(layer->channel)) { min_scale = SUN8I_UI_SCALER_SCALE_MIN; max_scale = SUN8I_UI_SCALER_SCALE_MAX; } @@ -288,53 +197,26 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane, true, true); } -static void sun8i_ui_layer_atomic_disable(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, - plane); - struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); - unsigned int old_zpos = old_state->normalized_zpos; - struct sun8i_mixer *mixer = layer->mixer; - - sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false, 0, - old_zpos); -} static void sun8i_ui_layer_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) { - struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, - plane); struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); - struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); - unsigned int zpos = new_state->normalized_zpos; - unsigned int old_zpos = old_state->normalized_zpos; - struct sun8i_mixer *mixer = layer->mixer; - - if (!new_state->visible) { - sun8i_ui_layer_enable(mixer, layer->channel, - layer->overlay, false, 0, old_zpos); + struct sun8i_layer *layer = plane_to_sun8i_layer(plane); + + if (!new_state->crtc || !new_state->visible) { + sun8i_ui_layer_disable(layer); return; } - sun8i_ui_layer_update_coord(mixer, layer->channel, - layer->overlay, plane, zpos); - sun8i_ui_layer_update_alpha(mixer, layer->channel, - layer->overlay, plane); - sun8i_ui_layer_update_formats(mixer, layer->channel, - layer->overlay, plane); - sun8i_ui_layer_update_buffer(mixer, layer->channel, - layer->overlay, plane); - sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, - true, zpos, old_zpos); + sun8i_ui_layer_update_attributes(layer, plane); + sun8i_ui_layer_update_coord(layer, plane); + sun8i_ui_layer_update_buffer(layer, plane); } static const struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = { - .prepare_fb = drm_gem_plane_helper_prepare_fb, .atomic_check = sun8i_ui_layer_atomic_check, - .atomic_disable = sun8i_ui_layer_atomic_disable, .atomic_update = sun8i_ui_layer_atomic_update, }; @@ -375,22 +257,26 @@ static const uint64_t sun8i_layer_modifiers[] = { DRM_FORMAT_MOD_INVALID }; -struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm, - struct sun8i_mixer *mixer, - int index) +struct sun8i_layer *sun8i_ui_layer_init_one(struct drm_device *drm, + enum drm_plane_type type, + struct regmap *regs, + int index, int phy_index, + int plane_cnt, + const struct sun8i_layer_cfg *cfg) { - enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY; - int channel = mixer->cfg->vi_num + index; - struct sun8i_ui_layer *layer; - unsigned int plane_cnt; + struct sun8i_layer *layer; int ret; layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL); if (!layer) return ERR_PTR(-ENOMEM); - if (index == 0) - type = DRM_PLANE_TYPE_PRIMARY; + layer->type = SUN8I_LAYER_TYPE_UI; + layer->index = index; + layer->channel = phy_index; + layer->overlay = 0; + layer->regs = regs; + layer->cfg = cfg; /* possible crtcs are set later */ ret = drm_universal_plane_init(drm, &layer->plane, 0, @@ -403,15 +289,13 @@ struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm, return ERR_PTR(ret); } - plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num; - ret = drm_plane_create_alpha_property(&layer->plane); if (ret) { dev_err(drm->dev, "Couldn't add alpha property\n"); return ERR_PTR(ret); } - ret = drm_plane_create_zpos_property(&layer->plane, channel, + ret = drm_plane_create_zpos_property(&layer->plane, index, 0, plane_cnt - 1); if (ret) { dev_err(drm->dev, "Couldn't add zpos property\n"); @@ -419,9 +303,6 @@ struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm, } drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs); - layer->mixer = mixer; - layer->channel = channel; - layer->overlay = 0; return layer; } |
