#include <linux/reset.h>
#include <linux/delay.h>
#include <linux/sort.h>
+#include <uapi/drm/rockchip_drm.h>
#include "rockchip_drm_drv.h"
#include "rockchip_drm_gem.h"
#include "rockchip_drm_fb.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 VOP_REG_SUPPORT(vop, reg) \
+ (!reg.major || (reg.major == VOP_MAJOR(vop->data->version) && \
+ reg.begin_minor <= VOP_MINOR(vop->data->version) && \
+ reg.end_minor >= VOP_MINOR(vop->data->version) && \
+ reg.mask))
-#define __REG_SET_NORMAL(x, off, mask, shift, v, write_mask) \
- vop_mask_write(x, off, mask, shift, v, write_mask, false)
+#define VOP_WIN_SUPPORT(vop, win, name) \
+ VOP_REG_SUPPORT(vop, win->phy->name)
-#define REG_SET(x, off, reg, v, mode) \
- __REG_SET_##mode(x, off + reg.offset, \
- reg.mask, reg.shift, v, reg.write_mask)
-#define REG_SET_MASK(x, off, reg, mask, v, mode) \
- __REG_SET_##mode(x, off + reg.offset, \
- mask, reg.shift, v, reg.write_mask)
+#define VOP_CTRL_SUPPORT(vop, win, name) \
+ VOP_REG_SUPPORT(vop, vop->data->ctrl->name)
+
+#define VOP_INTR_SUPPORT(vop, win, name) \
+ VOP_REG_SUPPORT(vop, vop->data->intr->name)
+
+#define __REG_SET(x, off, mask, shift, v, write_mask, relaxed) \
+ vop_mask_write(x, off, mask, shift, v, write_mask, relaxed)
+
+#define _REG_SET(vop, name, off, reg, mask, v, relaxed) \
+ do { \
+ if (VOP_REG_SUPPORT(vop, reg)) \
+ __REG_SET(vop, off + reg.offset, mask, reg.shift, \
+ v, reg.write_mask, relaxed); \
+ else \
+ dev_dbg(vop->dev, "Warning: not support "#name"\n"); \
+ } while(0)
+
+#define REG_SET(x, name, off, reg, v, relaxed) \
+ _REG_SET(x, name, off, reg, reg.mask, v, relaxed)
+#define REG_SET_MASK(x, name, off, reg, mask, v, relaxed) \
+ _REG_SET(x, name, off, reg, reg.mask & mask, v, relaxed)
#define VOP_WIN_SET(x, win, name, v) \
- REG_SET(x, win->offset, VOP_WIN_NAME(win, name), v, RELAXED)
+ REG_SET(x, name, win->offset, VOP_WIN_NAME(win, name), v, true)
#define VOP_SCL_SET(x, win, name, v) \
- REG_SET(x, win->offset, win->phy->scl->name, v, RELAXED)
+ REG_SET(x, name, win->offset, win->phy->scl->name, v, true)
#define VOP_SCL_SET_EXT(x, win, name, v) \
- REG_SET(x, win->offset, win->phy->scl->ext->name, v, RELAXED)
+ REG_SET(x, name, win->offset, win->phy->scl->ext->name, v, true)
#define VOP_CTRL_SET(x, name, v) \
- REG_SET(x, 0, (x)->data->ctrl->name, v, NORMAL)
+ REG_SET(x, name, 0, (x)->data->ctrl->name, v, false)
#define VOP_INTR_GET(vop, name) \
vop_read_reg(vop, 0, &vop->data->ctrl->name)
#define VOP_INTR_SET(vop, name, mask, v) \
- REG_SET_MASK(vop, 0, vop->data->intr->name, mask, v, NORMAL)
+ REG_SET_MASK(vop, name, 0, vop->data->intr->name, \
+ mask, v, false)
+
#define VOP_INTR_SET_TYPE(vop, name, type, v) \
do { \
int i, reg = 0, mask = 0; \
#define VOP_INTR_GET_TYPE(vop, name, type) \
vop_get_intr_type(vop, &vop->data->intr->name, type)
+#define VOP_CTRL_GET(x, name) \
+ vop_read_reg(x, 0, vop->data->ctrl->name)
+
#define VOP_WIN_GET(x, win, name) \
vop_read_reg(x, win->offset, &VOP_WIN_NAME(win, name))
uint32_t nformats;
struct vop *vop;
+ struct drm_property *rotation_prop;
struct vop_plane_state state;
};
struct device *dev;
struct drm_device *drm_dev;
struct drm_property *plane_zpos_prop;
- bool is_enabled;
+ struct drm_property *plane_feature_prop;
+ bool is_iommu_enabled;
+ bool is_iommu_needed;
/* mutex vsync_ work */
struct mutex vsync_mutex;
VOP_CTRL_SET(vop, cfg_done, 1);
}
+static bool vop_is_allwin_disabled(struct vop *vop)
+{
+ int i;
+
+ for (i = 0; i < vop->num_wins; i++) {
+ struct vop_win *win = &vop->win[i];
+
+ if (VOP_WIN_GET(vop, win, enable) != 0)
+ return false;
+ }
+
+ return true;
+}
+
+static bool vop_win_pending_is_complete(struct vop *vop)
+{
+ dma_addr_t yrgb_mst;
+ int i;
+
+ for (i = 0; i < vop->num_wins; i++) {
+ struct vop_win *win = &vop->win[i];
+ struct drm_plane *plane = &win->base;
+ struct vop_plane_state *state =
+ to_vop_plane_state(plane->state);
+ if (!state->enable) {
+ if (VOP_WIN_GET(vop, win, enable) != 0)
+ return false;
+ continue;
+ }
+ yrgb_mst = VOP_WIN_GET_YRGBADDR(vop, win);
+ if (yrgb_mst != state->yrgb_mst)
+ return false;
+ }
+
+ return true;
+}
+
static bool has_rb_swapped(uint32_t format)
{
switch (format) {
{
unsigned long flags;
- if (WARN_ON(!vop->is_enabled))
- return;
-
spin_lock_irqsave(&vop->irq_lock, flags);
VOP_INTR_SET_TYPE(vop, enable, DSP_HOLD_VALID_INTR, 1);
{
unsigned long flags;
- if (WARN_ON(!vop->is_enabled))
- return;
-
spin_lock_irqsave(&vop->irq_lock, flags);
VOP_INTR_SET_TYPE(vop, enable, DSP_HOLD_VALID_INTR, 0);
static void vop_enable(struct drm_crtc *crtc)
{
struct vop *vop = to_vop(crtc);
- int ret;
-
- if (vop->is_enabled)
- return;
+ int ret, i;
- ret = clk_enable(vop->hclk);
+ ret = clk_prepare_enable(vop->hclk);
if (ret < 0) {
dev_err(vop->dev, "failed to enable hclk - %d\n", ret);
return;
}
- ret = clk_enable(vop->dclk);
+ ret = clk_prepare_enable(vop->dclk);
if (ret < 0) {
dev_err(vop->dev, "failed to enable dclk - %d\n", ret);
goto err_disable_hclk;
}
- ret = clk_enable(vop->aclk);
+ ret = clk_prepare_enable(vop->aclk);
if (ret < 0) {
dev_err(vop->dev, "failed to enable aclk - %d\n", ret);
goto err_disable_dclk;
return;
}
- /*
- * Slave iommu shares power, irq and clock with vop. It was associated
- * automatically with this master device via common driver code.
- * Now that we have enabled the clock we attach it to the shared drm
- * mapping.
- */
- ret = rockchip_drm_dma_attach_device(vop->drm_dev, vop->dev);
- if (ret) {
- dev_err(vop->dev, "failed to attach dma mapping, %d\n", ret);
- goto err_disable_aclk;
- }
+ memcpy(vop->regsbak, vop->regs, vop->len);
- memcpy(vop->regs, vop->regsbak, vop->len);
- /*
- * At here, vop clock & iommu is enable, R/W vop regs would be safe.
- */
- vop->is_enabled = true;
+ VOP_CTRL_SET(vop, global_regdone_en, 1);
+
+ for (i = 0; i < vop->num_wins; i++) {
+ struct vop_win *win = &vop->win[i];
+
+ VOP_WIN_SET(vop, win, gate, 1);
+ }
spin_lock(&vop->reg_lock);
return;
-err_disable_aclk:
- clk_disable(vop->aclk);
err_disable_dclk:
- clk_disable(vop->dclk);
+ clk_disable_unprepare(vop->dclk);
err_disable_hclk:
- clk_disable(vop->hclk);
+ clk_disable_unprepare(vop->hclk);
}
static void vop_crtc_disable(struct drm_crtc *crtc)
struct vop *vop = to_vop(crtc);
int i;
- if (!vop->is_enabled)
- return;
-
/*
* We need to make sure that all windows are disabled before we
* disable that crtc. Otherwise we might try to scan from a destroyed
VOP_WIN_SET(vop, win, enable, 0);
spin_unlock(&vop->reg_lock);
}
+ vop_cfg_done(vop);
drm_crtc_vblank_off(crtc);
disable_irq(vop->irq);
- vop->is_enabled = false;
-
- /*
- * vop standby complete, so iommu detach is safe.
- */
- rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev);
+ if (vop->is_iommu_enabled) {
+ /*
+ * vop standby complete, so iommu detach is safe.
+ */
+ rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev);
+ vop->is_iommu_enabled = false;
+ }
pm_runtime_put(vop->dev);
- clk_disable(vop->dclk);
- clk_disable(vop->aclk);
- clk_disable(vop->hclk);
+ clk_disable_unprepare(vop->dclk);
+ clk_disable_unprepare(vop->aclk);
+ clk_disable_unprepare(vop->hclk);
}
static void vop_plane_destroy(struct drm_plane *plane)
uint32_t act_info, dsp_info, dsp_st;
struct drm_rect *src = &vop_plane_state->src;
struct drm_rect *dest = &vop_plane_state->dest;
- struct drm_gem_object *obj, *uv_obj;
- struct rockchip_gem_object *rk_obj, *rk_uv_obj;
unsigned long offset;
dma_addr_t dma_addr;
+ int ymirror, xmirror;
uint32_t val;
bool rb_swap;
if (!crtc)
return;
- if (WARN_ON(!vop->is_enabled))
- return;
-
if (!vop_plane_state->enable) {
vop_plane_atomic_disable(plane, old_state);
return;
}
- obj = rockchip_fb_get_gem_obj(fb, 0);
- rk_obj = to_rockchip_obj(obj);
-
actual_w = drm_rect_width(src) >> 16;
actual_h = drm_rect_height(src) >> 16;
act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);
dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff);
offset = (src->x1 >> 16) * drm_format_plane_cpp(fb->pixel_format, 0);
- offset += (src->y1 >> 16) * fb->pitches[0];
- vop_plane_state->yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];
+ if (state->rotation & BIT(DRM_REFLECT_Y))
+ offset += ((src->y2 >> 16) - 1) * fb->pitches[0];
+ else
+ offset += (src->y1 >> 16) * fb->pitches[0];
+
+ dma_addr = rockchip_fb_get_dma_addr(fb, 0);
+ vop_plane_state->yrgb_mst = dma_addr + offset + fb->offsets[0];
+
+ ymirror = !!(state->rotation & BIT(DRM_REFLECT_Y));
+ xmirror = !!(state->rotation & BIT(DRM_REFLECT_X));
spin_lock(&vop->reg_lock);
+ VOP_WIN_SET(vop, win, xmirror, xmirror);
+ VOP_WIN_SET(vop, win, ymirror, ymirror);
VOP_WIN_SET(vop, win, format, vop_plane_state->format);
VOP_WIN_SET(vop, win, yrgb_vir, fb->pitches[0] >> 2);
VOP_WIN_SET(vop, win, yrgb_mst, vop_plane_state->yrgb_mst);
int vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
int bpp = drm_format_plane_cpp(fb->pixel_format, 1);
- uv_obj = rockchip_fb_get_gem_obj(fb, 1);
- rk_uv_obj = to_rockchip_obj(uv_obj);
-
offset = (src->x1 >> 16) * bpp / hsub;
offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
- dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1];
+ dma_addr = rockchip_fb_get_dma_addr(fb, 1);
+ dma_addr += offset + fb->offsets[1];
VOP_WIN_SET(vop, win, uv_vir, fb->pitches[1] >> 2);
VOP_WIN_SET(vop, win, uv_mst, dma_addr);
}
SRC_ALPHA_CAL_M0(ALPHA_NO_SATURATION) |
SRC_FACTOR_M0(ALPHA_ONE);
VOP_WIN_SET(vop, win, src_alpha_ctl, val);
+ VOP_WIN_SET(vop, win, alpha_mode, 1);
+ VOP_WIN_SET(vop, win, alpha_en, 1);
} else {
VOP_WIN_SET(vop, win, src_alpha_ctl, SRC_ALPHA_EN(0));
+ VOP_WIN_SET(vop, win, alpha_en, 0);
}
VOP_WIN_SET(vop, win, enable, 1);
spin_unlock(&vop->reg_lock);
+ vop->is_iommu_needed = true;
}
static const struct drm_plane_helper_funcs plane_helper_funcs = {
return 0;
}
+ if (property == win->rotation_prop) {
+ state->rotation = val;
+ return 0;
+ }
+
DRM_ERROR("failed to set vop plane property\n");
return -EINVAL;
}
return 0;
}
+ if (property == win->rotation_prop) {
+ *val = state->rotation;
+ return 0;
+ }
+
DRM_ERROR("failed to get vop plane property\n");
return -EINVAL;
}
struct vop *vop = to_vop(crtc);
unsigned long flags;
- if (WARN_ON(!vop->is_enabled))
- return -EPERM;
-
spin_lock_irqsave(&vop->irq_lock, flags);
VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 1);
struct vop *vop = to_vop(crtc);
unsigned long flags;
- if (WARN_ON(!vop->is_enabled))
- return;
-
spin_lock_irqsave(&vop->irq_lock, flags);
VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 0);
struct vop_zpos *pa = (struct vop_zpos *)a;
struct vop_zpos *pb = (struct vop_zpos *)b;
- return pb->zpos - pa->zpos;
+ return pa->zpos - pb->zpos;
}
static int vop_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_crtc_state *state)
+ struct drm_crtc_state *crtc_state)
{
- struct drm_device *dev = crtc->dev;
- struct rockchip_crtc_state *s = to_rockchip_crtc_state(state);
+ struct drm_atomic_state *state = crtc_state->state;
+ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
struct vop *vop = to_vop(crtc);
const struct vop_data *vop_data = vop->data;
struct drm_plane *plane;
+ struct drm_plane_state *pstate;
+ struct vop_plane_state *plane_state;
struct vop_zpos *pzpos;
int dsp_layer_sel = 0;
- int i, cnt = 0, ret = 0;
+ int i, j, cnt = 0, ret = 0;
- pzpos = kmalloc_array(vop->num_wins, sizeof(*pzpos), GFP_KERNEL);
+ pzpos = kmalloc_array(vop_data->win_size, sizeof(*pzpos), GFP_KERNEL);
if (!pzpos)
return -ENOMEM;
- drm_atomic_crtc_state_for_each_plane(plane, state) {
- struct drm_plane_state *pstate;
- struct vop_plane_state *plane_state;
- struct vop_win *win = to_vop_win(plane);
+ for (i = 0; i < vop_data->win_size; i++) {
+ const struct vop_win_data *win_data = &vop_data->win[i];
+ struct vop_win *win;
- if (plane->parent)
+ if (!win_data->phy)
continue;
- if (cnt >= vop->num_wins) {
- dev_err(dev->dev, "too many planes!\n");
+
+ for (j = 0; j < vop->num_wins; j++) {
+ win = &vop->win[j];
+
+ if (win->win_id == i && !win->area_id)
+ break;
+ }
+ if (WARN_ON(j >= vop->num_wins)) {
ret = -EINVAL;
goto err_free_pzpos;
}
- pstate = state->state->plane_states[drm_plane_index(plane)];
+ plane = &win->base;
+ pstate = state->plane_states[drm_plane_index(plane)];
/*
* plane might not have changed, in which case take
* current state:
pstate = plane->state;
plane_state = to_vop_plane_state(pstate);
pzpos[cnt].zpos = plane_state->zpos;
- pzpos[cnt].win_id = win->win_id;
-
- cnt++;
+ pzpos[cnt++].win_id = win->win_id;
}
sort(pzpos, cnt, sizeof(pzpos[0]), vop_zpos_cmp, NULL);
- WARN_ON(vop_data->win_size < cnt);
- for (i = 0; i < (vop_data->win_size - cnt); i++) {
- dsp_layer_sel <<= 2;
- /*
- * after sort, pzpos[0] is the top zpos layer.
- */
- dsp_layer_sel |= pzpos[0].win_id;
- }
+ for (i = 0, cnt = 0; i < vop_data->win_size; i++) {
+ const struct vop_win_data *win_data = &vop_data->win[i];
+ int shift = i * 2;
- for (i = 0; i < cnt; i++) {
- struct vop_zpos *zpos = &pzpos[i];
+ if (win_data->phy) {
+ struct vop_zpos *zpos = &pzpos[cnt++];
- dsp_layer_sel <<= 2;
- dsp_layer_sel |= zpos->win_id;
+ dsp_layer_sel |= zpos->win_id << shift;
+ } else {
+ dsp_layer_sel |= i << shift;
+ }
}
s->dsp_layer_sel = dsp_layer_sel;
return ret;
}
-static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_crtc_state)
+static void vop_cfg_update(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
{
struct rockchip_crtc_state *s =
to_rockchip_crtc_state(crtc->state);
struct vop *vop = to_vop(crtc);
- if (WARN_ON(!vop->is_enabled))
- return;
-
spin_lock(&vop->reg_lock);
VOP_CTRL_SET(vop, dsp_layer_sel, s->dsp_layer_sel);
spin_unlock(&vop->reg_lock);
}
+static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ struct vop *vop = to_vop(crtc);
+
+ if (!vop->is_iommu_enabled && vop->is_iommu_needed) {
+ int ret;
+ if (!vop_is_allwin_disabled(vop)) {
+ vop_cfg_update(crtc, old_crtc_state);
+ while(!vop_win_pending_is_complete(vop));
+ }
+ ret = rockchip_drm_dma_attach_device(vop->drm_dev, vop->dev);
+ if (ret) {
+ dev_err(vop->dev, "failed to attach dma mapping, %d\n", ret);
+ }
+ vop->is_iommu_enabled = true;
+ }
+
+ vop_cfg_update(crtc, old_crtc_state);
+}
+
static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
drm_crtc_cleanup(crtc);
}
+static void vop_crtc_reset(struct drm_crtc *crtc)
+{
+ if (crtc->state)
+ __drm_atomic_helper_crtc_destroy_state(crtc, crtc->state);
+ kfree(crtc->state);
+
+ crtc->state = kzalloc(sizeof(struct rockchip_crtc_state), GFP_KERNEL);
+ if (crtc->state)
+ crtc->state->crtc = crtc;
+}
+
static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc)
{
struct rockchip_crtc_state *rockchip_state;
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.destroy = vop_crtc_destroy,
- .reset = drm_atomic_helper_crtc_reset,
+ .reset = vop_crtc_reset,
.atomic_duplicate_state = vop_crtc_duplicate_state,
.atomic_destroy_state = vop_crtc_destroy_state,
};
-static bool vop_win_pending_is_complete(struct vop_win *vop_win)
-{
- struct drm_plane *plane = &vop_win->base;
- struct vop_plane_state *state = to_vop_plane_state(plane->state);
- dma_addr_t yrgb_mst;
-
- if (!state->enable)
- return VOP_WIN_GET(vop_win->vop, vop_win, enable) == 0;
-
- yrgb_mst = VOP_WIN_GET_YRGBADDR(vop_win->vop, vop_win);
-
- return yrgb_mst == state->yrgb_mst;
-}
-
static void vop_handle_vblank(struct vop *vop)
{
struct drm_device *drm = vop->drm_dev;
struct drm_crtc *crtc = &vop->crtc;
unsigned long flags;
- int i;
- for (i = 0; i < vop->num_wins; i++) {
- if (!vop_win_pending_is_complete(&vop->win[i]))
- return;
- }
+ if (!vop_win_pending_is_complete(vop))
+ return;
if (vop->event) {
spin_lock_irqsave(&drm->event_lock, flags);
unsigned long possible_crtcs)
{
struct drm_plane *share = NULL;
+ unsigned int rotations = 0;
+ struct drm_property *prop;
+ uint64_t feature = 0;
int ret;
if (win->parent)
drm_plane_helper_add(&win->base, &plane_helper_funcs);
drm_object_attach_property(&win->base.base,
vop->plane_zpos_prop, win->win_id);
+
+ if (VOP_WIN_SUPPORT(vop, win, xmirror))
+ rotations |= BIT(DRM_REFLECT_X);
+
+ if (VOP_WIN_SUPPORT(vop, win, ymirror))
+ rotations |= BIT(DRM_REFLECT_Y);
+
+ if (rotations) {
+ rotations |= BIT(DRM_ROTATE_0);
+ prop = drm_mode_create_rotation_property(vop->drm_dev,
+ rotations);
+ if (!prop) {
+ DRM_ERROR("failed to create zpos property\n");
+ return -EINVAL;
+ }
+ drm_object_attach_property(&win->base.base, prop,
+ BIT(DRM_ROTATE_0));
+ win->rotation_prop = prop;
+ }
+ if (win->phy->scl)
+ feature |= BIT(ROCKCHIP_DRM_PLANE_FEATURE_SCALE);
+ if (VOP_WIN_SUPPORT(vop, win, src_alpha_ctl) ||
+ VOP_WIN_SUPPORT(vop, win, alpha_en))
+ feature |= BIT(ROCKCHIP_DRM_PLANE_FEATURE_ALPHA);
+
+ drm_object_attach_property(&win->base.base, vop->plane_feature_prop,
+ feature);
+
return 0;
}
drm_crtc_cleanup(crtc);
}
-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;
-
- vop->hclk = devm_clk_get(vop->dev, "hclk_vop");
- if (IS_ERR(vop->hclk)) {
- dev_err(vop->dev, "failed to get hclk source\n");
- return PTR_ERR(vop->hclk);
- }
- vop->aclk = devm_clk_get(vop->dev, "aclk_vop");
- if (IS_ERR(vop->aclk)) {
- dev_err(vop->dev, "failed to get aclk source\n");
- return PTR_ERR(vop->aclk);
- }
- vop->dclk = devm_clk_get(vop->dev, "dclk_vop");
- if (IS_ERR(vop->dclk)) {
- dev_err(vop->dev, "failed to get dclk source\n");
- return PTR_ERR(vop->dclk);
- }
-
- ret = clk_prepare(vop->dclk);
- if (ret < 0) {
- dev_err(vop->dev, "failed to prepare dclk\n");
- return ret;
- }
-
- /* Enable both the hclk and aclk to setup the vop */
- ret = clk_prepare_enable(vop->hclk);
- if (ret < 0) {
- dev_err(vop->dev, "failed to prepare/enable hclk\n");
- goto err_unprepare_dclk;
- }
-
- ret = clk_prepare_enable(vop->aclk);
- if (ret < 0) {
- dev_err(vop->dev, "failed to prepare/enable aclk\n");
- goto err_disable_hclk;
- }
-
- /*
- * do hclk_reset, reset all vop registers.
- */
- ahb_rst = devm_reset_control_get(vop->dev, "ahb");
- if (IS_ERR(ahb_rst)) {
- dev_err(vop->dev, "failed to get ahb reset\n");
- ret = PTR_ERR(ahb_rst);
- goto err_disable_aclk;
- }
- reset_control_assert(ahb_rst);
- usleep_range(10, 20);
- reset_control_deassert(ahb_rst);
-
- 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);
-
- for (i = 0; i < vop->num_wins; i++) {
- struct vop_win *win = &vop->win[i];
-
- VOP_WIN_SET(vop, win, enable, 0);
- }
-
- vop_cfg_done(vop);
-
- /*
- * do dclk_reset, let all config take affect.
- */
- vop->dclk_rst = devm_reset_control_get(vop->dev, "dclk");
- if (IS_ERR(vop->dclk_rst)) {
- dev_err(vop->dev, "failed to get dclk reset\n");
- ret = PTR_ERR(vop->dclk_rst);
- goto err_disable_aclk;
- }
- reset_control_assert(vop->dclk_rst);
- usleep_range(10, 20);
- reset_control_deassert(vop->dclk_rst);
-
- clk_disable(vop->hclk);
- clk_disable(vop->aclk);
-
- vop->is_enabled = false;
-
- return 0;
-
-err_disable_aclk:
- clk_disable_unprepare(vop->aclk);
-err_disable_hclk:
- clk_disable_unprepare(vop->hclk);
-err_unprepare_dclk:
- clk_unprepare(vop->dclk);
- return ret;
-}
-
/*
* Initialize the vop->win array elements.
*/
unsigned int i, j;
unsigned int num_wins = 0;
struct drm_property *prop;
+ static const struct drm_prop_enum_list props[] = {
+ { ROCKCHIP_DRM_PLANE_FEATURE_SCALE, "scale" },
+ { ROCKCHIP_DRM_PLANE_FEATURE_ALPHA, "alpha" },
+ };
for (i = 0; i < vop_data->win_size; i++) {
struct vop_win *vop_win = &vop->win[num_wins];
const struct vop_win_data *win_data = &vop_data->win[i];
+ if (!win_data->phy)
+ continue;
+
vop_win->phy = win_data->phy;
vop_win->offset = win_data->base;
vop_win->type = win_data->type;
num_wins++;
}
}
+
+ vop->num_wins = num_wins;
+
prop = drm_property_create_range(vop->drm_dev, DRM_MODE_PROP_ATOMIC,
"ZPOS", 0, vop->data->win_size);
if (!prop) {
}
vop->plane_zpos_prop = prop;
+ vop->plane_feature_prop = drm_property_create_bitmask(vop->drm_dev,
+ DRM_MODE_PROP_IMMUTABLE, "FEATURE",
+ props, ARRAY_SIZE(props),
+ BIT(ROCKCHIP_DRM_PLANE_FEATURE_SCALE) |
+ BIT(ROCKCHIP_DRM_PLANE_FEATURE_ALPHA));
+ if (!vop->plane_feature_prop) {
+ DRM_ERROR("failed to create feature property\n");
+ return -EINVAL;
+ }
+
return 0;
}
if (!vop->regsbak)
return -ENOMEM;
- ret = vop_initial(vop);
- if (ret < 0) {
- dev_err(&pdev->dev, "cannot initial vop dev - err %d\n", ret);
- return ret;
+ vop->hclk = devm_clk_get(vop->dev, "hclk_vop");
+ if (IS_ERR(vop->hclk)) {
+ dev_err(vop->dev, "failed to get hclk source\n");
+ return PTR_ERR(vop->hclk);
+ }
+ vop->aclk = devm_clk_get(vop->dev, "aclk_vop");
+ if (IS_ERR(vop->aclk)) {
+ dev_err(vop->dev, "failed to get aclk source\n");
+ return PTR_ERR(vop->aclk);
+ }
+ vop->dclk = devm_clk_get(vop->dev, "dclk_vop");
+ if (IS_ERR(vop->dclk)) {
+ dev_err(vop->dev, "failed to get dclk source\n");
+ return PTR_ERR(vop->dclk);
}
irq = platform_get_irq(pdev, 0);