msm: rotator: Support Fast YUV for 8960, 8064 and 8x30 targets.
Add Fast YUV support in rotator for 8960, 8064 and 8x30 based
targets to improve performance for YUV 420P and 420PP inputs.
CRs-fixed: 415246
Change-Id: Ib4cbbd0fd45a82b8d409e7f52ae8bf8420b2c4eb
Signed-off-by: Mayank Chopra <makchopra@codeaurora.org>
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index aebdf55..c80a58b 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -95,6 +95,9 @@
#define ROTATOR_REVISION_V1 1
#define ROTATOR_REVISION_V2 2
#define ROTATOR_REVISION_NONE 0xffffffff
+#define BASE_ADDR(height, y_stride) ((height % 64) * y_stride)
+#define HW_BASE_ADDR(height, y_stride) (((dstp0_ystride >> 5) << 11) - \
+ ((dst_height & 0x3f) * dstp0_ystride))
uint32_t rotator_hw_revision;
static char rot_iommu_split_domain;
@@ -128,12 +131,17 @@
struct list_head list;
};
+struct msm_rotator_session {
+ struct msm_rotator_img_info img_info;
+ struct msm_rotator_fd_info fd_info;
+ int fast_yuv_enable;
+};
+
struct msm_rotator_dev {
void __iomem *io_base;
int irq;
- struct msm_rotator_img_info *img_info[MAX_SESSIONS];
struct clk *core_clk;
- struct msm_rotator_fd_info *fd_info[MAX_SESSIONS];
+ struct msm_rotator_session *rot_session[MAX_SESSIONS];
struct list_head fd_list;
struct clk *pclk;
int rot_clk_state;
@@ -472,6 +480,110 @@
return 0;
}
+/* Checking invalid destination image size on FAST YUV for YUV420PP(NV12) with
+ * HW issue for rotation 90 + U/D filp + with/without flip operation
+ * (rotation 90 + U/D + L/R flip is rotation 270 degree option) and pix_rot
+ * block issue with tile line size is 4.
+ *
+ * Rotator structure is:
+ * if Fetch input image: W x H,
+ * Downscale: W` x H` = W/ScaleHor(2, 4 or 8) x H/ScaleVert(2, 4 or 8)
+ * Rotated output : W`` x H`` = (W` x H`) or (H` x W`) depends on "Rotation 90
+ * degree option"
+ *
+ * Pack: W`` x H``
+ *
+ * Rotator source ROI image width restriction is applied to W x H (case a,
+ * image resolution before downscaling)
+ *
+ * Packer source Image width/ height restriction are applied to W`` x H``
+ * (case c, image resolution after rotation)
+ *
+ * Supertile (64 x 8) and YUV (2 x 2) alignment restriction should be
+ * applied to the W x H (case a). Input image should be at least (2 x 2).
+ *
+ * "Support If packer source image height <= 256, multiple of 8", this
+ * restriction should be applied to the rotated image (W`` x H``)
+ */
+
+uint32_t fast_yuv_invalid_size_checker(unsigned char rot_mode,
+ uint32_t src_width,
+ uint32_t dst_width,
+ uint32_t dst_height,
+ uint32_t dstp0_ystride,
+ uint32_t is_planar420)
+{
+ uint32_t hw_limit;
+
+ hw_limit = is_planar420 ? 512 : 256;
+
+ /* checking image constaints for missing EOT event from pix_rot block */
+ if ((src_width > hw_limit) && ((src_width % (hw_limit / 2)) == 8))
+ return -EINVAL;
+
+ if (rot_mode & MDP_ROT_90) {
+
+ /* if rotation 90 degree on fast yuv
+ * rotator image input width has to be multiple of 8
+ * rotator image input height has to be multiple of 8
+ */
+ if (((dst_width % 8) != 0) || ((dst_height % 8) != 0))
+ return -EINVAL;
+
+ if ((rot_mode & MDP_FLIP_UD) ||
+ (rot_mode & (MDP_FLIP_UD | MDP_FLIP_LR))) {
+
+ /* image constraint checking for wrong address
+ * generation HW issue for Y plane checking
+ */
+ if (((dst_height % 64) != 0) &&
+ ((dst_height / 64) >= 4)) {
+
+ /* compare golden logic for second
+ * tile base address generation in row
+ * with actual HW implementation
+ */
+ if (BASE_ADDR(dst_height, dstp0_ystride) !=
+ HW_BASE_ADDR(dst_height, dstp0_ystride))
+ return -EINVAL;
+ }
+
+ if (is_planar420) {
+ dst_width = dst_width / 2;
+ dstp0_ystride = dstp0_ystride / 2;
+ }
+
+ dst_height = dst_height / 2;
+
+ /* image constraint checking for wrong
+ * address generation HW issue. for
+ * U/V (P) or UV (PP) plane checking
+ */
+ if (((dst_height % 64) != 0) && ((dst_height / 64) >=
+ (hw_limit / 128))) {
+
+ /* compare golden logic for
+ * second tile base address
+ * generation in row with
+ * actual HW implementation
+ */
+ if (BASE_ADDR(dst_height, dstp0_ystride) !=
+ HW_BASE_ADDR(dst_height, dstp0_ystride))
+ return -EINVAL;
+ }
+ }
+ } else {
+ /* if NOT applying rotation 90 degree on fast yuv,
+ * rotator image input width has to be multiple of 8
+ * rotator image input height has to be multiple of 2
+ */
+ if (((dst_width % 8) != 0) || ((dst_height % 2) != 0))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
unsigned int in_paddr,
unsigned int out_paddr,
@@ -552,22 +664,38 @@
int new_session,
unsigned int in_chroma_paddr,
unsigned int out_chroma_paddr,
- unsigned int in_chroma2_paddr)
+ unsigned int in_chroma2_paddr,
+ unsigned int out_chroma2_paddr)
{
uint32_t dst_format;
int is_tile = 0;
+ struct msm_rotator_session *rot_ssn =
+ container_of(info, struct msm_rotator_session, img_info);
+ int fast_yuv_en = rot_ssn->fast_yuv_enable;
switch (info->src.format) {
case MDP_Y_CRCB_H2V2_TILE:
is_tile = 1;
+ dst_format = MDP_Y_CRCB_H2V2;
+ break;
case MDP_Y_CR_CB_H2V2:
case MDP_Y_CR_CB_GH2V2:
+ if (fast_yuv_en) {
+ dst_format = info->src.format;
+ break;
+ }
case MDP_Y_CRCB_H2V2:
dst_format = MDP_Y_CRCB_H2V2;
break;
+ case MDP_Y_CB_CR_H2V2:
+ if (fast_yuv_en) {
+ dst_format = info->src.format;
+ break;
+ }
+ dst_format = MDP_Y_CBCR_H2V2;
+ break;
case MDP_Y_CBCR_H2V2_TILE:
is_tile = 1;
- case MDP_Y_CB_CR_H2V2:
case MDP_Y_CBCR_H2V2:
dst_format = MDP_Y_CBCR_H2V2;
break;
@@ -591,8 +719,12 @@
((info->dst_y * info->dst.width) + info->dst_x),
MSM_ROTATOR_OUTP0_ADDR);
iowrite32(out_chroma_paddr +
- ((info->dst_y * info->dst.width)/2 + info->dst_x),
+ (((info->dst_y * info->dst.width)/2) + info->dst_x),
MSM_ROTATOR_OUTP1_ADDR);
+ if (out_chroma2_paddr)
+ iowrite32(out_chroma2_paddr +
+ (((info->dst_y * info->dst.width)/2) + info->dst_x),
+ MSM_ROTATOR_OUTP2_ADDR);
if (new_session) {
if (in_chroma2_paddr) {
@@ -614,11 +746,28 @@
info->src.width << 16,
MSM_ROTATOR_SRC_YSTRIDE1);
}
- iowrite32(info->dst.width |
- info->dst.width << 16,
- MSM_ROTATOR_OUT_YSTRIDE1);
+ if (out_chroma2_paddr) {
+ if (info->dst.format == MDP_Y_CR_CB_GH2V2) {
+ iowrite32(ALIGN(info->dst.width, 16) |
+ ALIGN((info->dst.width / 2), 16) << 16,
+ MSM_ROTATOR_OUT_YSTRIDE1);
+ iowrite32(ALIGN((info->dst.width / 2), 16),
+ MSM_ROTATOR_OUT_YSTRIDE2);
+ } else {
+ iowrite32(info->dst.width |
+ info->dst.width/2 << 16,
+ MSM_ROTATOR_OUT_YSTRIDE1);
+ iowrite32(info->dst.width/2,
+ MSM_ROTATOR_OUT_YSTRIDE2);
+ }
+ } else {
+ iowrite32(info->dst.width |
+ info->dst.width << 16,
+ MSM_ROTATOR_OUT_YSTRIDE1);
+ }
- if (dst_format == MDP_Y_CBCR_H2V2) {
+ if (dst_format == MDP_Y_CBCR_H2V2 ||
+ dst_format == MDP_Y_CB_CR_H2V2) {
iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
MSM_ROTATOR_SRC_UNPACK_PATTERN1);
iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
@@ -629,9 +778,11 @@
iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
MSM_ROTATOR_OUT_PACK_PATTERN1);
}
+
iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
(ROTATIONS_TO_BITMASK(info->rotations) << 9) |
1 << 8 | /* ROT_EN */
+ fast_yuv_en << 4 | /*fast YUV*/
info->downscale_ratio << 2 | /* downscale v ratio */
info->downscale_ratio, /* downscale h ratio */
MSM_ROTATOR_SUB_BLOCK_CFG);
@@ -934,7 +1085,7 @@
struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
int ps0_need, p_need;
unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
- unsigned int in_chroma2_paddr = 0;
+ unsigned int in_chroma2_paddr = 0, out_chroma2_paddr = 0;
struct msm_rotator_img_info *img_info;
struct msm_rotator_mem_planes src_planes, dst_planes;
@@ -943,9 +1094,9 @@
mutex_lock(&msm_rotator_dev->rotator_lock);
for (s = 0; s < MAX_SESSIONS; s++)
- if ((msm_rotator_dev->img_info[s] != NULL) &&
+ if ((msm_rotator_dev->rot_session[s] != NULL) &&
(info.session_id ==
- (unsigned int)msm_rotator_dev->img_info[s]
+ (unsigned int)msm_rotator_dev->rot_session[s]
))
break;
@@ -956,15 +1107,14 @@
goto do_rotate_unlock_mutex;
}
- if (msm_rotator_dev->img_info[s]->enable == 0) {
+ img_info = &(msm_rotator_dev->rot_session[s]->img_info);
+ if (img_info->enable == 0) {
dev_dbg(msm_rotator_dev->device,
- "%s() : Session_id %d not enabled \n",
- __func__, s);
+ "%s() : Session_id %d not enabled\n", __func__, s);
rc = -EINVAL;
goto do_rotate_unlock_mutex;
}
- img_info = msm_rotator_dev->img_info[s];
if (msm_rotator_get_plane_sizes(img_info->src.format,
img_info->src.width,
img_info->src.height,
@@ -1000,7 +1150,7 @@
goto do_rotate_unlock_mutex;
}
- format = msm_rotator_dev->img_info[s]->src.format;
+ format = img_info->src.format;
if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
((info.version_key & ~VERSION_KEY_MASK) > 0) &&
(src_planes.num_planes == 2)) {
@@ -1089,6 +1239,8 @@
out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
if (src_planes.num_planes >= 3)
in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
+ if (dst_planes.num_planes >= 3)
+ out_chroma2_paddr = out_chroma_paddr + dst_planes.plane_size[1];
cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
if (msm_rotator_dev->rot_clk_state != CLK_EN) {
@@ -1110,17 +1262,17 @@
if (use_imem)
iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
- iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
+ iowrite32(((img_info->src_rect.h & 0x1fff)
<< 16) |
- (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
+ (img_info->src_rect.w & 0x1fff),
MSM_ROTATOR_SRC_SIZE);
- iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
+ iowrite32(((img_info->src_rect.y & 0x1fff)
<< 16) |
- (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
+ (img_info->src_rect.x & 0x1fff),
MSM_ROTATOR_SRC_XY);
- iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
+ iowrite32(((img_info->src.height & 0x1fff)
<< 16) |
- (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
+ (img_info->src.width & 0x1fff),
MSM_ROTATOR_SRC_IMAGE_SIZE);
switch (format) {
@@ -1134,7 +1286,7 @@
case MDP_RGBX_8888:
case MDP_YCBCR_H1V1:
case MDP_YCRCB_H1V1:
- rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
+ rc = msm_rotator_rgb_types(img_info,
in_paddr, out_paddr,
use_imem,
msm_rotator_dev->last_session_idx
@@ -1147,17 +1299,18 @@
case MDP_Y_CR_CB_GH2V2:
case MDP_Y_CRCB_H2V2_TILE:
case MDP_Y_CBCR_H2V2_TILE:
- rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
+ rc = msm_rotator_ycxcx_h2v2(img_info,
in_paddr, out_paddr, use_imem,
msm_rotator_dev->last_session_idx
!= s,
in_chroma_paddr,
out_chroma_paddr,
- in_chroma2_paddr);
+ in_chroma2_paddr,
+ out_chroma2_paddr);
break;
case MDP_Y_CBCR_H2V1:
case MDP_Y_CRCB_H2V1:
- rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
+ rc = msm_rotator_ycxcx_h2v1(img_info,
in_paddr, out_paddr, use_imem,
msm_rotator_dev->last_session_idx
!= s,
@@ -1165,7 +1318,7 @@
out_chroma_paddr);
break;
case MDP_YCRYCB_H2V1:
- rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
+ rc = msm_rotator_ycrycb(img_info,
in_paddr, out_paddr, use_imem,
msm_rotator_dev->last_session_idx != s,
out_chroma_paddr);
@@ -1206,10 +1359,10 @@
schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
do_rotate_unlock_mutex:
put_img(dstp1_file, dstp1_ihdl, ROTATOR_DST_DOMAIN,
- msm_rotator_dev->img_info[s]->secure);
+ msm_rotator_dev->rot_session[s]->img_info.secure);
put_img(srcp1_file, srcp1_ihdl, ROTATOR_SRC_DOMAIN, 0);
put_img(dstp0_file, dstp0_ihdl, ROTATOR_DST_DOMAIN,
- msm_rotator_dev->img_info[s]->secure);
+ msm_rotator_dev->rot_session[s]->img_info.secure);
/* only source may use frame buffer */
if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
@@ -1327,10 +1480,13 @@
struct msm_rotator_fd_info *fd_info)
{
struct msm_rotator_img_info info;
+ struct msm_rotator_session *rot_session = NULL;
int rc = 0;
int s, is_rgb = 0;
- int first_free_index = INVALID_SESSION;
+ int first_free_idx = INVALID_SESSION;
unsigned int dst_w, dst_h;
+ unsigned int is_planar420 = 0;
+ int fast_yuv_en = 0;
if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
return -EFAULT;
@@ -1362,6 +1518,30 @@
}
switch (info.src.format) {
+ case MDP_Y_CB_CR_H2V2:
+ case MDP_Y_CR_CB_H2V2:
+ case MDP_Y_CR_CB_GH2V2:
+ is_planar420 = 1;
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ case MDP_Y_CRCB_H2V2_TILE:
+ case MDP_Y_CBCR_H2V2_TILE:
+ if (rotator_hw_revision >= ROTATOR_REVISION_V2 &&
+ !(info.downscale_ratio &&
+ (info.rotations & MDP_ROT_90)))
+ fast_yuv_en = !fast_yuv_invalid_size_checker(
+ info.rotations,
+ info.src.width,
+ dst_w,
+ dst_h,
+ dst_w,
+ is_planar420);
+ break;
+ default:
+ fast_yuv_en = 0;
+ }
+
+ switch (info.src.format) {
case MDP_RGB_565:
case MDP_BGR_565:
case MDP_RGB_888:
@@ -1388,11 +1568,19 @@
info.dst.format = MDP_Y_CRCB_H2V1;
break;
case MDP_Y_CB_CR_H2V2:
+ if (fast_yuv_en) {
+ info.dst.format = info.src.format;
+ break;
+ }
case MDP_Y_CBCR_H2V2_TILE:
info.dst.format = MDP_Y_CBCR_H2V2;
break;
case MDP_Y_CR_CB_H2V2:
case MDP_Y_CR_CB_GH2V2:
+ if (fast_yuv_en) {
+ info.dst.format = info.src.format;
+ break;
+ }
case MDP_Y_CRCB_H2V2_TILE:
info.dst.format = MDP_Y_CRCB_H2V2;
break;
@@ -1405,12 +1593,14 @@
msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
for (s = 0; s < MAX_SESSIONS; s++) {
- if ((msm_rotator_dev->img_info[s] != NULL) &&
+ if ((msm_rotator_dev->rot_session[s] != NULL) &&
(info.session_id ==
- (unsigned int)msm_rotator_dev->img_info[s]
+ (unsigned int)msm_rotator_dev->rot_session[s]
)) {
- *(msm_rotator_dev->img_info[s]) = info;
- msm_rotator_dev->fd_info[s] = fd_info;
+ rot_session = msm_rotator_dev->rot_session[s];
+ rot_session->img_info = info;
+ rot_session->fd_info = *fd_info;
+ rot_session->fast_yuv_enable = fast_yuv_en;
if (msm_rotator_dev->last_session_idx == s)
msm_rotator_dev->last_session_idx =
@@ -1418,27 +1608,29 @@
break;
}
- if ((msm_rotator_dev->img_info[s] == NULL) &&
- (first_free_index ==
- INVALID_SESSION))
- first_free_index = s;
+ if ((msm_rotator_dev->rot_session[s] == NULL) &&
+ (first_free_idx == INVALID_SESSION))
+ first_free_idx = s;
}
- if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
+ if ((s == MAX_SESSIONS) && (first_free_idx != INVALID_SESSION)) {
/* allocate a session id */
- msm_rotator_dev->img_info[first_free_index] =
- kzalloc(sizeof(struct msm_rotator_img_info),
+ msm_rotator_dev->rot_session[first_free_idx] =
+ kzalloc(sizeof(struct msm_rotator_session),
GFP_KERNEL);
- if (!msm_rotator_dev->img_info[first_free_index]) {
+ if (!msm_rotator_dev->rot_session[first_free_idx]) {
printk(KERN_ERR "%s : unable to alloc mem\n",
__func__);
rc = -ENOMEM;
goto rotator_start_exit;
}
info.session_id = (unsigned int)
- msm_rotator_dev->img_info[first_free_index];
- *(msm_rotator_dev->img_info[first_free_index]) = info;
- msm_rotator_dev->fd_info[first_free_index] = fd_info;
+ msm_rotator_dev->rot_session[first_free_idx];
+ rot_session = msm_rotator_dev->rot_session[first_free_idx];
+
+ rot_session->img_info = info;
+ rot_session->fd_info = *fd_info;
+ rot_session->fast_yuv_enable = fast_yuv_en;
} else if (s == MAX_SESSIONS) {
dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
__func__);
@@ -1466,15 +1658,14 @@
mutex_lock(&msm_rotator_dev->rotator_lock);
for (s = 0; s < MAX_SESSIONS; s++) {
- if ((msm_rotator_dev->img_info[s] != NULL) &&
+ if ((msm_rotator_dev->rot_session[s] != NULL) &&
(session_id ==
- (unsigned int)msm_rotator_dev->img_info[s])) {
+ (unsigned int)msm_rotator_dev->rot_session[s])) {
if (msm_rotator_dev->last_session_idx == s)
msm_rotator_dev->last_session_idx =
INVALID_SESSION;
- kfree(msm_rotator_dev->img_info[s]);
- msm_rotator_dev->img_info[s] = NULL;
- msm_rotator_dev->fd_info[s] = NULL;
+ kfree(msm_rotator_dev->rot_session[s]);
+ msm_rotator_dev->rot_session[s] = NULL;
break;
}
}
@@ -1502,7 +1693,7 @@
mutex_lock(&msm_rotator_dev->rotator_lock);
for (i = 0; i < MAX_SESSIONS; i++) {
- if (msm_rotator_dev->fd_info[i] == NULL)
+ if (msm_rotator_dev->rot_session[i] == NULL)
break;
}
@@ -1552,14 +1743,13 @@
}
for (s = 0; s < MAX_SESSIONS; s++) {
- if (msm_rotator_dev->img_info[s] != NULL &&
- msm_rotator_dev->fd_info[s] == fd_info) {
+ if (msm_rotator_dev->rot_session[s] != NULL &&
+ &(msm_rotator_dev->rot_session[s]->fd_info) == fd_info) {
pr_debug("%s: freeing rotator session %p (pid %d)\n",
- __func__, msm_rotator_dev->img_info[s],
+ __func__, msm_rotator_dev->rot_session[s],
fd_info->pid);
- kfree(msm_rotator_dev->img_info[s]);
- msm_rotator_dev->img_info[s] = NULL;
- msm_rotator_dev->fd_info[s] = NULL;
+ kfree(msm_rotator_dev->rot_session[s]);
+ msm_rotator_dev->rot_session[s] = NULL;
if (msm_rotator_dev->last_session_idx == s)
msm_rotator_dev->last_session_idx =
INVALID_SESSION;
@@ -1619,7 +1809,7 @@
return -ENOMEM;
}
for (i = 0; i < MAX_SESSIONS; i++)
- msm_rotator_dev->img_info[i] = NULL;
+ msm_rotator_dev->rot_session[i] = NULL;
msm_rotator_dev->last_session_idx = INVALID_SESSION;
pdata = pdev->dev.platform_data;
@@ -1864,8 +2054,8 @@
msm_rotator_dev->pclk = NULL;
mutex_destroy(&msm_rotator_dev->imem_lock);
for (i = 0; i < MAX_SESSIONS; i++)
- if (msm_rotator_dev->img_info[i] != NULL)
- kfree(msm_rotator_dev->img_info[i]);
+ if (msm_rotator_dev->rot_session[i] != NULL)
+ kfree(msm_rotator_dev->rot_session[i]);
kfree(msm_rotator_dev);
return 0;
}