diff options
Diffstat (limited to 'drivers/gpu/drm/rockchip/rockchip_drm_vop.c')
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 190 |
1 files changed, 75 insertions, 115 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 9434d616bc37..948719dddc36 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -42,33 +42,20 @@ #include "rockchip_drm_psr.h" #include "rockchip_drm_vop.h" -#define __REG_SET_RELAXED(x, off, mask, shift, v, write_mask) \ - vop_mask_write(x, off, mask, shift, v, write_mask, true) - -#define __REG_SET_NORMAL(x, off, mask, shift, v, write_mask) \ - vop_mask_write(x, off, mask, shift, v, write_mask, false) - -#define REG_SET(x, base, reg, v, mode) \ - __REG_SET_##mode(x, base + reg.offset, \ - reg.mask, reg.shift, v, reg.write_mask) -#define REG_SET_MASK(x, base, reg, mask, v, mode) \ - __REG_SET_##mode(x, base + reg.offset, \ - mask, reg.shift, v, reg.write_mask) - #define VOP_WIN_SET(x, win, name, v) \ - REG_SET(x, win->base, win->phy->name, v, RELAXED) + vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name) #define VOP_SCL_SET(x, win, name, v) \ - REG_SET(x, win->base, win->phy->scl->name, v, RELAXED) + vop_reg_set(vop, &win->phy->scl->name, win->base, ~0, v, #name) #define VOP_SCL_SET_EXT(x, win, name, v) \ - REG_SET(x, win->base, win->phy->scl->ext->name, v, RELAXED) -#define VOP_CTRL_SET(x, name, v) \ - REG_SET(x, 0, (x)->data->ctrl->name, v, NORMAL) + vop_reg_set(vop, &win->phy->scl->ext->name, \ + win->base, ~0, v, #name) + +#define VOP_INTR_SET_MASK(vop, name, mask, v) \ + vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name) -#define VOP_INTR_GET(vop, name) \ - vop_read_reg(vop, 0, &vop->data->ctrl->name) +#define VOP_REG_SET(vop, group, name, v) \ + vop_reg_set(vop, &vop->data->group->name, 0, ~0, v, #name) -#define VOP_INTR_SET(vop, name, mask, v) \ - REG_SET_MASK(vop, 0, vop->data->intr->name, mask, v, NORMAL) #define VOP_INTR_SET_TYPE(vop, name, type, v) \ do { \ int i, reg = 0, mask = 0; \ @@ -78,13 +65,13 @@ mask |= 1 << i; \ } \ } \ - VOP_INTR_SET(vop, name, mask, reg); \ + VOP_INTR_SET_MASK(vop, name, mask, reg); \ } while (0) #define VOP_INTR_GET_TYPE(vop, name, type) \ vop_get_intr_type(vop, &vop->data->intr->name, type) #define VOP_WIN_GET(x, win, name) \ - vop_read_reg(x, win->base, &win->phy->name) + vop_read_reg(x, win->offset, win->phy->name) #define VOP_WIN_GET_YRGBADDR(vop, win) \ vop_readl(vop, win->base + win->phy->yrgb_mst.offset) @@ -166,14 +153,22 @@ static inline uint32_t vop_read_reg(struct vop *vop, uint32_t base, return (vop_readl(vop, base + reg->offset) >> reg->shift) & reg->mask; } -static inline void vop_mask_write(struct vop *vop, uint32_t offset, - uint32_t mask, uint32_t shift, uint32_t v, - bool write_mask, bool relaxed) +static void vop_reg_set(struct vop *vop, const struct vop_reg *reg, + uint32_t _offset, uint32_t _mask, uint32_t v, + const char *reg_name) { - if (!mask) + int offset, mask, shift; + + if (!reg || !reg->mask) { + dev_dbg(vop->dev, "Warning: not support %s\n", reg_name); return; + } + + offset = reg->offset + _offset; + mask = reg->mask & _mask; + shift = reg->shift; - if (write_mask) { + if (reg->write_mask) { v = ((v << shift) & 0xffff) | (mask << (shift + 16)); } else { uint32_t cached_val = vop->regsbak[offset >> 2]; @@ -182,7 +177,7 @@ static inline void vop_mask_write(struct vop *vop, uint32_t offset, vop->regsbak[offset >> 2] = v; } - if (relaxed) + if (reg->relaxed) writel_relaxed(v, vop->regs + offset); else writel(v, vop->regs + offset); @@ -204,7 +199,7 @@ static inline uint32_t vop_get_intr_type(struct vop *vop, static inline void vop_cfg_done(struct vop *vop) { - VOP_CTRL_SET(vop, cfg_done, 1); + VOP_REG_SET(vop, common, cfg_done, 1); } static bool has_rb_swapped(uint32_t format) @@ -500,7 +495,7 @@ static void vop_line_flag_irq_disable(struct vop *vop) static int vop_enable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); - int ret; + int ret, i; ret = pm_runtime_get_sync(vop->dev); if (ret < 0) { @@ -533,6 +528,20 @@ static int vop_enable(struct drm_crtc *crtc) } memcpy(vop->regs, vop->regsbak, vop->len); + /* + * We need to make sure that all windows are disabled before we + * enable the crtc. Otherwise we might try to scan from a destroyed + * buffer later. + */ + for (i = 0; i < vop->data->win_size; i++) { + struct vop_win *vop_win = &vop->win[i]; + const struct vop_win_data *win = vop_win->data; + + spin_lock(&vop->reg_lock); + VOP_WIN_SET(vop, win, enable, 0); + spin_unlock(&vop->reg_lock); + } + vop_cfg_done(vop); /* @@ -542,7 +551,7 @@ static int vop_enable(struct drm_crtc *crtc) spin_lock(&vop->reg_lock); - VOP_CTRL_SET(vop, standby, 0); + VOP_REG_SET(vop, common, standby, 1); spin_unlock(&vop->reg_lock); @@ -567,28 +576,11 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct vop *vop = to_vop(crtc); - int i; WARN_ON(vop->event); rockchip_drm_psr_deactivate(&vop->crtc); - /* - * We need to make sure that all windows are disabled before we - * disable that crtc. Otherwise we might try to scan from a destroyed - * buffer later. - */ - for (i = 0; i < vop->data->win_size; i++) { - struct vop_win *vop_win = &vop->win[i]; - const struct vop_win_data *win = vop_win->data; - - spin_lock(&vop->reg_lock); - VOP_WIN_SET(vop, win, enable, 0); - spin_unlock(&vop->reg_lock); - } - - vop_cfg_done(vop); - drm_crtc_vblank_off(crtc); /* @@ -603,7 +595,7 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, spin_lock(&vop->reg_lock); - VOP_CTRL_SET(vop, standby, 1); + VOP_REG_SET(vop, common, standby, 1); spin_unlock(&vop->reg_lock); @@ -683,8 +675,10 @@ static int vop_plane_atomic_check(struct drm_plane *plane, * Src.x1 can be odd when do clip, but yuv plane start point * need align with 2 pixel. */ - if (is_yuv_support(fb->format->format) && ((state->src.x1 >> 16) % 2)) + if (is_yuv_support(fb->format->format) && ((state->src.x1 >> 16) % 2)) { + DRM_ERROR("Invalid Source: Yuv format not support odd xpos\n"); return -EINVAL; + } return 0; } @@ -765,7 +759,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, spin_lock(&vop->reg_lock); VOP_WIN_SET(vop, win, format, format); - VOP_WIN_SET(vop, win, yrgb_vir, fb->pitches[0] >> 2); + VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); if (is_yuv_support(fb->format->format)) { int hsub = drm_format_horz_chroma_subsampling(fb->format->format); @@ -779,7 +773,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, offset += (src->y1 >> 16) * fb->pitches[1] / vsub; dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; - VOP_WIN_SET(vop, win, uv_vir, fb->pitches[1] >> 2); + VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4)); VOP_WIN_SET(vop, win, uv_mst, dma_addr); } @@ -900,70 +894,34 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, return; } - /* - * If dclk rate is zero, mean that scanout is stop, - * we don't need wait any more. - */ - if (clk_get_rate(vop->dclk)) { - /* - * Rk3288 vop timing register is immediately, when configure - * display timing on display time, may cause tearing. - * - * Vop standby will take effect at end of current frame, - * if dsp hold valid irq happen, it means standby complete. - * - * mode set: - * standby and wait complete --> |---- - * | display time - * |---- - * |---> dsp hold irq - * configure display timing --> | - * standby exit | - * | new frame start. - */ - - reinit_completion(&vop->dsp_hold_completion); - vop_dsp_hold_valid_irq_enable(vop); - - spin_lock(&vop->reg_lock); - - VOP_CTRL_SET(vop, standby, 1); - - spin_unlock(&vop->reg_lock); - - wait_for_completion(&vop->dsp_hold_completion); - - vop_dsp_hold_valid_irq_disable(vop); - } - pin_pol = BIT(DCLK_INVERT); pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) ? BIT(HSYNC_POSITIVE) : 0; pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ? BIT(VSYNC_POSITIVE) : 0; - VOP_CTRL_SET(vop, pin_pol, pin_pol); + VOP_REG_SET(vop, output, pin_pol, pin_pol); switch (s->output_type) { case DRM_MODE_CONNECTOR_LVDS: - VOP_CTRL_SET(vop, rgb_en, 1); - VOP_CTRL_SET(vop, rgb_pin_pol, pin_pol); + VOP_REG_SET(vop, output, rgb_en, 1); + VOP_REG_SET(vop, output, rgb_pin_pol, pin_pol); break; case DRM_MODE_CONNECTOR_eDP: - VOP_CTRL_SET(vop, edp_pin_pol, pin_pol); - VOP_CTRL_SET(vop, edp_en, 1); + VOP_REG_SET(vop, output, edp_pin_pol, pin_pol); + VOP_REG_SET(vop, output, edp_en, 1); break; case DRM_MODE_CONNECTOR_HDMIA: - VOP_CTRL_SET(vop, hdmi_pin_pol, pin_pol); - VOP_CTRL_SET(vop, hdmi_en, 1); + VOP_REG_SET(vop, output, hdmi_pin_pol, pin_pol); + VOP_REG_SET(vop, output, hdmi_en, 1); break; case DRM_MODE_CONNECTOR_DSI: - VOP_CTRL_SET(vop, mipi_pin_pol, pin_pol); - VOP_CTRL_SET(vop, mipi_en, 1); + VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol); + VOP_REG_SET(vop, output, mipi_en, 1); break; case DRM_MODE_CONNECTOR_DisplayPort: pin_pol &= ~BIT(DCLK_INVERT); - VOP_CTRL_SET(vop, dp_pin_pol, pin_pol); - VOP_CTRL_SET(vop, dp_en, 1); + VOP_REG_SET(vop, output, dp_pin_pol, pin_pol); + VOP_REG_SET(vop, output, dp_en, 1); break; default: DRM_DEV_ERROR(vop->dev, "unsupported connector_type [%d]\n", @@ -976,25 +934,25 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && !(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10)) s->output_mode = ROCKCHIP_OUT_MODE_P888; - VOP_CTRL_SET(vop, out_mode, s->output_mode); + VOP_REG_SET(vop, common, out_mode, s->output_mode); - VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len); + VOP_REG_SET(vop, modeset, htotal_pw, (htotal << 16) | hsync_len); val = hact_st << 16; val |= hact_end; - VOP_CTRL_SET(vop, hact_st_end, val); - VOP_CTRL_SET(vop, hpost_st_end, val); + VOP_REG_SET(vop, modeset, hact_st_end, val); + VOP_REG_SET(vop, modeset, hpost_st_end, val); - VOP_CTRL_SET(vop, vtotal_pw, (vtotal << 16) | vsync_len); + VOP_REG_SET(vop, modeset, vtotal_pw, (vtotal << 16) | vsync_len); val = vact_st << 16; val |= vact_end; - VOP_CTRL_SET(vop, vact_st_end, val); - VOP_CTRL_SET(vop, vpost_st_end, val); + VOP_REG_SET(vop, modeset, vact_st_end, val); + VOP_REG_SET(vop, modeset, vpost_st_end, val); - VOP_CTRL_SET(vop, line_flag_num[0], vact_end); + VOP_REG_SET(vop, intr, line_flag_num[0], vact_end); clk_set_rate(vop->dclk, adjusted_mode->clock * 1000); - VOP_CTRL_SET(vop, standby, 0); + VOP_REG_SET(vop, common, standby, 0); rockchip_drm_psr_activate(&vop->crtc); } @@ -1293,7 +1251,7 @@ static int vop_create_crtc(struct vop *vop) 0, &vop_plane_funcs, win_data->phy->data_formats, win_data->phy->nformats, - win_data->type, NULL); + NULL, win_data->type, NULL); if (ret) { DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n", ret); @@ -1332,7 +1290,7 @@ static int vop_create_crtc(struct vop *vop) &vop_plane_funcs, win_data->phy->data_formats, win_data->phy->nformats, - win_data->type, NULL); + NULL, win_data->type, NULL); if (ret) { DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n", ret); @@ -1398,7 +1356,6 @@ static void vop_destroy_crtc(struct vop *vop) static int vop_initial(struct vop *vop) { const struct vop_data *vop_data = vop->data; - const struct vop_reg_data *init_table = vop_data->init_table; struct reset_control *ahb_rst; int i, ret; @@ -1458,13 +1415,16 @@ static int vop_initial(struct vop *vop) memcpy(vop->regsbak, vop->regs, vop->len); - for (i = 0; i < vop_data->table_size; i++) - vop_writel(vop, init_table[i].offset, init_table[i].value); + VOP_REG_SET(vop, misc, global_regdone_en, 1); + VOP_REG_SET(vop, common, dsp_blank, 0); for (i = 0; i < vop_data->win_size; i++) { const struct vop_win_data *win = &vop_data->win[i]; + int channel = i * 2 + 1; + VOP_WIN_SET(vop, win, channel, (channel + 1) << 4 | channel); VOP_WIN_SET(vop, win, enable, 0); + VOP_WIN_SET(vop, win, gate, 1); } vop_cfg_done(vop); |