blob: be1b2874185ba9096bd566d07a376c5ff95282a3 [file] [log] [blame]
/* 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/hrtimer.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mdp4.h"
static struct mdp4_overlay_pipe *mddi_pipe;
static struct mdp4_overlay_pipe *pending_pipe;
static struct msm_fb_data_type *mddi_mfd;
#define WHOLESCREEN
void mdp4_overlay_update_lcd(struct msm_fb_data_type *mfd)
{
MDPIBUF *iBuf = &mfd->ibuf;
uint8 *src;
int bpp, ptype;
uint32 format;
uint32 mddi_ld_param;
uint16 mddi_vdo_packet_reg;
struct mdp4_overlay_pipe *pipe;
if (mfd->key != MFD_KEY)
return;
mddi_mfd = mfd; /* keep it */
bpp = iBuf->bpp;
if (bpp == 2)
format = MDP_RGB_565;
else if (bpp == 3)
format = MDP_RGB_888;
else
format = MDP_ARGB_8888;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
if (mddi_pipe == NULL) {
ptype = mdp4_overlay_format2type(format);
pipe = mdp4_overlay_pipe_alloc();
pipe->pipe_type = ptype;
/* use RGB1 pipe */
pipe->pipe_num = OVERLAY_PIPE_RGB1;
pipe->mixer_num = MDP4_MIXER0;
pipe->src_format = format;
mdp4_overlay_format2pipe(pipe);
mddi_pipe = pipe; /* keep it */
mddi_ld_param = 0;
mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
if (mfd->panel_info.type == MDDI_PANEL) {
if (mfd->panel_info.pdest == DISPLAY_1)
mddi_ld_param = 0;
else
mddi_ld_param = 1;
} else {
mddi_ld_param = 2;
}
MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param);
MDP_OUTP(MDP_BASE + 0x00094,
(MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
} else {
pipe = mddi_pipe;
}
src = (uint8 *) iBuf->buf;
#ifdef WHOLESCREEN
{
struct fb_info *fbi;
fbi = mfd->fbi;
pipe->src_height = fbi->var.yres;
pipe->src_width = fbi->var.xres;
pipe->src_h = fbi->var.yres;
pipe->src_w = fbi->var.xres;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->dst_h = fbi->var.yres;
pipe->dst_w = fbi->var.xres;
pipe->dst_y = 0;
pipe->dst_x = 0;
pipe->srcp0_addr = (uint32)src;
pipe->srcp0_ystride = fbi->var.xres_virtual * bpp;
}
#else
if (mdp4_overlay_active(MDP4_MIXER0)) {
struct fb_info *fbi;
fbi = mfd->fbi;
pipe->src_height = fbi->var.yres;
pipe->src_width = fbi->var.xres;
pipe->src_h = fbi->var.yres;
pipe->src_w = fbi->var.xres;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->dst_h = fbi->var.yres;
pipe->dst_w = fbi->var.xres;
pipe->dst_y = 0;
pipe->dst_x = 0;
pipe->srcp0_addr = (uint32) src;
pipe->srcp0_ystride = fbi->var.xres_virtual * bpp;
} else {
/* starting input address */
src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) * bpp;
pipe->src_height = iBuf->dma_h;
pipe->src_width = iBuf->dma_w;
pipe->src_h = iBuf->dma_h;
pipe->src_w = iBuf->dma_w;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->dst_h = iBuf->dma_h;
pipe->dst_w = iBuf->dma_w;
pipe->dst_y = iBuf->dma_y;
pipe->dst_x = iBuf->dma_x;
pipe->srcp0_addr = (uint32) src;
pipe->srcp0_ystride = iBuf->ibuf_width * bpp;
}
#endif
pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
mdp4_overlay_rgb_setup(pipe);
mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_dmap_xy(pipe);
mdp4_overlay_dmap_cfg(mfd, 0);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
/*
* mdp4_overlay0_done_mddi: called from isr
*/
void mdp4_overlay0_done_mddi()
{
if (pending_pipe)
complete(&pending_pipe->comp);
}
void mdp4_mddi_overlay_restore(void)
{
/* mutex holded by caller */
mdp4_overlay_update_lcd(mddi_mfd);
mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe);
}
void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
#ifdef MDP4_NONBLOCKING
unsigned long flag;
spin_lock_irqsave(&mdp_spin_lock, flag);
if (mfd->dma->busy == TRUE) {
INIT_COMPLETION(pipe->comp);
pending_pipe = pipe;
}
spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (pending_pipe != NULL) {
/* wait until DMA finishes the current job */
wait_for_completion_killable(&pipe->comp);
pending_pipe = NULL;
}
down(&mfd->sem);
mdp_enable_irq(MDP_OVERLAY0_TERM);
mfd->dma->busy = TRUE;
/* start OVERLAY pipe */
mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
up(&mfd->sem);
#else
down(&mfd->sem);
mdp_enable_irq(MDP_OVERLAY0_TERM);
mfd->dma->busy = TRUE;
INIT_COMPLETION(pipe->comp);
pending_pipe = pipe;
/* start OVERLAY pipe */
mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
up(&mfd->sem);
/* wait until DMA finishes the current job */
wait_for_completion_killable(&pipe->comp);
mdp_disable_irq(MDP_OVERLAY0_TERM);
#endif
}
void mdp4_mddi_overlay(struct msm_fb_data_type *mfd)
{
mutex_lock(&mfd->dma->ov_mutex);
if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
mdp4_overlay_update_lcd(mfd);
mdp4_mddi_overlay_kickoff(mfd, mddi_pipe);
/* signal if pan function is waiting for the update completion */
if (mfd->pan_waiting) {
mfd->pan_waiting = FALSE;
complete(&mfd->pan_comp);
}
}
mutex_unlock(&mfd->dma->ov_mutex);
}