diff options
Diffstat (limited to 'drivers/gpu/drm/rockchip/rockchip_drm_vop2.c')
| -rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 142 |
1 files changed, 80 insertions, 62 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 7ec7bea5e38e..498df0ce4680 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -29,6 +29,7 @@ #include <drm/drm_flip_work.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> @@ -101,7 +102,7 @@ enum vop2_afbc_format { VOP2_AFBC_FMT_INVALID = -1, }; -#define VOP2_MAX_DCLK_RATE 600000000 +#define VOP2_MAX_DCLK_RATE 600000000UL /* * bus-format types. @@ -1003,6 +1004,8 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_rect *src = &pstate->src; int min_scale = FRAC_16_16(1, 8); int max_scale = FRAC_16_16(8, 1); + int src_x, src_w, src_h; + int dest_w, dest_h; int format; int ret; @@ -1013,7 +1016,7 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, vop2 = vp->vop2; vop2_data = vop2->data; - cstate = drm_atomic_get_existing_crtc_state(pstate->state, crtc); + cstate = drm_atomic_get_new_crtc_state(pstate->state, crtc); if (WARN_ON(!cstate)) return -EINVAL; @@ -1030,22 +1033,25 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, if (format < 0) return format; - if (drm_rect_width(src) >> 16 < 4 || drm_rect_height(src) >> 16 < 4 || - drm_rect_width(dest) < 4 || drm_rect_height(dest) < 4) { - drm_err(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n", - drm_rect_width(src) >> 16, drm_rect_height(src) >> 16, - drm_rect_width(dest), drm_rect_height(dest)); - pstate->visible = false; - return 0; + /* Co-ordinates have now been clipped */ + src_x = src->x1 >> 16; + src_w = drm_rect_width(src) >> 16; + src_h = drm_rect_height(src) >> 16; + dest_w = drm_rect_width(dest); + dest_h = drm_rect_height(dest); + + if (src_w < 4 || src_h < 4 || dest_w < 4 || dest_h < 4) { + drm_dbg_kms(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n", + src_w, src_h, dest_w, dest_h); + return -EINVAL; } - if (drm_rect_width(src) >> 16 > vop2_data->max_input.width || - drm_rect_height(src) >> 16 > vop2_data->max_input.height) { - drm_err(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n", - drm_rect_width(src) >> 16, - drm_rect_height(src) >> 16, - vop2_data->max_input.width, - vop2_data->max_input.height); + if (src_w > vop2_data->max_input.width || + src_h > vop2_data->max_input.height) { + drm_dbg_kms(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n", + src_w, src_h, + vop2_data->max_input.width, + vop2_data->max_input.height); return -EINVAL; } @@ -1053,8 +1059,8 @@ static int vop2_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 (fb->format->is_yuv && ((pstate->src.x1 >> 16) % 2)) { - drm_err(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n"); + if (fb->format->is_yuv && src_x % 2) { + drm_dbg_kms(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n"); return -EINVAL; } @@ -1140,7 +1146,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, struct vop2 *vop2 = win->vop2; struct drm_framebuffer *fb = pstate->fb; u32 bpp = vop2_get_bpp(fb->format); - u32 actual_w, actual_h, dsp_w, dsp_h; + u32 src_w, src_h, dsp_w, dsp_h; u32 act_info, dsp_info; u32 format; u32 afbc_format; @@ -1204,8 +1210,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, uv_mst = rk_obj->dma_addr + offset + fb->offsets[1]; } - actual_w = drm_rect_width(src) >> 16; - actual_h = drm_rect_height(src) >> 16; + src_w = drm_rect_width(src) >> 16; + src_h = drm_rect_height(src) >> 16; dsp_w = drm_rect_width(dest); if (dest->x1 + dsp_w > adjusted_mode->hdisplay) { @@ -1215,7 +1221,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, dsp_w = adjusted_mode->hdisplay - dest->x1; if (dsp_w < 4) dsp_w = 4; - actual_w = dsp_w * actual_w / drm_rect_width(dest); + src_w = dsp_w * src_w / drm_rect_width(dest); } dsp_h = drm_rect_height(dest); @@ -1227,35 +1233,35 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, dsp_h = adjusted_mode->vdisplay - dest->y1; if (dsp_h < 4) dsp_h = 4; - actual_h = dsp_h * actual_h / drm_rect_height(dest); + src_h = dsp_h * src_h / drm_rect_height(dest); } /* * This is workaround solution for IC design: - * esmart can't support scale down when actual_w % 16 == 1. + * esmart can't support scale down when src_w % 16 == 1. */ if (!(win->data->feature & WIN_FEATURE_AFBDC)) { - if (actual_w > dsp_w && (actual_w & 0xf) == 1) { + if (src_w > dsp_w && (src_w & 0xf) == 1) { drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n", - vp->id, win->data->name, actual_w); - actual_w -= 1; + vp->id, win->data->name, src_w); + src_w -= 1; } } - if (afbc_en && actual_w % 4) { - drm_dbg_kms(vop2->drm, "vp%d %s actual_w[%d] not 4 pixel aligned\n", - vp->id, win->data->name, actual_w); - actual_w = ALIGN_DOWN(actual_w, 4); + if (afbc_en && src_w % 4) { + drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n", + vp->id, win->data->name, src_w); + src_w = ALIGN_DOWN(src_w, 4); } - act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); + act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff); dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff); format = vop2_convert_format(fb->format->format); half_block_en = vop2_half_block_enable(pstate); drm_dbg(vop2->drm, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%p4cc_%s] addr[%pad]\n", - vp->id, win->data->name, actual_w, actual_h, dsp_w, dsp_h, + vp->id, win->data->name, src_w, src_h, dsp_w, dsp_h, dest->x1, dest->y1, &fb->format->format, afbc_en ? "AFBC" : "", &yrgb_mst); @@ -1284,7 +1290,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, if (fb->modifier & AFBC_FORMAT_MOD_YTR) afbc_format |= (1 << 4); - afbc_tile_num = ALIGN(actual_w, block_w) / block_w; + afbc_tile_num = ALIGN(src_w, block_w) / block_w; /* * AFBC pic_vir_width is count by pixel, this is different @@ -1362,8 +1368,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, if (rotate_90 || rotate_270) { act_info = swahw32(act_info); - actual_w = drm_rect_height(src) >> 16; - actual_h = drm_rect_width(src) >> 16; + src_w = drm_rect_height(src) >> 16; + src_h = drm_rect_width(src) >> 16; } vop2_win_write(win, VOP2_WIN_FORMAT, format); @@ -1379,7 +1385,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, vop2_win_write(win, VOP2_WIN_UV_MST, uv_mst); } - vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, fb->format->format); + vop2_setup_scale(vop2, win, src_w, src_h, dsp_w, dsp_h, fb->format->format); if (!vop2_cluster_window(win)) vop2_plane_setup_color_key(plane, 0); vop2_win_write(win, VOP2_WIN_ACT_INFO, act_info); @@ -1737,36 +1743,42 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, * Switch to HDMI PHY PLL as DCLK source for display modes up * to 4K@60Hz, if available, otherwise keep using the system CRU. */ - if ((vop2->pll_hdmiphy0 || vop2->pll_hdmiphy1) && clock <= VOP2_MAX_DCLK_RATE) { - drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { - struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); - - if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) { - if (!vop2->pll_hdmiphy0) + if (vop2->pll_hdmiphy0 || vop2->pll_hdmiphy1) { + unsigned long max_dclk = DIV_ROUND_CLOSEST_ULL(VOP2_MAX_DCLK_RATE * 8, + vcstate->output_bpc); + if (clock <= max_dclk) { + drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); + + if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) { + if (!vop2->pll_hdmiphy0) + break; + + if (!vp->dclk_src) + vp->dclk_src = clk_get_parent(vp->dclk); + + ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy0); + if (ret < 0) + drm_warn(vop2->drm, + "Could not switch to HDMI0 PHY PLL: %d\n", + ret); break; + } - if (!vp->dclk_src) - vp->dclk_src = clk_get_parent(vp->dclk); + if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI1) { + if (!vop2->pll_hdmiphy1) + break; - ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy0); - if (ret < 0) - drm_warn(vop2->drm, - "Could not switch to HDMI0 PHY PLL: %d\n", ret); - break; - } + if (!vp->dclk_src) + vp->dclk_src = clk_get_parent(vp->dclk); - if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI1) { - if (!vop2->pll_hdmiphy1) + ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy1); + if (ret < 0) + drm_warn(vop2->drm, + "Could not switch to HDMI1 PHY PLL: %d\n", + ret); break; - - if (!vp->dclk_src) - vp->dclk_src = clk_get_parent(vp->dclk); - - ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy1); - if (ret < 0) - drm_warn(vop2->drm, - "Could not switch to HDMI1 PHY PLL: %d\n", ret); - break; + } } } } @@ -2647,6 +2659,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) if (IS_ERR(vop2->map)) return PTR_ERR(vop2->map); + /* Set the bounds for framebuffer creation */ + drm->mode_config.min_width = 4; + drm->mode_config.min_height = 4; + drm->mode_config.max_width = vop2_data->max_input.width; + drm->mode_config.max_height = vop2_data->max_input.height; + ret = vop2_win_init(vop2); if (ret) return ret; |
