mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
mdss: display: Add Mobile Display SubSystem driver
- Implements Linux frame buffer interface to interact with userspace libraries and applications, based on msm_fb frame buffer. - Implement MDP driver which handles MDP core data path setup and hardware blocks programming. - Support for UI through Linux frame buffer FBIOPAN_DISPLAY ioctl. Change-Id: Ib98677b8d81d74283b27dea08a9f1a705c101bce Signed-off-by: Adrian Salido-Moreno <adrianm@codeaurora.org>
This commit is contained in:
parent
5cc362beb1
commit
145cc2b53c
16 changed files with 5147 additions and 6 deletions
|
@ -84,6 +84,16 @@ config FB_MSM_MDP40
|
|||
Support for MSM MDP HW revision 4.0
|
||||
Say Y here if this is msm7x30 variant platform.
|
||||
|
||||
config FB_MSM_MDSS
|
||||
bool "MDSS HW"
|
||||
---help---
|
||||
The Mobile Display Sub System (MDSS) driver supports devices which
|
||||
contain MDSS hardware block.
|
||||
|
||||
The MDSS driver implements frame buffer interface to provide access to
|
||||
the display hardware and provide a way for users to display graphics
|
||||
on connected display panels.
|
||||
|
||||
config FB_MSM_MDP_NONE
|
||||
bool "MDP HW None"
|
||||
---help---
|
||||
|
@ -936,4 +946,5 @@ config FB_MSM_EBI2_PANEL_DETECT
|
|||
default n
|
||||
---help---
|
||||
Support for EBI2 panel auto detect
|
||||
|
||||
endif
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
ifeq ($(CONFIG_FB_MSM_MDSS),y)
|
||||
obj-y += mdss/
|
||||
else
|
||||
obj-y := msm_fb.o
|
||||
|
||||
obj-$(CONFIG_FB_MSM_LOGO) += logo.o
|
||||
obj-$(CONFIG_FB_BACKLIGHT) += msm_fb_bl.o
|
||||
|
||||
ifeq ($(CONFIG_FB_MSM_MDP_HW),y)
|
||||
|
||||
# MDP
|
||||
obj-y += mdp.o
|
||||
|
||||
|
@ -182,15 +184,15 @@ obj-$(CONFIG_FB_MSM_EXTMDDI_SVGA) += mddi_ext_lcd.o
|
|||
obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback_panel.o
|
||||
obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback.o
|
||||
obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_overlay_writeback.o
|
||||
|
||||
obj-$(CONFIG_MSM_VIDC_1080P) += vidc/
|
||||
obj-$(CONFIG_MSM_VIDC_720P) += vidc/
|
||||
else
|
||||
obj-$(CONFIG_FB_MSM_EBI2) += ebi2_host.o
|
||||
obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o
|
||||
obj-y += msm_fb_panel.o
|
||||
obj-$(CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL) += ebi2_epson_s1d_qvga.o
|
||||
endif
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_MSM_VIDC_1080P) += vidc/
|
||||
obj-$(CONFIG_MSM_VIDC_720P) += vidc/
|
||||
clean:
|
||||
rm *.o .*cmd
|
||||
|
|
4
drivers/video/msm/mdss/Makefile
Normal file
4
drivers/video/msm/mdss/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
|
||||
mdss-mdp-objs += mdss_mdp_overlay.o
|
||||
obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
|
||||
obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
|
63
drivers/video/msm/mdss/mdss.h
Normal file
63
drivers/video/msm/mdss/mdss.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MDSS_H
|
||||
#define MDSS_H
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define MDSS_REG_WRITE(addr, val) writel_relaxed(val, mdss_reg_base + addr)
|
||||
#define MDSS_REG_READ(addr) readl_relaxed(mdss_reg_base + addr)
|
||||
|
||||
extern unsigned char *mdss_reg_base;
|
||||
|
||||
struct mdss_res_type {
|
||||
u32 rev;
|
||||
u32 mdp_rev;
|
||||
struct clk *mdp_clk;
|
||||
struct clk *mdp_pclk;
|
||||
struct clk *mdp_lut_clk;
|
||||
struct clk *vsync_clk;
|
||||
struct regulator *fs;
|
||||
|
||||
struct workqueue_struct *clk_ctrl_wq;
|
||||
struct delayed_work clk_ctrl_worker;
|
||||
|
||||
u32 irq;
|
||||
u32 irq_mask;
|
||||
u32 irq_ena;
|
||||
u32 irq_buzy;
|
||||
|
||||
u32 clk_ena;
|
||||
u32 suspend;
|
||||
u32 timeout;
|
||||
|
||||
u32 fs_ena;
|
||||
u32 vsync_ena;
|
||||
|
||||
u32 intf;
|
||||
u32 eintf_ena;
|
||||
u32 prim_ptype;
|
||||
u32 res_init;
|
||||
u32 pdev_lcnt;
|
||||
u32 bus_hdl;
|
||||
|
||||
u32 smp_mb_cnt;
|
||||
u32 smp_mb_size;
|
||||
u32 *pipe_type_map;
|
||||
u32 *mixer_type_map;
|
||||
};
|
||||
extern struct mdss_res_type *mdss_res;
|
||||
#endif /* MDSS_H */
|
1228
drivers/video/msm/mdss/mdss_fb.c
Normal file
1228
drivers/video/msm/mdss/mdss_fb.c
Normal file
File diff suppressed because it is too large
Load diff
96
drivers/video/msm/mdss/mdss_fb.h
Normal file
96
drivers/video/msm/mdss/mdss_fb.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
/* Copyright (c) 2008-2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MDSS_FB_H
|
||||
#define MDSS_FB_H
|
||||
|
||||
#include <linux/ion.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/msm_mdp.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "mdss_mdp.h"
|
||||
#include "mdss_panel.h"
|
||||
|
||||
#define MSM_FB_DEFAULT_PAGE_SIZE 2
|
||||
#define MFD_KEY 0x11161126
|
||||
#define MSM_FB_MAX_DEV_LIST 32
|
||||
|
||||
#define MSM_FB_ENABLE_DBGFS
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
struct disp_info_type_suspend {
|
||||
int op_enable;
|
||||
int panel_power_on;
|
||||
};
|
||||
|
||||
struct msm_fb_data_type {
|
||||
u32 key;
|
||||
u32 index;
|
||||
u32 ref_cnt;
|
||||
u32 fb_page;
|
||||
|
||||
struct panel_id panel;
|
||||
struct mdss_panel_info panel_info;
|
||||
|
||||
u32 dest;
|
||||
struct fb_info *fbi;
|
||||
|
||||
int op_enable;
|
||||
u32 fb_imgType;
|
||||
|
||||
int hw_refresh;
|
||||
|
||||
int overlay_play_enable;
|
||||
|
||||
int panel_power_on;
|
||||
struct disp_info_type_suspend suspend;
|
||||
|
||||
int (*on_fnc) (struct msm_fb_data_type *mfd);
|
||||
int (*off_fnc) (struct msm_fb_data_type *mfd);
|
||||
void (*dma_fnc) (struct msm_fb_data_type *mfd);
|
||||
int (*cursor_update) (struct fb_info *info,
|
||||
struct fb_cursor *cursor);
|
||||
int (*lut_update) (struct fb_info *info,
|
||||
struct fb_cmap *cmap);
|
||||
int (*do_histogram) (struct fb_info *info,
|
||||
struct mdp_histogram *hist);
|
||||
void *cursor_buf;
|
||||
void *cursor_buf_phys;
|
||||
|
||||
u32 bl_level;
|
||||
struct mutex lock;
|
||||
|
||||
struct platform_device *pdev;
|
||||
|
||||
u32 var_xres;
|
||||
u32 var_yres;
|
||||
u32 var_pixclock;
|
||||
|
||||
u32 mdp_fb_page_protection;
|
||||
struct ion_client *iclient;
|
||||
|
||||
struct mdss_mdp_ctl *ctl;
|
||||
};
|
||||
|
||||
int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
|
||||
void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl);
|
||||
void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
|
||||
#endif /* MDSS_FB_H */
|
494
drivers/video/msm/mdss/mdss_mdp.c
Normal file
494
drivers/video/msm/mdss/mdss_mdp.c
Normal file
|
@ -0,0 +1,494 @@
|
|||
/*
|
||||
* MDSS MDP Interface (used by framebuffer core)
|
||||
*
|
||||
* Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
|
||||
* Copyright (C) 2007 Google Incorporated
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/memory_alloc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <mach/board.h>
|
||||
#include <mach/clk.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#include "mdss.h"
|
||||
#include "mdss_fb.h"
|
||||
#include "mdss_mdp.h"
|
||||
|
||||
/* 1.15 mdp clk factor */
|
||||
#define MDP_CLK_FACTOR(rate) (((rate) * 23) / 20)
|
||||
|
||||
unsigned char *mdss_reg_base;
|
||||
|
||||
struct mdss_res_type *mdss_res;
|
||||
static struct msm_panel_common_pdata *mdp_pdata;
|
||||
|
||||
static DEFINE_SPINLOCK(mdp_lock);
|
||||
static DEFINE_MUTEX(mdp_clk_lock);
|
||||
static DEFINE_MUTEX(mdp_suspend_mutex);
|
||||
|
||||
u32 mdss_mdp_pipe_type_map[MDSS_MDP_MAX_SSPP] = {
|
||||
MDSS_MDP_PIPE_TYPE_VIG,
|
||||
MDSS_MDP_PIPE_TYPE_VIG,
|
||||
MDSS_MDP_PIPE_TYPE_VIG,
|
||||
MDSS_MDP_PIPE_TYPE_RGB,
|
||||
MDSS_MDP_PIPE_TYPE_RGB,
|
||||
MDSS_MDP_PIPE_TYPE_RGB,
|
||||
MDSS_MDP_PIPE_TYPE_DMA,
|
||||
MDSS_MDP_PIPE_TYPE_DMA,
|
||||
};
|
||||
|
||||
u32 mdss_mdp_mixer_type_map[MDSS_MDP_MAX_LAYERMIXER] = {
|
||||
MDSS_MDP_MIXER_TYPE_INTF,
|
||||
MDSS_MDP_MIXER_TYPE_INTF,
|
||||
MDSS_MDP_MIXER_TYPE_INTF,
|
||||
MDSS_MDP_MIXER_TYPE_WRITEBACK,
|
||||
MDSS_MDP_MIXER_TYPE_WRITEBACK,
|
||||
};
|
||||
|
||||
irqreturn_t mdss_irq_handler(int mdss_irq, void *ptr)
|
||||
{
|
||||
u32 intr = MDSS_MDP_REG_READ(MDSS_REG_HW_INTR_STATUS);
|
||||
|
||||
mdss_res->irq_buzy = true;
|
||||
|
||||
if (intr & MDSS_INTR_MDP)
|
||||
mdss_mdp_isr(mdss_irq, ptr);
|
||||
|
||||
mdss_res->irq_buzy = false;
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num)
|
||||
{
|
||||
u32 irq;
|
||||
unsigned long irq_flags;
|
||||
int ret = 0;
|
||||
|
||||
if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
|
||||
intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
|
||||
intf_num = intf_num << 1;
|
||||
|
||||
irq = BIT(intr_type + intf_num);
|
||||
|
||||
spin_lock_irqsave(&mdp_lock, irq_flags);
|
||||
if (mdss_res->irq_mask & irq) {
|
||||
pr_warn("MDSS IRQ-0x%x is already set, mask=%x irq=%d\n",
|
||||
irq, mdss_res->irq_mask, mdss_res->irq_ena);
|
||||
ret = -EBUSY;
|
||||
} else {
|
||||
mdss_res->irq_mask |= irq;
|
||||
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, irq);
|
||||
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
|
||||
if (!mdss_res->irq_ena) {
|
||||
mdss_res->irq_ena = true;
|
||||
enable_irq(mdss_res->irq);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&mdp_lock, irq_flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num)
|
||||
{
|
||||
u32 irq;
|
||||
unsigned long irq_flags;
|
||||
|
||||
|
||||
if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
|
||||
intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
|
||||
intf_num = intf_num << 1;
|
||||
|
||||
irq = BIT(intr_type + intf_num);
|
||||
|
||||
spin_lock_irqsave(&mdp_lock, irq_flags);
|
||||
if (!(mdss_res->irq_mask & irq)) {
|
||||
pr_warn("MDSS IRQ-%x is NOT set, mask=%x irq=%d\n",
|
||||
irq, mdss_res->irq_mask, mdss_res->irq_ena);
|
||||
} else {
|
||||
mdss_res->irq_mask &= ~irq;
|
||||
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
|
||||
if (!mdss_res->irq_mask) {
|
||||
mdss_res->irq_ena = false;
|
||||
disable_irq(mdss_res->irq);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&mdp_lock, irq_flags);
|
||||
}
|
||||
|
||||
void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num)
|
||||
{
|
||||
u32 irq;
|
||||
|
||||
if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
|
||||
intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
|
||||
intf_num = intf_num << 1;
|
||||
|
||||
irq = BIT(intr_type + intf_num);
|
||||
|
||||
spin_lock(&mdp_lock);
|
||||
if (!(mdss_res->irq_mask & irq)) {
|
||||
pr_warn("MDSS IRQ-%x is NOT set, mask=%x irq=%d\n",
|
||||
irq, mdss_res->irq_mask, mdss_res->irq_ena);
|
||||
} else {
|
||||
mdss_res->irq_mask &= ~irq;
|
||||
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
|
||||
if (!mdss_res->irq_mask) {
|
||||
mdss_res->irq_ena = false;
|
||||
disable_irq_nosync(mdss_res->irq);
|
||||
}
|
||||
}
|
||||
spin_unlock(&mdp_lock);
|
||||
}
|
||||
|
||||
static void mdss_mdp_clk_ctrl_update(int enable)
|
||||
{
|
||||
if (mdss_res->clk_ena == enable)
|
||||
return;
|
||||
|
||||
pr_debug("MDP CLKS %s\n", (enable ? "Enable" : "Disable"));
|
||||
mdss_res->clk_ena = enable;
|
||||
}
|
||||
|
||||
void mdss_mdp_clk_ctrl(int enable, int isr)
|
||||
{
|
||||
static atomic_t clk_ref = ATOMIC_INIT(0);
|
||||
static DEFINE_MUTEX(clk_ctrl_lock);
|
||||
int force_off = 0;
|
||||
|
||||
pr_debug("clk enable=%d isr=%d clk_ref=%d\n", enable, isr,
|
||||
atomic_read(&clk_ref));
|
||||
/*
|
||||
* It is assumed that if isr = TRUE then start = OFF
|
||||
* if start = ON when isr = TRUE it could happen that the usercontext
|
||||
* could turn off the clocks while the interrupt is updating the
|
||||
* power to ON
|
||||
*/
|
||||
WARN_ON(isr == true && enable);
|
||||
|
||||
if (enable) {
|
||||
atomic_inc(&clk_ref);
|
||||
} else if (!atomic_add_unless(&clk_ref, -1, 0)) {
|
||||
pr_debug("master power-off req\n");
|
||||
force_off = 1;
|
||||
}
|
||||
|
||||
if (isr) {
|
||||
/* if it's power off send workqueue to turn off clocks */
|
||||
if (mdss_res->clk_ena && !atomic_read(&clk_ref))
|
||||
queue_delayed_work(mdss_res->clk_ctrl_wq,
|
||||
&mdss_res->clk_ctrl_worker,
|
||||
mdss_res->timeout);
|
||||
} else {
|
||||
mutex_lock(&clk_ctrl_lock);
|
||||
if (delayed_work_pending(&mdss_res->clk_ctrl_worker))
|
||||
cancel_delayed_work(&mdss_res->clk_ctrl_worker);
|
||||
|
||||
if (atomic_read(&clk_ref)) {
|
||||
mdss_mdp_clk_ctrl_update(true);
|
||||
} else if (mdss_res->clk_ena) {
|
||||
mutex_lock(&mdp_suspend_mutex);
|
||||
if (force_off || mdss_res->suspend) {
|
||||
mdss_mdp_clk_ctrl_update(false);
|
||||
} else {
|
||||
/* send workqueue to turn off mdp power */
|
||||
queue_delayed_work(mdss_res->clk_ctrl_wq,
|
||||
&mdss_res->clk_ctrl_worker,
|
||||
mdss_res->timeout);
|
||||
}
|
||||
mutex_unlock(&mdp_suspend_mutex);
|
||||
}
|
||||
mutex_unlock(&clk_ctrl_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
|
||||
{
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
|
||||
}
|
||||
|
||||
static int mdss_mdp_irq_clk_setup(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = request_irq(mdss_res->irq, mdss_irq_handler, IRQF_DISABLED,
|
||||
"MDSS", 0);
|
||||
if (ret) {
|
||||
pr_err("mdp request_irq() failed!\n");
|
||||
return ret;
|
||||
}
|
||||
disable_irq(mdss_res->irq);
|
||||
|
||||
mdss_res->fs = regulator_get(NULL, "fs_mdp");
|
||||
if (IS_ERR(mdss_res->fs))
|
||||
mdss_res->fs = NULL;
|
||||
else {
|
||||
regulator_enable(mdss_res->fs);
|
||||
mdss_res->fs_ena = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct msm_panel_common_pdata *mdss_mdp_populate_pdata(
|
||||
struct device *dev)
|
||||
{
|
||||
struct msm_panel_common_pdata *pdata;
|
||||
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
dev_err(dev, "could not allocate memory for pdata\n");
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static u32 mdss_mdp_res_init(void)
|
||||
{
|
||||
u32 rc;
|
||||
|
||||
rc = mdss_mdp_irq_clk_setup();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
mdss_res->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
|
||||
INIT_DELAYED_WORK(&mdss_res->clk_ctrl_worker,
|
||||
mdss_mdp_clk_ctrl_workqueue_handler);
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
|
||||
mdss_res->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION);
|
||||
mdss_res->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
|
||||
|
||||
mdss_res->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
|
||||
mdss_res->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
|
||||
mdss_res->pipe_type_map = mdss_mdp_pipe_type_map;
|
||||
mdss_res->mixer_type_map = mdss_mdp_mixer_type_map;
|
||||
|
||||
pr_info("mdss_revision=%x\n", mdss_res->rev);
|
||||
pr_info("mdp_hw_revision=%x\n", mdss_res->mdp_rev);
|
||||
|
||||
mdss_res->res_init = true;
|
||||
mdss_res->timeout = HZ/20;
|
||||
mdss_res->clk_ena = false;
|
||||
mdss_res->irq_mask = MDSS_MDP_DEFAULT_INTR_MASK;
|
||||
mdss_res->suspend = false;
|
||||
mdss_res->prim_ptype = NO_PANEL;
|
||||
mdss_res->irq_ena = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *mdss_mdp_mres;
|
||||
struct resource *mdss_mdp_ires;
|
||||
resource_size_t size;
|
||||
int rc;
|
||||
|
||||
if (!mdss_res) {
|
||||
mdss_res = devm_kzalloc(&pdev->dev, sizeof(*mdss_res),
|
||||
GFP_KERNEL);
|
||||
if (mdss_res == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
pdev->id = 0;
|
||||
mdp_pdata = mdss_mdp_populate_pdata(&pdev->dev);
|
||||
mdss_mdp_mres = platform_get_resource(pdev,
|
||||
IORESOURCE_MEM, 0);
|
||||
mdss_mdp_ires = platform_get_resource(pdev,
|
||||
IORESOURCE_IRQ, 0);
|
||||
if (!mdss_mdp_mres || !mdss_mdp_ires) {
|
||||
pr_err("unable to get the MDSS resources");
|
||||
rc = -ENOMEM;
|
||||
goto probe_done;
|
||||
}
|
||||
mdss_reg_base = ioremap(mdss_mdp_mres->start,
|
||||
resource_size(mdss_mdp_mres));
|
||||
|
||||
pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
|
||||
(int) mdss_mdp_mres->start,
|
||||
(int) mdss_reg_base);
|
||||
|
||||
mdss_res->irq = mdss_mdp_ires->start;
|
||||
} else if ((pdev->id == 0) && (pdev->num_resources > 0)) {
|
||||
mdp_pdata = pdev->dev.platform_data;
|
||||
|
||||
size = resource_size(&pdev->resource[0]);
|
||||
mdss_reg_base = ioremap(pdev->resource[0].start, size);
|
||||
|
||||
pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
|
||||
(int) pdev->resource[0].start,
|
||||
(int) mdss_reg_base);
|
||||
|
||||
mdss_res->irq = platform_get_irq(pdev, 0);
|
||||
if (mdss_res->irq < 0) {
|
||||
pr_err("can not get mdp irq\n");
|
||||
rc = -ENOMEM;
|
||||
goto probe_done;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(!mdss_reg_base)) {
|
||||
rc = -ENOMEM;
|
||||
goto probe_done;
|
||||
}
|
||||
|
||||
rc = mdss_mdp_res_init();
|
||||
if (rc) {
|
||||
pr_err("unable to initialize mdss mdp resources\n");
|
||||
goto probe_done;
|
||||
}
|
||||
|
||||
probe_done:
|
||||
if (IS_ERR_VALUE(rc)) {
|
||||
if (mdss_res) {
|
||||
devm_kfree(&pdev->dev, mdss_res);
|
||||
mdss_res = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void mdss_mdp_footswitch_ctrl(int on)
|
||||
{
|
||||
mutex_lock(&mdp_suspend_mutex);
|
||||
if (!mdss_res->suspend || mdss_res->eintf_ena || !mdss_res->fs) {
|
||||
mutex_unlock(&mdp_suspend_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (on && !mdss_res->fs_ena) {
|
||||
pr_debug("Enable MDP FS\n");
|
||||
regulator_enable(mdss_res->fs);
|
||||
mdss_res->fs_ena = true;
|
||||
} else if (!on && mdss_res->fs_ena) {
|
||||
pr_debug("Disable MDP FS\n");
|
||||
regulator_disable(mdss_res->fs);
|
||||
mdss_res->fs_ena = false;
|
||||
}
|
||||
mutex_unlock(&mdp_suspend_mutex);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static void mdss_mdp_suspend_sub(void)
|
||||
{
|
||||
cancel_delayed_work(&mdss_res->clk_ctrl_worker);
|
||||
|
||||
flush_workqueue(mdss_res->clk_ctrl_wq);
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
|
||||
|
||||
mutex_lock(&mdp_suspend_mutex);
|
||||
mdss_res->suspend = true;
|
||||
mutex_unlock(&mdp_suspend_mutex);
|
||||
}
|
||||
|
||||
static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
if (pdev->id == 0) {
|
||||
mdss_mdp_suspend_sub();
|
||||
if (mdss_res->clk_ena) {
|
||||
pr_err("MDP suspend failed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
mdss_mdp_footswitch_ctrl(false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_resume(struct platform_device *pdev)
|
||||
{
|
||||
mdss_mdp_footswitch_ctrl(true);
|
||||
mutex_lock(&mdp_suspend_mutex);
|
||||
mdss_res->suspend = false;
|
||||
mutex_unlock(&mdp_suspend_mutex);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define mdss_mdp_suspend NULL
|
||||
#define mdss_mdp_resume NULL
|
||||
#endif
|
||||
|
||||
static int mdss_mdp_remove(struct platform_device *pdev)
|
||||
{
|
||||
if (mdss_res->fs != NULL)
|
||||
regulator_put(mdss_res->fs);
|
||||
iounmap(mdss_reg_base);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mdss_mdp_dt_match[] = {
|
||||
{ .compatible = "qcom,mdss_mdp",},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mdss_mdp_dt_match);
|
||||
|
||||
static struct platform_driver mdss_mdp_driver = {
|
||||
.probe = mdss_mdp_probe,
|
||||
.remove = mdss_mdp_remove,
|
||||
.suspend = mdss_mdp_suspend,
|
||||
.resume = mdss_mdp_resume,
|
||||
.shutdown = NULL,
|
||||
.driver = {
|
||||
/*
|
||||
* Driver name must match the device name added in
|
||||
* platform.c.
|
||||
*/
|
||||
.name = "mdp",
|
||||
.of_match_table = mdss_mdp_dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int mdss_mdp_register_driver(void)
|
||||
{
|
||||
return platform_driver_register(&mdss_mdp_driver);
|
||||
}
|
||||
|
||||
static int __init mdss_mdp_driver_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mdss_mdp_register_driver();
|
||||
if (ret) {
|
||||
pr_err("mdp_register_driver() failed!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
module_init(mdss_mdp_driver_init);
|
289
drivers/video/msm/mdss/mdss_mdp.h
Normal file
289
drivers/video/msm/mdss/mdss_mdp.h
Normal file
|
@ -0,0 +1,289 @@
|
|||
/* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MDSS_MDP_H
|
||||
#define MDSS_MDP_H
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/msm_mdp.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "mdss.h"
|
||||
#include "mdss_mdp_hwio.h"
|
||||
|
||||
#define MDSS_MDP_DEFAULT_INTR_MASK 0
|
||||
#define MDSS_MDP_CURSOR_WIDTH 64
|
||||
#define MDSS_MDP_CURSOR_HEIGHT 64
|
||||
#define MDSS_MDP_CURSOR_SIZE (MDSS_MDP_CURSOR_WIDTH*MDSS_MDP_CURSOR_WIDTH*4)
|
||||
|
||||
#define MDP_CLK_DEFAULT_RATE 37500000
|
||||
#define PHASE_STEP_SHIFT 21
|
||||
#define MAX_MIXER_WIDTH 2048
|
||||
#define MAX_MIXER_HEIGHT 2048
|
||||
#define MAX_IMG_WIDTH 0x3FFF
|
||||
#define MAX_IMG_HEIGHT 0x3FFF
|
||||
#define MIN_DST_W 10
|
||||
#define MIN_DST_H 10
|
||||
#define MAX_DST_W MAX_MIXER_WIDTH
|
||||
#define MAX_DST_H MAX_MIXER_HEIGHT
|
||||
#define MAX_PLANES 4
|
||||
#define MAX_DOWNSCALE_RATIO 4
|
||||
#define MAX_UPSCALE_RATIO 20
|
||||
|
||||
#ifdef MDSS_MDP_DEBUG_REG
|
||||
static inline void mdss_mdp_reg_write(u32 addr, u32 val)
|
||||
{
|
||||
pr_debug("0x%05X = 0x%08X\n", addr, val);
|
||||
MDSS_REG_WRITE(addr, val);
|
||||
}
|
||||
#define MDSS_MDP_REG_WRITE(addr, val) mdss_mdp_reg_write((u32)addr, (u32)(val))
|
||||
static inline u32 mdss_mdp_reg_read(u32 addr)
|
||||
{
|
||||
u32 val;
|
||||
val = MDSS_REG_READ(addr);
|
||||
pr_debug("0x%05X = 0x%08X\n", addr, val);
|
||||
return val;
|
||||
}
|
||||
#define MDSS_MDP_REG_READ(addr) mdss_mdp_reg_read((u32)(addr))
|
||||
#else
|
||||
#define MDSS_MDP_REG_WRITE(addr, val) MDSS_REG_WRITE((u32)(addr), (u32)(val))
|
||||
#define MDSS_MDP_REG_READ(addr) MDSS_REG_READ((u32)(addr))
|
||||
#endif
|
||||
|
||||
enum mdss_mdp_block_power_state {
|
||||
MDP_BLOCK_POWER_OFF,
|
||||
MDP_BLOCK_POWER_ON
|
||||
};
|
||||
|
||||
enum mdss_mdp_mixer_type {
|
||||
MDSS_MDP_MIXER_TYPE_UNUSED,
|
||||
MDSS_MDP_MIXER_TYPE_INTF,
|
||||
MDSS_MDP_MIXER_TYPE_WRITEBACK,
|
||||
};
|
||||
|
||||
enum mdss_mdp_mixer_mux {
|
||||
MDSS_MDP_MIXER_MUX_DEFAULT,
|
||||
MDSS_MDP_MIXER_MUX_LEFT,
|
||||
MDSS_MDP_MIXER_MUX_RIGHT,
|
||||
};
|
||||
|
||||
enum mdss_mdp_pipe_type {
|
||||
MDSS_MDP_PIPE_TYPE_UNUSED,
|
||||
MDSS_MDP_PIPE_TYPE_VIG,
|
||||
MDSS_MDP_PIPE_TYPE_RGB,
|
||||
MDSS_MDP_PIPE_TYPE_DMA,
|
||||
};
|
||||
|
||||
enum mdss_mdp_block_type {
|
||||
MDSS_MDP_BLOCK_UNUSED,
|
||||
MDSS_MDP_BLOCK_SSPP,
|
||||
MDSS_MDP_BLOCK_MIXER,
|
||||
MDSS_MDP_BLOCK_DSPP,
|
||||
MDSS_MDP_BLOCK_WB,
|
||||
MDSS_MDP_BLOCK_MAX
|
||||
};
|
||||
|
||||
struct mdss_mdp_ctl {
|
||||
u32 num;
|
||||
u32 ref_cnt;
|
||||
|
||||
u32 intf_num;
|
||||
u32 intf_type;
|
||||
|
||||
u32 opmode;
|
||||
u32 flush_bits;
|
||||
|
||||
u32 play_cnt;
|
||||
|
||||
u16 width;
|
||||
u16 height;
|
||||
|
||||
struct msm_fb_data_type *mfd;
|
||||
struct mdss_mdp_mixer *mixer_left;
|
||||
struct mdss_mdp_mixer *mixer_right;
|
||||
struct mutex lock;
|
||||
|
||||
int (*start_fnc) (struct mdss_mdp_ctl *ctl);
|
||||
int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
|
||||
int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
|
||||
int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
|
||||
|
||||
void *priv_data;
|
||||
};
|
||||
|
||||
struct mdss_mdp_mixer {
|
||||
u32 num;
|
||||
u32 ref_cnt;
|
||||
u8 type;
|
||||
u8 params_changed;
|
||||
|
||||
u16 width;
|
||||
u16 height;
|
||||
u8 cursor_enabled;
|
||||
u8 rotator_mode;
|
||||
|
||||
struct mdss_mdp_ctl *ctl;
|
||||
struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
|
||||
};
|
||||
|
||||
struct mdss_mdp_img_rect {
|
||||
u16 x;
|
||||
u16 y;
|
||||
u16 w;
|
||||
u16 h;
|
||||
};
|
||||
|
||||
struct mdss_mdp_format_params {
|
||||
u32 format;
|
||||
u8 is_yuv;
|
||||
|
||||
u8 frame_format;
|
||||
u8 chroma_sample;
|
||||
u8 solid_fill;
|
||||
u8 fetch_planes;
|
||||
u8 unpack_align_msb; /* 0 to LSB, 1 to MSB */
|
||||
u8 unpack_tight; /* 0 for loose, 1 for tight */
|
||||
u8 unpack_count; /* 0 = 1 component, 1 = 2 component ... */
|
||||
u8 bpp;
|
||||
u8 alpha_enable; /* source has alpha */
|
||||
|
||||
/*
|
||||
* number of bits for source component,
|
||||
* 0 = 1 bit, 1 = 2 bits, 2 = 6 bits, 3 = 8 bits
|
||||
*/
|
||||
u8 a_bit; /* component 3, alpha */
|
||||
u8 r_bit; /* component 2, R_Cr */
|
||||
u8 b_bit; /* component 1, B_Cb */
|
||||
u8 g_bit; /* component 0, G_lumz */
|
||||
|
||||
/*
|
||||
* unpack pattern
|
||||
* A = C3, R = C2, B = C1, G = C0
|
||||
*/
|
||||
u8 element3;
|
||||
u8 element2;
|
||||
u8 element1;
|
||||
u8 element0;
|
||||
};
|
||||
|
||||
struct mdss_mdp_plane_sizes {
|
||||
u32 num_planes;
|
||||
u32 plane_size[MAX_PLANES];
|
||||
u32 total_size;
|
||||
u32 ystride[MAX_PLANES];
|
||||
};
|
||||
|
||||
struct mdss_mdp_img_data {
|
||||
u32 addr;
|
||||
u32 len;
|
||||
u32 flags;
|
||||
int p_need;
|
||||
struct file *srcp_file;
|
||||
struct ion_handle *srcp_ihdl;
|
||||
struct ion_client *iclient;
|
||||
};
|
||||
|
||||
struct mdss_mdp_data {
|
||||
u8 num_planes;
|
||||
u8 bwc_enabled;
|
||||
struct mdss_mdp_img_data p[MAX_PLANES];
|
||||
};
|
||||
|
||||
struct mdss_mdp_pipe {
|
||||
u32 num;
|
||||
u32 type;
|
||||
u32 ndx;
|
||||
atomic_t ref_cnt;
|
||||
u32 play_cnt;
|
||||
|
||||
u32 flags;
|
||||
u32 bwc_mode;
|
||||
|
||||
u16 img_width;
|
||||
u16 img_height;
|
||||
struct mdss_mdp_img_rect src;
|
||||
struct mdss_mdp_img_rect dst;
|
||||
|
||||
struct mdss_mdp_format_params *src_fmt;
|
||||
struct mdss_mdp_plane_sizes src_planes;
|
||||
|
||||
u8 mixer_stage;
|
||||
u8 is_fg;
|
||||
u8 alpha;
|
||||
u32 transp;
|
||||
|
||||
struct msm_fb_data_type *mfd;
|
||||
struct mdss_mdp_mixer *mixer;
|
||||
struct mutex lock;
|
||||
|
||||
struct mdp_overlay req_data;
|
||||
u32 params_changed;
|
||||
|
||||
unsigned long smp[MAX_PLANES];
|
||||
};
|
||||
|
||||
static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
|
||||
u32 reg, u32 val)
|
||||
{
|
||||
int offset = MDSS_MDP_REG_CTL_OFFSET(ctl->num);
|
||||
MDSS_MDP_REG_WRITE(offset + reg, val);
|
||||
}
|
||||
|
||||
static inline u32 mdss_mdp_ctl_read(struct mdss_mdp_ctl *ctl, u32 reg)
|
||||
{
|
||||
int offset = MDSS_MDP_REG_CTL_OFFSET(ctl->num);
|
||||
return MDSS_MDP_REG_READ(offset + reg);
|
||||
}
|
||||
|
||||
irqreturn_t mdss_mdp_isr(int irq, void *ptr);
|
||||
int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
|
||||
void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num);
|
||||
void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num);
|
||||
int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
|
||||
void (*fnc_ptr)(void *), void *arg);
|
||||
|
||||
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
|
||||
int mdss_mdp_vsync_clk_enable(int enable);
|
||||
void mdss_mdp_clk_ctrl(int enable, int isr);
|
||||
void mdss_mdp_footswitch_ctrl(int on);
|
||||
|
||||
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd);
|
||||
|
||||
int mdss_mdp_ctl_on(struct msm_fb_data_type *mfd);
|
||||
int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd);
|
||||
|
||||
struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux);
|
||||
struct mdss_mdp_pipe *mdss_mdp_mixer_stage_pipe(struct mdss_mdp_ctl *ctl,
|
||||
int mux, int stage);
|
||||
int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed);
|
||||
int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
|
||||
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
|
||||
|
||||
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum);
|
||||
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type);
|
||||
struct mdss_mdp_pipe *mdss_mdp_pipe_get_locked(u32 ndx);
|
||||
int mdss_mdp_pipe_lock(struct mdss_mdp_pipe *pipe);
|
||||
void mdss_mdp_pipe_unlock(struct mdss_mdp_pipe *pipe);
|
||||
|
||||
int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe);
|
||||
int mdss_mdp_pipe_release_all(struct msm_fb_data_type *mfd);
|
||||
int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
|
||||
struct mdss_mdp_data *src_data);
|
||||
|
||||
int mdss_mdp_data_check(struct mdss_mdp_data *data,
|
||||
struct mdss_mdp_plane_sizes *ps);
|
||||
int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
|
||||
struct mdss_mdp_plane_sizes *ps);
|
||||
struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format);
|
||||
|
||||
#endif /* MDSS_MDP_H */
|
598
drivers/video/msm/mdss/mdss_mdp_ctl.c
Normal file
598
drivers/video/msm/mdss/mdss_mdp_ctl.c
Normal file
|
@ -0,0 +1,598 @@
|
|||
/* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "mdss_fb.h"
|
||||
#include "mdss_mdp.h"
|
||||
|
||||
static DEFINE_MUTEX(mdss_mdp_ctl_lock);
|
||||
static struct mdss_mdp_ctl mdss_mdp_ctl_list[MDSS_MDP_MAX_CTL];
|
||||
static struct mdss_mdp_mixer mdss_mdp_mixer_list[MDSS_MDP_MAX_LAYERMIXER];
|
||||
|
||||
static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(void)
|
||||
{
|
||||
struct mdss_mdp_ctl *ctl = NULL;
|
||||
int cnum;
|
||||
|
||||
mutex_lock(&mdss_mdp_ctl_lock);
|
||||
for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
|
||||
if (mdss_mdp_ctl_list[cnum].ref_cnt == 0) {
|
||||
ctl = &mdss_mdp_ctl_list[cnum];
|
||||
ctl->num = cnum;
|
||||
ctl->ref_cnt++;
|
||||
mutex_init(&ctl->lock);
|
||||
|
||||
pr_debug("alloc ctl_num=%d\n", ctl->num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&mdss_mdp_ctl_lock);
|
||||
|
||||
return ctl;
|
||||
}
|
||||
|
||||
static int mdss_mdp_ctl_free(struct mdss_mdp_ctl *ctl)
|
||||
{
|
||||
if (!ctl)
|
||||
return -ENODEV;
|
||||
|
||||
pr_debug("free ctl_num=%d ref_cnt=%d\n", ctl->num, ctl->ref_cnt);
|
||||
|
||||
if (!ctl->ref_cnt) {
|
||||
pr_err("called with ref_cnt=0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&mdss_mdp_ctl_lock);
|
||||
if (--ctl->ref_cnt == 0)
|
||||
memset(ctl, 0, sizeof(*ctl));
|
||||
mutex_unlock(&mdss_mdp_ctl_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mdss_mdp_mixer *mdss_mdp_mixer_alloc(u32 type)
|
||||
{
|
||||
struct mdss_mdp_mixer *mixer = NULL;
|
||||
int mnum;
|
||||
|
||||
mutex_lock(&mdss_mdp_ctl_lock);
|
||||
for (mnum = 0; mnum < MDSS_MDP_MAX_LAYERMIXER; mnum++) {
|
||||
if (type == mdss_res->mixer_type_map[mnum] &&
|
||||
mdss_mdp_mixer_list[mnum].ref_cnt == 0) {
|
||||
mixer = &mdss_mdp_mixer_list[mnum];
|
||||
mixer->num = mnum;
|
||||
mixer->ref_cnt++;
|
||||
mixer->params_changed++;
|
||||
mixer->type = type;
|
||||
|
||||
pr_debug("mixer_num=%d\n", mixer->num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&mdss_mdp_ctl_lock);
|
||||
|
||||
return mixer;
|
||||
}
|
||||
|
||||
static int mdss_mdp_mixer_free(struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
if (!mixer)
|
||||
return -ENODEV;
|
||||
|
||||
pr_debug("free mixer_num=%d ref_cnt=%d\n", mixer->num, mixer->ref_cnt);
|
||||
|
||||
if (!mixer->ref_cnt) {
|
||||
pr_err("called with ref_cnt=0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&mdss_mdp_ctl_lock);
|
||||
if (--mixer->ref_cnt == 0)
|
||||
memset(mixer, 0, sizeof(*mixer));
|
||||
mutex_unlock(&mdss_mdp_ctl_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_ctl_init(struct msm_fb_data_type *mfd)
|
||||
{
|
||||
struct mdss_mdp_ctl *ctl;
|
||||
u32 width, height;
|
||||
|
||||
if (!mfd)
|
||||
return -ENODEV;
|
||||
|
||||
width = mfd->fbi->var.xres;
|
||||
height = mfd->fbi->var.yres;
|
||||
|
||||
if (width > (2 * MAX_MIXER_WIDTH)) {
|
||||
pr_err("unsupported resolution\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctl = mdss_mdp_ctl_alloc();
|
||||
|
||||
if (!ctl) {
|
||||
pr_err("unable to allocate ctl\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ctl->mfd = mfd;
|
||||
ctl->width = width;
|
||||
ctl->height = height;
|
||||
|
||||
ctl->mixer_left = mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
|
||||
if (!ctl->mixer_left) {
|
||||
pr_err("unable to allocate layer mixer\n");
|
||||
mdss_mdp_ctl_free(ctl);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ctl->mixer_left->width = MIN(width, MAX_MIXER_WIDTH);
|
||||
ctl->mixer_left->height = height;
|
||||
ctl->mixer_left->ctl = ctl;
|
||||
|
||||
width -= ctl->mixer_left->width;
|
||||
|
||||
if (width) {
|
||||
ctl->mixer_right =
|
||||
mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
|
||||
if (!ctl->mixer_right) {
|
||||
pr_err("unable to allocate layer mixer\n");
|
||||
mdss_mdp_mixer_free(ctl->mixer_left);
|
||||
mdss_mdp_ctl_free(ctl);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ctl->mixer_right->width = width;
|
||||
ctl->mixer_right->height = height;
|
||||
ctl->mixer_right->ctl = ctl;
|
||||
}
|
||||
|
||||
switch (mfd->panel_info.type) {
|
||||
case WRITEBACK_PANEL:
|
||||
ctl->intf_num = MDSS_MDP_NO_INTF;
|
||||
ctl->opmode = MDSS_MDP_CTL_OP_WFD_MODE;
|
||||
break;
|
||||
default:
|
||||
pr_err("unsupported panel type (%d)\n", mfd->panel_info.type);
|
||||
mdss_mdp_ctl_free(ctl);
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
ctl->opmode |= (ctl->intf_num << 4);
|
||||
|
||||
if (ctl->mixer_right) {
|
||||
ctl->opmode |= MDSS_MDP_CTL_OP_PACK_3D_ENABLE |
|
||||
MDSS_MDP_CTL_OP_PACK_3D_H_ROW_INT;
|
||||
}
|
||||
|
||||
mfd->ctl = ctl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_ctl_destroy(struct msm_fb_data_type *mfd)
|
||||
{
|
||||
struct mdss_mdp_ctl *ctl;
|
||||
if (!mfd || !mfd->ctl)
|
||||
return -ENODEV;
|
||||
|
||||
ctl = mfd->ctl;
|
||||
mfd->ctl = NULL;
|
||||
|
||||
if (ctl->mixer_left)
|
||||
mdss_mdp_mixer_free(ctl->mixer_left);
|
||||
if (ctl->mixer_right)
|
||||
mdss_mdp_mixer_free(ctl->mixer_right);
|
||||
mdss_mdp_ctl_free(ctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdss_mdp_ctl_on(struct msm_fb_data_type *mfd)
|
||||
{
|
||||
struct mdss_panel_data *pdata;
|
||||
struct mdss_mdp_ctl *ctl;
|
||||
struct mdss_mdp_mixer *mixer;
|
||||
u32 outsize, temp, off;
|
||||
int ret = 0;
|
||||
|
||||
if (!mfd)
|
||||
return -ENODEV;
|
||||
|
||||
if (mfd->key != MFD_KEY)
|
||||
return -EINVAL;
|
||||
|
||||
pdata = dev_get_platdata(&mfd->pdev->dev);
|
||||
if (!pdata) {
|
||||
pr_err("no panel connected\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!mfd->ctl) {
|
||||
if (mdss_mdp_ctl_init(mfd)) {
|
||||
pr_err("unable to initialize ctl\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
ctl = mfd->ctl;
|
||||
|
||||
mutex_lock(&ctl->lock);
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
|
||||
if (ctl->start_fnc)
|
||||
ret = ctl->start_fnc(ctl);
|
||||
else
|
||||
pr_warn("no start function for ctl=%d type=%d\n", ctl->num,
|
||||
mfd->panel_info.type);
|
||||
|
||||
if (ret) {
|
||||
pr_err("unable to start intf\n");
|
||||
goto start_fail;
|
||||
}
|
||||
|
||||
pr_debug("ctl_num=%d\n", ctl->num);
|
||||
|
||||
mixer = ctl->mixer_left;
|
||||
mixer->params_changed++;
|
||||
|
||||
temp = MDSS_MDP_REG_READ(MDSS_MDP_REG_DISP_INTF_SEL);
|
||||
temp |= (ctl->intf_type << (ctl->intf_num * 8));
|
||||
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_DISP_INTF_SEL, temp);
|
||||
|
||||
outsize = (mixer->height << 16) | mixer->width;
|
||||
off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
|
||||
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OUT_SIZE, outsize);
|
||||
|
||||
if (ctl->mixer_right) {
|
||||
mixer = ctl->mixer_right;
|
||||
mixer->params_changed++;
|
||||
outsize = (mixer->height << 16) | mixer->width;
|
||||
off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
|
||||
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OUT_SIZE, outsize);
|
||||
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
|
||||
}
|
||||
|
||||
ret = pdata->on(pdata);
|
||||
|
||||
start_fail:
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
|
||||
mutex_unlock(&ctl->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd)
|
||||
{
|
||||
struct mdss_panel_data *pdata;
|
||||
struct mdss_mdp_ctl *ctl;
|
||||
int ret = 0;
|
||||
|
||||
if (!mfd)
|
||||
return -ENODEV;
|
||||
|
||||
if (mfd->key != MFD_KEY)
|
||||
return -EINVAL;
|
||||
|
||||
if (!mfd->ctl) {
|
||||
pr_err("ctl not initialized\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdata = dev_get_platdata(&mfd->pdev->dev);
|
||||
if (!pdata) {
|
||||
pr_err("no panel connected\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ctl = mfd->ctl;
|
||||
|
||||
pr_debug("ctl_num=%d\n", mfd->ctl->num);
|
||||
|
||||
mutex_lock(&ctl->lock);
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
|
||||
if (ctl->stop_fnc)
|
||||
ret = ctl->stop_fnc(ctl);
|
||||
else
|
||||
pr_warn("no stop func for ctl=%d\n", ctl->num);
|
||||
|
||||
if (ret)
|
||||
pr_warn("error powering off intf ctl=%d\n", ctl->num);
|
||||
|
||||
ret = pdata->off(pdata);
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
|
||||
|
||||
ctl->play_cnt = 0;
|
||||
mutex_unlock(&ctl->lock);
|
||||
|
||||
mdss_mdp_pipe_release_all(mfd);
|
||||
|
||||
if (!mfd->ref_cnt)
|
||||
mdss_mdp_ctl_destroy(mfd);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl,
|
||||
struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
struct mdss_mdp_pipe *pipe, *bgpipe = NULL;
|
||||
u32 off, blend_op, blend_stage;
|
||||
u32 mixercfg = 0, blend_color_out = 0, bgalpha = 0;
|
||||
int stage;
|
||||
|
||||
if (!mixer)
|
||||
return -ENODEV;
|
||||
|
||||
pr_debug("setup mixer=%d\n", mixer->num);
|
||||
|
||||
for (stage = MDSS_MDP_STAGE_BASE; stage < MDSS_MDP_MAX_STAGE; stage++) {
|
||||
pipe = mixer->stage_pipe[stage];
|
||||
if (pipe == NULL) {
|
||||
if (stage == MDSS_MDP_STAGE_BASE)
|
||||
mixercfg |= MDSS_MDP_LM_BORDER_COLOR;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stage != pipe->mixer_stage) {
|
||||
mixer->stage_pipe[stage] = NULL;
|
||||
continue;
|
||||
}
|
||||
mixercfg |= stage << (3 * pipe->num);
|
||||
|
||||
if (stage == MDSS_MDP_STAGE_BASE) {
|
||||
bgpipe = pipe;
|
||||
if (pipe->src_fmt->alpha_enable)
|
||||
bgalpha = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
blend_stage = stage - MDSS_MDP_STAGE_0;
|
||||
off = MDSS_MDP_REG_LM_OFFSET(mixer->num) +
|
||||
MDSS_MDP_REG_LM_BLEND_OFFSET(blend_stage);
|
||||
|
||||
if (pipe->is_fg) {
|
||||
bgalpha = 0;
|
||||
if (bgpipe) {
|
||||
mixercfg &= ~(0x7 << (3 * bgpipe->num));
|
||||
mixercfg |= MDSS_MDP_LM_BORDER_COLOR;
|
||||
}
|
||||
blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
|
||||
MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
|
||||
/* keep fg alpha */
|
||||
blend_color_out |= 1 << (blend_stage + 1);
|
||||
|
||||
pr_debug("pnum=%d stg=%d alpha=IS_FG\n", pipe->num,
|
||||
stage);
|
||||
} else if (pipe->src_fmt->alpha_enable) {
|
||||
bgalpha = 0;
|
||||
blend_op = (MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL |
|
||||
MDSS_MDP_BLEND_BG_INV_ALPHA);
|
||||
/* keep fg alpha */
|
||||
blend_color_out |= 1 << (blend_stage + 1);
|
||||
|
||||
pr_debug("pnum=%d stg=%d alpha=FG PIXEL\n", pipe->num,
|
||||
stage);
|
||||
} else if (bgalpha) {
|
||||
blend_op = (MDSS_MDP_BLEND_BG_ALPHA_BG_PIXEL |
|
||||
MDSS_MDP_BLEND_FG_ALPHA_BG_PIXEL |
|
||||
MDSS_MDP_BLEND_FG_INV_ALPHA);
|
||||
/* keep bg alpha */
|
||||
pr_debug("pnum=%d stg=%d alpha=BG_PIXEL\n", pipe->num,
|
||||
stage);
|
||||
} else {
|
||||
blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
|
||||
MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
|
||||
pr_debug("pnum=%d stg=%d alpha=CONST\n", pipe->num,
|
||||
stage);
|
||||
}
|
||||
|
||||
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OP_MODE, blend_op);
|
||||
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_BLEND_FG_ALPHA,
|
||||
pipe->alpha);
|
||||
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_BLEND_BG_ALPHA,
|
||||
0xFF - pipe->alpha);
|
||||
}
|
||||
|
||||
if (mixer->cursor_enabled)
|
||||
mixercfg |= MDSS_MDP_LM_CURSOR_OUT;
|
||||
|
||||
pr_debug("mixer=%d mixer_cfg=%x\n", mixer->num, mixercfg);
|
||||
|
||||
ctl->flush_bits |= BIT(6) << mixer->num; /* LAYER_MIXER */
|
||||
|
||||
off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
|
||||
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OP_MODE, blend_color_out);
|
||||
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(mixer->num), mixercfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux)
|
||||
{
|
||||
struct mdss_mdp_mixer *mixer = NULL;
|
||||
if (!ctl)
|
||||
return NULL;
|
||||
|
||||
switch (mux) {
|
||||
case MDSS_MDP_MIXER_MUX_DEFAULT:
|
||||
case MDSS_MDP_MIXER_MUX_LEFT:
|
||||
mixer = ctl->mixer_left;
|
||||
break;
|
||||
case MDSS_MDP_MIXER_MUX_RIGHT:
|
||||
mixer = ctl->mixer_right;
|
||||
break;
|
||||
}
|
||||
|
||||
return mixer;
|
||||
}
|
||||
|
||||
struct mdss_mdp_pipe *mdss_mdp_mixer_stage_pipe(struct mdss_mdp_ctl *ctl,
|
||||
int mux, int stage)
|
||||
{
|
||||
struct mdss_mdp_pipe *pipe = NULL;
|
||||
struct mdss_mdp_mixer *mixer;
|
||||
if (!ctl)
|
||||
return NULL;
|
||||
|
||||
if (mutex_lock_interruptible(&ctl->lock))
|
||||
return NULL;
|
||||
|
||||
mixer = mdss_mdp_mixer_get(ctl, mux);
|
||||
if (mixer)
|
||||
pipe = mixer->stage_pipe[stage];
|
||||
mutex_unlock(&ctl->lock);
|
||||
|
||||
return pipe;
|
||||
}
|
||||
|
||||
int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed)
|
||||
{
|
||||
struct mdss_mdp_ctl *ctl;
|
||||
struct mdss_mdp_mixer *mixer;
|
||||
|
||||
if (!pipe)
|
||||
return -EINVAL;
|
||||
mixer = pipe->mixer;
|
||||
if (!mixer)
|
||||
return -EINVAL;
|
||||
ctl = mixer->ctl;
|
||||
if (!ctl)
|
||||
return -EINVAL;
|
||||
|
||||
if (pipe->mixer_stage >= MDSS_MDP_MAX_STAGE) {
|
||||
pr_err("invalid mixer stage\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pr_debug("pnum=%x mixer=%d stage=%d\n", pipe->num, mixer->num,
|
||||
pipe->mixer_stage);
|
||||
|
||||
if (mutex_lock_interruptible(&ctl->lock))
|
||||
return -EINTR;
|
||||
|
||||
if (params_changed) {
|
||||
mixer->params_changed++;
|
||||
mixer->stage_pipe[pipe->mixer_stage] = pipe;
|
||||
}
|
||||
|
||||
if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
|
||||
ctl->flush_bits |= BIT(pipe->num) << 5;
|
||||
else /* RGB/VIG pipe */
|
||||
ctl->flush_bits |= BIT(pipe->num);
|
||||
|
||||
mutex_unlock(&ctl->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
struct mdss_mdp_ctl *ctl;
|
||||
struct mdss_mdp_mixer *mixer;
|
||||
|
||||
if (!pipe)
|
||||
return -EINVAL;
|
||||
mixer = pipe->mixer;
|
||||
if (!mixer)
|
||||
return -EINVAL;
|
||||
ctl = mixer->ctl;
|
||||
if (!ctl)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("unstage pnum=%d stage=%d mixer=%d\n", pipe->num,
|
||||
pipe->mixer_stage, mixer->num);
|
||||
|
||||
if (mutex_lock_interruptible(&ctl->lock))
|
||||
return -EINTR;
|
||||
|
||||
mixer->params_changed++;
|
||||
mixer->stage_pipe[pipe->mixer_stage] = NULL;
|
||||
|
||||
mutex_unlock(&ctl->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_mixer_update(struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
mixer->params_changed = 0;
|
||||
|
||||
/* skip mixer setup for rotator */
|
||||
if (!mixer->rotator_mode)
|
||||
mdss_mdp_mixer_setup(mixer->ctl, mixer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
|
||||
{
|
||||
int mixer1_changed, mixer2_changed;
|
||||
int ret = 0;
|
||||
|
||||
if (!ctl) {
|
||||
pr_err("display function not set\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pr_debug("commit ctl=%d\n", ctl->num);
|
||||
|
||||
if (mutex_lock_interruptible(&ctl->lock))
|
||||
return -EINTR;
|
||||
|
||||
mixer1_changed = (ctl->mixer_left && ctl->mixer_left->params_changed);
|
||||
mixer2_changed = (ctl->mixer_right && ctl->mixer_right->params_changed);
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
|
||||
if (mixer1_changed || mixer2_changed) {
|
||||
if (ctl->prepare_fnc)
|
||||
ret = ctl->prepare_fnc(ctl, arg);
|
||||
if (ret) {
|
||||
pr_err("error preparing display\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (mixer1_changed)
|
||||
mdss_mdp_mixer_update(ctl->mixer_left);
|
||||
if (mixer2_changed)
|
||||
mdss_mdp_mixer_update(ctl->mixer_right);
|
||||
|
||||
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_TOP, ctl->opmode);
|
||||
ctl->flush_bits |= BIT(17); /* CTL */
|
||||
}
|
||||
|
||||
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
|
||||
wmb();
|
||||
ctl->flush_bits = 0;
|
||||
|
||||
if (ctl->display_fnc)
|
||||
ret = ctl->display_fnc(ctl, arg); /* kickoff */
|
||||
if (ret)
|
||||
pr_warn("error displaying frame\n");
|
||||
|
||||
ctl->play_cnt++;
|
||||
|
||||
done:
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
|
||||
|
||||
mutex_unlock(&ctl->lock);
|
||||
|
||||
return ret;
|
||||
}
|
328
drivers/video/msm/mdss/mdss_mdp_formats.h
Normal file
328
drivers/video/msm/mdss/mdss_mdp_formats.h
Normal file
|
@ -0,0 +1,328 @@
|
|||
/* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MDSS_MDP_FORMATS_H
|
||||
#define MDSS_MDP_FORMATS_H
|
||||
|
||||
#include <linux/msm_mdp.h>
|
||||
|
||||
#include "mdss_mdp.h"
|
||||
|
||||
#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 */
|
||||
|
||||
static struct mdss_mdp_format_params mdss_mdp_format_map[MDP_IMGTYPE_LIMIT] = {
|
||||
[MDP_RGB_565] = {
|
||||
.format = MDP_RGB_565,
|
||||
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
|
||||
.a_bit = 0,
|
||||
.r_bit = 1, /* R, 5 bits */
|
||||
.b_bit = 1, /* B, 5 bits */
|
||||
.g_bit = 2, /* G, 6 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 2,
|
||||
.element2 = C2_R_Cr,
|
||||
.element1 = C0_G_Y,
|
||||
.element0 = C1_B_Cb,
|
||||
.bpp = 1, /* 2 bpp */
|
||||
},
|
||||
[MDP_BGR_565] = {
|
||||
.format = MDP_BGR_565,
|
||||
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
|
||||
.a_bit = 0,
|
||||
.r_bit = 1, /* R, 5 bits */
|
||||
.b_bit = 1, /* B, 5 bits */
|
||||
.g_bit = 2, /* G, 6 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 2,
|
||||
.element2 = C1_B_Cb,
|
||||
.element1 = C0_G_Y,
|
||||
.element0 = C2_R_Cr,
|
||||
.bpp = 1, /* 2 bpp */
|
||||
},
|
||||
[MDP_RGB_888] = {
|
||||
.format = MDP_RGB_888,
|
||||
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
|
||||
.a_bit = 0,
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 2,
|
||||
.element2 = C1_B_Cb,
|
||||
.element1 = C0_G_Y,
|
||||
.element0 = C2_R_Cr,
|
||||
.bpp = 2, /* 3 bpp */
|
||||
},
|
||||
[MDP_XRGB_8888] = {
|
||||
.format = MDP_XRGB_8888,
|
||||
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
|
||||
.a_bit = 3, /* alpha, 4 bits */
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 3,
|
||||
.element3 = C1_B_Cb,
|
||||
.element2 = C0_G_Y,
|
||||
.element1 = C2_R_Cr,
|
||||
.element0 = C3_ALPHA,
|
||||
.bpp = 3, /* 4 bpp */
|
||||
},
|
||||
[MDP_ARGB_8888] = {
|
||||
.format = MDP_ARGB_8888,
|
||||
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
|
||||
.a_bit = 3, /* alpha, 4 bits */
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 1,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 3,
|
||||
.element3 = C1_B_Cb,
|
||||
.element2 = C0_G_Y,
|
||||
.element1 = C2_R_Cr,
|
||||
.element0 = C3_ALPHA,
|
||||
.bpp = 3, /* 4 bpp */
|
||||
},
|
||||
[MDP_RGBA_8888] = {
|
||||
.format = MDP_RGBA_8888,
|
||||
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
|
||||
.a_bit = 3, /* alpha, 4 bits */
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 1,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 3,
|
||||
.element3 = C3_ALPHA,
|
||||
.element2 = C1_B_Cb,
|
||||
.element1 = C0_G_Y,
|
||||
.element0 = C2_R_Cr,
|
||||
.bpp = 3, /* 4 bpp */
|
||||
},
|
||||
[MDP_RGBX_8888] = {
|
||||
.format = MDP_RGBX_8888,
|
||||
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
|
||||
.a_bit = 3,
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 3,
|
||||
.element3 = C3_ALPHA,
|
||||
.element2 = C1_B_Cb,
|
||||
.element1 = C0_G_Y,
|
||||
.element0 = C2_R_Cr,
|
||||
.bpp = 3, /* 4 bpp */
|
||||
},
|
||||
[MDP_BGRA_8888] = {
|
||||
.format = MDP_BGRA_8888,
|
||||
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
|
||||
.a_bit = 3, /* alpha, 4 bits */
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 1,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 3,
|
||||
.element3 = C3_ALPHA,
|
||||
.element2 = C2_R_Cr,
|
||||
.element1 = C0_G_Y,
|
||||
.element0 = C1_B_Cb,
|
||||
.bpp = 3, /* 4 bpp */
|
||||
},
|
||||
[MDP_YCRYCB_H2V1] = {
|
||||
.format = MDP_YCRYCB_H2V1,
|
||||
.is_yuv = 1,
|
||||
.a_bit = 0,
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 1, /* 2 */
|
||||
.bpp = 1, /* 2 bpp */
|
||||
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
|
||||
.chroma_sample = MDSS_MDP_CHROMA_H2V1,
|
||||
.unpack_count = 3,
|
||||
.element3 = C0_G_Y,
|
||||
.element2 = C2_R_Cr,
|
||||
.element1 = C0_G_Y,
|
||||
.element0 = C1_B_Cb,
|
||||
},
|
||||
[MDP_Y_CRCB_H2V1] = {
|
||||
.format = MDP_Y_CRCB_H2V1,
|
||||
.is_yuv = 1,
|
||||
.a_bit = 0,
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 1, /* 2 */
|
||||
.bpp = 1, /* 2 bpp */
|
||||
.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
|
||||
.chroma_sample = MDSS_MDP_CHROMA_H2V1,
|
||||
.element1 = C1_B_Cb,
|
||||
.element0 = C2_R_Cr,
|
||||
},
|
||||
[MDP_Y_CBCR_H2V1] = {
|
||||
.format = MDP_Y_CBCR_H2V1,
|
||||
.is_yuv = 1,
|
||||
.a_bit = 0,
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 1, /* 2 */
|
||||
.bpp = 1, /* 2 bpp */
|
||||
.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
|
||||
.chroma_sample = MDSS_MDP_CHROMA_H2V1,
|
||||
.element1 = C2_R_Cr,
|
||||
.element0 = C1_B_Cb,
|
||||
},
|
||||
[MDP_Y_CRCB_H1V2] = {
|
||||
.format = MDP_Y_CRCB_H1V2,
|
||||
.is_yuv = 1,
|
||||
.a_bit = 0,
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 1, /* 2 */
|
||||
.bpp = 1, /* 2 bpp */
|
||||
.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
|
||||
.chroma_sample = MDSS_MDP_CHROMA_H1V2,
|
||||
.element1 = C1_B_Cb,
|
||||
.element0 = C2_R_Cr,
|
||||
},
|
||||
[MDP_Y_CBCR_H1V2] = {
|
||||
.format = MDP_Y_CBCR_H1V2,
|
||||
.is_yuv = 1,
|
||||
.a_bit = 0,
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 1, /* 2 */
|
||||
.bpp = 1, /* 2 bpp */
|
||||
.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
|
||||
.chroma_sample = MDSS_MDP_CHROMA_H1V2,
|
||||
.element1 = C2_R_Cr,
|
||||
.element0 = C1_B_Cb,
|
||||
},
|
||||
[MDP_Y_CRCB_H2V2] = {
|
||||
.format = MDP_Y_CRCB_H2V2,
|
||||
.is_yuv = 1,
|
||||
.a_bit = 0,
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 1, /* 2 */
|
||||
.bpp = 1, /* 2 bpp */
|
||||
.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
|
||||
.chroma_sample = MDSS_MDP_CHROMA_420,
|
||||
.element1 = C1_B_Cb,
|
||||
.element0 = C2_R_Cr,
|
||||
},
|
||||
[MDP_Y_CBCR_H2V2] = {
|
||||
.format = MDP_Y_CBCR_H2V2,
|
||||
.is_yuv = 1,
|
||||
.a_bit = 0,
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 1, /* 2 */
|
||||
.bpp = 1, /* 2 bpp */
|
||||
.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
|
||||
.chroma_sample = MDSS_MDP_CHROMA_420,
|
||||
.element1 = C2_R_Cr,
|
||||
.element0 = C1_B_Cb,
|
||||
},
|
||||
[MDP_Y_CR_CB_H2V2] = {
|
||||
.format = MDP_Y_CR_CB_H2V2,
|
||||
.is_yuv = 1,
|
||||
.a_bit = 0,
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 1, /* 2 */
|
||||
.bpp = 1, /* 2 bpp */
|
||||
.fetch_planes = MDSS_MDP_PLANE_PLANAR,
|
||||
.chroma_sample = MDSS_MDP_CHROMA_420,
|
||||
},
|
||||
[MDP_Y_CB_CR_H2V2] = {
|
||||
.format = MDP_Y_CB_CR_H2V2,
|
||||
.is_yuv = 1,
|
||||
.a_bit = 0,
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 1, /* 2 */
|
||||
.bpp = 1, /* 2 bpp */
|
||||
.fetch_planes = MDSS_MDP_PLANE_PLANAR,
|
||||
.chroma_sample = MDSS_MDP_CHROMA_420,
|
||||
},
|
||||
[MDP_Y_CR_CB_GH2V2] = {
|
||||
.format = MDP_Y_CR_CB_GH2V2,
|
||||
.is_yuv = 1,
|
||||
.a_bit = 0,
|
||||
.r_bit = 3, /* R, 8 bits */
|
||||
.b_bit = 3, /* B, 8 bits */
|
||||
.g_bit = 3, /* G, 8 bits */
|
||||
.alpha_enable = 0,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.unpack_count = 1, /* 2 */
|
||||
.bpp = 1, /* 2 bpp */
|
||||
.fetch_planes = MDSS_MDP_PLANE_PLANAR,
|
||||
.chroma_sample = MDSS_MDP_CHROMA_420,
|
||||
},
|
||||
};
|
||||
#endif
|
430
drivers/video/msm/mdss/mdss_mdp_hwio.h
Normal file
430
drivers/video/msm/mdss/mdss_mdp_hwio.h
Normal file
|
@ -0,0 +1,430 @@
|
|||
/* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MDSS_MDP_HWIO_H
|
||||
#define MDSS_MDP_HWIO_H
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define MDSS_REG_HW_VERSION 0x0
|
||||
#define MDSS_REG_HW_INTR_STATUS 0x10
|
||||
|
||||
#define MDSS_INTR_MDP BIT(0)
|
||||
#define MDSS_INTR_DSI0 BIT(4)
|
||||
#define MDSS_INTR_DSI1 BIT(5)
|
||||
#define MDSS_INTR_HDMI BIT(8)
|
||||
#define MDSS_INTR_EDP BIT(12)
|
||||
|
||||
#define MDSS_MDP_REG_HW_VERSION 0x00100
|
||||
#define MDSS_MDP_REG_DISP_INTF_SEL 0x00104
|
||||
#define MDSS_MDP_REG_INTR_EN 0x00110
|
||||
#define MDSS_MDP_REG_INTR_STATUS 0x00114
|
||||
#define MDSS_MDP_REG_INTR_CLEAR 0x00118
|
||||
#define MDSS_MDP_REG_HIST_INTR_EN 0x0011C
|
||||
#define MDSS_MDP_REG_HIST_INTR_STATUS 0x00120
|
||||
#define MDSS_MDP_REG_HIST_INTR_CLEAR 0x00124
|
||||
|
||||
#define MDSS_INTF_DSI 0x1
|
||||
#define MDSS_INTF_HDMI 0x3
|
||||
#define MDSS_INTF_LCDC 0x5
|
||||
#define MDSS_INTF_EDP 0x9
|
||||
|
||||
#define MDSS_MDP_INTR_WB_0_DONE BIT(0)
|
||||
#define MDSS_MDP_INTR_WB_1_DONE BIT(1)
|
||||
#define MDSS_MDP_INTR_WB_2_DONE BIT(4)
|
||||
#define MDSS_MDP_INTR_PING_PONG_0_DONE BIT(8)
|
||||
#define MDSS_MDP_INTR_PING_PONG_1_DONE BIT(9)
|
||||
#define MDSS_MDP_INTR_PING_PONG_2_DONE BIT(10)
|
||||
#define MDSS_MDP_INTR_PING_PONG_0_RD_PTR BIT(12)
|
||||
#define MDSS_MDP_INTR_PING_PONG_1_RD_PTR BIT(13)
|
||||
#define MDSS_MDP_INTR_PING_PONG_2_RD_PTR BIT(14)
|
||||
#define MDSS_MDP_INTR_PING_PONG_0_WR_PTR BIT(16)
|
||||
#define MDSS_MDP_INTR_PING_PONG_1_WR_PTR BIT(17)
|
||||
#define MDSS_MDP_INTR_PING_PONG_2_WR_PTR BIT(18)
|
||||
#define MDSS_MDP_INTR_PING_PONG_0_AUTOREFRESH_DONE BIT(20)
|
||||
#define MDSS_MDP_INTR_PING_PONG_1_AUTOREFRESH_DONE BIT(21)
|
||||
#define MDSS_MDP_INTR_PING_PONG_2_AUTOREFRESH_DONE BIT(22)
|
||||
#define MDSS_MDP_INTR_INTF_0_UNDERRUN BIT(24)
|
||||
#define MDSS_MDP_INTR_INTF_0_VSYNC BIT(25)
|
||||
#define MDSS_MDP_INTR_INTF_1_UNDERRUN BIT(26)
|
||||
#define MDSS_MDP_INTR_INTF_1_VSYNC BIT(27)
|
||||
#define MDSS_MDP_INTR_INTF_2_UNDERRUN BIT(28)
|
||||
#define MDSS_MDP_INTR_INTF_2_VSYNC BIT(29)
|
||||
#define MDSS_MDP_INTR_INTF_3_UNDERRUN BIT(30)
|
||||
#define MDSS_MDP_INTR_INTF_3_VSYNC BIT(31)
|
||||
|
||||
enum mdss_mdp_intr_type {
|
||||
MDSS_MDP_IRQ_WB_ROT_COMP = 0,
|
||||
MDSS_MDP_IRQ_WB_WFD = 4,
|
||||
MDSS_MDP_IRQ_PING_PONG_COMP = 8,
|
||||
MDSS_MDP_IRQ_PING_PONG_RD_PTR = 12,
|
||||
MDSS_MDP_IRQ_PING_PONG_WR_PTR = 16,
|
||||
MDSS_MDP_IRQ_PING_PONG_AUTO_REF = 20,
|
||||
MDSS_MDP_IRQ_INTF_UNDER_RUN = 24,
|
||||
MDSS_MDP_IRQ_INTF_VSYNC = 25,
|
||||
};
|
||||
|
||||
enum mdss_mdp_ctl_index {
|
||||
MDSS_MDP_CTL0,
|
||||
MDSS_MDP_CTL1,
|
||||
MDSS_MDP_CTL2,
|
||||
MDSS_MDP_CTL3,
|
||||
MDSS_MDP_CTL4,
|
||||
MDSS_MDP_MAX_CTL
|
||||
};
|
||||
|
||||
#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * 0x100))
|
||||
|
||||
#define MDSS_MDP_REG_CTL_LAYER(lm) ((lm) * 0x004)
|
||||
#define MDSS_MDP_REG_CTL_TOP 0x014
|
||||
#define MDSS_MDP_REG_CTL_FLUSH 0x018
|
||||
#define MDSS_MDP_REG_CTL_START 0x01C
|
||||
#define MDSS_MDP_REG_CTL_PACK_3D 0x020
|
||||
|
||||
#define MDSS_MDP_CTL_OP_VIDEO_MODE (0 << 17)
|
||||
#define MDSS_MDP_CTL_OP_CMD_MODE (1 << 17)
|
||||
|
||||
#define MDSS_MDP_CTL_OP_ROT0_MODE 0x1
|
||||
#define MDSS_MDP_CTL_OP_ROT1_MODE 0x2
|
||||
#define MDSS_MDP_CTL_OP_WB0_MODE 0x3
|
||||
#define MDSS_MDP_CTL_OP_WB1_MODE 0x4
|
||||
#define MDSS_MDP_CTL_OP_WFD_MODE 0x5
|
||||
|
||||
#define MDSS_MDP_CTL_OP_PACK_3D_ENABLE BIT(19)
|
||||
#define MDSS_MDP_CTL_OP_PACK_3D_FRAME_INT (0 << 20)
|
||||
#define MDSS_MDP_CTL_OP_PACK_3D_H_ROW_INT (1 << 20)
|
||||
#define MDSS_MDP_CTL_OP_PACK_3D_V_ROW_INT (2 << 20)
|
||||
#define MDSS_MDP_CTL_OP_PACK_3D_COL_INT (3 << 20)
|
||||
|
||||
enum mdss_mdp_sspp_index {
|
||||
MDSS_MDP_SSPP_VIG0,
|
||||
MDSS_MDP_SSPP_VIG1,
|
||||
MDSS_MDP_SSPP_VIG2,
|
||||
MDSS_MDP_SSPP_RGB0,
|
||||
MDSS_MDP_SSPP_RGB1,
|
||||
MDSS_MDP_SSPP_RGB2,
|
||||
MDSS_MDP_SSPP_DMA0,
|
||||
MDSS_MDP_SSPP_DMA1,
|
||||
MDSS_MDP_MAX_SSPP
|
||||
};
|
||||
|
||||
enum mdss_mdp_sspp_fetch_type {
|
||||
MDSS_MDP_PLANE_INTERLEAVED,
|
||||
MDSS_MDP_PLANE_PLANAR,
|
||||
MDSS_MDP_PLANE_PSEUDO_PLANAR,
|
||||
};
|
||||
|
||||
enum mdss_mdp_sspp_chroma_samp_type {
|
||||
MDSS_MDP_CHROMA_RGB,
|
||||
MDSS_MDP_CHROMA_H2V1,
|
||||
MDSS_MDP_CHROMA_H1V2,
|
||||
MDSS_MDP_CHROMA_420
|
||||
};
|
||||
|
||||
#define MDSS_MDP_REG_SSPP_OFFSET(pipe) (0x01200 + ((pipe) * 0x400))
|
||||
|
||||
#define MDSS_MDP_REG_SSPP_SRC_SIZE 0x000
|
||||
#define MDSS_MDP_REG_SSPP_SRC_IMG_SIZE 0x004
|
||||
#define MDSS_MDP_REG_SSPP_SRC_XY 0x008
|
||||
#define MDSS_MDP_REG_SSPP_OUT_SIZE 0x00C
|
||||
#define MDSS_MDP_REG_SSPP_OUT_XY 0x010
|
||||
#define MDSS_MDP_REG_SSPP_SRC0_ADDR 0x014
|
||||
#define MDSS_MDP_REG_SSPP_SRC1_ADDR 0x018
|
||||
#define MDSS_MDP_REG_SSPP_SRC2_ADDR 0x01C
|
||||
#define MDSS_MDP_REG_SSPP_SRC3_ADDR 0x020
|
||||
#define MDSS_MDP_REG_SSPP_SRC_YSTRIDE0 0x024
|
||||
#define MDSS_MDP_REG_SSPP_SRC_YSTRIDE1 0x028
|
||||
#define MDSS_MDP_REG_SSPP_STILE_FRAME_SIZE 0x02C
|
||||
#define MDSS_MDP_REG_SSPP_SRC_FORMAT 0x030
|
||||
#define MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN 0x034
|
||||
|
||||
#define MDSS_MDP_REG_SSPP_SRC_OP_MODE 0x038
|
||||
#define MDSS_MDP_OP_DEINTERLACE BIT(22)
|
||||
#define MDSS_MDP_OP_DEINTERLACE_ODD BIT(23)
|
||||
#define MDSS_MDP_OP_FLIP_UD BIT(14)
|
||||
#define MDSS_MDP_OP_FLIP_LR BIT(13)
|
||||
#define MDSS_MDP_OP_BWC_EN BIT(0)
|
||||
#define MDSS_MDP_OP_BWC_LOSSLESS (0 << 1)
|
||||
#define MDSS_MDP_OP_BWC_Q_HIGH (1 << 1)
|
||||
#define MDSS_MDP_OP_BWC_Q_MED (2 << 1)
|
||||
|
||||
#define MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR 0x03C
|
||||
#define MDSS_MDP_REG_SSPP_FETCH_CONFIG 0x048
|
||||
#define MDSS_MDP_REG_SSPP_VC1_RANGE 0x04C
|
||||
|
||||
#define MDSS_MDP_REG_SSPP_CURRENT_SRC0_ADDR 0x0A4
|
||||
#define MDSS_MDP_REG_SSPP_CURRENT_SRC1_ADDR 0x0A8
|
||||
#define MDSS_MDP_REG_SSPP_CURRENT_SRC2_ADDR 0x0AC
|
||||
#define MDSS_MDP_REG_SSPP_CURRENT_SRC3_ADDR 0x0B0
|
||||
#define MDSS_MDP_REG_SSPP_LINE_SKIP_STEP_C03 0x0B4
|
||||
#define MDSS_MDP_REG_SSPP_LINE_SKIP_STEP_C12 0x0B8
|
||||
|
||||
#define MDSS_MDP_REG_VIG_OP_MODE 0x200
|
||||
#define MDSS_MDP_REG_VIG_QSEED2_CONFIG 0x204
|
||||
#define MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPX 0x210
|
||||
#define MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPY 0x214
|
||||
#define MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX 0x218
|
||||
#define MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY 0x21C
|
||||
#define MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEX 0x220
|
||||
#define MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY 0x224
|
||||
#define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX 0x228
|
||||
#define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY 0x22C
|
||||
|
||||
#define MDSS_MDP_REG_SCALE_CONFIG 0x204
|
||||
#define MDSS_MDP_REG_SCALE_PHASE_STEP_X 0x210
|
||||
#define MDSS_MDP_REG_SCALE_PHASE_STEP_Y 0x214
|
||||
#define MDSS_MDP_REG_SCALE_INIT_PHASE_X 0x220
|
||||
#define MDSS_MDP_REG_SCALE_INIT_PHASE_Y 0x224
|
||||
|
||||
#define MDSS_MDP_REG_VIG_CSC_0_BASE 0x280
|
||||
#define MDSS_MDP_REG_VIG_CSC_1_BASE 0x320
|
||||
|
||||
#define MDSS_MDP_SCALE_FILTER_NEAREST 0x0
|
||||
#define MDSS_MDP_SCALE_FILTER_BIL 0x1
|
||||
#define MDSS_MDP_SCALE_FILTER_PCMN 0x2
|
||||
#define MDSS_MDP_SCALE_FILTER_CA 0x3
|
||||
#define MDSS_MDP_SCALEY_EN BIT(1)
|
||||
#define MDSS_MDP_SCALEX_EN BIT(0)
|
||||
|
||||
#define MDSS_MDP_NUM_REG_MIXERS 3
|
||||
#define MDSS_MDP_NUM_WB_MIXERS 2
|
||||
|
||||
enum mdss_mdp_mixer_index {
|
||||
MDSS_MDP_LAYERMIXER0,
|
||||
MDSS_MDP_LAYERMIXER1,
|
||||
MDSS_MDP_LAYERMIXER2,
|
||||
MDSS_MDP_LAYERMIXER3,
|
||||
MDSS_MDP_LAYERMIXER4,
|
||||
MDSS_MDP_MAX_LAYERMIXER
|
||||
};
|
||||
|
||||
enum mdss_mdp_stage_index {
|
||||
MDSS_MDP_STAGE_UNUSED,
|
||||
MDSS_MDP_STAGE_BASE,
|
||||
MDSS_MDP_STAGE_0,
|
||||
MDSS_MDP_STAGE_1,
|
||||
MDSS_MDP_STAGE_2,
|
||||
MDSS_MDP_STAGE_3,
|
||||
MDSS_MDP_MAX_STAGE
|
||||
};
|
||||
|
||||
enum mdss_mdp_blend_index {
|
||||
MDSS_MDP_BLEND_STAGE0,
|
||||
MDSS_MDP_BLEND_STAGE1,
|
||||
MDSS_MDP_BLEND_STAGE2,
|
||||
MDSS_MDP_BLEND_STAGE3,
|
||||
MDSS_MDP_MAX_BLEND_STAGE,
|
||||
};
|
||||
|
||||
#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * 0x400))
|
||||
|
||||
#define MDSS_MDP_REG_LM_OP_MODE 0x000
|
||||
#define MDSS_MDP_REG_LM_OUT_SIZE 0x004
|
||||
#define MDSS_MDP_REG_LM_BORDER_COLOR_0 0x008
|
||||
#define MDSS_MDP_REG_LM_BORDER_COLOR_1 0x010
|
||||
|
||||
#define MDSS_MDP_REG_LM_BLEND_OFFSET(stage) (0x20 + ((stage) * 0x30))
|
||||
#define MDSS_MDP_REG_LM_BLEND_OP 0x00
|
||||
#define MDSS_MDP_REG_LM_BLEND_FG_ALPHA 0x04
|
||||
#define MDSS_MDP_REG_LM_BLEND_BG_ALPHA 0x08
|
||||
#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_LOW0 0x0C
|
||||
#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_LOW1 0x10
|
||||
#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_HIGH0 0x14
|
||||
#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_HIGH1 0x18
|
||||
#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_LOW0 0x1C
|
||||
#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_LOW1 0x20
|
||||
#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_HIGH0 0x24
|
||||
#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_HIGH1 0x28
|
||||
|
||||
#define MDSS_MDP_REG_LM_CURSOR_IMG_SIZE 0xE0
|
||||
#define MDSS_MDP_REG_LM_CURSOR_SIZE 0xE4
|
||||
#define MDSS_MDP_REG_LM_CURSOR_XY 0xE8
|
||||
#define MDSS_MDP_REG_LM_CURSOR_STRIDE 0xDC
|
||||
#define MDSS_MDP_REG_LM_CURSOR_FORMAT 0xEC
|
||||
#define MDSS_MDP_REG_LM_CURSOR_BASE_ADDR 0xF0
|
||||
#define MDSS_MDP_REG_LM_CURSOR_START_XY 0xF4
|
||||
#define MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG 0xF8
|
||||
#define MDSS_MDP_REG_LM_CURSOR_BLEND_PARAM 0xFC
|
||||
#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW0 0x100
|
||||
#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW1 0x104
|
||||
#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH0 0x108
|
||||
#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH1 0x10C
|
||||
|
||||
#define MDSS_MDP_LM_BORDER_COLOR (1 << 24)
|
||||
#define MDSS_MDP_LM_CURSOR_OUT (1 << 25)
|
||||
#define MDSS_MDP_BLEND_FG_ALPHA_FG_CONST (0 << 0)
|
||||
#define MDSS_MDP_BLEND_FG_ALPHA_BG_CONST (1 << 0)
|
||||
#define MDSS_MDP_BLEND_FG_ALPHA_FG_PIXEL (2 << 0)
|
||||
#define MDSS_MDP_BLEND_FG_ALPHA_BG_PIXEL (3 << 0)
|
||||
#define MDSS_MDP_BLEND_FG_INV_ALPHA (1 << 2)
|
||||
#define MDSS_MDP_BLEND_FG_MOD_ALPHA (1 << 3)
|
||||
#define MDSS_MDP_BLEND_FG_INV_MOD_ALPHA (1 << 4)
|
||||
#define MDSS_MDP_BLEND_FG_TRANSP_EN (1 << 5)
|
||||
#define MDSS_MDP_BLEND_BG_ALPHA_FG_CONST (0 << 8)
|
||||
#define MDSS_MDP_BLEND_BG_ALPHA_BG_CONST (1 << 8)
|
||||
#define MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL (2 << 8)
|
||||
#define MDSS_MDP_BLEND_BG_ALPHA_BG_PIXEL (3 << 8)
|
||||
#define MDSS_MDP_BLEND_BG_INV_ALPHA (1 << 10)
|
||||
#define MDSS_MDP_BLEND_BG_MOD_ALPHA (1 << 11)
|
||||
#define MDSS_MDP_BLEND_BG_INV_MOD_ALPHA (1 << 12)
|
||||
#define MDSS_MDP_BLEND_BG_TRANSP_EN (1 << 13)
|
||||
|
||||
enum mdss_mdp_writeback_index {
|
||||
MDSS_MDP_WRITEBACK0,
|
||||
MDSS_MDP_WRITEBACK1,
|
||||
MDSS_MDP_WRITEBACK2,
|
||||
MDSS_MDP_WRITEBACK3,
|
||||
MDSS_MDP_WRITEBACK4,
|
||||
MDSS_MDP_MAX_WRITEBACK
|
||||
};
|
||||
|
||||
#define MDSS_MDP_REG_WB_OFFSET(wb) (0x11100 + ((wb) * 0x2000))
|
||||
|
||||
#define MDSS_MDP_REG_WB_DST_FORMAT 0x000
|
||||
#define MDSS_MDP_REG_WB_DST_OP_MODE 0x004
|
||||
#define MDSS_MDP_REG_WB_DST_PACK_PATTERN 0x008
|
||||
#define MDSS_MDP_REG_WB_DST0_ADDR 0x00C
|
||||
#define MDSS_MDP_REG_WB_DST1_ADDR 0x010
|
||||
#define MDSS_MDP_REG_WB_DST2_ADDR 0x014
|
||||
#define MDSS_MDP_REG_WB_DST3_ADDR 0x018
|
||||
#define MDSS_MDP_REG_WB_DST_YSTRIDE0 0x01C
|
||||
#define MDSS_MDP_REG_WB_DST_YSTRIDE1 0x020
|
||||
#define MDSS_MDP_REG_WB_DST_YSTRIDE1 0x020
|
||||
#define MDSS_MDP_REG_WB_DST_DITHER_BITDEPTH 0x024
|
||||
#define MDSS_MDP_REG_WB_DST_MATRIX_ROW0 0x030
|
||||
#define MDSS_MDP_REG_WB_DST_MATRIX_ROW1 0x034
|
||||
#define MDSS_MDP_REG_WB_DST_MATRIX_ROW2 0x038
|
||||
#define MDSS_MDP_REG_WB_DST_MATRIX_ROW3 0x03C
|
||||
#define MDSS_MDP_REG_WB_ROTATION_DNSCALER 0x050
|
||||
#define MDSS_MDP_REG_WB_N16_INIT_PHASE_X_C03 0x060
|
||||
#define MDSS_MDP_REG_WB_N16_INIT_PHASE_X_C12 0x064
|
||||
#define MDSS_MDP_REG_WB_N16_INIT_PHASE_Y_C03 0x068
|
||||
#define MDSS_MDP_REG_WB_N16_INIT_PHASE_Y_C12 0x06C
|
||||
#define MDSS_MDP_REG_WB_OUT_SIZE 0x074
|
||||
#define MDSS_MDP_REG_WB_ALPHA_X_VALUE 0x078
|
||||
#define MDSS_MDP_REG_WB_CSC_BASE 0x260
|
||||
|
||||
enum mdss_mdp_dspp_index {
|
||||
MDSS_MDP_DSPP0,
|
||||
MDSS_MDP_DSPP1,
|
||||
MDSS_MDP_DSPP2,
|
||||
MDSS_MDP_MAX_DSPP
|
||||
};
|
||||
|
||||
enum mdss_mpd_intf_index {
|
||||
MDSS_MDP_NO_INTF,
|
||||
MDSS_MDP_INTF0,
|
||||
MDSS_MDP_INTF1,
|
||||
MDSS_MDP_INTF2,
|
||||
MDSS_MDP_INTF3,
|
||||
MDSS_MDP_MAX_INTF
|
||||
};
|
||||
|
||||
#define MDSS_MDP_REG_INTF_OFFSET(intf) (0x20F00 + ((intf) * 0x200))
|
||||
|
||||
#define MDSS_MDP_REG_INTF_TIMING_ENGINE_EN 0x000
|
||||
#define MDSS_MDP_REG_INTF_CONFIG 0x004
|
||||
#define MDSS_MDP_REG_INTF_HSYNC_CTL 0x008
|
||||
#define MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0 0x00C
|
||||
#define MDSS_MDP_REG_INTF_VSYNC_PERIOD_F1 0x010
|
||||
#define MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F0 0x014
|
||||
#define MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F1 0x018
|
||||
#define MDSS_MDP_REG_INTF_DISPLAY_V_START_F0 0x01C
|
||||
#define MDSS_MDP_REG_INTF_DISPLAY_V_START_F1 0x020
|
||||
#define MDSS_MDP_REG_INTF_DISPLAY_V_END_F0 0x024
|
||||
#define MDSS_MDP_REG_INTF_DISPLAY_V_END_F1 0x028
|
||||
#define MDSS_MDP_REG_INTF_ACTIVE_V_START_F0 0x02C
|
||||
#define MDSS_MDP_REG_INTF_ACTIVE_V_START_F1 0x030
|
||||
#define MDSS_MDP_REG_INTF_ACTIVE_V_END_F0 0x034
|
||||
#define MDSS_MDP_REG_INTF_ACTIVE_V_END_F1 0x038
|
||||
#define MDSS_MDP_REG_INTF_DISPLAY_HCTL 0x03C
|
||||
#define MDSS_MDP_REG_INTF_ACTIVE_HCTL 0x040
|
||||
#define MDSS_MDP_REG_INTF_BORDER_COLOR 0x044
|
||||
#define MDSS_MDP_REG_INTF_UNDERFLOW_COLOR 0x048
|
||||
#define MDSS_MDP_REG_INTF_HSYNC_SKEW 0x04C
|
||||
#define MDSS_MDP_REG_INTF_POLARITY_CTL 0x050
|
||||
#define MDSS_MDP_REG_INTF_TEST_CTL 0x054
|
||||
#define MDSS_MDP_REG_INTF_TP_COLOR0 0x058
|
||||
#define MDSS_MDP_REG_INTF_TP_COLOR1 0x05C
|
||||
|
||||
#define MDSS_MDP_REG_INTF_DEFLICKER_CONFIG 0x0F0
|
||||
#define MDSS_MDP_REG_INTF_DEFLICKER_STRNG_COEFF 0x0F4
|
||||
#define MDSS_MDP_REG_INTF_DEFLICKER_WEAK_COEFF 0x0F8
|
||||
|
||||
#define MDSS_MDP_REG_INTF_DSI_CMD_MODE_TRIGGER_EN 0x084
|
||||
#define MDSS_MDP_REG_INTF_PANEL_FORMAT 0x090
|
||||
#define MDSS_MDP_REG_INTF_TPG_ENABLE 0x100
|
||||
#define MDSS_MDP_REG_INTF_TPG_MAIN_CONTROL 0x104
|
||||
#define MDSS_MDP_REG_INTF_TPG_VIDEO_CONFIG 0x108
|
||||
#define MDSS_MDP_REG_INTF_TPG_COMPONENT_LIMITS 0x10C
|
||||
#define MDSS_MDP_REG_INTF_TPG_RECTANGLE 0x110
|
||||
#define MDSS_MDP_REG_INTF_TPG_INITIAL_VALUE 0x114
|
||||
#define MDSS_MDP_REG_INTF_TPG_BLK_WHITE_PATTERN_FRAMES 0x118
|
||||
#define MDSS_MDP_REG_INTF_TPG_RGB_MAPPING 0x11C
|
||||
|
||||
#define MDSS_MDP_REG_INTF_FRAME_LINE_COUNT_EN 0x0A8
|
||||
#define MDSS_MDP_REG_INTF_FRAME_COUNT 0x0AC
|
||||
#define MDSS_MDP_REG_INTF_LINE_COUNT 0x0B0
|
||||
|
||||
enum mdss_mdp_pingpong_index {
|
||||
MDSS_MDP_PINGPONG0,
|
||||
MDSS_MDP_PINGPONG1,
|
||||
MDSS_MDP_PINGPONG2,
|
||||
MDSS_MDP_MAX_PINGPONG
|
||||
};
|
||||
|
||||
#define MDSS_MDP_REG_PP_OFFSET(pp) (0x21B00 + ((pp) * 0x100))
|
||||
|
||||
#define MDSS_MDP_REG_PP_TEAR_CHECK_EN 0x000
|
||||
#define MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC 0x004
|
||||
#define MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT 0x008
|
||||
#define MDSS_MDP_REG_PP_SYNC_WRCOUNT 0x00C
|
||||
#define MDSS_MDP_REG_PP_VSYNC_INIT_VAL 0x010
|
||||
#define MDSS_MDP_REG_PP_INT_COUNT_VAL 0x014
|
||||
#define MDSS_MDP_REG_PP_SYNC_THRESH 0x018
|
||||
#define MDSS_MDP_REG_PP_START_POS 0x01C
|
||||
#define MDSS_MDP_REG_PP_RD_PTR_IRQ 0x020
|
||||
#define MDSS_MDP_REG_PP_WR_PTR_IRQ 0x024
|
||||
#define MDSS_MDP_REG_PP_OUT_LINE_COUNT 0x028
|
||||
#define MDSS_MDP_REG_PP_LINE_COUNT 0x02C
|
||||
#define MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG 0x030
|
||||
|
||||
#define MDSS_MDP_REG_SMP_ALLOC_W0 0x00180
|
||||
#define MDSS_MDP_REG_SMP_ALLOC_R0 0x00230
|
||||
|
||||
#define MDSS_MDP_SMP_MMB_SIZE 4096
|
||||
#define MDSS_MDP_SMP_MMB_BLOCKS 22
|
||||
|
||||
enum mdss_mdp_smp_client_index {
|
||||
MDSS_MDP_SMP_CLIENT_UNUSED,
|
||||
MDSS_MDP_SMP_CLIENT_VIG0_FETCH_Y,
|
||||
MDSS_MDP_SMP_CLIENT_VIG0_FETCH_CR,
|
||||
MDSS_MDP_SMP_CLIENT_VIG0_FETCH_CB,
|
||||
MDSS_MDP_SMP_CLIENT_VIG1_FETCH_Y,
|
||||
MDSS_MDP_SMP_CLIENT_VIG1_FETCH_CR,
|
||||
MDSS_MDP_SMP_CLIENT_VIG1_FETCH_CB,
|
||||
MDSS_MDP_SMP_CLIENT_VIG2_FETCH_Y,
|
||||
MDSS_MDP_SMP_CLIENT_VIG2_FETCH_CR,
|
||||
MDSS_MDP_SMP_CLIENT_VIG2_FETCH_CB,
|
||||
MDSS_MDP_SMP_CLIENT_DMA0_FETCH_Y,
|
||||
MDSS_MDP_SMP_CLIENT_DMA0_FETCH_CR,
|
||||
MDSS_MDP_SMP_CLIENT_DMA0_FETCH_CB,
|
||||
MDSS_MDP_SMP_CLIENT_DMA1_FETCH_Y,
|
||||
MDSS_MDP_SMP_CLIENT_DMA1_FETCH_CR,
|
||||
MDSS_MDP_SMP_CLIENT_DMA1_FETCH_CB,
|
||||
MDSS_MDP_SMP_CLIENT_RGB0_FETCH,
|
||||
MDSS_MDP_SMP_CLIENT_RGB1_FETCH,
|
||||
MDSS_MDP_SMP_CLIENT_RGB2_FETCH,
|
||||
};
|
||||
|
||||
#endif /* MDSS_MDP_HWIO_H */
|
465
drivers/video/msm/mdss/mdss_mdp_overlay.c
Normal file
465
drivers/video/msm/mdss/mdss_mdp_overlay.c
Normal file
|
@ -0,0 +1,465 @@
|
|||
/* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "mdss_fb.h"
|
||||
#include "mdss_mdp.h"
|
||||
|
||||
#define CHECK_BOUNDS(offset, size, max_size) \
|
||||
(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
|
||||
|
||||
static int mdss_mdp_overlay_req_check(struct msm_fb_data_type *mfd,
|
||||
struct mdp_overlay *req,
|
||||
struct mdss_mdp_format_params *fmt)
|
||||
{
|
||||
u32 xres, yres;
|
||||
u32 dst_w, dst_h;
|
||||
|
||||
xres = mfd->fbi->var.xres;
|
||||
yres = mfd->fbi->var.yres;
|
||||
|
||||
if (req->z_order >= MDSS_MDP_MAX_STAGE) {
|
||||
pr_err("zorder %d out of range\n", req->z_order);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
if (req->src.width > MAX_IMG_WIDTH ||
|
||||
req->src.height > MAX_IMG_HEIGHT ||
|
||||
req->src_rect.w == 0 || req->src_rect.h == 0 ||
|
||||
req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
|
||||
req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H ||
|
||||
CHECK_BOUNDS(req->src_rect.x, req->src_rect.w, req->src.width) ||
|
||||
CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height) ||
|
||||
CHECK_BOUNDS(req->dst_rect.x, req->dst_rect.w, xres) ||
|
||||
CHECK_BOUNDS(req->dst_rect.y, req->dst_rect.h, yres)) {
|
||||
pr_err("invalid image img_w=%d img_h=%d\n",
|
||||
req->src.width, req->src.height);
|
||||
|
||||
pr_err("\tsrc_rect=%d,%d,%d,%d dst_rect=%d,%d,%d,%d\n",
|
||||
req->src_rect.x, req->src_rect.y,
|
||||
req->src_rect.w, req->src_rect.h,
|
||||
req->dst_rect.x, req->dst_rect.y,
|
||||
req->dst_rect.w, req->dst_rect.h);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (req->flags & MDP_ROT_90) {
|
||||
dst_h = req->dst_rect.w;
|
||||
dst_w = req->dst_rect.h;
|
||||
} else {
|
||||
dst_w = req->dst_rect.w;
|
||||
dst_h = req->dst_rect.h;
|
||||
}
|
||||
|
||||
if ((req->src_rect.w * MAX_UPSCALE_RATIO) < dst_w) {
|
||||
pr_err("too much upscaling Width %d->%d\n",
|
||||
req->src_rect.w, req->dst_rect.w);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((req->src_rect.h * MAX_UPSCALE_RATIO) < dst_h) {
|
||||
pr_err("too much upscaling. Height %d->%d\n",
|
||||
req->src_rect.h, req->dst_rect.h);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (req->src_rect.w > (dst_w * MAX_DOWNSCALE_RATIO)) {
|
||||
pr_err("too much downscaling. Width %d->%d\n",
|
||||
req->src_rect.w, req->dst_rect.w);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (req->src_rect.h > (dst_h * MAX_DOWNSCALE_RATIO)) {
|
||||
pr_err("too much downscaling. Height %d->%d\n",
|
||||
req->src_rect.h, req->dst_rect.h);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fmt->is_yuv) {
|
||||
if ((req->src_rect.x & 0x1) || (req->src_rect.y & 0x1) ||
|
||||
(req->src_rect.w & 0x1) || (req->src_rect.h & 0x1)) {
|
||||
pr_err("invalid odd src resolution\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((req->dst_rect.x & 0x1) || (req->dst_rect.y & 0x1) ||
|
||||
(req->dst_rect.w & 0x1) || (req->dst_rect.h & 0x1)) {
|
||||
pr_err("invalid odd dst resolution\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (((req->src_rect.w * (MAX_UPSCALE_RATIO / 2)) < dst_w) &&
|
||||
(fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
|
||||
fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
|
||||
pr_err("too much YUV upscaling Width %d->%d\n",
|
||||
req->src_rect.w, req->dst_rect.w);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (((req->src_rect.h * (MAX_UPSCALE_RATIO / 2)) < dst_h) &&
|
||||
(fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
|
||||
fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
|
||||
pr_err("too much YUV upscaling Height %d->%d\n",
|
||||
req->src_rect.h, req->dst_rect.h);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
|
||||
struct mdp_overlay *req,
|
||||
struct mdss_mdp_pipe **ppipe)
|
||||
{
|
||||
struct mdss_mdp_format_params *fmt;
|
||||
struct mdss_mdp_pipe *pipe;
|
||||
struct mdss_mdp_mixer *mixer = NULL;
|
||||
u32 pipe_type, mixer_mux;
|
||||
int ret;
|
||||
|
||||
if (mfd == NULL || mfd->ctl == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
if (req->flags & MDSS_MDP_RIGHT_MIXER)
|
||||
mixer_mux = MDSS_MDP_MIXER_MUX_RIGHT;
|
||||
else
|
||||
mixer_mux = MDSS_MDP_MIXER_MUX_LEFT;
|
||||
|
||||
pr_debug("pipe ctl=%u req id=%x mux=%d\n", mfd->ctl->num, req->id,
|
||||
mixer_mux);
|
||||
|
||||
if (req->flags & MDP_ROT_90) {
|
||||
pr_err("unsupported inline rotation\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
fmt = mdss_mdp_get_format_params(req->src.format);
|
||||
if (!fmt) {
|
||||
pr_err("invalid pipe format %d\n", req->src.format);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = mdss_mdp_overlay_req_check(mfd, req, fmt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux, req->z_order);
|
||||
if (pipe && pipe->ndx != req->id) {
|
||||
pr_err("stage %d taken by pnum=%d\n", req->z_order, pipe->num);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
||||
if (req->id == MSMFB_NEW_REQUEST) {
|
||||
mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
|
||||
if (!mixer) {
|
||||
pr_err("unable to get mixer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
|
||||
pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
|
||||
else
|
||||
pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
|
||||
|
||||
pipe = mdss_mdp_pipe_alloc_locked(pipe_type);
|
||||
|
||||
/* VIG pipes can also support RGB format */
|
||||
if (!pipe && pipe_type == MDSS_MDP_PIPE_TYPE_RGB) {
|
||||
pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
|
||||
pipe = mdss_mdp_pipe_alloc_locked(pipe_type);
|
||||
}
|
||||
|
||||
if (pipe == NULL) {
|
||||
pr_err("error allocating pipe\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pipe->mixer = mixer;
|
||||
pipe->mfd = mfd;
|
||||
} else {
|
||||
pipe = mdss_mdp_pipe_get_locked(req->id);
|
||||
if (pipe == NULL) {
|
||||
pr_err("invalid pipe ndx=%x\n", req->id);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
pipe->flags = req->flags;
|
||||
|
||||
pipe->img_width = req->src.width & 0x3fff;
|
||||
pipe->img_height = req->src.height & 0x3fff;
|
||||
pipe->src.x = req->src_rect.x;
|
||||
pipe->src.y = req->src_rect.y;
|
||||
pipe->src.w = req->src_rect.w;
|
||||
pipe->src.h = req->src_rect.h;
|
||||
pipe->dst.x = req->dst_rect.x;
|
||||
pipe->dst.y = req->dst_rect.y;
|
||||
pipe->dst.w = req->dst_rect.w;
|
||||
pipe->dst.h = req->dst_rect.h;
|
||||
|
||||
pipe->src_fmt = fmt;
|
||||
|
||||
pipe->mixer_stage = req->z_order;
|
||||
pipe->is_fg = req->is_fg;
|
||||
pipe->alpha = req->alpha;
|
||||
pipe->transp = req->transp_mask;
|
||||
|
||||
pipe->req_data = *req;
|
||||
|
||||
pipe->params_changed++;
|
||||
|
||||
req->id = pipe->ndx;
|
||||
|
||||
*ppipe = pipe;
|
||||
|
||||
mdss_mdp_pipe_unlock(pipe);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mdss_mdp_overlay_get_fb_pipe(struct msm_fb_data_type *mfd,
|
||||
struct mdss_mdp_pipe **ppipe,
|
||||
int mixer_mux)
|
||||
{
|
||||
struct mdss_mdp_pipe *pipe;
|
||||
|
||||
pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux,
|
||||
MDSS_MDP_STAGE_BASE);
|
||||
if (pipe == NULL) {
|
||||
struct mdp_overlay req;
|
||||
int ret;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
|
||||
req.id = MSMFB_NEW_REQUEST;
|
||||
req.src.format = mfd->fb_imgType;
|
||||
req.src.height = mfd->fbi->var.yres;
|
||||
req.src.width = mfd->fbi->var.xres;
|
||||
if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) {
|
||||
if (req.src.width <= MAX_MIXER_WIDTH)
|
||||
return -ENODEV;
|
||||
|
||||
req.flags |= MDSS_MDP_RIGHT_MIXER;
|
||||
req.src_rect.x = MAX_MIXER_WIDTH;
|
||||
req.src_rect.w = req.src.width - MAX_MIXER_WIDTH;
|
||||
} else {
|
||||
req.src_rect.x = 0;
|
||||
req.src_rect.w = MIN(req.src.width, MAX_MIXER_WIDTH);
|
||||
}
|
||||
|
||||
req.src_rect.y = 0;
|
||||
req.src_rect.h = req.src.height;
|
||||
req.dst_rect.x = req.src_rect.x;
|
||||
req.dst_rect.y = 0;
|
||||
req.dst_rect.w = req.src_rect.w;
|
||||
req.dst_rect.h = req.src_rect.h;
|
||||
req.z_order = MDSS_MDP_STAGE_BASE;
|
||||
|
||||
pr_debug("allocating base pipe mux=%d\n", mixer_mux);
|
||||
|
||||
ret = mdss_mdp_overlay_pipe_setup(mfd, &req, &pipe);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pr_debug("ctl=%d pnum=%d\n", mfd->ctl->num, pipe->num);
|
||||
}
|
||||
|
||||
*ppipe = pipe;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
|
||||
{
|
||||
struct mdss_mdp_data data;
|
||||
struct mdss_mdp_pipe *pipe;
|
||||
struct fb_info *fbi;
|
||||
u32 offset;
|
||||
int bpp, ret;
|
||||
|
||||
if (!mfd)
|
||||
return;
|
||||
|
||||
if (!mfd->ctl || !mfd->panel_power_on)
|
||||
return;
|
||||
|
||||
fbi = mfd->fbi;
|
||||
|
||||
if (fbi->fix.smem_len == 0) {
|
||||
pr_warn("fb memory not allocated\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
bpp = fbi->var.bits_per_pixel / 8;
|
||||
offset = fbi->var.xoffset * bpp +
|
||||
fbi->var.yoffset * fbi->fix.line_length;
|
||||
|
||||
data.p[0].addr = fbi->fix.smem_start + offset;
|
||||
data.p[0].len = fbi->fix.smem_len - offset;
|
||||
data.num_planes = 1;
|
||||
|
||||
ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe, MDSS_MDP_MIXER_MUX_LEFT);
|
||||
if (ret) {
|
||||
pr_err("unable to allocate base pipe\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mdss_mdp_pipe_lock(pipe);
|
||||
ret = mdss_mdp_pipe_queue_data(pipe, &data);
|
||||
mdss_mdp_pipe_unlock(pipe);
|
||||
if (ret) {
|
||||
pr_err("unable to queue data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fbi->var.xres > MAX_MIXER_WIDTH) {
|
||||
ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe,
|
||||
MDSS_MDP_MIXER_MUX_RIGHT);
|
||||
if (ret) {
|
||||
pr_err("unable to allocate right base pipe\n");
|
||||
return;
|
||||
}
|
||||
mdss_mdp_pipe_lock(pipe);
|
||||
ret = mdss_mdp_pipe_queue_data(pipe, &data);
|
||||
mdss_mdp_pipe_unlock(pipe);
|
||||
if (ret) {
|
||||
pr_err("unable to queue right data\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mdss_mdp_display_commit(mfd->ctl, NULL);
|
||||
}
|
||||
|
||||
static int mdss_mdp_hw_cursor_update(struct fb_info *info,
|
||||
struct fb_cursor *cursor)
|
||||
{
|
||||
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
|
||||
struct mdss_mdp_mixer *mixer;
|
||||
struct fb_image *img = &cursor->image;
|
||||
int calpha_en, transp_en, blendcfg, alpha;
|
||||
int off, ret = 0;
|
||||
|
||||
mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
|
||||
off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
|
||||
|
||||
if ((img->width > MDSS_MDP_CURSOR_WIDTH) ||
|
||||
(img->height > MDSS_MDP_CURSOR_HEIGHT) ||
|
||||
(img->depth != 32))
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("mixer=%d enable=%x set=%x\n", mixer->num, cursor->enable,
|
||||
cursor->set);
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
|
||||
blendcfg = MDSS_MDP_REG_READ(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG);
|
||||
|
||||
if (cursor->set & FB_CUR_SETPOS)
|
||||
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_START_XY,
|
||||
(img->dy << 16) | img->dx);
|
||||
|
||||
if (cursor->set & FB_CUR_SETIMAGE) {
|
||||
ret = copy_from_user(mfd->cursor_buf, img->data,
|
||||
img->width * img->height * 4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (img->bg_color == 0xffffffff)
|
||||
transp_en = 0;
|
||||
else
|
||||
transp_en = 1;
|
||||
|
||||
alpha = (img->fg_color & 0xff000000) >> 24;
|
||||
|
||||
if (alpha)
|
||||
calpha_en = 0x0; /* xrgb */
|
||||
else
|
||||
calpha_en = 0x2; /* argb */
|
||||
|
||||
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_SIZE,
|
||||
(img->height << 16) | img->width);
|
||||
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_STRIDE,
|
||||
img->width * 4);
|
||||
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BASE_ADDR,
|
||||
mfd->cursor_buf_phys);
|
||||
|
||||
wmb();
|
||||
|
||||
blendcfg &= ~0x1;
|
||||
blendcfg |= (transp_en << 3) | (calpha_en << 1);
|
||||
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG,
|
||||
blendcfg);
|
||||
if (calpha_en)
|
||||
MDSS_MDP_REG_WRITE(off +
|
||||
MDSS_MDP_REG_LM_CURSOR_BLEND_PARAM,
|
||||
alpha);
|
||||
|
||||
if (transp_en) {
|
||||
MDSS_MDP_REG_WRITE(off +
|
||||
MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW0,
|
||||
((img->bg_color & 0xff00) << 8) |
|
||||
(img->bg_color & 0xff));
|
||||
MDSS_MDP_REG_WRITE(off +
|
||||
MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW1,
|
||||
((img->bg_color & 0xff0000) >> 16));
|
||||
MDSS_MDP_REG_WRITE(off +
|
||||
MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH0,
|
||||
((img->bg_color & 0xff00) << 8) |
|
||||
(img->bg_color & 0xff));
|
||||
MDSS_MDP_REG_WRITE(off +
|
||||
MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH1,
|
||||
((img->bg_color & 0xff0000) >> 16));
|
||||
}
|
||||
}
|
||||
|
||||
if (!cursor->enable != !(blendcfg & 0x1)) {
|
||||
if (cursor->enable)
|
||||
blendcfg |= 0x1;
|
||||
else
|
||||
blendcfg &= ~0x1;
|
||||
|
||||
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG,
|
||||
blendcfg);
|
||||
|
||||
mixer->cursor_enabled = cursor->enable;
|
||||
mixer->params_changed++;
|
||||
}
|
||||
|
||||
mixer->ctl->flush_bits |= BIT(6) << mixer->num;
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
|
||||
{
|
||||
mfd->on_fnc = mdss_mdp_ctl_on;
|
||||
mfd->off_fnc = mdss_mdp_ctl_off;
|
||||
mfd->hw_refresh = true;
|
||||
mfd->lut_update = NULL;
|
||||
mfd->do_histogram = NULL;
|
||||
mfd->overlay_play_enable = false;
|
||||
mfd->cursor_update = mdss_mdp_hw_cursor_update;
|
||||
mfd->dma_fnc = mdss_mdp_overlay_pan_display;
|
||||
|
||||
return 0;
|
||||
}
|
675
drivers/video/msm/mdss/mdss_mdp_pipe.c
Normal file
675
drivers/video/msm/mdss/mdss_mdp_pipe.c
Normal file
|
@ -0,0 +1,675 @@
|
|||
/* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "mdss_mdp.h"
|
||||
|
||||
#define SMP_MB_CNT (mdss_res->smp_mb_cnt)
|
||||
|
||||
static DEFINE_MUTEX(mdss_mdp_sspp_lock);
|
||||
static DECLARE_BITMAP(mdss_mdp_smp_mmb_pool, MDSS_MDP_SMP_MMB_BLOCKS);
|
||||
|
||||
static struct mdss_mdp_pipe mdss_mdp_pipe_list[MDSS_MDP_MAX_SSPP];
|
||||
|
||||
static u32 mdss_mdp_smp_mmb_reserve(unsigned long *smp, size_t n)
|
||||
{
|
||||
u32 i, mmb;
|
||||
|
||||
/* reserve more blocks if needed, but can't free mmb at this point */
|
||||
for (i = bitmap_weight(smp, SMP_MB_CNT); i < n; i++) {
|
||||
if (bitmap_full(mdss_mdp_smp_mmb_pool, SMP_MB_CNT))
|
||||
break;
|
||||
|
||||
mmb = find_first_zero_bit(mdss_mdp_smp_mmb_pool, SMP_MB_CNT);
|
||||
set_bit(mmb, smp);
|
||||
set_bit(mmb, mdss_mdp_smp_mmb_pool);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static void mdss_mdp_smp_mmb_set(int client_id, unsigned long *smp)
|
||||
{
|
||||
u32 mmb, off, data, s;
|
||||
|
||||
for_each_set_bit(mmb, smp, SMP_MB_CNT) {
|
||||
off = (mmb / 3) * 4;
|
||||
s = (mmb % 3) * 8;
|
||||
data = MDSS_MDP_REG_READ(MDSS_MDP_REG_SMP_ALLOC_W0 + off);
|
||||
data &= ~(0xFF << s);
|
||||
data |= client_id << s;
|
||||
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_SMP_ALLOC_W0 + off, data);
|
||||
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_SMP_ALLOC_R0 + off, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void mdss_mdp_smp_mmb_free(unsigned long *smp)
|
||||
{
|
||||
if (!bitmap_empty(smp, SMP_MB_CNT)) {
|
||||
mdss_mdp_smp_mmb_set(MDSS_MDP_SMP_CLIENT_UNUSED, smp);
|
||||
bitmap_andnot(mdss_mdp_smp_mmb_pool, mdss_mdp_smp_mmb_pool,
|
||||
smp, SMP_MB_CNT);
|
||||
bitmap_zero(smp, SMP_MB_CNT);
|
||||
}
|
||||
}
|
||||
|
||||
static void mdss_mdp_smp_free(struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
mdss_mdp_smp_mmb_free(&pipe->smp[0]);
|
||||
mdss_mdp_smp_mmb_free(&pipe->smp[1]);
|
||||
mdss_mdp_smp_mmb_free(&pipe->smp[2]);
|
||||
}
|
||||
|
||||
static int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
u32 num_blks = 0, reserved = 0;
|
||||
int i;
|
||||
|
||||
if ((pipe->src_planes.num_planes > 1) &&
|
||||
(pipe->type == MDSS_MDP_PIPE_TYPE_RGB))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&mdss_mdp_sspp_lock);
|
||||
for (i = 0; i < pipe->src_planes.num_planes; i++) {
|
||||
num_blks = DIV_ROUND_UP(2 * pipe->src_planes.ystride[i],
|
||||
mdss_res->smp_mb_size);
|
||||
|
||||
pr_debug("reserving %d mmb for pnum=%d plane=%d\n",
|
||||
num_blks, pipe->num, i);
|
||||
reserved = mdss_mdp_smp_mmb_reserve(&pipe->smp[i], num_blks);
|
||||
|
||||
if (reserved < num_blks)
|
||||
break;
|
||||
}
|
||||
|
||||
if (reserved < num_blks) {
|
||||
pr_err("insufficient MMB blocks\n");
|
||||
mdss_mdp_smp_free(pipe);
|
||||
return -ENOMEM;
|
||||
}
|
||||
mutex_unlock(&mdss_mdp_sspp_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_smp_alloc(struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
u32 client_id;
|
||||
int i;
|
||||
|
||||
switch (pipe->num) {
|
||||
case MDSS_MDP_SSPP_VIG0:
|
||||
client_id = MDSS_MDP_SMP_CLIENT_VIG0_FETCH_Y;
|
||||
break;
|
||||
case MDSS_MDP_SSPP_VIG1:
|
||||
client_id = MDSS_MDP_SMP_CLIENT_VIG1_FETCH_Y;
|
||||
break;
|
||||
case MDSS_MDP_SSPP_VIG2:
|
||||
client_id = MDSS_MDP_SMP_CLIENT_VIG2_FETCH_Y;
|
||||
break;
|
||||
case MDSS_MDP_SSPP_RGB0:
|
||||
client_id = MDSS_MDP_SMP_CLIENT_RGB0_FETCH;
|
||||
break;
|
||||
case MDSS_MDP_SSPP_RGB1:
|
||||
client_id = MDSS_MDP_SMP_CLIENT_RGB1_FETCH;
|
||||
break;
|
||||
case MDSS_MDP_SSPP_RGB2:
|
||||
client_id = MDSS_MDP_SMP_CLIENT_RGB2_FETCH;
|
||||
break;
|
||||
case MDSS_MDP_SSPP_DMA0:
|
||||
client_id = MDSS_MDP_SMP_CLIENT_DMA0_FETCH_Y;
|
||||
break;
|
||||
case MDSS_MDP_SSPP_DMA1:
|
||||
client_id = MDSS_MDP_SMP_CLIENT_DMA1_FETCH_Y;
|
||||
break;
|
||||
default:
|
||||
pr_err("no valid smp client for pnum=%d\n", pipe->num);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&mdss_mdp_sspp_lock);
|
||||
for (i = 0; i < pipe->src_planes.num_planes; i++)
|
||||
mdss_mdp_smp_mmb_set(client_id + i, &pipe->smp[i]);
|
||||
mutex_unlock(&mdss_mdp_sspp_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mdss_mdp_pipe_unlock(struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
atomic_dec(&pipe->ref_cnt);
|
||||
mutex_unlock(&pipe->lock);
|
||||
}
|
||||
|
||||
int mdss_mdp_pipe_lock(struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
if (atomic_inc_not_zero(&pipe->ref_cnt)) {
|
||||
if (mutex_lock_interruptible(&pipe->lock)) {
|
||||
atomic_dec(&pipe->ref_cnt);
|
||||
return -EINTR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct mdss_mdp_pipe *mdss_mdp_pipe_init(u32 pnum)
|
||||
{
|
||||
struct mdss_mdp_pipe *pipe = NULL;
|
||||
|
||||
if (atomic_read(&mdss_mdp_pipe_list[pnum].ref_cnt) == 0) {
|
||||
pipe = &mdss_mdp_pipe_list[pnum];
|
||||
memset(pipe, 0, sizeof(*pipe));
|
||||
|
||||
mutex_init(&pipe->lock);
|
||||
atomic_set(&pipe->ref_cnt, 1);
|
||||
|
||||
if (mdss_mdp_pipe_lock(pipe) == 0) {
|
||||
pipe->num = pnum;
|
||||
pipe->type = mdss_res->pipe_type_map[pnum];
|
||||
pipe->ndx = BIT(pnum);
|
||||
|
||||
pr_debug("ndx=%x pnum=%d\n", pipe->ndx, pipe->num);
|
||||
} else {
|
||||
atomic_set(&pipe->ref_cnt, 0);
|
||||
pipe = NULL;
|
||||
}
|
||||
}
|
||||
return pipe;
|
||||
}
|
||||
|
||||
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum)
|
||||
{
|
||||
struct mdss_mdp_pipe *pipe = NULL;
|
||||
mutex_lock(&mdss_mdp_sspp_lock);
|
||||
if (mdss_res->pipe_type_map[pnum] != MDSS_MDP_PIPE_TYPE_UNUSED)
|
||||
pipe = mdss_mdp_pipe_init(pnum);
|
||||
mutex_unlock(&mdss_mdp_sspp_lock);
|
||||
return pipe;
|
||||
}
|
||||
|
||||
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type)
|
||||
{
|
||||
struct mdss_mdp_pipe *pipe = NULL;
|
||||
int pnum;
|
||||
|
||||
mutex_lock(&mdss_mdp_sspp_lock);
|
||||
for (pnum = 0; pnum < MDSS_MDP_MAX_SSPP; pnum++) {
|
||||
if (type == mdss_res->pipe_type_map[pnum]) {
|
||||
pipe = mdss_mdp_pipe_init(pnum);
|
||||
if (pipe)
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&mdss_mdp_sspp_lock);
|
||||
|
||||
return pipe;
|
||||
}
|
||||
|
||||
struct mdss_mdp_pipe *mdss_mdp_pipe_get_locked(u32 ndx)
|
||||
{
|
||||
struct mdss_mdp_pipe *pipe = NULL;
|
||||
int i;
|
||||
|
||||
if (!ndx)
|
||||
return NULL;
|
||||
|
||||
mutex_lock(&mdss_mdp_sspp_lock);
|
||||
for (i = 0; i < MDSS_MDP_MAX_SSPP; i++) {
|
||||
pipe = &mdss_mdp_pipe_list[i];
|
||||
if (ndx == pipe->ndx)
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&mdss_mdp_sspp_lock);
|
||||
|
||||
if (i == MDSS_MDP_MAX_SSPP)
|
||||
return NULL;
|
||||
|
||||
if (mdss_mdp_pipe_lock(pipe))
|
||||
return NULL;
|
||||
|
||||
if (pipe->ndx != ndx) {
|
||||
mdss_mdp_pipe_unlock(pipe);
|
||||
pipe = NULL;
|
||||
}
|
||||
|
||||
return pipe;
|
||||
}
|
||||
|
||||
|
||||
static void mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
mdss_mdp_smp_free(pipe);
|
||||
pipe->ndx = 0;
|
||||
atomic_dec(&pipe->ref_cnt);
|
||||
mdss_mdp_pipe_unlock(pipe);
|
||||
}
|
||||
|
||||
int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
pr_debug("ndx=%x pnum=%d ref_cnt=%d\n", pipe->ndx, pipe->num,
|
||||
atomic_read(&pipe->ref_cnt));
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
|
||||
mutex_lock(&mdss_mdp_sspp_lock);
|
||||
mdss_mdp_pipe_free(pipe);
|
||||
mutex_unlock(&mdss_mdp_sspp_lock);
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdss_mdp_pipe_release_all(struct msm_fb_data_type *mfd)
|
||||
{
|
||||
struct mdss_mdp_pipe *pipe;
|
||||
int i;
|
||||
|
||||
if (!mfd)
|
||||
return -ENODEV;
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
|
||||
mutex_lock(&mdss_mdp_sspp_lock);
|
||||
for (i = 0; i < MDSS_MDP_MAX_SSPP; i++) {
|
||||
pipe = &mdss_mdp_pipe_list[i];
|
||||
if (atomic_read(&pipe->ref_cnt) && pipe->mfd == mfd) {
|
||||
pr_debug("release pnum=%d\n", pipe->num);
|
||||
if (mdss_mdp_pipe_lock(pipe) == 0) {
|
||||
mdss_mdp_mixer_pipe_unstage(pipe);
|
||||
mdss_mdp_pipe_free(pipe);
|
||||
} else {
|
||||
pr_err("unable to lock pipe=%d for release",
|
||||
pipe->num);
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&mdss_mdp_sspp_lock);
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
|
||||
u32 reg, u32 val)
|
||||
{
|
||||
int offset = MDSS_MDP_REG_SSPP_OFFSET(pipe->num);
|
||||
MDSS_MDP_REG_WRITE(offset + reg, val);
|
||||
}
|
||||
|
||||
static inline u32 mdss_mdp_pipe_read(struct mdss_mdp_pipe *pipe, u32 reg)
|
||||
{
|
||||
int offset = MDSS_MDP_REG_SSPP_OFFSET(pipe->num);
|
||||
return MDSS_MDP_REG_READ(offset + reg);
|
||||
}
|
||||
|
||||
static int mdss_mdp_leading_zero(u32 num)
|
||||
{
|
||||
u32 bit = 0x80000000;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (bit & num)
|
||||
return i;
|
||||
bit >>= 1;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 mdss_mdp_scale_phase_step(int f_num, u32 src, u32 dst)
|
||||
{
|
||||
u32 val, s;
|
||||
int n;
|
||||
|
||||
n = mdss_mdp_leading_zero(src);
|
||||
if (n > f_num)
|
||||
n = f_num;
|
||||
s = src << n; /* maximum to reduce lose of resolution */
|
||||
val = s / dst;
|
||||
if (n < f_num) {
|
||||
n = f_num - n;
|
||||
val <<= n;
|
||||
val |= ((s % dst) << n) / dst;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
u32 scale_config = 0;
|
||||
u32 phasex_step = 0, phasey_step = 0;
|
||||
u32 chroma_sample;
|
||||
|
||||
if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA) {
|
||||
if (!(pipe->flags & MDP_ROT_90) && (pipe->dst.h != pipe->src.h
|
||||
|| pipe->dst.w != pipe->src.w))
|
||||
return -EINVAL; /* no scaling supported on dma pipes */
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
chroma_sample = pipe->src_fmt->chroma_sample;
|
||||
|
||||
if ((pipe->src.h != pipe->dst.h) ||
|
||||
(chroma_sample == MDSS_MDP_CHROMA_420) ||
|
||||
(chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
|
||||
pr_debug("scale y - src_h=%d dst_h=%d\n",
|
||||
pipe->src.h, pipe->dst.h);
|
||||
|
||||
if ((pipe->src.h / MAX_DOWNSCALE_RATIO) > pipe->dst.h) {
|
||||
pr_err("too much downscaling height=%d->%d",
|
||||
pipe->src.h, pipe->dst.h);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
scale_config |= MDSS_MDP_SCALEY_EN;
|
||||
|
||||
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
|
||||
u32 chr_dst_h = pipe->dst.h;
|
||||
if ((chroma_sample == MDSS_MDP_CHROMA_420) ||
|
||||
(chroma_sample == MDSS_MDP_CHROMA_H1V2))
|
||||
chr_dst_h *= 2; /* 2x upsample chroma */
|
||||
|
||||
if (pipe->src.h <= pipe->dst.h)
|
||||
scale_config |= /* G/Y, A */
|
||||
(MDSS_MDP_SCALE_FILTER_BIL << 10) |
|
||||
(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
|
||||
else
|
||||
scale_config |= /* G/Y, A */
|
||||
(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
|
||||
(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
|
||||
|
||||
if (pipe->src.h <= chr_dst_h)
|
||||
scale_config |= /* CrCb */
|
||||
(MDSS_MDP_SCALE_FILTER_BIL << 14);
|
||||
else
|
||||
scale_config |= /* CrCb */
|
||||
(MDSS_MDP_SCALE_FILTER_PCMN << 14);
|
||||
|
||||
phasey_step = mdss_mdp_scale_phase_step(
|
||||
PHASE_STEP_SHIFT, pipe->src.h, chr_dst_h);
|
||||
|
||||
mdss_mdp_pipe_write(pipe,
|
||||
MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY,
|
||||
phasey_step);
|
||||
} else {
|
||||
if (pipe->src.h <= pipe->dst.h)
|
||||
scale_config |= /* RGB, A */
|
||||
(MDSS_MDP_SCALE_FILTER_BIL << 10) |
|
||||
(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
|
||||
else
|
||||
scale_config |= /* RGB, A */
|
||||
(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
|
||||
(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
|
||||
}
|
||||
|
||||
phasey_step = mdss_mdp_scale_phase_step(
|
||||
PHASE_STEP_SHIFT, pipe->src.h, pipe->dst.h);
|
||||
}
|
||||
|
||||
if ((pipe->src.w != pipe->dst.w) ||
|
||||
(chroma_sample == MDSS_MDP_CHROMA_420) ||
|
||||
(chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
|
||||
pr_debug("scale x - src_w=%d dst_w=%d\n",
|
||||
pipe->src.w, pipe->dst.w);
|
||||
|
||||
if ((pipe->src.w / MAX_DOWNSCALE_RATIO) > pipe->dst.w) {
|
||||
pr_err("too much downscaling width=%d->%d",
|
||||
pipe->src.w, pipe->dst.w);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
scale_config |= MDSS_MDP_SCALEX_EN;
|
||||
|
||||
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
|
||||
u32 chr_dst_w = pipe->dst.w;
|
||||
|
||||
if ((chroma_sample == MDSS_MDP_CHROMA_420) ||
|
||||
(chroma_sample == MDSS_MDP_CHROMA_H2V1))
|
||||
chr_dst_w *= 2; /* 2x upsample chroma */
|
||||
|
||||
if (pipe->src.w <= pipe->dst.w)
|
||||
scale_config |= /* G/Y, A */
|
||||
(MDSS_MDP_SCALE_FILTER_BIL << 8) |
|
||||
(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
|
||||
else
|
||||
scale_config |= /* G/Y, A */
|
||||
(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
|
||||
(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
|
||||
|
||||
if (pipe->src.w <= chr_dst_w)
|
||||
scale_config |= /* CrCb */
|
||||
(MDSS_MDP_SCALE_FILTER_BIL << 12);
|
||||
else
|
||||
scale_config |= /* CrCb */
|
||||
(MDSS_MDP_SCALE_FILTER_PCMN << 12);
|
||||
|
||||
phasex_step = mdss_mdp_scale_phase_step(
|
||||
PHASE_STEP_SHIFT, pipe->src.w, chr_dst_w);
|
||||
mdss_mdp_pipe_write(pipe,
|
||||
MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX,
|
||||
phasex_step);
|
||||
} else {
|
||||
if (pipe->src.w <= pipe->dst.w)
|
||||
scale_config |= /* RGB, A */
|
||||
(MDSS_MDP_SCALE_FILTER_BIL << 8) |
|
||||
(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
|
||||
else
|
||||
scale_config |= /* RGB, A */
|
||||
(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
|
||||
(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
|
||||
}
|
||||
|
||||
phasex_step = mdss_mdp_scale_phase_step(
|
||||
PHASE_STEP_SHIFT, pipe->src.w, pipe->dst.w);
|
||||
}
|
||||
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_CONFIG, scale_config);
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_PHASE_STEP_X, phasex_step);
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_PHASE_STEP_Y, phasey_step);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
u32 img_size, src_size, src_xy, dst_size, dst_xy, ystride0, ystride1;
|
||||
|
||||
pr_debug("pnum=%d wh=%dx%d src={%d,%d,%d,%d} dst={%d,%d,%d,%d}\n",
|
||||
pipe->num, pipe->img_width, pipe->img_height,
|
||||
pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h,
|
||||
pipe->dst.x, pipe->dst.y, pipe->dst.w, pipe->dst.h);
|
||||
|
||||
if (mdss_mdp_scale_setup(pipe))
|
||||
return -EINVAL;
|
||||
|
||||
mdss_mdp_get_plane_sizes(pipe->src_fmt->format, pipe->img_width,
|
||||
pipe->img_height, &pipe->src_planes);
|
||||
|
||||
img_size = (pipe->img_height << 16) | pipe->img_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;
|
||||
ystride0 = (pipe->src_planes.ystride[0]) |
|
||||
(pipe->src_planes.ystride[1] << 16);
|
||||
ystride1 = (pipe->src_planes.ystride[2]) |
|
||||
(pipe->src_planes.ystride[3] << 16);
|
||||
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_IMG_SIZE, img_size);
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_SIZE, src_size);
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_XY, src_xy);
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_OUT_SIZE, dst_size);
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_OUT_XY, dst_xy);
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_YSTRIDE0, ystride0);
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_YSTRIDE1, ystride1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_format_setup(struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
struct mdss_mdp_format_params *fmt;
|
||||
u32 rot90, opmode, chroma_samp;
|
||||
|
||||
fmt = pipe->src_fmt;
|
||||
|
||||
opmode = pipe->bwc_mode;
|
||||
if (pipe->flags & MDP_FLIP_LR)
|
||||
opmode |= MDSS_MDP_OP_FLIP_LR;
|
||||
if (pipe->flags & MDP_FLIP_UD)
|
||||
opmode |= MDSS_MDP_OP_FLIP_UD;
|
||||
|
||||
pr_debug("pnum=%d format=%d opmode=%x\n", pipe->num, fmt->format,
|
||||
opmode);
|
||||
|
||||
rot90 = !!(pipe->flags & MDP_SOURCE_ROTATED_90);
|
||||
|
||||
chroma_samp = fmt->chroma_sample;
|
||||
if (rot90) {
|
||||
if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
|
||||
chroma_samp = MDSS_MDP_CHROMA_H1V2;
|
||||
else if (chroma_samp == MDSS_MDP_CHROMA_H1V2)
|
||||
chroma_samp = MDSS_MDP_CHROMA_H2V1;
|
||||
}
|
||||
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT,
|
||||
(chroma_samp << 23) |
|
||||
(fmt->fetch_planes << 19) |
|
||||
(fmt->unpack_align_msb << 18) |
|
||||
(fmt->unpack_tight << 17) |
|
||||
(fmt->unpack_count << 12) |
|
||||
(rot90 << 11) |
|
||||
(fmt->bpp << 9) |
|
||||
(fmt->alpha_enable << 8) |
|
||||
(fmt->a_bit << 6) |
|
||||
(fmt->r_bit << 4) |
|
||||
(fmt->b_bit << 2) |
|
||||
(fmt->g_bit << 0));
|
||||
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN,
|
||||
(fmt->element3 << 24) |
|
||||
(fmt->element2 << 16) |
|
||||
(fmt->element1 << 8) |
|
||||
(fmt->element0 << 0));
|
||||
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_OP_MODE, opmode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_vig_setup(struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
u32 opmode = 0;
|
||||
|
||||
pr_debug("pnum=%x\n", pipe->num);
|
||||
|
||||
if (pipe->src_fmt->is_yuv)
|
||||
opmode |= (0 << 19) | /* DST_DATA=RGB */
|
||||
(1 << 18) | /* SRC_DATA=YCBCR */
|
||||
(1 << 17); /* CSC_1_EN */
|
||||
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE, opmode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
|
||||
struct mdss_mdp_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_debug("pnum=%d\n", pipe->num);
|
||||
|
||||
if (pipe->type != MDSS_MDP_PIPE_TYPE_DMA)
|
||||
data->bwc_enabled = pipe->bwc_mode;
|
||||
|
||||
ret = mdss_mdp_data_check(data, &pipe->src_planes);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data->p[0].addr);
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data->p[1].addr);
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data->p[2].addr);
|
||||
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data->p[3].addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
|
||||
struct mdss_mdp_data *src_data)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 params_changed;
|
||||
|
||||
if (!pipe) {
|
||||
pr_err("pipe not setup properly for queue\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!pipe->mixer) {
|
||||
pr_err("pipe mixer not setup properly for queue\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pr_debug("pnum=%x mixer=%d\n", pipe->num, pipe->mixer->num);
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
|
||||
|
||||
params_changed = pipe->params_changed;
|
||||
if (params_changed) {
|
||||
pipe->params_changed = 0;
|
||||
|
||||
ret = mdss_mdp_image_setup(pipe);
|
||||
if (ret) {
|
||||
pr_err("image setup error for pnum=%d\n", pipe->num);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = mdss_mdp_format_setup(pipe);
|
||||
if (ret) {
|
||||
pr_err("format %d setup error pnum=%d\n",
|
||||
pipe->src_fmt->format, pipe->num);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)
|
||||
mdss_mdp_vig_setup(pipe);
|
||||
|
||||
ret = mdss_mdp_smp_reserve(pipe);
|
||||
if (ret) {
|
||||
pr_err("unable to reserve smp for pnum=%d\n",
|
||||
pipe->num);
|
||||
goto done;
|
||||
}
|
||||
|
||||
mdss_mdp_smp_alloc(pipe);
|
||||
}
|
||||
|
||||
ret = mdss_mdp_src_addr_setup(pipe, src_data);
|
||||
if (ret) {
|
||||
pr_err("addr setup error for pnum=%d\n", pipe->num);
|
||||
goto done;
|
||||
}
|
||||
|
||||
mdss_mdp_mixer_pipe_update(pipe, params_changed);
|
||||
|
||||
pipe->play_cnt++;
|
||||
|
||||
done:
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
|
||||
|
||||
return ret;
|
||||
}
|
278
drivers/video/msm/mdss/mdss_mdp_util.c
Normal file
278
drivers/video/msm/mdss/mdss_mdp_util.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
/* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/android_pmem.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/ion.h>
|
||||
#include <linux/msm_kgsl.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "mdss_fb.h"
|
||||
#include "mdss_mdp.h"
|
||||
#include "mdss_mdp_formats.h"
|
||||
|
||||
enum {
|
||||
MDP_INTR_VSYNC_INTF_0,
|
||||
MDP_INTR_VSYNC_INTF_1,
|
||||
MDP_INTR_VSYNC_INTF_2,
|
||||
MDP_INTR_VSYNC_INTF_3,
|
||||
MDP_INTR_PING_PONG_0,
|
||||
MDP_INTR_PING_PONG_1,
|
||||
MDP_INTR_PING_PONG_2,
|
||||
MDP_INTR_WB_0,
|
||||
MDP_INTR_WB_1,
|
||||
MDP_INTR_WB_2,
|
||||
MDP_INTR_MAX,
|
||||
};
|
||||
|
||||
struct intr_callback {
|
||||
void (*func)(void *);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
struct intr_callback mdp_intr_cb[MDP_INTR_MAX];
|
||||
static DEFINE_SPINLOCK(mdss_mdp_intr_lock);
|
||||
|
||||
static int mdss_mdp_intr2index(u32 intr_type, u32 intf_num)
|
||||
{
|
||||
int index = -1;
|
||||
switch (intr_type) {
|
||||
case MDSS_MDP_IRQ_INTF_VSYNC:
|
||||
index = MDP_INTR_VSYNC_INTF_0 + intf_num;
|
||||
break;
|
||||
case MDSS_MDP_IRQ_PING_PONG_COMP:
|
||||
index = MDP_INTR_PING_PONG_0 + intf_num;
|
||||
break;
|
||||
case MDSS_MDP_IRQ_WB_ROT_COMP:
|
||||
index = MDP_INTR_WB_0 + intf_num;
|
||||
break;
|
||||
case MDSS_MDP_IRQ_WB_WFD:
|
||||
index = MDP_INTR_WB_2 + intf_num;
|
||||
break;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
|
||||
void (*fnc_ptr)(void *), void *arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
int index, ret;
|
||||
|
||||
index = mdss_mdp_intr2index(intr_type, intf_num);
|
||||
if (index < 0) {
|
||||
pr_warn("invalid intr type=%u intf_num=%u\n",
|
||||
intr_type, intf_num);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&mdss_mdp_intr_lock, flags);
|
||||
if (!mdp_intr_cb[index].func) {
|
||||
mdp_intr_cb[index].func = fnc_ptr;
|
||||
mdp_intr_cb[index].arg = arg;
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = -EBUSY;
|
||||
}
|
||||
spin_unlock_irqrestore(&mdss_mdp_intr_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void mdss_mdp_intr_done(int index)
|
||||
{
|
||||
void (*fnc)(void *);
|
||||
void *arg;
|
||||
|
||||
spin_lock(&mdss_mdp_intr_lock);
|
||||
fnc = mdp_intr_cb[index].func;
|
||||
arg = mdp_intr_cb[index].arg;
|
||||
if (fnc != NULL)
|
||||
mdp_intr_cb[index].func = NULL;
|
||||
spin_unlock(&mdss_mdp_intr_lock);
|
||||
if (fnc)
|
||||
fnc(arg);
|
||||
}
|
||||
|
||||
irqreturn_t mdss_mdp_isr(int irq, void *ptr)
|
||||
{
|
||||
u32 isr, mask;
|
||||
|
||||
|
||||
isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_STATUS);
|
||||
if (isr == 0)
|
||||
goto done;
|
||||
|
||||
pr_devel("isr=%x\n", isr);
|
||||
|
||||
mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN);
|
||||
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr);
|
||||
|
||||
isr &= mask;
|
||||
if (isr == 0)
|
||||
goto done;
|
||||
|
||||
if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE)
|
||||
mdss_mdp_intr_done(MDP_INTR_PING_PONG_0);
|
||||
|
||||
if (isr & MDSS_MDP_INTR_PING_PONG_1_DONE)
|
||||
mdss_mdp_intr_done(MDP_INTR_PING_PONG_1);
|
||||
|
||||
if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE)
|
||||
mdss_mdp_intr_done(MDP_INTR_PING_PONG_2);
|
||||
|
||||
if (isr & MDSS_MDP_INTR_INTF_0_VSYNC)
|
||||
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
|
||||
|
||||
if (isr & MDSS_MDP_INTR_INTF_1_VSYNC)
|
||||
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_1);
|
||||
|
||||
if (isr & MDSS_MDP_INTR_INTF_2_VSYNC)
|
||||
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_2);
|
||||
|
||||
if (isr & MDSS_MDP_INTR_INTF_3_VSYNC)
|
||||
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_3);
|
||||
|
||||
if (isr & MDSS_MDP_INTR_WB_0_DONE)
|
||||
mdss_mdp_intr_done(MDP_INTR_WB_0);
|
||||
|
||||
if (isr & MDSS_MDP_INTR_WB_1_DONE)
|
||||
mdss_mdp_intr_done(MDP_INTR_WB_1);
|
||||
|
||||
if (isr & MDSS_MDP_INTR_WB_2_DONE)
|
||||
mdss_mdp_intr_done(MDP_INTR_WB_2);
|
||||
|
||||
done:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format)
|
||||
{
|
||||
struct mdss_mdp_format_params *fmt = NULL;
|
||||
if (format < MDP_IMGTYPE_LIMIT) {
|
||||
fmt = &mdss_mdp_format_map[format];
|
||||
if (fmt->format != format)
|
||||
fmt = NULL;
|
||||
}
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
|
||||
struct mdss_mdp_plane_sizes *ps)
|
||||
{
|
||||
struct mdss_mdp_format_params *fmt;
|
||||
int i;
|
||||
|
||||
if (ps == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if ((w > MAX_IMG_WIDTH) || (h > MAX_IMG_HEIGHT))
|
||||
return -ERANGE;
|
||||
|
||||
fmt = mdss_mdp_get_format_params(format);
|
||||
if (!fmt)
|
||||
return -EINVAL;
|
||||
|
||||
memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
|
||||
|
||||
if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
|
||||
u32 bpp = fmt->bpp + 1;
|
||||
ps->num_planes = 1;
|
||||
ps->plane_size[0] = w * h * bpp;
|
||||
ps->ystride[0] = w * bpp;
|
||||
} else {
|
||||
u8 hmap[] = { 1, 2, 1, 2 };
|
||||
u8 vmap[] = { 1, 1, 2, 2 };
|
||||
u8 horiz, vert;
|
||||
|
||||
horiz = hmap[fmt->chroma_sample];
|
||||
vert = vmap[fmt->chroma_sample];
|
||||
|
||||
if (format == MDP_Y_CR_CB_GH2V2) {
|
||||
ps->plane_size[0] = ALIGN(w, 16) * h;
|
||||
ps->plane_size[1] = ALIGN(w / horiz, 16) * (h / vert);
|
||||
ps->ystride[0] = ALIGN(w, 16);
|
||||
ps->ystride[1] = ALIGN(w / horiz, 16);
|
||||
} else {
|
||||
ps->plane_size[0] = w * h;
|
||||
ps->plane_size[1] = (w / horiz) * (h / vert);
|
||||
ps->ystride[0] = w;
|
||||
ps->ystride[1] = (w / horiz);
|
||||
}
|
||||
|
||||
if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
|
||||
ps->num_planes = 2;
|
||||
ps->plane_size[1] *= 2;
|
||||
ps->ystride[1] *= 2;
|
||||
} else { /* planar */
|
||||
ps->num_planes = 3;
|
||||
ps->plane_size[2] = ps->plane_size[1];
|
||||
ps->ystride[2] = ps->ystride[1];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ps->num_planes; i++)
|
||||
ps->total_size += ps->plane_size[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdss_mdp_data_check(struct mdss_mdp_data *data,
|
||||
struct mdss_mdp_plane_sizes *ps)
|
||||
{
|
||||
if (!ps)
|
||||
return 0;
|
||||
|
||||
if (!data || data->num_planes == 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (data->bwc_enabled) {
|
||||
return -EPERM; /* not supported */
|
||||
} else {
|
||||
struct mdss_mdp_img_data *prev, *curr;
|
||||
int i;
|
||||
|
||||
pr_debug("srcp0=%x len=%u frame_size=%u\n", data->p[0].addr,
|
||||
data->p[0].len, ps->total_size);
|
||||
|
||||
for (i = 0; i < ps->num_planes; i++) {
|
||||
curr = &data->p[i];
|
||||
if (i >= data->num_planes) {
|
||||
u32 psize = ps->plane_size[i-1];
|
||||
prev = &data->p[i-1];
|
||||
if (prev->len > psize) {
|
||||
curr->len = prev->len - psize;
|
||||
prev->len = psize;
|
||||
}
|
||||
curr->addr = prev->addr + psize;
|
||||
}
|
||||
if (curr->len < ps->plane_size[i]) {
|
||||
pr_err("insufficient mem=%u p=%d len=%u\n",
|
||||
curr->len, i, ps->plane_size[i]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
pr_debug("plane[%d] addr=%x len=%u\n", i,
|
||||
curr->addr, curr->len);
|
||||
}
|
||||
data->num_planes = ps->num_planes;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
176
drivers/video/msm/mdss/mdss_panel.h
Normal file
176
drivers/video/msm/mdss/mdss_panel.h
Normal file
|
@ -0,0 +1,176 @@
|
|||
/* Copyright (c) 2008-2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MDSS_PANEL_H
|
||||
#define MDSS_PANEL_H
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* panel id type */
|
||||
struct panel_id {
|
||||
u16 id;
|
||||
u16 type;
|
||||
};
|
||||
|
||||
/* panel type list */
|
||||
#define NO_PANEL 0xffff /* No Panel */
|
||||
#define MDDI_PANEL 1 /* MDDI */
|
||||
#define EBI2_PANEL 2 /* EBI2 */
|
||||
#define LCDC_PANEL 3 /* internal LCDC type */
|
||||
#define EXT_MDDI_PANEL 4 /* Ext.MDDI */
|
||||
#define TV_PANEL 5 /* TV */
|
||||
#define HDMI_PANEL 6 /* HDMI TV */
|
||||
#define DTV_PANEL 7 /* DTV */
|
||||
#define MIPI_VIDEO_PANEL 8 /* MIPI */
|
||||
#define MIPI_CMD_PANEL 9 /* MIPI */
|
||||
#define WRITEBACK_PANEL 10 /* Wifi display */
|
||||
#define LVDS_PANEL 11 /* LVDS */
|
||||
#define EDP_PANEL 12 /* LVDS */
|
||||
|
||||
/* panel class */
|
||||
enum {
|
||||
DISPLAY_LCD = 0, /* lcd = ebi2/mddi */
|
||||
DISPLAY_LCDC, /* lcdc */
|
||||
DISPLAY_TV, /* TV Out */
|
||||
DISPLAY_EXT_MDDI, /* External MDDI */
|
||||
DISPLAY_WRITEBACK,
|
||||
};
|
||||
|
||||
/* panel device locaiton */
|
||||
enum {
|
||||
DISPLAY_1 = 0, /* attached as first device */
|
||||
DISPLAY_2, /* attached on second device */
|
||||
DISPLAY_3, /* attached on third writeback device */
|
||||
MAX_PHYS_TARGET_NUM,
|
||||
};
|
||||
|
||||
/* panel info type */
|
||||
struct lcd_panel_info {
|
||||
u32 vsync_enable;
|
||||
u32 refx100;
|
||||
u32 v_back_porch;
|
||||
u32 v_front_porch;
|
||||
u32 v_pulse_width;
|
||||
u32 hw_vsync_mode;
|
||||
u32 vsync_notifier_period;
|
||||
u32 rev;
|
||||
};
|
||||
|
||||
struct lcdc_panel_info {
|
||||
u32 h_back_porch;
|
||||
u32 h_front_porch;
|
||||
u32 h_pulse_width;
|
||||
u32 v_back_porch;
|
||||
u32 v_front_porch;
|
||||
u32 v_pulse_width;
|
||||
u32 border_clr;
|
||||
u32 underflow_clr;
|
||||
u32 hsync_skew;
|
||||
/* Pad width */
|
||||
u32 xres_pad;
|
||||
/* Pad height */
|
||||
u32 yres_pad;
|
||||
};
|
||||
|
||||
struct mipi_panel_info {
|
||||
char mode; /* video/cmd */
|
||||
char interleave_mode;
|
||||
char crc_check;
|
||||
char ecc_check;
|
||||
char dst_format; /* shared by video and command */
|
||||
char data_lane0;
|
||||
char data_lane1;
|
||||
char data_lane2;
|
||||
char data_lane3;
|
||||
char dlane_swap; /* data lane swap */
|
||||
char rgb_swap;
|
||||
char b_sel;
|
||||
char g_sel;
|
||||
char r_sel;
|
||||
char rx_eot_ignore;
|
||||
char tx_eot_append;
|
||||
char t_clk_post; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
|
||||
char t_clk_pre; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
|
||||
char vc; /* virtual channel */
|
||||
struct mipi_dsi_phy_ctrl *dsi_phy_db;
|
||||
/* video mode */
|
||||
char pulse_mode_hsa_he;
|
||||
char hfp_power_stop;
|
||||
char hbp_power_stop;
|
||||
char hsa_power_stop;
|
||||
char eof_bllp_power_stop;
|
||||
char bllp_power_stop;
|
||||
char traffic_mode;
|
||||
char frame_rate;
|
||||
/* command mode */
|
||||
char interleave_max;
|
||||
char insert_dcs_cmd;
|
||||
char wr_mem_continue;
|
||||
char wr_mem_start;
|
||||
char te_sel;
|
||||
char stream; /* 0 or 1 */
|
||||
char mdp_trigger;
|
||||
char dma_trigger;
|
||||
u32 dsi_pclk_rate;
|
||||
/* The packet-size should not bet changed */
|
||||
char no_max_pkt_size;
|
||||
/* Clock required during LP commands */
|
||||
char force_clk_lane_hs;
|
||||
};
|
||||
|
||||
enum lvds_mode {
|
||||
LVDS_SINGLE_CHANNEL_MODE,
|
||||
LVDS_DUAL_CHANNEL_MODE,
|
||||
};
|
||||
|
||||
struct lvds_panel_info {
|
||||
enum lvds_mode channel_mode;
|
||||
/* Channel swap in dual mode */
|
||||
char channel_swap;
|
||||
};
|
||||
|
||||
struct mdss_panel_info {
|
||||
u32 xres;
|
||||
u32 yres;
|
||||
u32 bpp;
|
||||
u32 type;
|
||||
u32 wait_cycle;
|
||||
u32 pdest;
|
||||
u32 bl_max;
|
||||
u32 bl_min;
|
||||
u32 fb_num;
|
||||
u32 clk_rate;
|
||||
u32 clk_min;
|
||||
u32 clk_max;
|
||||
u32 frame_count;
|
||||
u32 is_3d_panel;
|
||||
u32 out_format;
|
||||
|
||||
struct lcd_panel_info lcd;
|
||||
struct lcdc_panel_info lcdc;
|
||||
struct mipi_panel_info mipi;
|
||||
struct lvds_panel_info lvds;
|
||||
};
|
||||
|
||||
struct mdss_panel_data {
|
||||
struct mdss_panel_info panel_info;
|
||||
void (*set_backlight) (u32 bl_level);
|
||||
|
||||
/* function entry chain */
|
||||
int (*on) (struct mdss_panel_data *pdata);
|
||||
int (*off) (struct mdss_panel_data *pdata);
|
||||
};
|
||||
|
||||
int mdss_register_panel(struct mdss_panel_data *pdata);
|
||||
#endif /* MDSS_PANEL_H */
|
|
@ -86,6 +86,8 @@ enum {
|
|||
MDP_YCRYCB_H2V1, /* YCrYCb interleave */
|
||||
MDP_Y_CRCB_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */
|
||||
MDP_Y_CBCR_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */
|
||||
MDP_Y_CRCB_H1V2,
|
||||
MDP_Y_CBCR_H1V2,
|
||||
MDP_RGBA_8888, /* ARGB 888 */
|
||||
MDP_BGRA_8888, /* ABGR 888 */
|
||||
MDP_RGBX_8888, /* RGBX 888 */
|
||||
|
@ -98,10 +100,10 @@ enum {
|
|||
MDP_Y_CBCR_H1V1, /* Y and CbCr, pseduo planer w/ Cb is in MSB */
|
||||
MDP_YCRCB_H1V1, /* YCrCb interleave */
|
||||
MDP_YCBCR_H1V1, /* YCbCr interleave */
|
||||
MDP_BGR_565, /* BGR 565 planer */
|
||||
MDP_IMGTYPE_LIMIT,
|
||||
MDP_RGB_BORDERFILL, /* border fill pipe */
|
||||
MDP_BGR_565 = MDP_IMGTYPE2_START, /* BGR 565 planer */
|
||||
MDP_FB_FORMAT, /* framebuffer format */
|
||||
MDP_FB_FORMAT = MDP_IMGTYPE2_START, /* framebuffer format */
|
||||
MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */
|
||||
};
|
||||
|
||||
|
@ -118,6 +120,8 @@ enum {
|
|||
NUM_HSIC_PARAM,
|
||||
};
|
||||
|
||||
#define MDSS_MDP_RIGHT_MIXER 0x100
|
||||
|
||||
/* mdp_blit_req flag values */
|
||||
#define MDP_ROT_NOP 0
|
||||
#define MDP_FLIP_LR 0x1
|
||||
|
|
Loading…
Reference in a new issue