diff options
author | Mark Yao <mark.yao@rock-chips.com> | 2015-06-26 05:14:46 -0400 |
---|---|---|
committer | Mark Yao <mark.yao@rock-chips.com> | 2015-08-26 02:16:26 -0400 |
commit | 4c156c21c7948a0be854cbe5914af3181303e529 (patch) | |
tree | 17fb95b6bfd0ab5f07404afafdef86848f6f13ea /drivers/gpu/drm | |
parent | 77faa1619a5ae9ed600b0836bc1eec57bad1895b (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.c | 198 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 88 |
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 | ||
169 | struct 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 | |||
167 | struct vop_win_phy { | 198 | struct 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 | ||
257 | static 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 | |||
225 | static const struct vop_win_phy win01_data = { | 285 | static 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 | ||
486 | static 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 | |||
517 | static 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 | |||
425 | static void vop_dsp_hold_valid_irq_enable(struct vop *vop) | 606 | static 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 | ||
201 | enum scale_mode { | ||
202 | SCALE_NONE = 0x0, | ||
203 | SCALE_UP = 0x1, | ||
204 | SCALE_DOWN = 0x2 | ||
205 | }; | ||
206 | |||
207 | enum 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 | |||
216 | enum sacle_up_mode { | ||
217 | SCALE_UP_BIL = 0x0, | ||
218 | SCALE_UP_BIC = 0x1 | ||
219 | }; | ||
220 | |||
221 | enum 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 | |||
231 | static 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 | |||
240 | static 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 | |||
250 | static 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 | |||
260 | static 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 | |||
271 | static 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 */ |