| /* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| * 02110-1301, USA. |
| */ |
| |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/sched.h> |
| #include <linux/time.h> |
| #include <linux/init.h> |
| #include <linux/interrupt.h> |
| #include <linux/spinlock.h> |
| #include <linux/hrtimer.h> |
| #include <linux/clk.h> |
| #include <mach/hardware.h> |
| #include <linux/io.h> |
| #include <linux/debugfs.h> |
| #include <linux/fb.h> |
| #include <msm_mdp.h> |
| #include <linux/file.h> |
| #include "android_pmem.h" |
| #include <linux/major.h> |
| #include <asm/system.h> |
| #include <asm/mach-types.h> |
| #include <linux/semaphore.h> |
| #include <linux/uaccess.h> |
| #include <linux/mutex.h> |
| |
| #include "mdp.h" |
| #include "msm_fb.h" |
| #include "mdp4.h" |
| |
| |
| struct mdp4_overlay_ctrl { |
| struct mdp4_overlay_pipe plist[MDP4_MAX_OVERLAY_PIPE]; |
| struct mdp4_overlay_pipe *stage[MDP4_MAX_MIXER][MDP4_MAX_STAGE]; |
| } mdp4_overlay_db; |
| |
| static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db; |
| |
| |
| void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc) |
| { |
| uint32 dma2_cfg_reg; |
| |
| dma2_cfg_reg = DMA_DITHER_EN; |
| |
| if (mfd->fb_imgType == MDP_BGR_565) |
| dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; |
| else |
| dma2_cfg_reg |= DMA_PACK_PATTERN_RGB; |
| |
| |
| if (mfd->panel_info.bpp == 18) { |
| dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ |
| DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; |
| } else if (mfd->panel_info.bpp == 16) { |
| dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ |
| DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; |
| } else { |
| dma2_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 16BPP */ |
| DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; |
| } |
| |
| if (lcdc) |
| dma2_cfg_reg |= DMA_PACK_ALIGN_MSB; |
| |
| /* dma2 config register */ |
| MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg); |
| |
| } |
| |
| void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe) |
| { |
| |
| /* dma_p source */ |
| MDP_OUTP(MDP_BASE + 0x90004, |
| (pipe->src_height << 16 | pipe->src_width)); |
| MDP_OUTP(MDP_BASE + 0x90008, pipe->srcp0_addr); |
| MDP_OUTP(MDP_BASE + 0x9000c, pipe->srcp0_ystride); |
| |
| /* dma_p dest */ |
| MDP_OUTP(MDP_BASE + 0x90010, (pipe->dst_y << 16 | pipe->dst_x)); |
| } |
| |
| #define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000 |
| #define MDP4_VG_PHASE_STEP_SHIFT 29 |
| |
| static int mdp4_leading_0(uint32 num) |
| { |
| uint32 bit = 0x80000000; |
| int i; |
| |
| for (i = 0; i < 32; i++) { |
| if (bit & num) |
| return i; |
| bit >>= 1; |
| } |
| |
| return i; |
| } |
| |
| static uint32 mdp4_scale_phase_step(int f_num, uint32 src, uint32 dst) |
| { |
| uint32 val; |
| int n; |
| |
| n = mdp4_leading_0(src); |
| if (n > f_num) |
| n = f_num; |
| val = src << n; /* maximum to reduce lose of resolution */ |
| val /= dst; |
| if (n < f_num) { |
| n = f_num - n; |
| val <<= n; |
| } |
| |
| return val; |
| } |
| |
| static void mdp4_scale_setup(struct mdp4_overlay_pipe *pipe) |
| { |
| |
| pipe->phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; |
| pipe->phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; |
| |
| if (pipe->dst_h && pipe->src_h != pipe->dst_h) { |
| if (pipe->dst_h >= pipe->src_h * 8) /* too much */ |
| return; |
| pipe->op_mode |= MDP4_OP_SCALEY_EN; |
| |
| if (pipe->pipe_type == OVERLAY_TYPE_VG) { |
| if (pipe->dst_h <= (pipe->src_h / 4)) |
| pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE; |
| else |
| pipe->op_mode |= MDP4_OP_SCALEY_FIR; |
| } |
| |
| pipe->phasey_step = mdp4_scale_phase_step(29, |
| pipe->src_h, pipe->dst_h); |
| } |
| |
| if (pipe->dst_w && pipe->src_w != pipe->dst_w) { |
| if (pipe->dst_w >= pipe->src_w * 8) /* too much */ |
| return; |
| pipe->op_mode |= MDP4_OP_SCALEX_EN; |
| |
| if (pipe->pipe_type == OVERLAY_TYPE_VG) { |
| if (pipe->dst_w <= (pipe->src_w / 4)) |
| pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE; |
| else |
| pipe->op_mode |= MDP4_OP_SCALEY_FIR; |
| } |
| |
| pipe->phasex_step = mdp4_scale_phase_step(29, |
| pipe->src_w, pipe->dst_w); |
| } |
| } |
| |
| void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe) |
| { |
| char *rgb_base; |
| uint32 src_size, src_xy, dst_size, dst_xy; |
| uint32 format, pattern; |
| |
| rgb_base = MDP_BASE + MDP4_RGB_BASE; |
| rgb_base += (MDP4_RGB_OFF * pipe->pipe_num); |
| |
| src_size = ((pipe->src_h << 16) | pipe->src_w); |
| src_xy = ((pipe->src_y << 16) | pipe->src_x); |
| dst_size = ((pipe->dst_h << 16) | pipe->dst_w); |
| dst_xy = ((pipe->dst_y << 16) | pipe->dst_x); |
| |
| format = mdp4_overlay_format(pipe); |
| pattern = mdp4_overlay_unpack_pattern(pipe); |
| |
| pipe->op_mode |= MDP4_OP_IGC_LUT_EN; |
| |
| mdp4_scale_setup(pipe); |
| |
| outpdw(rgb_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */ |
| outpdw(rgb_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ |
| outpdw(rgb_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */ |
| outpdw(rgb_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */ |
| |
| outpdw(rgb_base + 0x0010, pipe->srcp0_addr); |
| outpdw(rgb_base + 0x0040, pipe->srcp0_ystride); |
| |
| outpdw(rgb_base + 0x0050, format);/* MDP_RGB_SRC_FORMAT */ |
| outpdw(rgb_base + 0x0054, pattern);/* MDP_RGB_SRC_UNPACK_PATTERN */ |
| outpdw(rgb_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ |
| outpdw(rgb_base + 0x005c, pipe->phasex_step); |
| outpdw(rgb_base + 0x0060, pipe->phasey_step); |
| |
| /* 16 bytes-burst x 3 req <= 48 bytes */ |
| outpdw(rgb_base + 0x1004, 0xc2); /* MDP_RGB_FETCH_CFG */ |
| } |
| |
| void mdp4_overlay_vg_setup(struct mdp4_overlay_pipe *pipe) |
| { |
| char *vg_base; |
| uint32 frame_size, src_size, src_xy, dst_size, dst_xy; |
| uint32 format, pattern; |
| |
| vg_base = MDP_BASE + MDP4_VIDEO_BASE; |
| vg_base += (MDP4_VIDEO_OFF * pipe->pipe_num); |
| |
| frame_size = ((pipe->src_height << 16) | pipe->src_width); |
| src_size = ((pipe->src_h << 16) | pipe->src_w); |
| src_xy = ((pipe->src_y << 16) | pipe->src_x); |
| dst_size = ((pipe->dst_h << 16) | pipe->dst_w); |
| dst_xy = ((pipe->dst_y << 16) | pipe->dst_x); |
| |
| format = mdp4_overlay_format(pipe); |
| pattern = mdp4_overlay_unpack_pattern(pipe); |
| |
| pipe->op_mode |= (MDP4_OP_CSC_EN | MDP4_OP_SRC_DATA_YCBCR | |
| MDP4_OP_IGC_LUT_EN); |
| |
| mdp4_scale_setup(pipe); |
| |
| outpdw(vg_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */ |
| outpdw(vg_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ |
| outpdw(vg_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */ |
| outpdw(vg_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */ |
| outpdw(vg_base + 0x0048, frame_size); /* TILE frame size */ |
| |
| /* luma component plane */ |
| outpdw(vg_base + 0x0010, pipe->srcp0_addr); |
| |
| /* chroma component plane */ |
| outpdw(vg_base + 0x0014, pipe->srcp1_addr); |
| |
| outpdw(vg_base + 0x0040, |
| pipe->srcp1_ystride << 16 | pipe->srcp0_ystride); |
| |
| outpdw(vg_base + 0x0050, format); /* MDP_RGB_SRC_FORMAT */ |
| outpdw(vg_base + 0x0054, pattern); /* MDP_RGB_SRC_UNPACK_PATTERN */ |
| outpdw(vg_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ |
| outpdw(vg_base + 0x005c, pipe->phasex_step); |
| outpdw(vg_base + 0x0060, pipe->phasey_step); |
| |
| if (pipe->op_mode & MDP4_OP_DITHER_EN) { |
| outpdw(vg_base + 0x0068, |
| pipe->r_bit << 4 | pipe->b_bit << 2 | pipe->g_bit); |
| } |
| |
| /* 16 bytes-burst x 3 req <= 48 bytes */ |
| outpdw(vg_base + 0x1004, 0xc2); /* MDP_VG_FETCH_CFG */ |
| } |
| |
| int mdp4_overlay_format2type(uint32 format) |
| { |
| switch (format) { |
| case MDP_RGB_565: |
| case MDP_RGB_888: |
| case MDP_BGR_565: |
| case MDP_ARGB_8888: |
| case MDP_RGBA_8888: |
| case MDP_BGRA_8888: |
| return OVERLAY_TYPE_RGB; |
| case MDP_YCRYCB_H2V1: |
| case MDP_Y_CRCB_H2V1: |
| case MDP_Y_CBCR_H2V1: |
| case MDP_Y_CRCB_H2V2: |
| case MDP_Y_CBCR_H2V2: |
| case MDP_Y_CBCR_H2V2_TILE: |
| case MDP_Y_CRCB_H2V2_TILE: |
| return OVERLAY_TYPE_VG; |
| default: |
| return -ERANGE; |
| } |
| |
| } |
| |
| #define C3_ALPHA 3 /* alpha */ |
| #define C2_R_Cr 2 /* R/Cr */ |
| #define C1_B_Cb 1 /* B/Cb */ |
| #define C0_G_Y 0 /* G/luma */ |
| |
| int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe) |
| { |
| switch (pipe->src_format) { |
| case MDP_RGB_565: |
| pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; |
| pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; |
| pipe->a_bit = 0; |
| pipe->r_bit = 1; /* R, 5 bits */ |
| pipe->b_bit = 1; /* B, 5 bits */ |
| pipe->g_bit = 2; /* G, 6 bits */ |
| pipe->alpha_enable = 0; |
| pipe->unpack_tight = 1; |
| pipe->unpack_align_msb = 0; |
| pipe->unpack_count = 2; |
| pipe->element2 = C2_R_Cr; /* R */ |
| pipe->element1 = C0_G_Y; /* G */ |
| pipe->element0 = C1_B_Cb; /* B */ |
| pipe->bpp = 2; /* 2 bpp */ |
| break; |
| case MDP_RGB_888: |
| pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; |
| pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; |
| pipe->a_bit = 0; |
| pipe->r_bit = 3; /* R, 8 bits */ |
| pipe->b_bit = 3; /* B, 8 bits */ |
| pipe->g_bit = 3; /* G, 8 bits */ |
| pipe->alpha_enable = 0; |
| pipe->unpack_tight = 1; |
| pipe->unpack_align_msb = 0; |
| pipe->unpack_count = 2; |
| pipe->element2 = C2_R_Cr; /* R */ |
| pipe->element1 = C0_G_Y; /* G */ |
| pipe->element0 = C1_B_Cb; /* B */ |
| pipe->bpp = 3; /* 3 bpp */ |
| break; |
| case MDP_BGR_565: |
| pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; |
| pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; |
| pipe->a_bit = 0; |
| pipe->r_bit = 1; /* R, 5 bits */ |
| pipe->b_bit = 1; /* B, 5 bits */ |
| pipe->g_bit = 2; /* G, 6 bits */ |
| pipe->alpha_enable = 0; |
| pipe->unpack_tight = 1; |
| pipe->unpack_align_msb = 0; |
| pipe->unpack_count = 2; |
| pipe->element2 = C1_B_Cb; /* B */ |
| pipe->element1 = C0_G_Y; /* G */ |
| pipe->element0 = C2_R_Cr; /* R */ |
| pipe->bpp = 2; /* 2 bpp */ |
| break; |
| case MDP_ARGB_8888: |
| pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; |
| pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; |
| pipe->a_bit = 3; /* alpha, 4 bits */ |
| pipe->r_bit = 3; /* R, 8 bits */ |
| pipe->b_bit = 3; /* B, 8 bits */ |
| pipe->g_bit = 3; /* G, 8 bits */ |
| pipe->alpha_enable = 1; |
| pipe->unpack_tight = 1; |
| pipe->unpack_align_msb = 0; |
| pipe->unpack_count = 3; |
| pipe->element3 = C3_ALPHA; /* alpha */ |
| pipe->element2 = C2_R_Cr; /* R */ |
| pipe->element1 = C0_G_Y; /* G */ |
| pipe->element0 = C1_B_Cb; /* B */ |
| pipe->bpp = 4; /* 4 bpp */ |
| break; |
| case MDP_RGBA_8888: |
| pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; |
| pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; |
| pipe->a_bit = 3; /* alpha, 4 bits */ |
| pipe->r_bit = 3; /* R, 8 bits */ |
| pipe->b_bit = 3; /* B, 8 bits */ |
| pipe->g_bit = 3; /* G, 8 bits */ |
| pipe->alpha_enable = 1; |
| pipe->unpack_tight = 1; |
| pipe->unpack_align_msb = 0; |
| pipe->unpack_count = 3; |
| pipe->element3 = C2_R_Cr; /* R */ |
| pipe->element2 = C0_G_Y; /* G */ |
| pipe->element1 = C1_B_Cb; /* B */ |
| pipe->element0 = C3_ALPHA; /* alpha */ |
| pipe->bpp = 4; /* 4 bpp */ |
| break; |
| case MDP_BGRA_8888: |
| pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; |
| pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; |
| pipe->a_bit = 3; /* alpha, 4 bits */ |
| pipe->r_bit = 3; /* R, 8 bits */ |
| pipe->b_bit = 3; /* B, 8 bits */ |
| pipe->g_bit = 3; /* G, 8 bits */ |
| pipe->alpha_enable = 1; |
| pipe->unpack_tight = 1; |
| pipe->unpack_align_msb = 0; |
| pipe->unpack_count = 3; |
| pipe->element3 = C1_B_Cb; /* B */ |
| pipe->element2 = C0_G_Y; /* G */ |
| pipe->element1 = C2_R_Cr; /* R */ |
| pipe->element0 = C3_ALPHA; /* alpha */ |
| pipe->bpp = 4; /* 4 bpp */ |
| break; |
| case MDP_YCRYCB_H2V1: |
| pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; |
| pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; |
| pipe->a_bit = 0; /* alpha, 4 bits */ |
| pipe->r_bit = 3; /* R, 8 bits */ |
| pipe->b_bit = 3; /* B, 8 bits */ |
| pipe->g_bit = 3; /* G, 8 bits */ |
| pipe->alpha_enable = 0; |
| pipe->unpack_tight = 1; |
| pipe->unpack_align_msb = 0; |
| pipe->unpack_count = 3; |
| pipe->element3 = C0_G_Y; /* G */ |
| pipe->element2 = C2_R_Cr; /* R */ |
| pipe->element1 = C0_G_Y; /* G */ |
| pipe->element0 = C1_B_Cb; /* B */ |
| pipe->bpp = 2; /* 2 bpp */ |
| pipe->chroma_sample = MDP4_CHROMA_H2V1; |
| break; |
| case MDP_Y_CRCB_H2V1: |
| case MDP_Y_CBCR_H2V1: |
| case MDP_Y_CRCB_H2V2: |
| case MDP_Y_CBCR_H2V2: |
| pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; |
| pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR; |
| pipe->a_bit = 0; |
| pipe->r_bit = 3; /* R, 8 bits */ |
| pipe->b_bit = 3; /* B, 8 bits */ |
| pipe->g_bit = 3; /* G, 8 bits */ |
| pipe->alpha_enable = 0; |
| pipe->unpack_tight = 1; |
| pipe->unpack_align_msb = 0; |
| pipe->unpack_count = 1; /* 2 */ |
| pipe->element3 = C0_G_Y; /* not used */ |
| pipe->element2 = C0_G_Y; /* not used */ |
| if (pipe->src_format == MDP_Y_CRCB_H2V1) { |
| pipe->element1 = C2_R_Cr; /* R */ |
| pipe->element0 = C1_B_Cb; /* B */ |
| pipe->chroma_sample = MDP4_CHROMA_H2V1; |
| } else if (pipe->src_format == MDP_Y_CBCR_H2V1) { |
| pipe->element1 = C1_B_Cb; /* B */ |
| pipe->element0 = C2_R_Cr; /* R */ |
| pipe->chroma_sample = MDP4_CHROMA_H2V1; |
| } else if (pipe->src_format == MDP_Y_CRCB_H2V2) { |
| pipe->element1 = C2_R_Cr; /* R */ |
| pipe->element0 = C1_B_Cb; /* B */ |
| pipe->chroma_sample = MDP4_CHROMA_420; |
| } else if (pipe->src_format == MDP_Y_CBCR_H2V2) { |
| pipe->element1 = C1_B_Cb; /* B */ |
| pipe->element0 = C2_R_Cr; /* R */ |
| pipe->chroma_sample = MDP4_CHROMA_420; |
| } |
| pipe->bpp = 2; /* 2 bpp */ |
| break; |
| case MDP_Y_CBCR_H2V2_TILE: |
| case MDP_Y_CRCB_H2V2_TILE: |
| pipe->frame_format = MDP4_FRAME_FORMAT_VIDEO_SUPERTILE; |
| pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR; |
| pipe->a_bit = 0; |
| pipe->r_bit = 3; /* R, 8 bits */ |
| pipe->b_bit = 3; /* B, 8 bits */ |
| pipe->g_bit = 3; /* G, 8 bits */ |
| pipe->alpha_enable = 0; |
| pipe->unpack_tight = 1; |
| pipe->unpack_align_msb = 0; |
| pipe->unpack_count = 1; /* 2 */ |
| pipe->element3 = C0_G_Y; /* not used */ |
| pipe->element2 = C0_G_Y; /* not used */ |
| if (pipe->src_format == MDP_Y_CRCB_H2V2_TILE) { |
| pipe->element1 = C2_R_Cr; /* R */ |
| pipe->element0 = C1_B_Cb; /* B */ |
| pipe->chroma_sample = MDP4_CHROMA_420; |
| } else if (pipe->src_format == MDP_Y_CBCR_H2V2_TILE) { |
| pipe->element1 = C1_B_Cb; /* B */ |
| pipe->element0 = C2_R_Cr; /* R */ |
| pipe->chroma_sample = MDP4_CHROMA_420; |
| } |
| pipe->bpp = 2; /* 2 bpp */ |
| break; |
| default: |
| /* not likely */ |
| return -ERANGE; |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * color_key_convert: output with 12 bits color key |
| */ |
| static uint32 color_key_convert(int start, int num, uint32 color) |
| { |
| |
| uint32 data; |
| |
| data = (color >> start) & ((1 << num) - 1); |
| |
| if (num == 5) |
| data = (data << 7) + (data << 2) + (data >> 3); |
| else if (num == 6) |
| data = (data << 6) + data; |
| else /* 8 bits */ |
| data = (data << 4) + (data >> 4); |
| |
| return data; |
| |
| } |
| |
| void transp_color_key(int format, uint32 transp, |
| uint32 *c0, uint32 *c1, uint32 *c2) |
| { |
| int b_start, g_start, r_start; |
| int b_num, g_num, r_num; |
| |
| switch (format) { |
| case MDP_RGB_565: |
| b_start = 0; |
| g_start = 5; |
| r_start = 11; |
| r_num = 5; |
| g_num = 6; |
| b_num = 5; |
| break; |
| case MDP_RGB_888: |
| case MDP_XRGB_8888: |
| case MDP_ARGB_8888: |
| b_start = 0; |
| g_start = 8; |
| r_start = 16; |
| r_num = 8; |
| g_num = 8; |
| b_num = 8; |
| break; |
| case MDP_BGR_565: |
| b_start = 11; |
| g_start = 5; |
| r_start = 0; |
| r_num = 5; |
| g_num = 6; |
| b_num = 5; |
| break; |
| case MDP_Y_CBCR_H2V2: |
| case MDP_Y_CBCR_H2V1: |
| b_start = 8; |
| g_start = 16; |
| r_start = 0; |
| r_num = 8; |
| g_num = 8; |
| b_num = 8; |
| break; |
| case MDP_Y_CRCB_H2V2: |
| case MDP_Y_CRCB_H2V1: |
| b_start = 0; |
| g_start = 16; |
| r_start = 8; |
| r_num = 8; |
| g_num = 8; |
| b_num = 8; |
| break; |
| default: |
| b_start = 0; |
| g_start = 8; |
| r_start = 16; |
| r_num = 8; |
| g_num = 8; |
| b_num = 8; |
| break; |
| } |
| |
| *c0 = color_key_convert(g_start, g_num, transp); |
| *c1 = color_key_convert(b_start, b_num, transp); |
| *c2 = color_key_convert(r_start, r_num, transp); |
| } |
| |
| uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe) |
| { |
| uint32 format; |
| |
| format = 0; |
| |
| if (pipe->solid_fill) |
| format |= MDP4_FORMAT_SOLID_FILL; |
| |
| if (pipe->unpack_align_msb) |
| format |= MDP4_FORMAT_UNPACK_ALIGN_MSB; |
| |
| if (pipe->unpack_tight) |
| format |= MDP4_FORMAT_UNPACK_TIGHT; |
| |
| if (pipe->alpha_enable) |
| format |= MDP4_FORMAT_ALPHA_ENABLE; |
| |
| format |= (pipe->unpack_count << 13); |
| format |= ((pipe->bpp - 1) << 9); |
| format |= (pipe->a_bit << 6); |
| format |= (pipe->r_bit << 4); |
| format |= (pipe->b_bit << 2); |
| format |= pipe->g_bit; |
| |
| format |= (pipe->frame_format << 29); |
| |
| if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) { |
| /* video/graphic */ |
| format |= (pipe->fetch_plane << 19); |
| format |= (pipe->chroma_site << 28); |
| format |= (pipe->chroma_sample << 26); |
| } |
| |
| return format; |
| } |
| |
| uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe) |
| { |
| return (pipe->element3 << 24) | (pipe->element2 << 16) | |
| (pipe->element1 << 8) | pipe->element0; |
| } |
| |
| void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe) |
| { |
| uint32 data; |
| char *overlay_base; |
| |
| if (pipe->mixer_num == MDP4_MIXER1) |
| overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ |
| else |
| overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ |
| |
| /* MDP_OVERLAYPROC_CFG */ |
| outpdw(overlay_base + 0x0004, 0x01); /* directout */ |
| data = pipe->src_height; |
| data <<= 16; |
| data |= pipe->src_width; |
| outpdw(overlay_base + 0x0008, data); /* ROI, height + width */ |
| outpdw(overlay_base + 0x000c, pipe->srcp0_addr); |
| outpdw(overlay_base + 0x0010, pipe->srcp0_ystride); |
| outpdw(overlay_base + 0x0014, 0x4); /* GC_LUT_EN, 888 */ |
| } |
| |
| int mdp4_overlay_active(int mixer) |
| { |
| uint32 data, mask, i; |
| int p1, p2; |
| |
| data = inpdw(MDP_BASE + 0x10100); |
| p1 = 0; |
| p2 = 0; |
| for (i = 0; i < 8; i++) { |
| mask = data & 0x0f; |
| if (mask) { |
| if (mask <= 4) |
| p1++; |
| else |
| p2++; |
| } |
| data >>= 4; |
| } |
| |
| if (mixer) |
| return p2; |
| else |
| return p1; |
| } |
| |
| void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe) |
| { |
| uint32 data, mask, snum, stage, mixer; |
| |
| stage = pipe->mixer_stage; |
| mixer = pipe->mixer_num; |
| |
| /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */ |
| data = inpdw(MDP_BASE + 0x10100); |
| |
| if (mixer == MDP4_MIXER1) |
| stage += 8; |
| |
| if (pipe->pipe_type == OVERLAY_TYPE_VG) {/* VG1 and VG2 */ |
| snum = 0; |
| snum += (4 * pipe->pipe_num); |
| } else { |
| snum = 8; |
| snum += (4 * pipe->pipe_num); /* RGB1 and RGB2 */ |
| } |
| |
| mask = 0x0f; |
| mask <<= snum; |
| stage <<= snum; |
| data &= ~mask; /* clear old bits */ |
| |
| data |= stage; |
| |
| outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */ |
| |
| data = inpdw(MDP_BASE + 0x10100); |
| |
| ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = pipe; /* keep it */ |
| } |
| |
| void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe) |
| { |
| uint32 data, mask, snum, stage, mixer; |
| |
| stage = pipe->mixer_stage; |
| mixer = pipe->mixer_num; |
| |
| if (pipe != ctrl->stage[mixer][stage]) /* not runing */ |
| return; |
| |
| /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */ |
| data = inpdw(MDP_BASE + 0x10100); |
| |
| if (mixer == MDP4_MIXER1) |
| stage += 8; |
| |
| if (pipe->pipe_type == OVERLAY_TYPE_VG) {/* VG1 and VG2 */ |
| snum = 0; |
| snum += (4 * pipe->pipe_num); |
| } else { |
| snum = 8; |
| snum += (4 * pipe->pipe_num); /* RGB1 and RGB2 */ |
| } |
| |
| mask = 0x0f; |
| mask <<= snum; |
| data &= ~mask; /* clear old bits */ |
| |
| outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */ |
| |
| data = inpdw(MDP_BASE + 0x10100); |
| |
| ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL; /* clear it */ |
| } |
| |
| void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe) |
| { |
| unsigned char *overlay_base; |
| uint32 c0, c1, c2, blend_op; |
| int off; |
| |
| if (pipe->mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */ |
| overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ |
| else |
| overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ |
| |
| /* stage 0 to stage 2 */ |
| off = 0x20 * (pipe->mixer_stage - MDP4_MIXER_STAGE0); |
| |
| blend_op = 0; |
| if (pipe->alpha_enable) /* ARGB */ |
| blend_op = MDP4_BLEND_FG_ALPHA_FG_PIXEL | |
| MDP4_BLEND_BG_ALPHA_FG_PIXEL; |
| else |
| blend_op = (MDP4_BLEND_BG_ALPHA_BG_CONST | |
| MDP4_BLEND_FG_ALPHA_FG_CONST); |
| |
| |
| if (pipe->alpha_enable == 0) { /* not ARGB */ |
| if (pipe->is_fg) { |
| outpdw(overlay_base + off + 0x108, pipe->alpha); |
| outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha); |
| } else { |
| outpdw(overlay_base + off + 0x108, 0xff - pipe->alpha); |
| outpdw(overlay_base + off + 0x10c, pipe->alpha); |
| } |
| } |
| |
| if (pipe->transp != MDP_TRANSP_NOP) { |
| transp_color_key(pipe->src_format, pipe->transp, &c0, &c1, &c2); |
| if (pipe->is_fg) { |
| blend_op |= MDP4_BLEND_FG_TRANSP_EN; /* Fg blocked */ |
| /* lower limit */ |
| if (c0 > 0x10) |
| c0 -= 0x10; |
| if (c1 > 0x10) |
| c1 -= 0x10; |
| if (c2 > 0x10) |
| c2 -= 0x10; |
| outpdw(overlay_base + off + 0x110, |
| (c1 << 16 | c0));/* low */ |
| outpdw(overlay_base + off + 0x114, c2);/* low */ |
| /* upper limit */ |
| if ((c0 + 0x20) < 0x0fff) |
| c0 += 0x20; |
| else |
| c0 = 0x0fff; |
| if ((c1 + 0x20) < 0x0fff) |
| c1 += 0x20; |
| else |
| c1 = 0x0fff; |
| if ((c2 + 0x20) < 0x0fff) |
| c2 += 0x20; |
| else |
| c2 = 0x0fff; |
| outpdw(overlay_base + off + 0x118, |
| (c1 << 16 | c0));/* high */ |
| outpdw(overlay_base + off + 0x11c, c2);/* high */ |
| } else { |
| blend_op |= MDP4_BLEND_BG_TRANSP_EN; /* bg blocked */ |
| /* lower limit */ |
| if (c0 > 0x10) |
| c0 -= 0x10; |
| if (c1 > 0x10) |
| c1 -= 0x10; |
| if (c2 > 0x10) |
| c2 -= 0x10; |
| outpdw(overlay_base + 0x180, |
| (c1 << 16 | c0));/* low */ |
| outpdw(overlay_base + 0x184, c2);/* low */ |
| /* upper limit */ |
| if ((c0 + 0x20) < 0x0fff) |
| c0 += 0x20; |
| else |
| c0 = 0x0fff; |
| if ((c1 + 0x20) < 0x0fff) |
| c1 += 0x20; |
| else |
| c1 = 0x0fff; |
| if ((c2 + 0x20) < 0x0fff) |
| c2 += 0x20; |
| else |
| c2 = 0x0fff; |
| outpdw(overlay_base + 0x188, |
| (c1 << 16 | c0));/* high */ |
| outpdw(overlay_base + 0x18c, c2);/* high */ |
| } |
| } |
| outpdw(overlay_base + off + 0x104, blend_op); |
| } |
| |
| void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all) |
| { |
| uint32 bits = 0; |
| |
| if (pipe->mixer_num == MDP4_MIXER1) |
| bits |= 0x02; |
| else |
| bits |= 0x01; |
| |
| if (all) { |
| if (pipe->pipe_type == OVERLAY_TYPE_RGB) { |
| if (pipe->pipe_num == OVERLAY_PIPE_RGB2) |
| bits |= 0x20; |
| else |
| bits |= 0x10; |
| } else { |
| if (pipe->pipe_num == OVERLAY_PIPE_VG2) |
| bits |= 0x08; |
| else |
| bits |= 0x04; |
| } |
| } |
| |
| outpdw(MDP_BASE + 0x18000, bits); /* MDP_OVERLAY_REG_FLUSH */ |
| |
| while (inpdw(MDP_BASE + 0x18000) & bits) /* self clear when complete */ |
| ; |
| } |
| |
| struct mdp4_overlay_pipe *mdp4_overlay_ndx2pipe(int ndx) |
| { |
| struct mdp4_overlay_pipe *pipe; |
| |
| if (ndx == 0 || ndx >= MDP4_MAX_OVERLAY_PIPE) |
| return NULL; |
| |
| pipe = &ctrl->plist[ndx - 1]; /* ndx start from 1 */ |
| |
| if (pipe->pipe_ndx == 0) |
| return NULL; |
| |
| return pipe; |
| } |
| |
| struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(void) |
| { |
| int i; |
| struct mdp4_overlay_pipe *pipe; |
| |
| pipe = &ctrl->plist[0]; |
| for (i = 0; i < MDP4_MAX_OVERLAY_PIPE; i++) { |
| if (pipe->pipe_ndx == 0) { |
| pipe->pipe_ndx = i + 1; /* start from 1 */ |
| init_completion(&pipe->comp); |
| printk(KERN_INFO "mdp4_overlay_pipe_alloc: pipe=%x ndx=%d\n", |
| (int)pipe, pipe->pipe_ndx); |
| return pipe; |
| } |
| pipe++; |
| } |
| |
| return NULL; |
| } |
| |
| |
| void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe) |
| { |
| printk(KERN_INFO "mdp4_overlay_pipe_free: pipe=%x ndx=%d\n", |
| (int)pipe, pipe->pipe_ndx); |
| memset(pipe, 0, sizeof(*pipe)); |
| } |
| |
| static int get_pipe_num(int ptype, int stage) |
| { |
| if (ptype == OVERLAY_TYPE_RGB) { |
| if (stage == MDP4_MIXER_STAGE_BASE) |
| return OVERLAY_PIPE_RGB1; |
| else |
| return OVERLAY_PIPE_RGB2; |
| } else { |
| if (stage == MDP4_MIXER_STAGE0) |
| return OVERLAY_PIPE_VG1; |
| else |
| return OVERLAY_PIPE_VG2; |
| } |
| } |
| |
| int mdp4_overlay_req_check(uint32 id, uint32 z_order, uint32 mixer) |
| { |
| struct mdp4_overlay_pipe *pipe; |
| |
| pipe = ctrl->stage[mixer][z_order]; |
| |
| if (pipe == NULL) |
| return 0; |
| |
| if (pipe->pipe_ndx == id) /* same req, recycle */ |
| return 0; |
| |
| return -EPERM; |
| } |
| |
| static int mdp4_overlay_req2pipe(struct mdp_overlay *req, int mixer, |
| struct mdp4_overlay_pipe **ppipe) |
| { |
| struct mdp4_overlay_pipe *pipe; |
| int ret, ptype; |
| |
| if (mixer >= MDP4_MAX_MIXER) { |
| printk(KERN_ERR "mpd_overlay_req2pipe: mixer out of range!\n"); |
| return -ERANGE; |
| } |
| |
| if (req->z_order < 0 || req->z_order > 2) { |
| printk(KERN_ERR "mpd_overlay_req2pipe: z_order=%d out of range!\n", |
| req->z_order); |
| return -ERANGE; |
| } |
| |
| if (req->src_rect.h == 0 || req->src_rect.w == 0) { |
| printk(KERN_ERR "mpd_overlay_req2pipe: src img of zero size!\n"); |
| return -EINVAL; |
| } |
| |
| ret = mdp4_overlay_req_check(req->id, req->z_order, mixer); |
| if (ret < 0) |
| return ret; |
| |
| ptype = mdp4_overlay_format2type(req->src.format); |
| if (ptype < 0) |
| return ptype; |
| |
| if (req->id == MSMFB_NEW_REQUEST) /* new request */ |
| pipe = mdp4_overlay_pipe_alloc(); |
| else |
| pipe = mdp4_overlay_ndx2pipe(req->id); |
| |
| if (pipe == NULL) |
| return -ENOMEM; |
| |
| pipe->src_format = req->src.format; |
| ret = mdp4_overlay_format2pipe(pipe); |
| |
| if (ret < 0) |
| return ret; |
| |
| /* |
| * base layer == 1, reserved for frame buffer |
| * zorder 0 == stage 0 == 2 |
| * zorder 1 == stage 1 == 3 |
| * zorder 2 == stage 2 == 4 |
| */ |
| if (req->id == MSMFB_NEW_REQUEST) { /* new request */ |
| pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0; |
| pipe->pipe_type = ptype; |
| pipe->pipe_num = get_pipe_num(ptype, pipe->mixer_stage); |
| printk(KERN_INFO "mpd4_overlay_req2pipe: zorder=%d pipe_num=%d\n", |
| req->z_order, pipe->pipe_num); |
| } |
| |
| pipe->src_width = req->src.width & 0x07ff; /* source img width */ |
| pipe->src_height = req->src.height & 0x07ff; /* source img height */ |
| pipe->src_h = req->src_rect.h & 0x07ff; |
| pipe->src_w = req->src_rect.w & 0x07ff; |
| pipe->src_y = req->src_rect.y & 0x07ff; |
| pipe->src_x = req->src_rect.x & 0x07ff; |
| pipe->dst_h = req->dst_rect.h & 0x07ff; |
| pipe->dst_w = req->dst_rect.w & 0x07ff; |
| pipe->dst_y = req->dst_rect.y & 0x07ff; |
| pipe->dst_x = req->dst_rect.x & 0x07ff; |
| |
| if (req->flags & MDP_FLIP_LR) |
| pipe->op_mode |= MDP4_OP_FLIP_LR; |
| |
| if (req->flags & MDP_FLIP_UD) |
| pipe->op_mode |= MDP4_OP_FLIP_UD; |
| |
| if (req->flags & MDP_DITHER) |
| pipe->op_mode |= MDP4_OP_DITHER_EN; |
| |
| if (req->flags & MDP_DEINTERLACE) |
| pipe->op_mode |= MDP4_OP_DEINT_ODD_REF; |
| |
| pipe->is_fg = req->is_fg;/* control alpha and color key */ |
| |
| pipe->alpha = req->alpha & 0x0ff; |
| |
| pipe->transp = req->transp_mask; |
| |
| *ppipe = pipe; |
| |
| return 0; |
| } |
| |
| int get_img(struct msmfb_data *img, struct fb_info *info, |
| unsigned long *start, unsigned long *len, struct file **pp_file) |
| { |
| int put_needed, ret = 0; |
| struct file *file; |
| #ifdef CONFIG_ANDROID_PMEM |
| unsigned long vstart; |
| #endif |
| |
| #ifdef CONFIG_ANDROID_PMEM |
| if (!get_pmem_file(img->memory_id, start, &vstart, len, pp_file)) |
| return 0; |
| #endif |
| file = fget_light(img->memory_id, &put_needed); |
| if (file == NULL) |
| return -1; |
| |
| if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { |
| *start = info->fix.smem_start; |
| *len = info->fix.smem_len; |
| *pp_file = file; |
| } else { |
| ret = -1; |
| fput_light(file, put_needed); |
| } |
| return ret; |
| } |
| int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req) |
| { |
| struct mdp4_overlay_pipe *pipe; |
| |
| pipe = mdp4_overlay_ndx2pipe(req->id); |
| if (pipe == NULL) |
| return -ENODEV; |
| |
| *req = pipe->req_data; |
| |
| return 0; |
| } |
| |
| int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req) |
| { |
| struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; |
| int ret, mixer; |
| struct mdp4_overlay_pipe *pipe; |
| int lcdc; |
| |
| if (mfd == NULL) |
| return -ENODEV; |
| |
| if (req->src.format == MDP_FB_FORMAT) |
| req->src.format = mfd->fb_imgType; |
| |
| if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) |
| return -EINTR; |
| |
| mixer = info->node; /* minor number of char device */ |
| |
| ret = mdp4_overlay_req2pipe(req, mixer, &pipe); |
| if (ret < 0) { |
| mutex_unlock(&mfd->dma->ov_mutex); |
| return ret; |
| } |
| |
| lcdc = inpdw(MDP_BASE + 0xc0000); |
| |
| if (lcdc == 0) { /* mddi */ |
| /* MDP cmd block enable */ |
| mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); |
| } |
| |
| /* return id back to user */ |
| req->id = pipe->pipe_ndx; /* pipe_ndx start from 1 */ |
| pipe->req_data = *req; /* keep original req */ |
| |
| mutex_unlock(&mfd->dma->ov_mutex); |
| |
| return 0; |
| } |
| |
| int mdp4_overlay_unset(struct fb_info *info, int ndx) |
| { |
| struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; |
| struct mdp4_overlay_pipe *pipe; |
| int lcdc; |
| |
| if (mfd == NULL) |
| return -ENODEV; |
| |
| if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) |
| return -EINTR; |
| |
| pipe = mdp4_overlay_ndx2pipe(ndx); |
| |
| if (pipe == NULL) { |
| mutex_unlock(&mfd->dma->ov_mutex); |
| return -ENODEV; |
| } |
| |
| lcdc = inpdw(MDP_BASE + 0xc0000); |
| |
| mdp4_mixer_stage_down(pipe); |
| |
| if (lcdc == 0) { /* mddi */ |
| /* MDP cmd block disable */ |
| mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); |
| } |
| |
| if (lcdc) /* LCDC mode */ |
| mdp4_overlay_reg_flush(pipe, 0); |
| |
| mdp4_overlay_pipe_free(pipe); |
| |
| if (lcdc == 0) { /* mddi */ |
| mdp4_mddi_overlay_restore(); |
| } |
| |
| mutex_unlock(&mfd->dma->ov_mutex); |
| |
| return 0; |
| } |
| |
| struct tile_desc { |
| uint32 width; /* tile's width */ |
| uint32 height; /* tile's height */ |
| uint32 row_tile_w; /* tiles per row's width */ |
| uint32 row_tile_h; /* tiles per row's height */ |
| }; |
| |
| void tile_samsung(struct tile_desc *tp) |
| { |
| /* |
| * each row of samsung tile consists of two tiles in height |
| * and two tiles in width which means width should align to |
| * 64 x 2 bytes and height should align to 32 x 2 bytes. |
| * video decoder generate two tiles in width and one tile |
| * in height which ends up height align to 32 X 1 bytes. |
| */ |
| tp->width = 64; /* 64 bytes */ |
| tp->row_tile_w = 2; /* 2 tiles per row's width */ |
| tp->height = 32; /* 32 bytes */ |
| tp->row_tile_h = 1; /* 1 tiles per row's height */ |
| } |
| |
| uint32 tile_mem_size(struct mdp4_overlay_pipe *pipe, struct tile_desc *tp) |
| { |
| uint32 tile_w, tile_h; |
| uint32 row_num_w, row_num_h; |
| |
| |
| tile_w = tp->width * tp->row_tile_w; |
| tile_h = tp->height * tp->row_tile_h; |
| |
| row_num_w = (pipe->src_width + tile_w - 1) / tile_w; |
| row_num_h = (pipe->src_height + tile_h - 1) / tile_h; |
| |
| return row_num_w * row_num_h * tile_w * tile_h; |
| } |
| |
| int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req, |
| struct file **pp_src_file) |
| { |
| struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; |
| struct msmfb_data *img; |
| struct mdp4_overlay_pipe *pipe; |
| ulong start, addr; |
| ulong len = 0; |
| struct file *p_src_file = 0; |
| int lcdc; |
| |
| if (mfd == NULL) |
| return -ENODEV; |
| |
| pipe = mdp4_overlay_ndx2pipe(req->id); |
| if (pipe == NULL) |
| return -ENODEV; |
| |
| if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) |
| return -EINTR; |
| |
| img = &req->data; |
| get_img(img, info, &start, &len, &p_src_file); |
| if (len == 0) { |
| mutex_unlock(&mfd->dma->ov_mutex); |
| printk(KERN_ERR "mdp_overlay_play: could not retrieve" |
| " image from memory\n"); |
| return -1; |
| } |
| *pp_src_file = p_src_file; |
| |
| addr = start + img->offset; |
| pipe->srcp0_addr = addr; |
| pipe->srcp0_ystride = pipe->src_width * pipe->bpp; |
| |
| if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) { |
| if (pipe->frame_format == MDP4_FRAME_FORMAT_VIDEO_SUPERTILE) { |
| struct tile_desc tile; |
| |
| tile_samsung(&tile); |
| pipe->srcp1_addr = addr + tile_mem_size(pipe, &tile); |
| } else |
| pipe->srcp1_addr = addr + |
| pipe->src_width * pipe->src_height; |
| |
| pipe->srcp0_ystride = pipe->src_width; |
| pipe->srcp1_ystride = pipe->src_width; |
| } |
| |
| lcdc = inpdw(MDP_BASE + 0xc0000); |
| lcdc &= 0x01; /* LCDC mode */ |
| |
| if (pipe->pipe_type == OVERLAY_TYPE_VG) |
| mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */ |
| else |
| mdp4_overlay_rgb_setup(pipe); /* rgb pipe */ |
| |
| mdp4_mixer_blend_setup(pipe); |
| mdp4_mixer_stage_up(pipe); |
| |
| if (lcdc) { /* LCDC mode */ |
| mdp4_overlay_reg_flush(pipe, 1); |
| } |
| |
| if (lcdc) { /* LCDC mode */ |
| if (pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) { /* done */ |
| mutex_unlock(&mfd->dma->ov_mutex); |
| return 0; |
| } |
| } |
| |
| if (lcdc == 0) { /* MDDI mode */ |
| #ifdef MDP4_NONBLOCKING |
| if (mfd->panel_power_on) |
| #else |
| if (!mfd->dma->busy && mfd->panel_power_on) |
| #endif |
| mdp4_mddi_overlay_kickoff(mfd, pipe); |
| } |
| |
| mutex_unlock(&mfd->dma->ov_mutex); |
| |
| return 0; |
| } |