aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorMark Yao <mark.yao@rock-chips.com>2015-06-26 05:14:46 -0400
committerMark Yao <mark.yao@rock-chips.com>2015-08-26 02:16:26 -0400
commit4c156c21c7948a0be854cbe5914af3181303e529 (patch)
tree17fb95b6bfd0ab5f07404afafdef86848f6f13ea /drivers/gpu/drm
parent77faa1619a5ae9ed600b0836bc1eec57bad1895b (diff)
drm/rockchip: vop: support plane scale
Win_full support 1/8 to 8 scale down/up engine, support all format scale. Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c198
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.h88
2 files changed, 284 insertions, 2 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 16b7d98362b0..5d8ae5e49c44 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -50,6 +50,8 @@
50 50
51#define VOP_WIN_SET(x, win, name, v) \ 51#define VOP_WIN_SET(x, win, name, v) \
52 REG_SET(x, win->base, win->phy->name, v, RELAXED) 52 REG_SET(x, win->base, win->phy->name, v, RELAXED)
53#define VOP_SCL_SET(x, win, name, v) \
54 REG_SET(x, win->base, win->phy->scl->name, v, RELAXED)
53#define VOP_CTRL_SET(x, name, v) \ 55#define VOP_CTRL_SET(x, name, v) \
54 REG_SET(x, 0, (x)->data->ctrl->name, v, NORMAL) 56 REG_SET(x, 0, (x)->data->ctrl->name, v, NORMAL)
55 57
@@ -164,7 +166,37 @@ struct vop_ctrl {
164 struct vop_reg vpost_st_end; 166 struct vop_reg vpost_st_end;
165}; 167};
166 168
169struct vop_scl_regs {
170 struct vop_reg cbcr_vsd_mode;
171 struct vop_reg cbcr_vsu_mode;
172 struct vop_reg cbcr_hsd_mode;
173 struct vop_reg cbcr_ver_scl_mode;
174 struct vop_reg cbcr_hor_scl_mode;
175 struct vop_reg yrgb_vsd_mode;
176 struct vop_reg yrgb_vsu_mode;
177 struct vop_reg yrgb_hsd_mode;
178 struct vop_reg yrgb_ver_scl_mode;
179 struct vop_reg yrgb_hor_scl_mode;
180 struct vop_reg line_load_mode;
181 struct vop_reg cbcr_axi_gather_num;
182 struct vop_reg yrgb_axi_gather_num;
183 struct vop_reg vsd_cbcr_gt2;
184 struct vop_reg vsd_cbcr_gt4;
185 struct vop_reg vsd_yrgb_gt2;
186 struct vop_reg vsd_yrgb_gt4;
187 struct vop_reg bic_coe_sel;
188 struct vop_reg cbcr_axi_gather_en;
189 struct vop_reg yrgb_axi_gather_en;
190
191 struct vop_reg lb_mode;
192 struct vop_reg scale_yrgb_x;
193 struct vop_reg scale_yrgb_y;
194 struct vop_reg scale_cbcr_x;
195 struct vop_reg scale_cbcr_y;
196};
197
167struct vop_win_phy { 198struct vop_win_phy {
199 const struct vop_scl_regs *scl;
168 const uint32_t *data_formats; 200 const uint32_t *data_formats;
169 uint32_t nformats; 201 uint32_t nformats;
170 202
@@ -222,7 +254,36 @@ static const uint32_t formats_234[] = {
222 DRM_FORMAT_BGR565, 254 DRM_FORMAT_BGR565,
223}; 255};
224 256
257static const struct vop_scl_regs win_full_scl = {
258 .cbcr_vsd_mode = VOP_REG(WIN0_CTRL1, 0x1, 31),
259 .cbcr_vsu_mode = VOP_REG(WIN0_CTRL1, 0x1, 30),
260 .cbcr_hsd_mode = VOP_REG(WIN0_CTRL1, 0x3, 28),
261 .cbcr_ver_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 26),
262 .cbcr_hor_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 24),
263 .yrgb_vsd_mode = VOP_REG(WIN0_CTRL1, 0x1, 23),
264 .yrgb_vsu_mode = VOP_REG(WIN0_CTRL1, 0x1, 22),
265 .yrgb_hsd_mode = VOP_REG(WIN0_CTRL1, 0x3, 20),
266 .yrgb_ver_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 18),
267 .yrgb_hor_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 16),
268 .line_load_mode = VOP_REG(WIN0_CTRL1, 0x1, 15),
269 .cbcr_axi_gather_num = VOP_REG(WIN0_CTRL1, 0x7, 12),
270 .yrgb_axi_gather_num = VOP_REG(WIN0_CTRL1, 0xf, 8),
271 .vsd_cbcr_gt2 = VOP_REG(WIN0_CTRL1, 0x1, 7),
272 .vsd_cbcr_gt4 = VOP_REG(WIN0_CTRL1, 0x1, 6),
273 .vsd_yrgb_gt2 = VOP_REG(WIN0_CTRL1, 0x1, 5),
274 .vsd_yrgb_gt4 = VOP_REG(WIN0_CTRL1, 0x1, 4),
275 .bic_coe_sel = VOP_REG(WIN0_CTRL1, 0x3, 2),
276 .cbcr_axi_gather_en = VOP_REG(WIN0_CTRL1, 0x1, 1),
277 .yrgb_axi_gather_en = VOP_REG(WIN0_CTRL1, 0x1, 0),
278 .lb_mode = VOP_REG(WIN0_CTRL0, 0x7, 5),
279 .scale_yrgb_x = VOP_REG(WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
280 .scale_yrgb_y = VOP_REG(WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
281 .scale_cbcr_x = VOP_REG(WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
282 .scale_cbcr_y = VOP_REG(WIN0_SCL_FACTOR_CBR, 0xffff, 16),
283};
284
225static const struct vop_win_phy win01_data = { 285static const struct vop_win_phy win01_data = {
286 .scl = &win_full_scl,
226 .data_formats = formats_01, 287 .data_formats = formats_01,
227 .nformats = ARRAY_SIZE(formats_01), 288 .nformats = ARRAY_SIZE(formats_01),
228 .enable = VOP_REG(WIN0_CTRL0, 0x1, 0), 289 .enable = VOP_REG(WIN0_CTRL0, 0x1, 0),
@@ -422,6 +483,126 @@ static bool is_alpha_support(uint32_t format)
422 } 483 }
423} 484}
424 485
486static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src,
487 uint32_t dst, bool is_horizontal,
488 int vsu_mode, int *vskiplines)
489{
490 uint16_t val = 1 << SCL_FT_DEFAULT_FIXPOINT_SHIFT;
491
492 if (is_horizontal) {
493 if (mode == SCALE_UP)
494 val = GET_SCL_FT_BIC(src, dst);
495 else if (mode == SCALE_DOWN)
496 val = GET_SCL_FT_BILI_DN(src, dst);
497 } else {
498 if (mode == SCALE_UP) {
499 if (vsu_mode == SCALE_UP_BIL)
500 val = GET_SCL_FT_BILI_UP(src, dst);
501 else
502 val = GET_SCL_FT_BIC(src, dst);
503 } else if (mode == SCALE_DOWN) {
504 if (vskiplines) {
505 *vskiplines = scl_get_vskiplines(src, dst);
506 val = scl_get_bili_dn_vskip(src, dst,
507 *vskiplines);
508 } else {
509 val = GET_SCL_FT_BILI_DN(src, dst);
510 }
511 }
512 }
513
514 return val;
515}
516
517static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win,
518 uint32_t src_w, uint32_t src_h, uint32_t dst_w,
519 uint32_t dst_h, uint32_t pixel_format)
520{
521 uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode;
522 uint16_t cbcr_hor_scl_mode = SCALE_NONE;
523 uint16_t cbcr_ver_scl_mode = SCALE_NONE;
524 int hsub = drm_format_horz_chroma_subsampling(pixel_format);
525 int vsub = drm_format_vert_chroma_subsampling(pixel_format);
526 bool is_yuv = is_yuv_support(pixel_format);
527 uint16_t cbcr_src_w = src_w / hsub;
528 uint16_t cbcr_src_h = src_h / vsub;
529 uint16_t vsu_mode;
530 uint16_t lb_mode;
531 uint32_t val;
532 int vskiplines;
533
534 if (dst_w > 3840) {
535 DRM_ERROR("Maximum destination width (3840) exceeded\n");
536 return;
537 }
538
539 yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
540 yrgb_ver_scl_mode = scl_get_scl_mode(src_h, dst_h);
541
542 if (is_yuv) {
543 cbcr_hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w);
544 cbcr_ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h);
545 if (cbcr_hor_scl_mode == SCALE_DOWN)
546 lb_mode = scl_vop_cal_lb_mode(dst_w, true);
547 else
548 lb_mode = scl_vop_cal_lb_mode(cbcr_src_w, true);
549 } else {
550 if (yrgb_hor_scl_mode == SCALE_DOWN)
551 lb_mode = scl_vop_cal_lb_mode(dst_w, false);
552 else
553 lb_mode = scl_vop_cal_lb_mode(src_w, false);
554 }
555
556 VOP_SCL_SET(vop, win, lb_mode, lb_mode);
557 if (lb_mode == LB_RGB_3840X2) {
558 if (yrgb_ver_scl_mode != SCALE_NONE) {
559 DRM_ERROR("ERROR : not allow yrgb ver scale\n");
560 return;
561 }
562 if (cbcr_ver_scl_mode != SCALE_NONE) {
563 DRM_ERROR("ERROR : not allow cbcr ver scale\n");
564 return;
565 }
566 vsu_mode = SCALE_UP_BIL;
567 } else if (lb_mode == LB_RGB_2560X4) {
568 vsu_mode = SCALE_UP_BIL;
569 } else {
570 vsu_mode = SCALE_UP_BIC;
571 }
572
573 val = scl_vop_cal_scale(yrgb_hor_scl_mode, src_w, dst_w,
574 true, 0, NULL);
575 VOP_SCL_SET(vop, win, scale_yrgb_x, val);
576 val = scl_vop_cal_scale(yrgb_ver_scl_mode, src_h, dst_h,
577 false, vsu_mode, &vskiplines);
578 VOP_SCL_SET(vop, win, scale_yrgb_y, val);
579
580 VOP_SCL_SET(vop, win, vsd_yrgb_gt4, vskiplines == 4);
581 VOP_SCL_SET(vop, win, vsd_yrgb_gt2, vskiplines == 2);
582
583 VOP_SCL_SET(vop, win, yrgb_hor_scl_mode, yrgb_hor_scl_mode);
584 VOP_SCL_SET(vop, win, yrgb_ver_scl_mode, yrgb_ver_scl_mode);
585 VOP_SCL_SET(vop, win, yrgb_hsd_mode, SCALE_DOWN_BIL);
586 VOP_SCL_SET(vop, win, yrgb_vsd_mode, SCALE_DOWN_BIL);
587 VOP_SCL_SET(vop, win, yrgb_vsu_mode, vsu_mode);
588 if (is_yuv) {
589 val = scl_vop_cal_scale(cbcr_hor_scl_mode, cbcr_src_w,
590 dst_w, true, 0, NULL);
591 VOP_SCL_SET(vop, win, scale_cbcr_x, val);
592 val = scl_vop_cal_scale(cbcr_ver_scl_mode, cbcr_src_h,
593 dst_h, false, vsu_mode, &vskiplines);
594 VOP_SCL_SET(vop, win, scale_cbcr_y, val);
595
596 VOP_SCL_SET(vop, win, vsd_cbcr_gt4, vskiplines == 4);
597 VOP_SCL_SET(vop, win, vsd_cbcr_gt2, vskiplines == 2);
598 VOP_SCL_SET(vop, win, cbcr_hor_scl_mode, cbcr_hor_scl_mode);
599 VOP_SCL_SET(vop, win, cbcr_ver_scl_mode, cbcr_ver_scl_mode);
600 VOP_SCL_SET(vop, win, cbcr_hsd_mode, SCALE_DOWN_BIL);
601 VOP_SCL_SET(vop, win, cbcr_vsd_mode, SCALE_DOWN_BIL);
602 VOP_SCL_SET(vop, win, cbcr_vsu_mode, vsu_mode);
603 }
604}
605
425static void vop_dsp_hold_valid_irq_enable(struct vop *vop) 606static void vop_dsp_hold_valid_irq_enable(struct vop *vop)
426{ 607{
427 unsigned long flags; 608 unsigned long flags;
@@ -653,11 +834,15 @@ static int vop_update_plane_event(struct drm_plane *plane,
653 .y2 = crtc->mode.vdisplay, 834 .y2 = crtc->mode.vdisplay,
654 }; 835 };
655 bool can_position = plane->type != DRM_PLANE_TYPE_PRIMARY; 836 bool can_position = plane->type != DRM_PLANE_TYPE_PRIMARY;
837 int min_scale = win->phy->scl ? FRAC_16_16(1, 8) :
838 DRM_PLANE_HELPER_NO_SCALING;
839 int max_scale = win->phy->scl ? FRAC_16_16(8, 1) :
840 DRM_PLANE_HELPER_NO_SCALING;
656 841
657 ret = drm_plane_helper_check_update(plane, crtc, fb, 842 ret = drm_plane_helper_check_update(plane, crtc, fb,
658 &src, &dest, &clip, 843 &src, &dest, &clip,
659 DRM_PLANE_HELPER_NO_SCALING, 844 min_scale,
660 DRM_PLANE_HELPER_NO_SCALING, 845 max_scale,
661 can_position, false, &visible); 846 can_position, false, &visible);
662 if (ret) 847 if (ret)
663 return ret; 848 return ret;
@@ -761,9 +946,18 @@ static int vop_update_plane_event(struct drm_plane *plane,
761 VOP_WIN_SET(vop, win, uv_vir, uv_vir_stride); 946 VOP_WIN_SET(vop, win, uv_vir, uv_vir_stride);
762 VOP_WIN_SET(vop, win, uv_mst, uv_mst); 947 VOP_WIN_SET(vop, win, uv_mst, uv_mst);
763 } 948 }
949
950 if (win->phy->scl)
951 scl_vop_cal_scl_fac(vop, win, actual_w, actual_h,
952 dest.x2 - dest.x1, dest.y2 - dest.y1,
953 fb->pixel_format);
954
764 val = (actual_h - 1) << 16; 955 val = (actual_h - 1) << 16;
765 val |= (actual_w - 1) & 0xffff; 956 val |= (actual_w - 1) & 0xffff;
766 VOP_WIN_SET(vop, win, act_info, val); 957 VOP_WIN_SET(vop, win, act_info, val);
958
959 val = (dest.y2 - dest.y1 - 1) << 16;
960 val |= (dest.x2 - dest.x1 - 1) & 0xffff;
767 VOP_WIN_SET(vop, win, dsp_info, val); 961 VOP_WIN_SET(vop, win, dsp_info, val);
768 val = (dsp_sty - 1) << 16; 962 val = (dsp_sty - 1) << 16;
769 val |= (dsp_stx - 1) & 0xffff; 963 val |= (dsp_stx - 1) & 0xffff;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 63e9b3a084c5..a2d4ddb896fa 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -198,4 +198,92 @@ enum factor_mode {
198 ALPHA_SRC_GLOBAL, 198 ALPHA_SRC_GLOBAL,
199}; 199};
200 200
201enum scale_mode {
202 SCALE_NONE = 0x0,
203 SCALE_UP = 0x1,
204 SCALE_DOWN = 0x2
205};
206
207enum lb_mode {
208 LB_YUV_3840X5 = 0x0,
209 LB_YUV_2560X8 = 0x1,
210 LB_RGB_3840X2 = 0x2,
211 LB_RGB_2560X4 = 0x3,
212 LB_RGB_1920X5 = 0x4,
213 LB_RGB_1280X8 = 0x5
214};
215
216enum sacle_up_mode {
217 SCALE_UP_BIL = 0x0,
218 SCALE_UP_BIC = 0x1
219};
220
221enum scale_down_mode {
222 SCALE_DOWN_BIL = 0x0,
223 SCALE_DOWN_AVG = 0x1
224};
225
226#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
227#define SCL_FT_DEFAULT_FIXPOINT_SHIFT 12
228#define SCL_MAX_VSKIPLINES 4
229#define MIN_SCL_FT_AFTER_VSKIP 1
230
231static inline uint16_t scl_cal_scale(int src, int dst, int shift)
232{
233 return ((src * 2 - 3) << (shift - 1)) / (dst - 1);
234}
235
236#define GET_SCL_FT_BILI_DN(src, dst) scl_cal_scale(src, dst, 12)
237#define GET_SCL_FT_BILI_UP(src, dst) scl_cal_scale(src, dst, 16)
238#define GET_SCL_FT_BIC(src, dst) scl_cal_scale(src, dst, 16)
239
240static inline uint16_t scl_get_bili_dn_vskip(int src_h, int dst_h,
241 int vskiplines)
242{
243 int act_height;
244
245 act_height = (src_h + vskiplines - 1) / vskiplines;
246
247 return GET_SCL_FT_BILI_DN(act_height, dst_h);
248}
249
250static inline enum scale_mode scl_get_scl_mode(int src, int dst)
251{
252 if (src < dst)
253 return SCALE_UP;
254 else if (src > dst)
255 return SCALE_DOWN;
256
257 return SCALE_NONE;
258}
259
260static inline int scl_get_vskiplines(uint32_t srch, uint32_t dsth)
261{
262 uint32_t vskiplines;
263
264 for (vskiplines = SCL_MAX_VSKIPLINES; vskiplines > 1; vskiplines /= 2)
265 if (srch >= vskiplines * dsth * MIN_SCL_FT_AFTER_VSKIP)
266 break;
267
268 return vskiplines;
269}
270
271static inline int scl_vop_cal_lb_mode(int width, bool is_yuv)
272{
273 int lb_mode;
274
275 if (width > 2560)
276 lb_mode = LB_RGB_3840X2;
277 else if (width > 1920)
278 lb_mode = LB_RGB_2560X4;
279 else if (!is_yuv)
280 lb_mode = LB_RGB_1920X5;
281 else if (width > 1280)
282 lb_mode = LB_YUV_3840X5;
283 else
284 lb_mode = LB_YUV_2560X8;
285
286 return lb_mode;
287}
288
201#endif /* _ROCKCHIP_DRM_VOP_H */ 289#endif /* _ROCKCHIP_DRM_VOP_H */