diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index d3c80337b083..2785bcf8a800 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -42,19 +42,20 @@ #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, \ +#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, base, reg, mask, v, mode) \ - __REG_SET_##mode(x, base + reg.offset, \ +#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_WIN_SET(x, win, name, v) \ - REG_SET(x, win->base, win->phy->name, v, RELAXED) + REG_SET(x, win->offset, VOP_WIN_NAME(win, name), v, RELAXED) #define VOP_SCL_SET(x, win, name, v) \ - REG_SET(x, win->base, win->phy->scl->name, v, RELAXED) + REG_SET(x, win->offset, win->phy->scl->name, v, RELAXED) #define VOP_SCL_SET_EXT(x, win, name, v) \ - REG_SET(x, win->base, win->phy->scl->ext->name, v, RELAXED) + REG_SET(x, win->offset, win->phy->scl->ext->name, v, RELAXED) + #define VOP_CTRL_SET(x, name, v) \ REG_SET(x, 0, (x)->data->ctrl->name, v, NORMAL) @@ -78,10 +79,13 @@ 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, &VOP_WIN_NAME(win, name)) + +#define VOP_WIN_NAME(win, name) \ + (vop_get_win_phy(win, &win->phy->name)->name) #define VOP_WIN_GET_YRGBADDR(vop, win) \ - vop_readl(vop, win->base + win->phy->yrgb_mst.offset) + vop_readl(vop, win->offset + VOP_WIN_NAME(win, yrgb_mst).offset) #define to_vop(x) container_of(x, struct vop, crtc) #define to_vop_win(x) container_of(x, struct vop_win, base) @@ -97,8 +101,14 @@ struct vop_plane_state { }; struct vop_win { + struct vop_win *parent; struct drm_plane base; - const struct vop_win_data *data; + + uint32_t offset; + enum drm_plane_type type; + const struct vop_win_phy *phy; + const uint32_t *data_formats; + uint32_t nformats; struct vop *vop; struct vop_plane_state state; @@ -118,6 +128,7 @@ struct vop { struct drm_pending_vblank_event *event; const struct vop_data *data; + int num_wins; uint32_t *regsbak; void __iomem *regs; @@ -184,6 +195,15 @@ static inline void vop_mask_write(struct vop *vop, uint32_t offset, writel(v, vop->regs + offset); } +static inline const struct vop_win_phy * +vop_get_win_phy(struct vop_win *win, const struct vop_reg *reg) +{ + if (!reg->mask && win->parent) + return win->parent->phy; + + return win->phy; +} + static inline uint32_t vop_get_intr_type(struct vop *vop, const struct vop_reg *reg, int type) { @@ -296,9 +316,9 @@ static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, return val; } -static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, - uint32_t src_w, uint32_t src_h, uint32_t dst_w, - uint32_t dst_h, uint32_t pixel_format) +static void scl_vop_cal_scl_fac(struct vop *vop, struct vop_win *win, + uint32_t src_w, uint32_t src_h, uint32_t dst_w, + uint32_t dst_h, uint32_t pixel_format) { uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode; uint16_t cbcr_hor_scl_mode = SCALE_NONE; @@ -313,6 +333,9 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, uint32_t val; int vskiplines; + if (!win->phy->scl) + return; + if (dst_w > 3840) { DRM_ERROR("Maximum destination width (3840) exceeded\n"); return; @@ -510,9 +533,8 @@ static void vop_crtc_disable(struct drm_crtc *crtc) * 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; + for (i = 0; i < vop->num_wins; i++) { + struct vop_win *win = &vop->win[i]; spin_lock(&vop->reg_lock); VOP_WIN_SET(vop, win, enable, 0); @@ -566,9 +588,8 @@ static int vop_plane_atomic_check(struct drm_plane *plane, { struct drm_crtc *crtc = state->crtc; struct drm_framebuffer *fb = state->fb; - struct vop_win *vop_win = to_vop_win(plane); + struct vop_win *win = to_vop_win(plane); struct vop_plane_state *vop_plane_state = to_vop_plane_state(state); - const struct vop_win_data *win = vop_win->data; bool visible; int ret; struct drm_rect *dest = &vop_plane_state->dest; @@ -634,8 +655,7 @@ static void vop_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { struct vop_plane_state *vop_plane_state = to_vop_plane_state(old_state); - struct vop_win *vop_win = to_vop_win(plane); - const struct vop_win_data *win = vop_win->data; + struct vop_win *win = to_vop_win(plane); struct vop *vop = to_vop(old_state->crtc); if (!old_state->crtc) @@ -655,9 +675,8 @@ static void vop_plane_atomic_update(struct drm_plane *plane, { struct drm_plane_state *state = plane->state; struct drm_crtc *crtc = state->crtc; - struct vop_win *vop_win = to_vop_win(plane); + struct vop_win *win = to_vop_win(plane); struct vop_plane_state *vop_plane_state = to_vop_plane_state(state); - const struct vop_win_data *win = vop_win->data; struct vop *vop = to_vop(state->crtc); struct drm_framebuffer *fb = state->fb; unsigned int actual_w, actual_h; @@ -725,10 +744,9 @@ static void vop_plane_atomic_update(struct drm_plane *plane, VOP_WIN_SET(vop, win, uv_mst, dma_addr); } - if (win->phy->scl) - scl_vop_cal_scl_fac(vop, win, actual_w, actual_h, - drm_rect_width(dest), drm_rect_height(dest), - fb->pixel_format); + scl_vop_cal_scl_fac(vop, win, actual_w, actual_h, + drm_rect_width(dest), drm_rect_height(dest), + fb->pixel_format); VOP_WIN_SET(vop, win, act_info, act_info); VOP_WIN_SET(vop, win, dsp_info, dsp_info); @@ -1066,9 +1084,9 @@ static bool vop_win_pending_is_complete(struct vop_win *vop_win) dma_addr_t yrgb_mst; if (!state->enable) - return VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0; + return VOP_WIN_GET(vop_win->vop, vop_win, enable) == 0; - yrgb_mst = VOP_WIN_GET_YRGBADDR(vop_win->vop, vop_win->data); + yrgb_mst = VOP_WIN_GET_YRGBADDR(vop_win->vop, vop_win); return yrgb_mst == state->yrgb_mst; } @@ -1080,7 +1098,7 @@ static void vop_handle_vblank(struct vop *vop) unsigned long flags; int i; - for (i = 0; i < vop->data->win_size; i++) { + for (i = 0; i < vop->num_wins; i++) { if (!vop_win_pending_is_complete(&vop->win[i])) return; } @@ -1143,9 +1161,29 @@ static irqreturn_t vop_isr(int irq, void *data) return ret; } +static int vop_plane_init(struct vop *vop, struct vop_win *win, + unsigned long possible_crtcs) +{ + struct drm_plane *share = NULL; + int ret; + + if (win->parent) + share = &win->parent->base; + + ret = drm_share_plane_init(vop->drm_dev, &win->base, share, + possible_crtcs, &vop_plane_funcs, + win->data_formats, win->nformats, win->type); + if (ret) { + DRM_ERROR("failed to initialize plane\n"); + return ret; + } + drm_plane_helper_add(&win->base, &plane_helper_funcs); + + return 0; +} + static int vop_create_crtc(struct vop *vop) { - const struct vop_data *vop_data = vop->data; struct device *dev = vop->dev; struct drm_device *drm_dev = vop->drm_dev; struct drm_plane *primary = NULL, *cursor = NULL, *plane, *tmp; @@ -1159,30 +1197,22 @@ static int vop_create_crtc(struct vop *vop) * to pass them to drm_crtc_init_with_planes, which sets the * "possible_crtcs" to the newly initialized crtc. */ - for (i = 0; i < vop_data->win_size; i++) { - struct vop_win *vop_win = &vop->win[i]; - const struct vop_win_data *win_data = vop_win->data; + for (i = 0; i < vop->num_wins; i++) { + struct vop_win *win = &vop->win[i]; - if (win_data->type != DRM_PLANE_TYPE_PRIMARY && - win_data->type != DRM_PLANE_TYPE_CURSOR) + if (win->type != DRM_PLANE_TYPE_PRIMARY && + win->type != DRM_PLANE_TYPE_CURSOR) continue; - ret = drm_universal_plane_init(vop->drm_dev, &vop_win->base, - 0, &vop_plane_funcs, - win_data->phy->data_formats, - win_data->phy->nformats, - win_data->type, NULL); - if (ret) { - DRM_ERROR("failed to initialize plane\n"); + if (vop_plane_init(vop, win, 0)) goto err_cleanup_planes; - } - plane = &vop_win->base; - drm_plane_helper_add(plane, &plane_helper_funcs); + plane = &win->base; if (plane->type == DRM_PLANE_TYPE_PRIMARY) primary = plane; else if (plane->type == DRM_PLANE_TYPE_CURSOR) cursor = plane; + } ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, @@ -1196,25 +1226,15 @@ static int vop_create_crtc(struct vop *vop) * Create drm_planes for overlay windows with possible_crtcs restricted * to the newly created crtc. */ - for (i = 0; i < vop_data->win_size; i++) { - struct vop_win *vop_win = &vop->win[i]; - const struct vop_win_data *win_data = vop_win->data; + for (i = 0; i < vop->num_wins; i++) { + struct vop_win *win = &vop->win[i]; unsigned long possible_crtcs = 1 << drm_crtc_index(crtc); - if (win_data->type != DRM_PLANE_TYPE_OVERLAY) + if (win->type != DRM_PLANE_TYPE_OVERLAY) continue; - ret = drm_universal_plane_init(vop->drm_dev, &vop_win->base, - possible_crtcs, - &vop_plane_funcs, - win_data->phy->data_formats, - win_data->phy->nformats, - win_data->type, NULL); - if (ret) { - DRM_ERROR("failed to initialize overlay plane\n"); + if (vop_plane_init(vop, win, possible_crtcs)) goto err_cleanup_crtc; - } - drm_plane_helper_add(&vop_win->base, &plane_helper_funcs); } port = of_get_child_by_name(dev->of_node, "port"); @@ -1329,8 +1349,8 @@ static int vop_initial(struct vop *vop) 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_data->win_size; i++) { - const struct vop_win_data *win = &vop_data->win[i]; + for (i = 0; i < vop->num_wins; i++) { + struct vop_win *win = &vop->win[i]; VOP_WIN_SET(vop, win, enable, 0); } @@ -1372,14 +1392,34 @@ err_unprepare_dclk: static void vop_win_init(struct vop *vop) { const struct vop_data *vop_data = vop->data; - unsigned int i; + unsigned int i, j; + unsigned int num_wins = 0; for (i = 0; i < vop_data->win_size; i++) { - struct vop_win *vop_win = &vop->win[i]; + struct vop_win *vop_win = &vop->win[num_wins]; const struct vop_win_data *win_data = &vop_data->win[i]; - vop_win->data = win_data; + vop_win->phy = win_data->phy; + vop_win->offset = win_data->base; + vop_win->type = win_data->type; + vop_win->data_formats = win_data->phy->data_formats; + vop_win->nformats = win_data->phy->nformats; vop_win->vop = vop; + num_wins++; + + for (j = 0; j < win_data->area_size; j++) { + struct vop_win *vop_area = &vop->win[num_wins]; + const struct vop_win_phy *area = win_data->area[j]; + + vop_area->parent = vop_win; + vop_area->offset = vop_win->offset; + vop_area->phy = area; + vop_area->type = DRM_PLANE_TYPE_OVERLAY; + vop_area->data_formats = vop_win->data_formats; + vop_area->nformats = vop_win->nformats; + vop_area->vop = vop; + num_wins++; + } } } @@ -1391,14 +1431,21 @@ static int vop_bind(struct device *dev, struct device *master, void *data) struct vop *vop; struct resource *res; size_t alloc_size; - int ret, irq; + int ret, irq, i; + int num_wins = 0; vop_data = of_device_get_match_data(dev); if (!vop_data) return -ENODEV; + for (i = 0; i < vop_data->win_size; i++) { + const struct vop_win_data *win_data = &vop_data->win[i]; + + num_wins += win_data->area_size + 1; + } + /* Allocate vop struct and its vop_win array */ - alloc_size = sizeof(*vop) + sizeof(*vop->win) * vop_data->win_size; + alloc_size = sizeof(*vop) + sizeof(*vop->win) * num_wins; vop = devm_kzalloc(dev, alloc_size, GFP_KERNEL); if (!vop) return -ENOMEM; @@ -1406,6 +1453,7 @@ static int vop_bind(struct device *dev, struct device *master, void *data) vop->dev = dev; vop->data = vop_data; vop->drm_dev = drm_dev; + vop->num_wins = num_wins; dev_set_drvdata(dev, vop); vop_win_init(vop); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index b996679d3a1c..679396451762 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -127,8 +127,10 @@ struct vop_win_phy { struct vop_win_data { uint32_t base; - const struct vop_win_phy *phy; enum drm_plane_type type; + const struct vop_win_phy *phy; + const struct vop_win_phy **area; + unsigned int area_size; }; struct vop_data {