Staging: add MSM framebuffer driver

Qualcomm development of the MSM SOC framebuffer driver has
diverged significantly from the driver used by Android. This
is a snapshot of our current driver, in all it's agony. We are
putting this in staging to help with the process of converging
the two drivers.

At this point, the driver has been tested only in dumb
framebuffer mode.

Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org>
Signed-off-by: David Brown <davidb@codeaurora.org>
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
[dwalker@codeaurora.org: added a small compile fix and TODO.]
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Stepan Moskovchenko 2010-05-19 11:03:30 -07:00 committed by Greg Kroah-Hartman
parent 34ef545aa8
commit 9d20015391
70 changed files with 30037 additions and 0 deletions

View file

@ -145,5 +145,7 @@ source "drivers/staging/xgifb/Kconfig"
source "drivers/staging/mrst-touchscreen/Kconfig"
source "drivers/staging/msm/Kconfig"
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING

View file

@ -53,3 +53,4 @@ obj-$(CONFIG_TI_ST) += ti-st/
obj-$(CONFIG_ADIS16255) += adis16255/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/
obj-$(CONFIG_MSM_STAGING) += msm/

134
drivers/staging/msm/Kconfig Normal file
View file

@ -0,0 +1,134 @@
config MSM_STAGING
tristate "MSM Frame Buffer Support"
depends on FB && ARCH_MSM && !FB_MSM
select FB_BACKLIGHT if FB_MSM_BACKLIGHT
select NEW_LEDS
select LEDS_CLASS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
---help---
Support for MSM Framebuffer.
if MSM_STAGING
config FB_MSM_LCDC_HW
bool
default n
choice
prompt "MDP HW version"
default FB_MSM_MDP31
config FB_MSM_MDP31
select FB_MSM_LCDC_HW
bool "MDP HW ver3.1"
---help---
Support for MSM MDP HW revision 3.1
Say Y here if this is msm8x50 variant platform.
endchoice
config FB_MSM_LCDC
bool
default n
config FB_MSM_TVOUT
bool
default n
config FB_MSM_LCDC_PANEL
bool
select FB_MSM_LCDC
default n
config FB_MSM_LCDC_PRISM_WVGA
bool
select FB_MSM_LCDC_PANEL
default n
config FB_MSM_LCDC_ST1_WXGA
bool
select FB_MSM_LCDC_PANEL
default n
config FB_MSM_LCDC_ST15_WXGA
bool
select FB_MSM_LCDC_PANEL
default n
config FB_MSM_LCDC_WXGA
bool
select FB_MSM_LCDC_PANEL
default n
choice
prompt "LCD Panel"
default FB_MSM_LCDC_ST15_PANEL
config FB_MSM_LCDC_PRISM_WVGA_PANEL
depends on FB_MSM_LCDC_HW
bool "LCDC Prism WVGA Panel"
select FB_MSM_LCDC_PRISM_WVGA
---help---
Support for LCDC Prism WVGA (800x480) panel
config FB_MSM_LCDC_ST15_PANEL
depends on FB_MSM_LCDC_HW
bool "LCDC ST1.5 Panel"
select FB_MSM_LCDC_ST15_WXGA
---help---
Support for ST1.5 WXGA (1366x768) panel
config FB_MSM_PANEL_NONE
bool "NONE"
---help---
This will disable LCD panel
endchoice
choice
prompt "Secondary LCD Panel"
depends on FB_MSM_MDP31
default FB_MSM_SECONDARY_PANEL_NONE
config FB_MSM_SECONDARY_PANEL_NONE
bool "NONE"
---help---
No secondary panel
endchoice
config FB_MSM_TVOUT_NTSC
bool
select FB_MSM_TVOUT
default n
config FB_MSM_TVOUT_PAL
bool
select FB_MSM_TVOUT
default n
choice
depends on (FB_MSM_MDP22 || FB_MSM_MDP31)
prompt "TVOut Region"
default FB_MSM_TVOUT_NTSC_M
config FB_MSM_TVOUT_NTSC_M
bool "NTSC M"
select FB_MSM_TVOUT_NTSC
---help---
Support for NTSC M region (North American and Korea)
config FB_MSM_TVOUT_NONE
bool "NONE"
---help---
This will disable TV Out functionality.
endchoice
config PMEM_KERNEL_SIZE
int "PMEM for kernel components (in MB)"
default 2
depends on ARCH_QSD8X50
help
Configures the amount of PMEM for use by kernel components
(in MB; minimum 2MB)
endif

View file

@ -0,0 +1,93 @@
obj-y := msm_fb.o staging-devices.o memory.o
obj-$(CONFIG_FB_MSM_LOGO) += logo.o
obj-$(CONFIG_FB_BACKLIGHT) += msm_fb_bl.o
# MDP
obj-y += mdp.o
ifeq ($(CONFIG_FB_MSM_MDP40),y)
obj-y += mdp4_util.o
obj-$(CONFIG_DEBUG_FS) += mdp4_debugfs.o
else
obj-y += mdp_hw_init.o
obj-y += mdp_ppp.o
ifeq ($(CONFIG_FB_MSM_MDP31),y)
obj-y += mdp_ppp_v31.o
obj-$(CONFIG_MDP_PPP_ASYNC_OP) += mdp_ppp_dq.o
else
obj-y += mdp_ppp_v20.o
endif
endif
ifeq ($(CONFIG_FB_MSM_OVERLAY),y)
obj-y += mdp4_overlay.o
obj-y += mdp4_overlay_lcdc.o
obj-y += mdp4_overlay_mddi.o
else
obj-y += mdp_dma_lcdc.o
endif
obj-y += mdp_dma.o
obj-y += mdp_dma_s.o
obj-y += mdp_vsync.o
obj-y += mdp_cursor.o
obj-y += mdp_dma_tv.o
# EBI2
obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o
# LCDC
obj-$(CONFIG_FB_MSM_LCDC) += lcdc.o
# MDDI
msm_mddi-objs := mddi.o mddihost.o mddihosti.o
obj-$(CONFIG_FB_MSM_MDDI) += msm_mddi.o
# External MDDI
msm_mddi_ext-objs := mddihost_e.o mddi_ext.o
obj-$(CONFIG_FB_MSM_EXTMDDI) += msm_mddi_ext.o
# TVEnc
obj-$(CONFIG_FB_MSM_TVOUT) += tvenc.o
# MSM FB Panel
obj-y += msm_fb_panel.o
obj-$(CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF) += ebi2_tmd20.o
obj-$(CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF) += ebi2_l2f.o
ifeq ($(CONFIG_FB_MSM_MDDI_AUTO_DETECT),y)
obj-y += mddi_prism.o
obj-y += mddi_toshiba.o
obj-y += mddi_toshiba_vga.o
obj-y += mddi_toshiba_wvga_pt.o
obj-y += mddi_toshiba_wvga.o
obj-y += mddi_sharp.o
else
obj-$(CONFIG_FB_MSM_MDDI_PRISM_WVGA) += mddi_prism.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON) += mddi_toshiba.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA) += mddi_toshiba_vga.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT) += mddi_toshiba_wvga_pt.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA) += mddi_toshiba_wvga.o
obj-$(CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128) += mddi_sharp.o
endif
obj-$(CONFIG_FB_MSM_LCDC_PANEL) += lcdc_panel.o
obj-$(CONFIG_FB_MSM_LCDC_PRISM_WVGA) += lcdc_prism.o
obj-$(CONFIG_FB_MSM_LCDC_EXTERNAL_WXGA) += lcdc_external.o
obj-$(CONFIG_FB_MSM_LCDC_GORDON_VGA) += lcdc_gordon.o
obj-$(CONFIG_FB_MSM_LCDC_WXGA) += lcdc_wxga.o
obj-$(CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT) += lcdc_toshiba_wvga_pt.o
obj-$(CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT) += lcdc_sharp_wvga_pt.o
obj-$(CONFIG_FB_MSM_LCDC_GRAPEFRUIT_VGA) += lcdc_grapefruit.o
obj-$(CONFIG_FB_MSM_LCDC_ST1_WXGA) += lcdc_st1_wxga.o
obj-$(CONFIG_FB_MSM_LCDC_ST15_WXGA) += lcdc_st15.o
obj-$(CONFIG_FB_MSM_HDMI_SII_EXTERNAL_720P) += hdmi_sii9022.o
obj-$(CONFIG_FB_MSM_TVOUT_NTSC) += tv_ntsc.o
obj-$(CONFIG_FB_MSM_TVOUT_PAL) += tv_pal.o
obj-$(CONFIG_FB_MSM_EXTMDDI_SVGA) += mddi_ext_lcd.o
clean:
rm *.o .*cmd

3
drivers/staging/msm/TODO Normal file
View file

@ -0,0 +1,3 @@
- Merge this code with the existing MSM framebuffer
- General style clean ups.

View file

@ -0,0 +1,569 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include <linux/memory.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include "linux/proc_fs.h"
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
/* The following are for MSM5100 on Gator
*/
#ifdef FEATURE_PM1000
#include "pm1000.h"
#endif /* FEATURE_PM1000 */
/* The following are for MSM6050 on Bambi
*/
#ifdef FEATURE_PMIC_LCDKBD_LED_DRIVER
#include "pm.h"
#endif /* FEATURE_PMIC_LCDKBD_LED_DRIVER */
#ifdef DISP_DEVICE_18BPP
#undef DISP_DEVICE_18BPP
#define DISP_DEVICE_16BPP
#endif
#define QCIF_WIDTH 176
#define QCIF_HEIGHT 220
static void *DISP_CMD_PORT;
static void *DISP_DATA_PORT;
#define DISP_CMD_DISON 0xaf
#define DISP_CMD_DISOFF 0xae
#define DISP_CMD_DISNOR 0xa6
#define DISP_CMD_DISINV 0xa7
#define DISP_CMD_DISCTL 0xca
#define DISP_CMD_GCP64 0xcb
#define DISP_CMD_GCP16 0xcc
#define DISP_CMD_GSSET 0xcd
#define DISP_GS_2 0x02
#define DISP_GS_16 0x01
#define DISP_GS_64 0x00
#define DISP_CMD_SLPIN 0x95
#define DISP_CMD_SLPOUT 0x94
#define DISP_CMD_SD_PSET 0x75
#define DISP_CMD_MD_PSET 0x76
#define DISP_CMD_SD_CSET 0x15
#define DISP_CMD_MD_CSET 0x16
#define DISP_CMD_DATCTL 0xbc
#define DISP_DATCTL_666 0x08
#define DISP_DATCTL_565 0x28
#define DISP_DATCTL_444 0x38
#define DISP_CMD_RAMWR 0x5c
#define DISP_CMD_RAMRD 0x5d
#define DISP_CMD_PTLIN 0xa8
#define DISP_CMD_PTLOUT 0xa9
#define DISP_CMD_ASCSET 0xaa
#define DISP_CMD_SCSTART 0xab
#define DISP_CMD_VOLCTL 0xc6
#define DISP_VOLCTL_TONE 0x80
#define DISP_CMD_NOp 0x25
#define DISP_CMD_OSSEL 0xd0
#define DISP_CMD_3500KSET 0xd1
#define DISP_CMD_3500KEND 0xd2
#define DISP_CMD_14MSET 0xd3
#define DISP_CMD_14MEND 0xd4
#define DISP_CMD_OUT(cmd) outpw(DISP_CMD_PORT, cmd);
#define DISP_DATA_OUT(data) outpw(DISP_DATA_PORT, data);
#define DISP_DATA_IN() inpw(DISP_DATA_PORT);
/* Epson device column number starts at 2
*/
#define DISP_SET_RECT(ulhc_row, lrhc_row, ulhc_col, lrhc_col) \
DISP_CMD_OUT(DISP_CMD_SD_PSET) \
DISP_DATA_OUT((ulhc_row) & 0xFF) \
DISP_DATA_OUT((ulhc_row) >> 8) \
DISP_DATA_OUT((lrhc_row) & 0xFF) \
DISP_DATA_OUT((lrhc_row) >> 8) \
DISP_CMD_OUT(DISP_CMD_SD_CSET) \
DISP_DATA_OUT(((ulhc_col)+2) & 0xFF) \
DISP_DATA_OUT(((ulhc_col)+2) >> 8) \
DISP_DATA_OUT(((lrhc_col)+2) & 0xFF) \
DISP_DATA_OUT(((lrhc_col)+2) >> 8)
#define DISP_MIN_CONTRAST 0
#define DISP_MAX_CONTRAST 127
#define DISP_DEFAULT_CONTRAST 80
#define DISP_MIN_BACKLIGHT 0
#define DISP_MAX_BACKLIGHT 15
#define DISP_DEFAULT_BACKLIGHT 2
#define WAIT_SEC(sec) mdelay((sec)/1000)
static word disp_area_start_row;
static word disp_area_end_row;
static byte disp_contrast = DISP_DEFAULT_CONTRAST;
static boolean disp_powered_up;
static boolean disp_initialized = FALSE;
/* For some reason the contrast set at init time is not good. Need to do
* it again
*/
static boolean display_on = FALSE;
static void epsonQcif_disp_init(struct platform_device *pdev);
static void epsonQcif_disp_set_contrast(word contrast);
static void epsonQcif_disp_set_display_area(word start_row, word end_row);
static int epsonQcif_disp_off(struct platform_device *pdev);
static int epsonQcif_disp_on(struct platform_device *pdev);
static void epsonQcif_disp_set_rect(int x, int y, int xres, int yres);
volatile word databack;
static void epsonQcif_disp_init(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
int i;
if (disp_initialized)
return;
mfd = platform_get_drvdata(pdev);
DISP_CMD_PORT = mfd->cmd_port;
DISP_DATA_PORT = mfd->data_port;
/* Sleep in */
DISP_CMD_OUT(DISP_CMD_SLPIN);
/* Display off */
DISP_CMD_OUT(DISP_CMD_DISOFF);
/* Display normal */
DISP_CMD_OUT(DISP_CMD_DISNOR);
/* Set data mode */
DISP_CMD_OUT(DISP_CMD_DATCTL);
DISP_DATA_OUT(DISP_DATCTL_565);
/* Set display timing */
DISP_CMD_OUT(DISP_CMD_DISCTL);
DISP_DATA_OUT(0x1c); /* p1 */
DISP_DATA_OUT(0x02); /* p1 */
DISP_DATA_OUT(0x82); /* p2 */
DISP_DATA_OUT(0x00); /* p3 */
DISP_DATA_OUT(0x00); /* p4 */
DISP_DATA_OUT(0xe0); /* p5 */
DISP_DATA_OUT(0x00); /* p5 */
DISP_DATA_OUT(0xdc); /* p6 */
DISP_DATA_OUT(0x00); /* p6 */
DISP_DATA_OUT(0x02); /* p7 */
DISP_DATA_OUT(0x00); /* p8 */
/* Set 64 gray scale level */
DISP_CMD_OUT(DISP_CMD_GCP64);
DISP_DATA_OUT(0x08); /* p01 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0x2a); /* p02 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0x4e); /* p03 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0x6b); /* p04 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0x88); /* p05 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0xa3); /* p06 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0xba); /* p07 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0xd1); /* p08 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0xe5); /* p09 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0xf3); /* p10 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0x03); /* p11 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x13); /* p12 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x22); /* p13 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x2f); /* p14 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x3b); /* p15 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x46); /* p16 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x51); /* p17 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x5b); /* p18 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x64); /* p19 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x6c); /* p20 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x74); /* p21 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x7c); /* p22 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x83); /* p23 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x8a); /* p24 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x91); /* p25 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x98); /* p26 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x9f); /* p27 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xa6); /* p28 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xac); /* p29 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xb2); /* p30 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xb7); /* p31 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xbc); /* p32 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xc1); /* p33 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xc6); /* p34 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xcb); /* p35 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xd0); /* p36 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xd4); /* p37 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xd8); /* p38 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xdc); /* p39 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xe0); /* p40 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xe4); /* p41 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xe8); /* p42 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xec); /* p43 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xf0); /* p44 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xf4); /* p45 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xf8); /* p46 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xfb); /* p47 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xfe); /* p48 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x01); /* p49 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x03); /* p50 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x05); /* p51 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x07); /* p52 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x09); /* p53 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x0b); /* p54 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x0d); /* p55 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x0f); /* p56 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x11); /* p57 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x13); /* p58 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x15); /* p59 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x17); /* p60 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x19); /* p61 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x1b); /* p62 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x1c); /* p63 */
DISP_DATA_OUT(0x02);
/* Set 16 gray scale level */
DISP_CMD_OUT(DISP_CMD_GCP16);
DISP_DATA_OUT(0x1a); /* p01 */
DISP_DATA_OUT(0x32); /* p02 */
DISP_DATA_OUT(0x42); /* p03 */
DISP_DATA_OUT(0x4c); /* p04 */
DISP_DATA_OUT(0x58); /* p05 */
DISP_DATA_OUT(0x5f); /* p06 */
DISP_DATA_OUT(0x66); /* p07 */
DISP_DATA_OUT(0x6b); /* p08 */
DISP_DATA_OUT(0x70); /* p09 */
DISP_DATA_OUT(0x74); /* p10 */
DISP_DATA_OUT(0x78); /* p11 */
DISP_DATA_OUT(0x7b); /* p12 */
DISP_DATA_OUT(0x7e); /* p13 */
DISP_DATA_OUT(0x80); /* p14 */
DISP_DATA_OUT(0x82); /* p15 */
/* Set DSP column */
DISP_CMD_OUT(DISP_CMD_MD_CSET);
DISP_DATA_OUT(0xff);
DISP_DATA_OUT(0x03);
DISP_DATA_OUT(0xff);
DISP_DATA_OUT(0x03);
/* Set DSP page */
DISP_CMD_OUT(DISP_CMD_MD_PSET);
DISP_DATA_OUT(0xff);
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xff);
DISP_DATA_OUT(0x01);
/* Set ARM column */
DISP_CMD_OUT(DISP_CMD_SD_CSET);
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x00);
DISP_DATA_OUT((QCIF_WIDTH + 1) & 0xFF);
DISP_DATA_OUT((QCIF_WIDTH + 1) >> 8);
/* Set ARM page */
DISP_CMD_OUT(DISP_CMD_SD_PSET);
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0x00);
DISP_DATA_OUT((QCIF_HEIGHT - 1) & 0xFF);
DISP_DATA_OUT((QCIF_HEIGHT - 1) >> 8);
/* Set 64 gray scales */
DISP_CMD_OUT(DISP_CMD_GSSET);
DISP_DATA_OUT(DISP_GS_64);
DISP_CMD_OUT(DISP_CMD_OSSEL);
DISP_DATA_OUT(0);
/* Sleep out */
DISP_CMD_OUT(DISP_CMD_SLPOUT);
WAIT_SEC(40000);
/* Initialize power IC */
DISP_CMD_OUT(DISP_CMD_VOLCTL);
DISP_DATA_OUT(DISP_VOLCTL_TONE);
WAIT_SEC(40000);
/* Set electronic volume, d'xx */
DISP_CMD_OUT(DISP_CMD_VOLCTL);
DISP_DATA_OUT(DISP_DEFAULT_CONTRAST); /* value from 0 to 127 */
/* Initialize display data */
DISP_SET_RECT(0, (QCIF_HEIGHT - 1), 0, (QCIF_WIDTH - 1));
DISP_CMD_OUT(DISP_CMD_RAMWR);
for (i = 0; i < QCIF_HEIGHT * QCIF_WIDTH; i++)
DISP_DATA_OUT(0xffff);
DISP_CMD_OUT(DISP_CMD_RAMRD);
databack = DISP_DATA_IN();
databack = DISP_DATA_IN();
databack = DISP_DATA_IN();
databack = DISP_DATA_IN();
WAIT_SEC(80000);
DISP_CMD_OUT(DISP_CMD_DISON);
disp_area_start_row = 0;
disp_area_end_row = QCIF_HEIGHT - 1;
disp_powered_up = TRUE;
disp_initialized = TRUE;
epsonQcif_disp_set_display_area(0, QCIF_HEIGHT - 1);
display_on = TRUE;
}
static void epsonQcif_disp_set_rect(int x, int y, int xres, int yres)
{
if (!disp_initialized)
return;
DISP_SET_RECT(y, y + yres - 1, x, x + xres - 1);
DISP_CMD_OUT(DISP_CMD_RAMWR);
}
static void epsonQcif_disp_set_display_area(word start_row, word end_row)
{
if (!disp_initialized)
return;
if ((start_row == disp_area_start_row)
&& (end_row == disp_area_end_row))
return;
disp_area_start_row = start_row;
disp_area_end_row = end_row;
/* Range checking
*/
if (end_row >= QCIF_HEIGHT)
end_row = QCIF_HEIGHT - 1;
if (start_row > end_row)
start_row = end_row;
/* When display is not the full screen, gray scale is set to
** 2; otherwise it is set to 64.
*/
if ((start_row == 0) && (end_row == (QCIF_HEIGHT - 1))) {
/* The whole screen */
DISP_CMD_OUT(DISP_CMD_PTLOUT);
WAIT_SEC(10000);
DISP_CMD_OUT(DISP_CMD_DISOFF);
WAIT_SEC(100000);
DISP_CMD_OUT(DISP_CMD_GSSET);
DISP_DATA_OUT(DISP_GS_64);
WAIT_SEC(100000);
DISP_CMD_OUT(DISP_CMD_DISON);
} else {
/* partial screen */
DISP_CMD_OUT(DISP_CMD_PTLIN);
DISP_DATA_OUT(start_row);
DISP_DATA_OUT(start_row >> 8);
DISP_DATA_OUT(end_row);
DISP_DATA_OUT(end_row >> 8);
DISP_CMD_OUT(DISP_CMD_GSSET);
DISP_DATA_OUT(DISP_GS_2);
}
}
static int epsonQcif_disp_off(struct platform_device *pdev)
{
if (!disp_initialized)
epsonQcif_disp_init(pdev);
if (display_on) {
DISP_CMD_OUT(DISP_CMD_DISOFF);
DISP_CMD_OUT(DISP_CMD_SLPIN);
display_on = FALSE;
}
return 0;
}
static int epsonQcif_disp_on(struct platform_device *pdev)
{
if (!disp_initialized)
epsonQcif_disp_init(pdev);
if (!display_on) {
DISP_CMD_OUT(DISP_CMD_SLPOUT);
WAIT_SEC(40000);
DISP_CMD_OUT(DISP_CMD_DISON);
epsonQcif_disp_set_contrast(disp_contrast);
display_on = TRUE;
}
return 0;
}
static void epsonQcif_disp_set_contrast(word contrast)
{
if (!disp_initialized)
return;
/* Initialize power IC, d'24 */
DISP_CMD_OUT(DISP_CMD_VOLCTL);
DISP_DATA_OUT(DISP_VOLCTL_TONE);
WAIT_SEC(40000);
/* Set electronic volume, d'xx */
DISP_CMD_OUT(DISP_CMD_VOLCTL);
if (contrast > 127)
contrast = 127;
DISP_DATA_OUT(contrast); /* value from 0 to 127 */
disp_contrast = (byte) contrast;
} /* End disp_set_contrast */
static void epsonQcif_disp_clear_screen_area(
word start_row, word end_row, word start_column, word end_column) {
int32 i;
/* Clear the display screen */
DISP_SET_RECT(start_row, end_row, start_column, end_column);
DISP_CMD_OUT(DISP_CMD_RAMWR);
i = (end_row - start_row + 1) * (end_column - start_column + 1);
for (; i > 0; i--)
DISP_DATA_OUT(0xffff);
}
static int __init epsonQcif_probe(struct platform_device *pdev)
{
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = epsonQcif_probe,
.driver = {
.name = "ebi2_epson_qcif",
},
};
static struct msm_fb_panel_data epsonQcif_panel_data = {
.on = epsonQcif_disp_on,
.off = epsonQcif_disp_off,
.set_rect = epsonQcif_disp_set_rect,
};
static struct platform_device this_device = {
.name = "ebi2_epson_qcif",
.id = 0,
.dev = {
.platform_data = &epsonQcif_panel_data,
}
};
static int __init epsonQcif_init(void)
{
int ret;
struct msm_panel_info *pinfo;
ret = platform_driver_register(&this_driver);
if (!ret) {
pinfo = &epsonQcif_panel_data.panel_info;
pinfo->xres = QCIF_WIDTH;
pinfo->yres = QCIF_HEIGHT;
pinfo->type = EBI2_PANEL;
pinfo->pdest = DISPLAY_2;
pinfo->wait_cycle = 0x808000;
pinfo->bpp = 16;
pinfo->fb_num = 2;
pinfo->lcd.vsync_enable = FALSE;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
}
return ret;
}
module_init(epsonQcif_init);

View file

@ -0,0 +1,250 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <linux/debugfs.h>
#include "msm_fb.h"
static int ebi2_lcd_probe(struct platform_device *pdev);
static int ebi2_lcd_remove(struct platform_device *pdev);
static struct platform_driver ebi2_lcd_driver = {
.probe = ebi2_lcd_probe,
.remove = ebi2_lcd_remove,
.suspend = NULL,
.suspend_late = NULL,
.resume_early = NULL,
.resume = NULL,
.shutdown = NULL,
.driver = {
.name = "ebi2_lcd",
},
};
static void *ebi2_base;
static void *ebi2_lcd_cfg0;
static void *ebi2_lcd_cfg1;
static void __iomem *lcd01_base;
static void __iomem *lcd02_base;
static int ebi2_lcd_resource_initialized;
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
static int ebi2_lcd_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
int rc, i;
if (pdev->id == 0) {
for (i = 0; i < pdev->num_resources; i++) {
if (!strncmp(pdev->resource[i].name, "base", 4)) {
ebi2_base = ioremap(pdev->resource[i].start,
pdev->resource[i].end -
pdev->resource[i].start + 1);
if (!ebi2_base) {
printk(KERN_ERR
"ebi2_base ioremap failed!\n");
return -ENOMEM;
}
ebi2_lcd_cfg0 = (void *)(ebi2_base + 0x20);
ebi2_lcd_cfg1 = (void *)(ebi2_base + 0x24);
} else if (!strncmp(pdev->resource[i].name,
"lcd01", 5)) {
lcd01_base = ioremap(pdev->resource[i].start,
pdev->resource[i].end -
pdev->resource[i].start + 1);
if (!lcd01_base) {
printk(KERN_ERR
"lcd01_base ioremap failed!\n");
return -ENOMEM;
}
} else if (!strncmp(pdev->resource[i].name,
"lcd02", 5)) {
lcd02_base = ioremap(pdev->resource[i].start,
pdev->resource[i].end -
pdev->resource[i].start + 1);
if (!lcd02_base) {
printk(KERN_ERR
"lcd02_base ioremap failed!\n");
return -ENOMEM;
}
}
}
ebi2_lcd_resource_initialized = 1;
return 0;
}
if (!ebi2_lcd_resource_initialized)
return -EPERM;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
return -ENOMEM;
if (ebi2_base == NULL)
return -ENOMEM;
mdp_dev = platform_device_alloc("mdp", pdev->id);
if (!mdp_dev)
return -ENOMEM;
/* link to the latest pdev */
mfd->pdev = mdp_dev;
mfd->dest = DISPLAY_LCD;
/* add panel data */
if (platform_device_add_data
(mdp_dev, pdev->dev.platform_data,
sizeof(struct msm_fb_panel_data))) {
printk(KERN_ERR "ebi2_lcd_probe: platform_device_add_data failed!\n");
platform_device_put(mdp_dev);
return -ENOMEM;
}
/* data chain */
pdata = mdp_dev->dev.platform_data;
pdata->on = panel_next_on;
pdata->off = panel_next_off;
pdata->next = pdev;
/* get/set panel specific fb info */
mfd->panel_info = pdata->panel_info;
if (mfd->panel_info.bpp == 24)
mfd->fb_imgType = MDP_RGB_888;
else
mfd->fb_imgType = MDP_RGB_565;
/* config msm ebi2 lcd register */
if (mfd->panel_info.pdest == DISPLAY_1) {
outp32(ebi2_base,
(inp32(ebi2_base) & (~(EBI2_PRIM_LCD_CLR))) |
EBI2_PRIM_LCD_SEL);
/*
* current design has one set of cfg0/1 register to control
* both EBI2 channels. so, we're using the PRIM channel to
* configure both.
*/
outp32(ebi2_lcd_cfg0, mfd->panel_info.wait_cycle);
if (mfd->panel_info.bpp == 18)
outp32(ebi2_lcd_cfg1, 0x01000000);
else
outp32(ebi2_lcd_cfg1, 0x0);
} else {
#ifdef DEBUG_EBI2_LCD
/*
* confliting with QCOM SURF FPGA CS.
* OEM should enable below for their CS mapping
*/
outp32(ebi2_base, (inp32(ebi2_base)&(~(EBI2_SECD_LCD_CLR)))
|EBI2_SECD_LCD_SEL);
#endif
}
/*
* map cs (chip select) address
*/
if (mfd->panel_info.pdest == DISPLAY_1) {
mfd->cmd_port = lcd01_base;
mfd->data_port =
(void *)((uint32) mfd->cmd_port + EBI2_PRIM_LCD_RS_PIN);
mfd->data_port_phys =
(void *)(LCD_PRIM_BASE_PHYS + EBI2_PRIM_LCD_RS_PIN);
} else {
mfd->cmd_port = lcd01_base;
mfd->data_port =
(void *)((uint32) mfd->cmd_port + EBI2_SECD_LCD_RS_PIN);
mfd->data_port_phys =
(void *)(LCD_SECD_BASE_PHYS + EBI2_SECD_LCD_RS_PIN);
}
/*
* set driver data
*/
platform_set_drvdata(mdp_dev, mfd);
/*
* register in mdp driver
*/
rc = platform_device_add(mdp_dev);
if (rc) {
goto ebi2_lcd_probe_err;
}
pdev_list[pdev_list_cnt++] = pdev;
return 0;
ebi2_lcd_probe_err:
platform_device_put(mdp_dev);
return rc;
}
static int ebi2_lcd_remove(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
if (!mfd)
return 0;
if (mfd->key != MFD_KEY)
return 0;
iounmap(mfd->cmd_port);
return 0;
}
static int ebi2_lcd_register_driver(void)
{
return platform_driver_register(&ebi2_lcd_driver);
}
static int __init ebi2_lcd_driver_init(void)
{
return ebi2_lcd_register_driver();
}
module_init(ebi2_lcd_driver_init);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,248 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/i2c.h>
#include <linux/delay.h>
#include "msm_fb.h"
#define DEVICE_NAME "sii9022"
#define SII9022_DEVICE_ID 0xB0
struct sii9022_i2c_addr_data{
u8 addr;
u8 data;
};
/* video mode data */
static u8 video_mode_data[] = {
0x00,
0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02,
};
static u8 avi_io_format[] = {
0x09,
0x00, 0x00,
};
/* power state */
static struct sii9022_i2c_addr_data regset0[] = {
{ 0x60, 0x04 },
{ 0x63, 0x00 },
{ 0x1E, 0x00 },
};
static u8 video_infoframe[] = {
0x0C,
0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00,
0xE9, 0x02, 0x04, 0x01, 0x04, 0x06,
};
/* configure audio */
static struct sii9022_i2c_addr_data regset1[] = {
{ 0x26, 0x90 },
{ 0x20, 0x90 },
{ 0x1F, 0x80 },
{ 0x26, 0x80 },
{ 0x24, 0x02 },
{ 0x25, 0x0B },
{ 0xBC, 0x02 },
{ 0xBD, 0x24 },
{ 0xBE, 0x02 },
};
/* enable audio */
static u8 misc_infoframe[] = {
0xBF,
0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/* set HDMI, active */
static struct sii9022_i2c_addr_data regset2[] = {
{ 0x1A, 0x01 },
{ 0x3D, 0x00 },
};
static int send_i2c_data(struct i2c_client *client,
struct sii9022_i2c_addr_data *regset,
int size)
{
int i;
int rc = 0;
for (i = 0; i < size; i++) {
rc = i2c_smbus_write_byte_data(
client,
regset[i].addr, regset[i].data);
if (rc)
break;
}
return rc;
}
static int hdmi_sii_enable(struct i2c_client *client)
{
int rc;
int retries = 10;
int count;
rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00);
if (rc)
goto enable_exit;
do {
msleep(1);
rc = i2c_smbus_read_byte_data(client, 0x1B);
} while ((rc != SII9022_DEVICE_ID) && retries--);
if (rc != SII9022_DEVICE_ID)
return -ENODEV;
rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11);
if (rc)
goto enable_exit;
count = ARRAY_SIZE(video_mode_data);
rc = i2c_master_send(client, video_mode_data, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = i2c_smbus_write_byte_data(client, 0x08, 0x20);
if (rc)
goto enable_exit;
count = ARRAY_SIZE(avi_io_format);
rc = i2c_master_send(client, avi_io_format, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0));
if (rc)
goto enable_exit;
count = ARRAY_SIZE(video_infoframe);
rc = i2c_master_send(client, video_infoframe, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1));
if (rc)
goto enable_exit;
count = ARRAY_SIZE(misc_infoframe);
rc = i2c_master_send(client, misc_infoframe, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2));
if (rc)
goto enable_exit;
return 0;
enable_exit:
printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc);
return rc;
}
static const struct i2c_device_id hmdi_sii_id[] = {
{ DEVICE_NAME, 0 },
{ }
};
static int hdmi_sii_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
return -ENODEV;
rc = hdmi_sii_enable(client);
return rc;
}
static struct i2c_driver hdmi_sii_i2c_driver = {
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
},
.probe = hdmi_sii_probe,
.remove = __exit_p(hdmi_sii_remove),
.id_table = hmdi_sii_id,
};
static int __init hdmi_sii_init(void)
{
int ret;
struct msm_panel_info pinfo;
if (msm_fb_detect_client("hdmi_sii9022"))
return 0;
pinfo.xres = 1280;
pinfo.yres = 720;
pinfo.type = HDMI_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 124;
pinfo.lcdc.h_front_porch = 110;
pinfo.lcdc.h_pulse_width = 136;
pinfo.lcdc.v_back_porch = 19;
pinfo.lcdc.v_front_porch = 5;
pinfo.lcdc.v_pulse_width = 6;
pinfo.lcdc.border_clr = 0;
pinfo.lcdc.underflow_clr = 0xff;
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret) {
printk(KERN_ERR "%s: failed to register device\n", __func__);
goto init_exit;
}
ret = i2c_add_driver(&hdmi_sii_i2c_driver);
if (ret)
printk(KERN_ERR "%s: failed to add i2c driver\n", __func__);
init_exit:
return ret;
}
static void __exit hdmi_sii_exit(void)
{
i2c_del_driver(&hdmi_sii_i2c_driver);
}
module_init(hdmi_sii_init);
module_exit(hdmi_sii_exit);
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.1");
MODULE_AUTHOR("Qualcomm Innovation Center, Inc.");
MODULE_DESCRIPTION("SiI9022 HDMI driver");
MODULE_ALIAS("platform:hdmi-sii9022");

239
drivers/staging/msm/lcdc.c Normal file
View file

@ -0,0 +1,239 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/pm_qos_params.h>
#include "msm_fb.h"
static int lcdc_probe(struct platform_device *pdev);
static int lcdc_remove(struct platform_device *pdev);
static int lcdc_off(struct platform_device *pdev);
static int lcdc_on(struct platform_device *pdev);
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
static struct clk *mdp_lcdc_pclk_clk;
static struct clk *mdp_lcdc_pad_pclk_clk;
int mdp_lcdc_pclk_clk_rate;
int mdp_lcdc_pad_pclk_clk_rate;
static struct platform_driver lcdc_driver = {
.probe = lcdc_probe,
.remove = lcdc_remove,
.suspend = NULL,
.resume = NULL,
.shutdown = NULL,
.driver = {
.name = "lcdc",
},
};
static struct lcdc_platform_data *lcdc_pdata;
static int lcdc_off(struct platform_device *pdev)
{
int ret = 0;
ret = panel_next_off(pdev);
clk_disable(mdp_lcdc_pclk_clk);
clk_disable(mdp_lcdc_pad_pclk_clk);
if (lcdc_pdata && lcdc_pdata->lcdc_power_save)
lcdc_pdata->lcdc_power_save(0);
if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config)
ret = lcdc_pdata->lcdc_gpio_config(0);
// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc",
// PM_QOS_DEFAULT_VALUE);
return ret;
}
static int lcdc_on(struct platform_device *pdev)
{
int ret = 0;
struct msm_fb_data_type *mfd;
unsigned long panel_pixclock_freq , pm_qos_freq;
mfd = platform_get_drvdata(pdev);
panel_pixclock_freq = mfd->fbi->var.pixclock;
if (panel_pixclock_freq > 58000000)
/* pm_qos_freq should be in Khz */
pm_qos_freq = panel_pixclock_freq / 1000 ;
else
pm_qos_freq = 58000;
// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc",
// pm_qos_freq);
mfd = platform_get_drvdata(pdev);
clk_enable(mdp_lcdc_pclk_clk);
clk_enable(mdp_lcdc_pad_pclk_clk);
if (lcdc_pdata && lcdc_pdata->lcdc_power_save)
lcdc_pdata->lcdc_power_save(1);
if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config)
ret = lcdc_pdata->lcdc_gpio_config(1);
clk_set_rate(mdp_lcdc_pclk_clk, mfd->fbi->var.pixclock);
clk_set_rate(mdp_lcdc_pad_pclk_clk, mfd->fbi->var.pixclock);
mdp_lcdc_pclk_clk_rate = clk_get_rate(mdp_lcdc_pclk_clk);
mdp_lcdc_pad_pclk_clk_rate = clk_get_rate(mdp_lcdc_pad_pclk_clk);
ret = panel_next_on(pdev);
return ret;
}
static int lcdc_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct fb_info *fbi;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
int rc;
if (pdev->id == 0) {
lcdc_pdata = pdev->dev.platform_data;
return 0;
}
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
return -ENOMEM;
mdp_dev = platform_device_alloc("mdp", pdev->id);
if (!mdp_dev)
return -ENOMEM;
/*
* link to the latest pdev
*/
mfd->pdev = mdp_dev;
mfd->dest = DISPLAY_LCDC;
/*
* alloc panel device data
*/
if (platform_device_add_data
(mdp_dev, pdev->dev.platform_data,
sizeof(struct msm_fb_panel_data))) {
printk(KERN_ERR "lcdc_probe: platform_device_add_data failed!\n");
platform_device_put(mdp_dev);
return -ENOMEM;
}
/*
* data chain
*/
pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data;
pdata->on = lcdc_on;
pdata->off = lcdc_off;
pdata->next = pdev;
/*
* get/set panel specific fb info
*/
mfd->panel_info = pdata->panel_info;
mfd->fb_imgType = MDP_RGB_565;
fbi = mfd->fbi;
fbi->var.pixclock = mfd->panel_info.clk_rate;
fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
/*
* set driver data
*/
platform_set_drvdata(mdp_dev, mfd);
/*
* register in mdp driver
*/
rc = platform_device_add(mdp_dev);
if (rc)
goto lcdc_probe_err;
pdev_list[pdev_list_cnt++] = pdev;
return 0;
lcdc_probe_err:
platform_device_put(mdp_dev);
return rc;
}
static int lcdc_remove(struct platform_device *pdev)
{
// pm_qos_remove_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc");
return 0;
}
static int lcdc_register_driver(void)
{
return platform_driver_register(&lcdc_driver);
}
static int __init lcdc_driver_init(void)
{
mdp_lcdc_pclk_clk = clk_get(NULL, "mdp_lcdc_pclk_clk");
if (IS_ERR(mdp_lcdc_pclk_clk)) {
printk(KERN_ERR "error: can't get mdp_lcdc_pclk_clk!\n");
return IS_ERR(mdp_lcdc_pclk_clk);
}
mdp_lcdc_pad_pclk_clk = clk_get(NULL, "mdp_lcdc_pad_pclk_clk");
if (IS_ERR(mdp_lcdc_pad_pclk_clk)) {
printk(KERN_ERR "error: can't get mdp_lcdc_pad_pclk_clk!\n");
return IS_ERR(mdp_lcdc_pad_pclk_clk);
}
// pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc",
// PM_QOS_DEFAULT_VALUE);
return lcdc_register_driver();
}
module_init(lcdc_driver_init);

View file

@ -0,0 +1,54 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
static int __init lcdc_external_init(void)
{
int ret;
struct msm_panel_info pinfo;
if (msm_fb_detect_client("lcdc_external"))
return 0;
pinfo.xres = 1280;
pinfo.yres = 720;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 124;
pinfo.lcdc.h_front_porch = 110;
pinfo.lcdc.h_pulse_width = 136;
pinfo.lcdc.v_back_porch = 19;
pinfo.lcdc.v_front_porch = 5;
pinfo.lcdc.v_pulse_width = 6;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_external_init);

View file

@ -0,0 +1,446 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/delay.h>
#include <mach/gpio.h>
#include "msm_fb.h"
/* registers */
#define GORDON_REG_NOP 0x00
#define GORDON_REG_IMGCTL1 0x10
#define GORDON_REG_IMGCTL2 0x11
#define GORDON_REG_IMGSET1 0x12
#define GORDON_REG_IMGSET2 0x13
#define GORDON_REG_IVBP1 0x14
#define GORDON_REG_IHBP1 0x15
#define GORDON_REG_IVNUM1 0x16
#define GORDON_REG_IHNUM1 0x17
#define GORDON_REG_IVBP2 0x18
#define GORDON_REG_IHBP2 0x19
#define GORDON_REG_IVNUM2 0x1A
#define GORDON_REG_IHNUM2 0x1B
#define GORDON_REG_LCDIFCTL1 0x30
#define GORDON_REG_VALTRAN 0x31
#define GORDON_REG_AVCTL 0x33
#define GORDON_REG_LCDIFCTL2 0x34
#define GORDON_REG_LCDIFCTL3 0x35
#define GORDON_REG_LCDIFSET1 0x36
#define GORDON_REG_PCCTL 0x3C
#define GORDON_REG_TPARAM1 0x40
#define GORDON_REG_TLCDIF1 0x41
#define GORDON_REG_TSSPB_ST1 0x42
#define GORDON_REG_TSSPB_ED1 0x43
#define GORDON_REG_TSCK_ST1 0x44
#define GORDON_REG_TSCK_WD1 0x45
#define GORDON_REG_TGSPB_VST1 0x46
#define GORDON_REG_TGSPB_VED1 0x47
#define GORDON_REG_TGSPB_CH1 0x48
#define GORDON_REG_TGCK_ST1 0x49
#define GORDON_REG_TGCK_ED1 0x4A
#define GORDON_REG_TPCTL_ST1 0x4B
#define GORDON_REG_TPCTL_ED1 0x4C
#define GORDON_REG_TPCHG_ED1 0x4D
#define GORDON_REG_TCOM_CH1 0x4E
#define GORDON_REG_THBP1 0x4F
#define GORDON_REG_TPHCTL1 0x50
#define GORDON_REG_EVPH1 0x51
#define GORDON_REG_EVPL1 0x52
#define GORDON_REG_EVNH1 0x53
#define GORDON_REG_EVNL1 0x54
#define GORDON_REG_TBIAS1 0x55
#define GORDON_REG_TPARAM2 0x56
#define GORDON_REG_TLCDIF2 0x57
#define GORDON_REG_TSSPB_ST2 0x58
#define GORDON_REG_TSSPB_ED2 0x59
#define GORDON_REG_TSCK_ST2 0x5A
#define GORDON_REG_TSCK_WD2 0x5B
#define GORDON_REG_TGSPB_VST2 0x5C
#define GORDON_REG_TGSPB_VED2 0x5D
#define GORDON_REG_TGSPB_CH2 0x5E
#define GORDON_REG_TGCK_ST2 0x5F
#define GORDON_REG_TGCK_ED2 0x60
#define GORDON_REG_TPCTL_ST2 0x61
#define GORDON_REG_TPCTL_ED2 0x62
#define GORDON_REG_TPCHG_ED2 0x63
#define GORDON_REG_TCOM_CH2 0x64
#define GORDON_REG_THBP2 0x65
#define GORDON_REG_TPHCTL2 0x66
#define GORDON_REG_POWCTL 0x80
static int lcdc_gordon_panel_off(struct platform_device *pdev);
static int spi_cs;
static int spi_sclk;
static int spi_sdo;
static int spi_sdi;
static int spi_dac;
static unsigned char bit_shift[8] = { (1 << 7), /* MSB */
(1 << 6),
(1 << 5),
(1 << 4),
(1 << 3),
(1 << 2),
(1 << 1),
(1 << 0) /* LSB */
};
struct gordon_state_type{
boolean disp_initialized;
boolean display_on;
boolean disp_powered_up;
};
static struct gordon_state_type gordon_state = { 0 };
static struct msm_panel_common_pdata *lcdc_gordon_pdata;
static void serigo(uint16 reg, uint8 data)
{
unsigned int tx_val = ((0x00FF & reg) << 8) | data;
unsigned char i, val = 0;
/* Enable the Chip Select */
gpio_set_value(spi_cs, 1);
udelay(33);
/* Transmit it in two parts, Higher Byte first, then Lower Byte */
val = (unsigned char)((tx_val & 0xFF00) >> 8);
/* Clock should be Low before entering ! */
for (i = 0; i < 8; i++) {
/* #1: Drive the Data (High or Low) */
if (val & bit_shift[i])
gpio_set_value(spi_sdi, 1);
else
gpio_set_value(spi_sdi, 0);
/* #2: Drive the Clk High and then Low */
udelay(33);
gpio_set_value(spi_sclk, 1);
udelay(33);
gpio_set_value(spi_sclk, 0);
}
/* Idle state of SDO (MOSI) is Low */
gpio_set_value(spi_sdi, 0);
/* ..then Lower Byte */
val = (uint8) (tx_val & 0x00FF);
/* Before we enter here the Clock should be Low ! */
for (i = 0; i < 8; i++) {
/* #1: Drive the Data (High or Low) */
if (val & bit_shift[i])
gpio_set_value(spi_sdi, 1);
else
gpio_set_value(spi_sdi, 0);
/* #2: Drive the Clk High and then Low */
udelay(33);
gpio_set_value(spi_sclk, 1);
udelay(33);
gpio_set_value(spi_sclk, 0);
}
/* Idle state of SDO (MOSI) is Low */
gpio_set_value(spi_sdi, 0);
/* Now Disable the Chip Select */
udelay(33);
gpio_set_value(spi_cs, 0);
}
static void spi_init(void)
{
/* Setting the Default GPIO's */
spi_sclk = *(lcdc_gordon_pdata->gpio_num);
spi_cs = *(lcdc_gordon_pdata->gpio_num + 1);
spi_sdi = *(lcdc_gordon_pdata->gpio_num + 2);
spi_sdo = *(lcdc_gordon_pdata->gpio_num + 3);
/* Set the output so that we dont disturb the slave device */
gpio_set_value(spi_sclk, 0);
gpio_set_value(spi_sdi, 0);
/* Set the Chip Select De-asserted */
gpio_set_value(spi_cs, 0);
}
static void gordon_disp_powerup(void)
{
if (!gordon_state.disp_powered_up && !gordon_state.display_on) {
/* Reset the hardware first */
/* Include DAC power up implementation here */
gordon_state.disp_powered_up = TRUE;
}
}
static void gordon_init(void)
{
/* Image interface settings */
serigo(GORDON_REG_IMGCTL2, 0x00);
serigo(GORDON_REG_IMGSET1, 0x00);
/* Exchange the RGB signal for J510(Softbank mobile) */
serigo(GORDON_REG_IMGSET2, 0x12);
serigo(GORDON_REG_LCDIFSET1, 0x00);
/* Pre-charge settings */
serigo(GORDON_REG_PCCTL, 0x09);
serigo(GORDON_REG_LCDIFCTL2, 0x7B);
mdelay(1);
}
static void gordon_disp_on(void)
{
if (gordon_state.disp_powered_up && !gordon_state.display_on) {
gordon_init();
mdelay(20);
/* gordon_dispmode setting */
serigo(GORDON_REG_TPARAM1, 0x30);
serigo(GORDON_REG_TLCDIF1, 0x00);
serigo(GORDON_REG_TSSPB_ST1, 0x8B);
serigo(GORDON_REG_TSSPB_ED1, 0x93);
serigo(GORDON_REG_TSCK_ST1, 0x88);
serigo(GORDON_REG_TSCK_WD1, 0x00);
serigo(GORDON_REG_TGSPB_VST1, 0x01);
serigo(GORDON_REG_TGSPB_VED1, 0x02);
serigo(GORDON_REG_TGSPB_CH1, 0x5E);
serigo(GORDON_REG_TGCK_ST1, 0x80);
serigo(GORDON_REG_TGCK_ED1, 0x3C);
serigo(GORDON_REG_TPCTL_ST1, 0x50);
serigo(GORDON_REG_TPCTL_ED1, 0x74);
serigo(GORDON_REG_TPCHG_ED1, 0x78);
serigo(GORDON_REG_TCOM_CH1, 0x50);
serigo(GORDON_REG_THBP1, 0x84);
serigo(GORDON_REG_TPHCTL1, 0x00);
serigo(GORDON_REG_EVPH1, 0x70);
serigo(GORDON_REG_EVPL1, 0x64);
serigo(GORDON_REG_EVNH1, 0x56);
serigo(GORDON_REG_EVNL1, 0x48);
serigo(GORDON_REG_TBIAS1, 0x88);
/* QVGA settings */
serigo(GORDON_REG_TPARAM2, 0x28);
serigo(GORDON_REG_TLCDIF2, 0x14);
serigo(GORDON_REG_TSSPB_ST2, 0x49);
serigo(GORDON_REG_TSSPB_ED2, 0x4B);
serigo(GORDON_REG_TSCK_ST2, 0x4A);
serigo(GORDON_REG_TSCK_WD2, 0x02);
serigo(GORDON_REG_TGSPB_VST2, 0x02);
serigo(GORDON_REG_TGSPB_VED2, 0x03);
serigo(GORDON_REG_TGSPB_CH2, 0x2F);
serigo(GORDON_REG_TGCK_ST2, 0x40);
serigo(GORDON_REG_TGCK_ED2, 0x1E);
serigo(GORDON_REG_TPCTL_ST2, 0x2C);
serigo(GORDON_REG_TPCTL_ED2, 0x3A);
serigo(GORDON_REG_TPCHG_ED2, 0x3C);
serigo(GORDON_REG_TCOM_CH2, 0x28);
serigo(GORDON_REG_THBP2, 0x4D);
serigo(GORDON_REG_TPHCTL2, 0x1A);
/* VGA settings */
serigo(GORDON_REG_IVBP1, 0x02);
serigo(GORDON_REG_IHBP1, 0x90);
serigo(GORDON_REG_IVNUM1, 0xA0);
serigo(GORDON_REG_IHNUM1, 0x78);
/* QVGA settings */
serigo(GORDON_REG_IVBP2, 0x02);
serigo(GORDON_REG_IHBP2, 0x48);
serigo(GORDON_REG_IVNUM2, 0x50);
serigo(GORDON_REG_IHNUM2, 0x3C);
/* Gordon Charge pump settings and ON */
serigo(GORDON_REG_POWCTL, 0x03);
mdelay(15);
serigo(GORDON_REG_POWCTL, 0x07);
mdelay(15);
serigo(GORDON_REG_POWCTL, 0x0F);
mdelay(15);
serigo(GORDON_REG_AVCTL, 0x03);
mdelay(15);
serigo(GORDON_REG_POWCTL, 0x1F);
mdelay(15);
serigo(GORDON_REG_POWCTL, 0x5F);
mdelay(15);
serigo(GORDON_REG_POWCTL, 0x7F);
mdelay(15);
serigo(GORDON_REG_LCDIFCTL1, 0x02);
mdelay(15);
serigo(GORDON_REG_IMGCTL1, 0x00);
mdelay(15);
serigo(GORDON_REG_LCDIFCTL3, 0x00);
mdelay(15);
serigo(GORDON_REG_VALTRAN, 0x01);
mdelay(15);
serigo(GORDON_REG_LCDIFCTL1, 0x03);
mdelay(1);
gordon_state.display_on = TRUE;
}
}
static int lcdc_gordon_panel_on(struct platform_device *pdev)
{
if (!gordon_state.disp_initialized) {
/* Configure reset GPIO that drives DAC */
lcdc_gordon_pdata->panel_config_gpio(1);
spi_dac = *(lcdc_gordon_pdata->gpio_num + 4);
gpio_set_value(spi_dac, 0);
udelay(15);
gpio_set_value(spi_dac, 1);
spi_init(); /* LCD needs SPI */
gordon_disp_powerup();
gordon_disp_on();
gordon_state.disp_initialized = TRUE;
}
return 0;
}
static int lcdc_gordon_panel_off(struct platform_device *pdev)
{
if (gordon_state.disp_powered_up && gordon_state.display_on) {
serigo(GORDON_REG_LCDIFCTL2, 0x7B);
serigo(GORDON_REG_VALTRAN, 0x01);
serigo(GORDON_REG_LCDIFCTL1, 0x02);
serigo(GORDON_REG_LCDIFCTL3, 0x01);
mdelay(20);
serigo(GORDON_REG_VALTRAN, 0x01);
serigo(GORDON_REG_IMGCTL1, 0x01);
serigo(GORDON_REG_LCDIFCTL1, 0x00);
mdelay(20);
serigo(GORDON_REG_POWCTL, 0x1F);
mdelay(40);
serigo(GORDON_REG_POWCTL, 0x07);
mdelay(40);
serigo(GORDON_REG_POWCTL, 0x03);
mdelay(40);
serigo(GORDON_REG_POWCTL, 0x00);
mdelay(40);
lcdc_gordon_pdata->panel_config_gpio(0);
gordon_state.display_on = FALSE;
gordon_state.disp_initialized = FALSE;
}
return 0;
}
static void lcdc_gordon_set_backlight(struct msm_fb_data_type *mfd)
{
int bl_level = mfd->bl_level;
if (bl_level <= 1) {
/* keep back light OFF */
serigo(GORDON_REG_LCDIFCTL2, 0x0B);
udelay(15);
serigo(GORDON_REG_VALTRAN, 0x01);
} else {
/* keep back light ON */
serigo(GORDON_REG_LCDIFCTL2, 0x7B);
udelay(15);
serigo(GORDON_REG_VALTRAN, 0x01);
}
}
static int __init gordon_probe(struct platform_device *pdev)
{
if (pdev->id == 0) {
lcdc_gordon_pdata = pdev->dev.platform_data;
return 0;
}
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = gordon_probe,
.driver = {
.name = "lcdc_gordon_vga",
},
};
static struct msm_fb_panel_data gordon_panel_data = {
.on = lcdc_gordon_panel_on,
.off = lcdc_gordon_panel_off,
.set_backlight = lcdc_gordon_set_backlight,
};
static struct platform_device this_device = {
.name = "lcdc_gordon_vga",
.id = 1,
.dev = {
.platform_data = &gordon_panel_data,
}
};
static int __init lcdc_gordon_panel_init(void)
{
int ret;
struct msm_panel_info *pinfo;
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
if (msm_fb_detect_client("lcdc_gordon_vga"))
return 0;
#endif
ret = platform_driver_register(&this_driver);
if (ret)
return ret;
pinfo = &gordon_panel_data.panel_info;
pinfo->xres = 480;
pinfo->yres = 640;
pinfo->type = LCDC_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->wait_cycle = 0;
pinfo->bpp = 24;
pinfo->fb_num = 2;
pinfo->clk_rate = 24500000;
pinfo->bl_max = 4;
pinfo->bl_min = 1;
pinfo->lcdc.h_back_porch = 84;
pinfo->lcdc.h_front_porch = 33;
pinfo->lcdc.h_pulse_width = 60;
pinfo->lcdc.v_back_porch = 0;
pinfo->lcdc.v_front_porch = 2;
pinfo->lcdc.v_pulse_width = 2;
pinfo->lcdc.border_clr = 0; /* blk */
pinfo->lcdc.underflow_clr = 0xff; /* blue */
pinfo->lcdc.hsync_skew = 0;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
return ret;
}
module_init(lcdc_gordon_panel_init);

View file

@ -0,0 +1,60 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
#include "mddihosti.h"
#endif
static int __init lcdc_grapefruit_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
if (msm_fb_detect_client("lcdc_grapefruit_vga"))
return 0;
#endif
pinfo.xres = 1024;
pinfo.yres = 600;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.fb_num = 2;
pinfo.clk_rate = 40000000;
pinfo.lcdc.h_back_porch = 88;
pinfo.lcdc.h_front_porch = 40;
pinfo.lcdc.h_pulse_width = 128;
pinfo.lcdc.v_back_porch = 23;
pinfo.lcdc.v_front_porch = 1;
pinfo.lcdc.v_pulse_width = 4;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_grapefruit_init);

View file

@ -0,0 +1,88 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
static int lcdc_panel_on(struct platform_device *pdev)
{
return 0;
}
static int lcdc_panel_off(struct platform_device *pdev)
{
return 0;
}
static int __init lcdc_panel_probe(struct platform_device *pdev)
{
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = lcdc_panel_probe,
.driver = {
.name = "lcdc_panel",
},
};
static struct msm_fb_panel_data lcdc_panel_data = {
.on = lcdc_panel_on,
.off = lcdc_panel_off,
};
static int lcdc_dev_id;
int lcdc_device_register(struct msm_panel_info *pinfo)
{
struct platform_device *pdev = NULL;
int ret;
pdev = platform_device_alloc("lcdc_panel", ++lcdc_dev_id);
if (!pdev)
return -ENOMEM;
lcdc_panel_data.panel_info = *pinfo;
ret = platform_device_add_data(pdev, &lcdc_panel_data,
sizeof(lcdc_panel_data));
if (ret) {
printk(KERN_ERR
"%s: platform_device_add_data failed!\n", __func__);
goto err_device_put;
}
ret = platform_device_add(pdev);
if (ret) {
printk(KERN_ERR
"%s: platform_device_register failed!\n", __func__);
goto err_device_put;
}
return 0;
err_device_put:
platform_device_put(pdev);
return ret;
}
static int __init lcdc_panel_init(void)
{
return platform_driver_register(&this_driver);
}
module_init(lcdc_panel_init);

View file

@ -0,0 +1,64 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
#include "mddihosti.h"
#endif
static int __init lcdc_prism_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
ret = msm_fb_detect_client("lcdc_prism_wvga");
if (ret == -ENODEV)
return 0;
if (ret && (mddi_get_client_id() != 0))
return 0;
#endif
pinfo.xres = 800;
pinfo.yres = 480;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 38460000;
pinfo.lcdc.h_back_porch = 21;
pinfo.lcdc.h_front_porch = 81;
pinfo.lcdc.h_pulse_width = 60;
pinfo.lcdc.v_back_porch = 18;
pinfo.lcdc.v_front_porch = 27;
pinfo.lcdc.v_pulse_width = 2;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_prism_init);

View file

@ -0,0 +1,290 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/delay.h>
#ifdef CONFIG_ARCH_MSM7X30
#include <linux/mfd/pmic8058.h>
#endif
#include <mach/gpio.h>
#include "msm_fb.h"
static int lcdc_sharp_panel_off(struct platform_device *pdev);
static int spi_cs;
static int spi_sclk;
static int spi_mosi;
static int spi_miso;
static unsigned char bit_shift[8] = { (1 << 7), /* MSB */
(1 << 6),
(1 << 5),
(1 << 4),
(1 << 3),
(1 << 2),
(1 << 1),
(1 << 0) /* LSB */
};
struct sharp_state_type {
boolean disp_initialized;
boolean display_on;
boolean disp_powered_up;
};
struct sharp_spi_data {
u8 addr;
u8 data;
};
static struct sharp_spi_data init_sequence[] = {
{ 15, 0x01 },
{ 5, 0x01 },
{ 7, 0x10 },
{ 9, 0x1E },
{ 10, 0x04 },
{ 17, 0xFF },
{ 21, 0x8A },
{ 22, 0x00 },
{ 23, 0x82 },
{ 24, 0x24 },
{ 25, 0x22 },
{ 26, 0x6D },
{ 27, 0xEB },
{ 28, 0xB9 },
{ 29, 0x3A },
{ 49, 0x1A },
{ 50, 0x16 },
{ 51, 0x05 },
{ 55, 0x7F },
{ 56, 0x15 },
{ 57, 0x7B },
{ 60, 0x05 },
{ 61, 0x0C },
{ 62, 0x80 },
{ 63, 0x00 },
{ 92, 0x90 },
{ 97, 0x01 },
{ 98, 0xFF },
{ 113, 0x11 },
{ 114, 0x02 },
{ 115, 0x08 },
{ 123, 0xAB },
{ 124, 0x04 },
{ 6, 0x02 },
{ 133, 0x00 },
{ 134, 0xFE },
{ 135, 0x22 },
{ 136, 0x0B },
{ 137, 0xFF },
{ 138, 0x0F },
{ 139, 0x00 },
{ 140, 0xFE },
{ 141, 0x22 },
{ 142, 0x0B },
{ 143, 0xFF },
{ 144, 0x0F },
{ 145, 0x00 },
{ 146, 0xFE },
{ 147, 0x22 },
{ 148, 0x0B },
{ 149, 0xFF },
{ 150, 0x0F },
{ 202, 0x30 },
{ 30, 0x01 },
{ 4, 0x01 },
{ 31, 0x41 },
};
static struct sharp_state_type sharp_state = { 0 };
static struct msm_panel_common_pdata *lcdc_sharp_pdata;
static void sharp_spi_write_byte(u8 val)
{
int i;
/* Clock should be Low before entering */
for (i = 0; i < 8; i++) {
/* #1: Drive the Data (High or Low) */
if (val & bit_shift[i])
gpio_set_value(spi_mosi, 1);
else
gpio_set_value(spi_mosi, 0);
/* #2: Drive the Clk High and then Low */
gpio_set_value(spi_sclk, 1);
gpio_set_value(spi_sclk, 0);
}
}
static void serigo(u8 reg, u8 data)
{
/* Enable the Chip Select - low */
gpio_set_value(spi_cs, 0);
udelay(1);
/* Transmit register address first, then data */
sharp_spi_write_byte(reg);
/* Idle state of MOSI is Low */
gpio_set_value(spi_mosi, 0);
udelay(1);
sharp_spi_write_byte(data);
gpio_set_value(spi_mosi, 0);
gpio_set_value(spi_cs, 1);
}
static void sharp_spi_init(void)
{
spi_sclk = *(lcdc_sharp_pdata->gpio_num);
spi_cs = *(lcdc_sharp_pdata->gpio_num + 1);
spi_mosi = *(lcdc_sharp_pdata->gpio_num + 2);
spi_miso = *(lcdc_sharp_pdata->gpio_num + 3);
/* Set the output so that we don't disturb the slave device */
gpio_set_value(spi_sclk, 0);
gpio_set_value(spi_mosi, 0);
/* Set the Chip Select deasserted (active low) */
gpio_set_value(spi_cs, 1);
}
static void sharp_disp_powerup(void)
{
if (!sharp_state.disp_powered_up && !sharp_state.display_on)
sharp_state.disp_powered_up = TRUE;
}
static void sharp_disp_on(void)
{
int i;
if (sharp_state.disp_powered_up && !sharp_state.display_on) {
for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
serigo(init_sequence[i].addr,
init_sequence[i].data);
}
mdelay(10);
serigo(31, 0xC1);
mdelay(10);
serigo(31, 0xD9);
serigo(31, 0xDF);
sharp_state.display_on = TRUE;
}
}
static int lcdc_sharp_panel_on(struct platform_device *pdev)
{
if (!sharp_state.disp_initialized) {
lcdc_sharp_pdata->panel_config_gpio(1);
sharp_spi_init();
sharp_disp_powerup();
sharp_disp_on();
sharp_state.disp_initialized = TRUE;
}
return 0;
}
static int lcdc_sharp_panel_off(struct platform_device *pdev)
{
if (sharp_state.disp_powered_up && sharp_state.display_on) {
serigo(4, 0x00);
mdelay(40);
serigo(31, 0xC1);
mdelay(40);
serigo(31, 0x00);
mdelay(100);
sharp_state.display_on = FALSE;
sharp_state.disp_initialized = FALSE;
}
return 0;
}
static int __init sharp_probe(struct platform_device *pdev)
{
if (pdev->id == 0) {
lcdc_sharp_pdata = pdev->dev.platform_data;
return 0;
}
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = sharp_probe,
.driver = {
.name = "lcdc_sharp_wvga",
},
};
static struct msm_fb_panel_data sharp_panel_data = {
.on = lcdc_sharp_panel_on,
.off = lcdc_sharp_panel_off,
};
static struct platform_device this_device = {
.name = "lcdc_sharp_wvga",
.id = 1,
.dev = {
.platform_data = &sharp_panel_data,
}
};
static int __init lcdc_sharp_panel_init(void)
{
int ret;
struct msm_panel_info *pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
if (msm_fb_detect_client("lcdc_sharp_wvga_pt"))
return 0;
#endif
ret = platform_driver_register(&this_driver);
if (ret)
return ret;
pinfo = &sharp_panel_data.panel_info;
pinfo->xres = 480;
pinfo->yres = 800;
pinfo->type = LCDC_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->wait_cycle = 0;
pinfo->bpp = 18;
pinfo->fb_num = 2;
pinfo->clk_rate = 24500000;
pinfo->bl_max = 4;
pinfo->bl_min = 1;
pinfo->lcdc.h_back_porch = 20;
pinfo->lcdc.h_front_porch = 10;
pinfo->lcdc.h_pulse_width = 10;
pinfo->lcdc.v_back_porch = 2;
pinfo->lcdc.v_front_porch = 2;
pinfo->lcdc.v_pulse_width = 2;
pinfo->lcdc.border_clr = 0;
pinfo->lcdc.underflow_clr = 0xff;
pinfo->lcdc.hsync_skew = 0;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
return ret;
}
module_init(lcdc_sharp_panel_init);

View file

@ -0,0 +1,237 @@
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/i2c.h>
#include <linux/delay.h>
#include "msm_fb.h"
#define DEVICE_NAME "sii9022"
#define SII9022_DEVICE_ID 0xB0
struct sii9022_i2c_addr_data{
u8 addr;
u8 data;
};
/* video mode data */
static u8 video_mode_data[] = {
0x00,
0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02,
};
static u8 avi_io_format[] = {
0x09,
0x00, 0x00,
};
/* power state */
static struct sii9022_i2c_addr_data regset0[] = {
{ 0x60, 0x04 },
{ 0x63, 0x00 },
{ 0x1E, 0x00 },
};
static u8 video_infoframe[] = {
0x0C,
0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00,
0xE9, 0x02, 0x04, 0x01, 0x04, 0x06,
};
/* configure audio */
static struct sii9022_i2c_addr_data regset1[] = {
{ 0x26, 0x90 },
{ 0x20, 0x90 },
{ 0x1F, 0x80 },
{ 0x26, 0x80 },
{ 0x24, 0x02 },
{ 0x25, 0x0B },
{ 0xBC, 0x02 },
{ 0xBD, 0x24 },
{ 0xBE, 0x02 },
};
/* enable audio */
static u8 misc_infoframe[] = {
0xBF,
0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/* set HDMI, active */
static struct sii9022_i2c_addr_data regset2[] = {
{ 0x1A, 0x01 },
{ 0x3D, 0x00 },
};
static int send_i2c_data(struct i2c_client *client,
struct sii9022_i2c_addr_data *regset,
int size)
{
int i;
int rc = 0;
for (i = 0; i < size; i++) {
rc = i2c_smbus_write_byte_data(
client,
regset[i].addr, regset[i].data);
if (rc)
break;
}
return rc;
}
static int hdmi_sii_enable(struct i2c_client *client)
{
int rc;
int retries = 10;
int count;
rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00);
if (rc)
goto enable_exit;
do {
msleep(1);
rc = i2c_smbus_read_byte_data(client, 0x1B);
} while ((rc != SII9022_DEVICE_ID) && retries--);
if (rc != SII9022_DEVICE_ID)
return -ENODEV;
rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11);
if (rc)
goto enable_exit;
count = ARRAY_SIZE(video_mode_data);
rc = i2c_master_send(client, video_mode_data, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = i2c_smbus_write_byte_data(client, 0x08, 0x20);
if (rc)
goto enable_exit;
count = ARRAY_SIZE(avi_io_format);
rc = i2c_master_send(client, avi_io_format, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0));
if (rc)
goto enable_exit;
count = ARRAY_SIZE(video_infoframe);
rc = i2c_master_send(client, video_infoframe, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1));
if (rc)
goto enable_exit;
count = ARRAY_SIZE(misc_infoframe);
rc = i2c_master_send(client, misc_infoframe, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2));
if (rc)
goto enable_exit;
return 0;
enable_exit:
printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc);
return rc;
}
static const struct i2c_device_id hmdi_sii_id[] = {
{ DEVICE_NAME, 0 },
{ }
};
static int hdmi_sii_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
return -ENODEV;
rc = hdmi_sii_enable(client);
return rc;
}
static struct i2c_driver hdmi_sii_i2c_driver = {
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
},
.probe = hdmi_sii_probe,
.remove = __exit_p(hdmi_sii_remove),
.id_table = hmdi_sii_id,
};
static int __init lcdc_st15_init(void)
{
int ret;
struct msm_panel_info pinfo;
if (msm_fb_detect_client("lcdc_st15"))
return 0;
pinfo.xres = 1366;
pinfo.yres = 768;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 120;
pinfo.lcdc.h_front_porch = 20;
pinfo.lcdc.h_pulse_width = 40;
pinfo.lcdc.v_back_porch = 25;
pinfo.lcdc.v_front_porch = 1;
pinfo.lcdc.v_pulse_width = 7;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret) {
printk(KERN_ERR "%s: failed to register device!\n", __func__);
goto init_exit;
}
ret = i2c_add_driver(&hdmi_sii_i2c_driver);
if (ret)
printk(KERN_ERR "%s: failed to add i2c driver\n", __func__);
init_exit:
return ret;
}
module_init(lcdc_st15_init);

View file

@ -0,0 +1,54 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
static int __init lcdc_st1_wxga_init(void)
{
int ret;
struct msm_panel_info pinfo;
if (msm_fb_detect_client("lcdc_st1_wxga"))
return 0;
pinfo.xres = 1280;
pinfo.yres = 720;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 124;
pinfo.lcdc.h_front_porch = 110;
pinfo.lcdc.h_pulse_width = 136;
pinfo.lcdc.v_back_porch = 19;
pinfo.lcdc.v_front_porch = 5;
pinfo.lcdc.v_pulse_width = 6;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_st1_wxga_init);

View file

@ -0,0 +1,374 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <mach/gpio.h>
#include <mach/pmic.h>
#include "msm_fb.h"
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
#include "mddihosti.h"
#endif
static int spi_cs;
static int spi_sclk;
static int spi_mosi;
static int spi_miso;
struct toshiba_state_type{
boolean disp_initialized;
boolean display_on;
boolean disp_powered_up;
};
static struct toshiba_state_type toshiba_state = { 0 };
static struct msm_panel_common_pdata *lcdc_toshiba_pdata;
static void toshiba_spi_write_byte(char dc, uint8 data)
{
uint32 bit;
int bnum;
gpio_set_value(spi_sclk, 0); /* clk low */
/* dc: 0 for command, 1 for parameter */
gpio_set_value(spi_mosi, dc);
udelay(1); /* at least 20 ns */
gpio_set_value(spi_sclk, 1); /* clk high */
udelay(1); /* at least 20 ns */
bnum = 8; /* 8 data bits */
bit = 0x80;
while (bnum) {
gpio_set_value(spi_sclk, 0); /* clk low */
if (data & bit)
gpio_set_value(spi_mosi, 1);
else
gpio_set_value(spi_mosi, 0);
udelay(1);
gpio_set_value(spi_sclk, 1); /* clk high */
udelay(1);
bit >>= 1;
bnum--;
}
}
static void toshiba_spi_write(char cmd, uint32 data, int num)
{
char *bp;
gpio_set_value(spi_cs, 1); /* cs high */
/* command byte first */
toshiba_spi_write_byte(0, cmd);
/* followed by parameter bytes */
if (num) {
bp = (char *)&data;;
bp += (num - 1);
while (num) {
toshiba_spi_write_byte(1, *bp);
num--;
bp--;
}
}
gpio_set_value(spi_cs, 0); /* cs low */
udelay(1);
}
void toshiba_spi_read_bytes(char cmd, uint32 *data, int num)
{
uint32 dbit, bits;
int bnum;
gpio_set_value(spi_cs, 1); /* cs high */
/* command byte first */
toshiba_spi_write_byte(0, cmd);
if (num > 1) {
/* extra dc bit */
gpio_set_value(spi_sclk, 0); /* clk low */
udelay(1);
dbit = gpio_get_value(spi_miso);/* dc bit */
udelay(1);
gpio_set_value(spi_sclk, 1); /* clk high */
}
/* followed by data bytes */
bnum = num * 8; /* number of bits */
bits = 0;
while (bnum) {
bits <<= 1;
gpio_set_value(spi_sclk, 0); /* clk low */
udelay(1);
dbit = gpio_get_value(spi_miso);
udelay(1);
gpio_set_value(spi_sclk, 1); /* clk high */
bits |= dbit;
bnum--;
}
*data = bits;
udelay(1);
gpio_set_value(spi_cs, 0); /* cs low */
udelay(1);
}
static void spi_pin_assign(void)
{
/* Setting the Default GPIO's */
spi_sclk = *(lcdc_toshiba_pdata->gpio_num);
spi_cs = *(lcdc_toshiba_pdata->gpio_num + 1);
spi_mosi = *(lcdc_toshiba_pdata->gpio_num + 2);
spi_miso = *(lcdc_toshiba_pdata->gpio_num + 3);
}
static void toshiba_disp_powerup(void)
{
if (!toshiba_state.disp_powered_up && !toshiba_state.display_on) {
/* Reset the hardware first */
/* Include DAC power up implementation here */
toshiba_state.disp_powered_up = TRUE;
}
}
static void toshiba_disp_on(void)
{
uint32 data;
gpio_set_value(spi_cs, 0); /* low */
gpio_set_value(spi_sclk, 1); /* high */
gpio_set_value(spi_mosi, 0);
gpio_set_value(spi_miso, 0);
if (toshiba_state.disp_powered_up && !toshiba_state.display_on) {
toshiba_spi_write(0, 0, 0);
mdelay(7);
toshiba_spi_write(0, 0, 0);
mdelay(7);
toshiba_spi_write(0, 0, 0);
mdelay(7);
toshiba_spi_write(0xba, 0x11, 1);
toshiba_spi_write(0x36, 0x00, 1);
mdelay(1);
toshiba_spi_write(0x3a, 0x60, 1);
toshiba_spi_write(0xb1, 0x5d, 1);
mdelay(1);
toshiba_spi_write(0xb2, 0x33, 1);
toshiba_spi_write(0xb3, 0x22, 1);
mdelay(1);
toshiba_spi_write(0xb4, 0x02, 1);
toshiba_spi_write(0xb5, 0x1e, 1); /* vcs -- adjust brightness */
mdelay(1);
toshiba_spi_write(0xb6, 0x27, 1);
toshiba_spi_write(0xb7, 0x03, 1);
mdelay(1);
toshiba_spi_write(0xb9, 0x24, 1);
toshiba_spi_write(0xbd, 0xa1, 1);
mdelay(1);
toshiba_spi_write(0xbb, 0x00, 1);
toshiba_spi_write(0xbf, 0x01, 1);
mdelay(1);
toshiba_spi_write(0xbe, 0x00, 1);
toshiba_spi_write(0xc0, 0x11, 1);
mdelay(1);
toshiba_spi_write(0xc1, 0x11, 1);
toshiba_spi_write(0xc2, 0x11, 1);
mdelay(1);
toshiba_spi_write(0xc3, 0x3232, 2);
mdelay(1);
toshiba_spi_write(0xc4, 0x3232, 2);
mdelay(1);
toshiba_spi_write(0xc5, 0x3232, 2);
mdelay(1);
toshiba_spi_write(0xc6, 0x3232, 2);
mdelay(1);
toshiba_spi_write(0xc7, 0x6445, 2);
mdelay(1);
toshiba_spi_write(0xc8, 0x44, 1);
toshiba_spi_write(0xc9, 0x52, 1);
mdelay(1);
toshiba_spi_write(0xca, 0x00, 1);
mdelay(1);
toshiba_spi_write(0xec, 0x02a4, 2); /* 0x02a4 */
mdelay(1);
toshiba_spi_write(0xcf, 0x01, 1);
mdelay(1);
toshiba_spi_write(0xd0, 0xc003, 2); /* c003 */
mdelay(1);
toshiba_spi_write(0xd1, 0x01, 1);
mdelay(1);
toshiba_spi_write(0xd2, 0x0028, 2);
mdelay(1);
toshiba_spi_write(0xd3, 0x0028, 2);
mdelay(1);
toshiba_spi_write(0xd4, 0x26a4, 2);
mdelay(1);
toshiba_spi_write(0xd5, 0x20, 1);
mdelay(1);
toshiba_spi_write(0xef, 0x3200, 2);
mdelay(32);
toshiba_spi_write(0xbc, 0x80, 1); /* wvga pass through */
toshiba_spi_write(0x3b, 0x00, 1);
mdelay(1);
toshiba_spi_write(0xb0, 0x16, 1);
mdelay(1);
toshiba_spi_write(0xb8, 0xfff5, 2);
mdelay(1);
toshiba_spi_write(0x11, 0, 0);
mdelay(5);
toshiba_spi_write(0x29, 0, 0);
mdelay(5);
toshiba_state.display_on = TRUE;
}
data = 0;
toshiba_spi_read_bytes(0x04, &data, 3);
printk(KERN_INFO "toshiba_disp_on: id=%x\n", data);
}
static int lcdc_toshiba_panel_on(struct platform_device *pdev)
{
if (!toshiba_state.disp_initialized) {
/* Configure reset GPIO that drives DAC */
if (lcdc_toshiba_pdata->panel_config_gpio)
lcdc_toshiba_pdata->panel_config_gpio(1);
toshiba_disp_powerup();
toshiba_disp_on();
toshiba_state.disp_initialized = TRUE;
}
return 0;
}
static int lcdc_toshiba_panel_off(struct platform_device *pdev)
{
if (toshiba_state.disp_powered_up && toshiba_state.display_on) {
/* Main panel power off (Deep standby in) */
toshiba_spi_write(0x28, 0, 0); /* display off */
mdelay(1);
toshiba_spi_write(0xb8, 0x8002, 2); /* output control */
mdelay(1);
toshiba_spi_write(0x10, 0x00, 1); /* sleep mode in */
mdelay(85); /* wait 85 msec */
toshiba_spi_write(0xb0, 0x00, 1); /* deep standby in */
mdelay(1);
if (lcdc_toshiba_pdata->panel_config_gpio)
lcdc_toshiba_pdata->panel_config_gpio(0);
toshiba_state.display_on = FALSE;
toshiba_state.disp_initialized = FALSE;
}
return 0;
}
static void lcdc_toshiba_set_backlight(struct msm_fb_data_type *mfd)
{
int bl_level;
int ret = -EPERM;
bl_level = mfd->bl_level;
ret = pmic_set_led_intensity(LED_LCD, bl_level);
if (ret)
printk(KERN_WARNING "%s: can't set lcd backlight!\n",
__func__);
}
static int __init toshiba_probe(struct platform_device *pdev)
{
if (pdev->id == 0) {
lcdc_toshiba_pdata = pdev->dev.platform_data;
spi_pin_assign();
return 0;
}
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = toshiba_probe,
.driver = {
.name = "lcdc_toshiba_wvga",
},
};
static struct msm_fb_panel_data toshiba_panel_data = {
.on = lcdc_toshiba_panel_on,
.off = lcdc_toshiba_panel_off,
.set_backlight = lcdc_toshiba_set_backlight,
};
static struct platform_device this_device = {
.name = "lcdc_toshiba_wvga",
.id = 1,
.dev = {
.platform_data = &toshiba_panel_data,
}
};
static int __init lcdc_toshiba_panel_init(void)
{
int ret;
struct msm_panel_info *pinfo;
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
if (mddi_get_client_id() != 0)
return 0;
ret = msm_fb_detect_client("lcdc_toshiba_wvga_pt");
if (ret)
return 0;
#endif
ret = platform_driver_register(&this_driver);
if (ret)
return ret;
pinfo = &toshiba_panel_data.panel_info;
pinfo->xres = 480;
pinfo->yres = 800;
pinfo->type = LCDC_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->wait_cycle = 0;
pinfo->bpp = 18;
pinfo->fb_num = 2;
/* 30Mhz mdp_lcdc_pclk and mdp_lcdc_pad_pcl */
pinfo->clk_rate = 27648000;
pinfo->bl_max = 15;
pinfo->bl_min = 1;
pinfo->lcdc.h_back_porch = 184; /* hsw = 8 + hbp=184 */
pinfo->lcdc.h_front_porch = 4;
pinfo->lcdc.h_pulse_width = 8;
pinfo->lcdc.v_back_porch = 2; /* vsw=1 + vbp = 2 */
pinfo->lcdc.v_front_porch = 3;
pinfo->lcdc.v_pulse_width = 1;
pinfo->lcdc.border_clr = 0; /* blk */
pinfo->lcdc.underflow_clr = 0xff; /* blue */
pinfo->lcdc.hsync_skew = 0;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
return ret;
}
device_initcall(lcdc_toshiba_panel_init);

View file

@ -0,0 +1,56 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
static int __init lcdc_wxga_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
if (msm_fb_detect_client("lcdc_wxga"))
return 0;
#endif
pinfo.xres = 1280;
pinfo.yres = 720;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 124;
pinfo.lcdc.h_front_porch = 110;
pinfo.lcdc.h_pulse_width = 136;
pinfo.lcdc.v_back_porch = 19;
pinfo.lcdc.v_front_porch = 5;
pinfo.lcdc.v_pulse_width = 6;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_wxga_init);

View file

@ -0,0 +1,98 @@
/* drivers/video/msm/logo.c
*
* Show Logo in RLE 565 format
*
* Copyright (C) 2008 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.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fb.h>
#include <linux/vt_kern.h>
#include <linux/unistd.h>
#include <linux/syscalls.h>
#include <linux/irq.h>
#include <asm/system.h>
#define fb_width(fb) ((fb)->var.xres)
#define fb_height(fb) ((fb)->var.yres)
#define fb_size(fb) ((fb)->var.xres * (fb)->var.yres * 2)
static void memset16(void *_ptr, unsigned short val, unsigned count)
{
unsigned short *ptr = _ptr;
count >>= 1;
while (count--)
*ptr++ = val;
}
/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
int load_565rle_image(char *filename)
{
struct fb_info *info;
int fd, err = 0;
unsigned count, max;
unsigned short *data, *bits, *ptr;
info = registered_fb[0];
if (!info) {
printk(KERN_WARNING "%s: Can not access framebuffer\n",
__func__);
return -ENODEV;
}
fd = sys_open(filename, O_RDONLY, 0);
if (fd < 0) {
printk(KERN_WARNING "%s: Can not open %s\n",
__func__, filename);
return -ENOENT;
}
count = (unsigned)sys_lseek(fd, (off_t)0, 2);
if (count == 0) {
sys_close(fd);
err = -EIO;
goto err_logo_close_file;
}
sys_lseek(fd, (off_t)0, 0);
data = kmalloc(count, GFP_KERNEL);
if (!data) {
printk(KERN_WARNING "%s: Can not alloc data\n", __func__);
err = -ENOMEM;
goto err_logo_close_file;
}
if ((unsigned)sys_read(fd, (char *)data, count) != count) {
err = -EIO;
goto err_logo_free_data;
}
max = fb_width(info) * fb_height(info);
ptr = data;
bits = (unsigned short *)(info->screen_base);
while (count > 3) {
unsigned n = ptr[0];
if (n > max)
break;
memset16(bits, ptr[1], n << 1);
bits += n;
max -= n;
ptr += 2;
count -= 4;
}
err_logo_free_data:
kfree(data);
err_logo_close_file:
sys_close(fd);
return err;
}
EXPORT_SYMBOL(load_565rle_image);

375
drivers/staging/msm/mddi.c Normal file
View file

@ -0,0 +1,375 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include "msm_fb.h"
#include "mddihosti.h"
#include "mddihost.h"
#include <mach/gpio.h>
#include <mach/clk.h>
static int mddi_probe(struct platform_device *pdev);
static int mddi_remove(struct platform_device *pdev);
static int mddi_off(struct platform_device *pdev);
static int mddi_on(struct platform_device *pdev);
static int mddi_suspend(struct platform_device *pdev, pm_message_t state);
static int mddi_resume(struct platform_device *pdev);
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mddi_early_suspend(struct early_suspend *h);
static void mddi_early_resume(struct early_suspend *h);
#endif
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
static struct clk *mddi_clk;
static struct clk *mddi_pclk;
static struct mddi_platform_data *mddi_pdata;
static struct platform_driver mddi_driver = {
.probe = mddi_probe,
.remove = mddi_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
#ifdef CONFIG_PM
.suspend = mddi_suspend,
.resume = mddi_resume,
#endif
#endif
.suspend_late = NULL,
.resume_early = NULL,
.shutdown = NULL,
.driver = {
.name = "mddi",
},
};
extern int int_mddi_pri_flag;
static int mddi_off(struct platform_device *pdev)
{
int ret = 0;
ret = panel_next_off(pdev);
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(0);
return ret;
}
static int mddi_on(struct platform_device *pdev)
{
int ret = 0;
u32 clk_rate;
struct msm_fb_data_type *mfd;
mfd = platform_get_drvdata(pdev);
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(1);
clk_rate = mfd->fbi->var.pixclock;
clk_rate = min(clk_rate, mfd->panel_info.clk_max);
if (mddi_pdata &&
mddi_pdata->mddi_sel_clk &&
mddi_pdata->mddi_sel_clk(&clk_rate))
printk(KERN_ERR
"%s: can't select mddi io clk targate rate = %d\n",
__func__, clk_rate);
if (clk_set_min_rate(mddi_clk, clk_rate) < 0)
printk(KERN_ERR "%s: clk_set_min_rate failed\n",
__func__);
ret = panel_next_on(pdev);
return ret;
}
static int mddi_resource_initialized;
static int mddi_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
int rc;
resource_size_t size ;
u32 clk_rate;
if ((pdev->id == 0) && (pdev->num_resources >= 0)) {
mddi_pdata = pdev->dev.platform_data;
size = resource_size(&pdev->resource[0]);
msm_pmdh_base = ioremap(pdev->resource[0].start, size);
MSM_FB_INFO("primary mddi base phy_addr = 0x%x virt = 0x%x\n",
pdev->resource[0].start, (int) msm_pmdh_base);
if (unlikely(!msm_pmdh_base))
return -ENOMEM;
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(1);
mddi_resource_initialized = 1;
return 0;
}
if (!mddi_resource_initialized)
return -EPERM;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
return -ENOMEM;
mdp_dev = platform_device_alloc("mdp", pdev->id);
if (!mdp_dev)
return -ENOMEM;
/*
* link to the latest pdev
*/
mfd->pdev = mdp_dev;
mfd->dest = DISPLAY_LCD;
/*
* alloc panel device data
*/
if (platform_device_add_data
(mdp_dev, pdev->dev.platform_data,
sizeof(struct msm_fb_panel_data))) {
printk(KERN_ERR "mddi_probe: platform_device_add_data failed!\n");
platform_device_put(mdp_dev);
return -ENOMEM;
}
/*
* data chain
*/
pdata = mdp_dev->dev.platform_data;
pdata->on = mddi_on;
pdata->off = mddi_off;
pdata->next = pdev;
/*
* get/set panel specific fb info
*/
mfd->panel_info = pdata->panel_info;
mfd->fb_imgType = MDP_RGB_565;
clk_rate = mfd->panel_info.clk_max;
if (mddi_pdata &&
mddi_pdata->mddi_sel_clk &&
mddi_pdata->mddi_sel_clk(&clk_rate))
printk(KERN_ERR
"%s: can't select mddi io clk targate rate = %d\n",
__func__, clk_rate);
if (clk_set_max_rate(mddi_clk, clk_rate) < 0)
printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__);
mfd->panel_info.clk_rate = mfd->panel_info.clk_min;
/*
* set driver data
*/
platform_set_drvdata(mdp_dev, mfd);
/*
* register in mdp driver
*/
rc = platform_device_add(mdp_dev);
if (rc)
goto mddi_probe_err;
pdev_list[pdev_list_cnt++] = pdev;
#ifdef CONFIG_HAS_EARLYSUSPEND
mfd->mddi_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
mfd->mddi_early_suspend.suspend = mddi_early_suspend;
mfd->mddi_early_suspend.resume = mddi_early_resume;
register_early_suspend(&mfd->mddi_early_suspend);
#endif
return 0;
mddi_probe_err:
platform_device_put(mdp_dev);
return rc;
}
static int mddi_pad_ctrl;
static int mddi_power_locked;
static int mddi_is_in_suspend;
void mddi_disable(int lock)
{
mddi_host_type host_idx = MDDI_HOST_PRIM;
if (mddi_power_locked)
return;
if (lock)
mddi_power_locked = 1;
if (mddi_host_timer.function)
del_timer_sync(&mddi_host_timer);
mddi_pad_ctrl = mddi_host_reg_in(PAD_CTL);
mddi_host_reg_out(PAD_CTL, 0x0);
if (clk_set_min_rate(mddi_clk, 0) < 0)
printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__);
clk_disable(mddi_clk);
if (mddi_pclk)
clk_disable(mddi_pclk);
disable_irq(INT_MDDI_PRI);
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(0);
}
static int mddi_suspend(struct platform_device *pdev, pm_message_t state)
{
if (mddi_is_in_suspend)
return 0;
mddi_is_in_suspend = 1;
mddi_disable(0);
return 0;
}
static int mddi_resume(struct platform_device *pdev)
{
mddi_host_type host_idx = MDDI_HOST_PRIM;
if (!mddi_is_in_suspend)
return 0;
mddi_is_in_suspend = 0;
if (mddi_power_locked)
return 0;
enable_irq(INT_MDDI_PRI);
clk_enable(mddi_clk);
if (mddi_pclk)
clk_enable(mddi_pclk);
mddi_host_reg_out(PAD_CTL, mddi_pad_ctrl);
if (mddi_host_timer.function)
mddi_host_timer_service(0);
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mddi_early_suspend(struct early_suspend *h)
{
pm_message_t state;
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
mddi_early_suspend);
state.event = PM_EVENT_SUSPEND;
mddi_suspend(mfd->pdev, state);
}
static void mddi_early_resume(struct early_suspend *h)
{
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
mddi_early_suspend);
mddi_resume(mfd->pdev);
}
#endif
static int mddi_remove(struct platform_device *pdev)
{
if (mddi_host_timer.function)
del_timer_sync(&mddi_host_timer);
iounmap(msm_pmdh_base);
return 0;
}
static int mddi_register_driver(void)
{
return platform_driver_register(&mddi_driver);
}
static int __init mddi_driver_init(void)
{
int ret;
mddi_clk = clk_get(NULL, "mddi_clk");
if (IS_ERR(mddi_clk)) {
printk(KERN_ERR "can't find mddi_clk \n");
return PTR_ERR(mddi_clk);
}
clk_enable(mddi_clk);
mddi_pclk = clk_get(NULL, "mddi_pclk");
if (IS_ERR(mddi_pclk))
mddi_pclk = NULL;
else
clk_enable(mddi_pclk);
ret = mddi_register_driver();
if (ret) {
clk_disable(mddi_clk);
clk_put(mddi_clk);
if (mddi_pclk) {
clk_disable(mddi_pclk);
clk_put(mddi_pclk);
}
printk(KERN_ERR "mddi_register_driver() failed!\n");
return ret;
}
mddi_init();
return ret;
}
module_init(mddi_driver_init);

View file

@ -0,0 +1,320 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <mach/clk.h>
#include <linux/platform_device.h>
#include "msm_fb.h"
#include "mddihosti.h"
static int mddi_ext_probe(struct platform_device *pdev);
static int mddi_ext_remove(struct platform_device *pdev);
static int mddi_ext_off(struct platform_device *pdev);
static int mddi_ext_on(struct platform_device *pdev);
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state);
static int mddi_ext_resume(struct platform_device *pdev);
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mddi_ext_early_suspend(struct early_suspend *h);
static void mddi_ext_early_resume(struct early_suspend *h);
#endif
static struct platform_driver mddi_ext_driver = {
.probe = mddi_ext_probe,
.remove = mddi_ext_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
#ifdef CONFIG_PM
.suspend = mddi_ext_suspend,
.resume = mddi_ext_resume,
#endif
#endif
.resume_early = NULL,
.resume = NULL,
.shutdown = NULL,
.driver = {
.name = "mddi_ext",
},
};
static struct clk *mddi_ext_clk;
static struct mddi_platform_data *mddi_ext_pdata;
extern int int_mddi_ext_flag;
static int mddi_ext_off(struct platform_device *pdev)
{
int ret = 0;
ret = panel_next_off(pdev);
mddi_host_stop_ext_display();
return ret;
}
static int mddi_ext_on(struct platform_device *pdev)
{
int ret = 0;
u32 clk_rate;
struct msm_fb_data_type *mfd;
mfd = platform_get_drvdata(pdev);
clk_rate = mfd->fbi->var.pixclock;
clk_rate = min(clk_rate, mfd->panel_info.clk_max);
if (mddi_ext_pdata &&
mddi_ext_pdata->mddi_sel_clk &&
mddi_ext_pdata->mddi_sel_clk(&clk_rate))
printk(KERN_ERR
"%s: can't select mddi io clk targate rate = %d\n",
__func__, clk_rate);
if (clk_set_min_rate(mddi_ext_clk, clk_rate) < 0)
printk(KERN_ERR "%s: clk_set_min_rate failed\n",
__func__);
mddi_host_start_ext_display();
ret = panel_next_on(pdev);
return ret;
}
static int mddi_ext_resource_initialized;
static int mddi_ext_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
int rc;
resource_size_t size ;
u32 clk_rate;
if ((pdev->id == 0) && (pdev->num_resources >= 0)) {
mddi_ext_pdata = pdev->dev.platform_data;
size = resource_size(&pdev->resource[0]);
msm_emdh_base = ioremap(pdev->resource[0].start, size);
MSM_FB_INFO("external mddi base address = 0x%x\n",
pdev->resource[0].start);
if (unlikely(!msm_emdh_base))
return -ENOMEM;
mddi_ext_resource_initialized = 1;
return 0;
}
if (!mddi_ext_resource_initialized)
return -EPERM;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
return -ENOMEM;
mdp_dev = platform_device_alloc("mdp", pdev->id);
if (!mdp_dev)
return -ENOMEM;
/*
* link to the latest pdev
*/
mfd->pdev = mdp_dev;
mfd->dest = DISPLAY_EXT_MDDI;
/*
* alloc panel device data
*/
if (platform_device_add_data
(mdp_dev, pdev->dev.platform_data,
sizeof(struct msm_fb_panel_data))) {
printk(KERN_ERR "mddi_ext_probe: platform_device_add_data failed!\n");
platform_device_put(mdp_dev);
return -ENOMEM;
}
/*
* data chain
*/
pdata = mdp_dev->dev.platform_data;
pdata->on = mddi_ext_on;
pdata->off = mddi_ext_off;
pdata->next = pdev;
/*
* get/set panel specific fb info
*/
mfd->panel_info = pdata->panel_info;
mfd->fb_imgType = MDP_RGB_565;
clk_rate = mfd->panel_info.clk_max;
if (mddi_ext_pdata &&
mddi_ext_pdata->mddi_sel_clk &&
mddi_ext_pdata->mddi_sel_clk(&clk_rate))
printk(KERN_ERR
"%s: can't select mddi io clk targate rate = %d\n",
__func__, clk_rate);
if (clk_set_max_rate(mddi_ext_clk, clk_rate) < 0)
printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__);
mfd->panel_info.clk_rate = mfd->panel_info.clk_min;
/*
* set driver data
*/
platform_set_drvdata(mdp_dev, mfd);
/*
* register in mdp driver
*/
rc = platform_device_add(mdp_dev);
if (rc)
goto mddi_ext_probe_err;
pdev_list[pdev_list_cnt++] = pdev;
#ifdef CONFIG_HAS_EARLYSUSPEND
mfd->mddi_ext_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
mfd->mddi_ext_early_suspend.suspend = mddi_ext_early_suspend;
mfd->mddi_ext_early_suspend.resume = mddi_ext_early_resume;
register_early_suspend(&mfd->mddi_ext_early_suspend);
#endif
return 0;
mddi_ext_probe_err:
platform_device_put(mdp_dev);
return rc;
}
static int mddi_ext_is_in_suspend;
static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state)
{
if (mddi_ext_is_in_suspend)
return 0;
mddi_ext_is_in_suspend = 1;
if (clk_set_min_rate(mddi_ext_clk, 0) < 0)
printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__);
clk_disable(mddi_ext_clk);
disable_irq(INT_MDDI_EXT);
return 0;
}
static int mddi_ext_resume(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
mfd = platform_get_drvdata(pdev);
if (!mddi_ext_is_in_suspend)
return 0;
mddi_ext_is_in_suspend = 0;
enable_irq(INT_MDDI_EXT);
clk_enable(mddi_ext_clk);
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mddi_ext_early_suspend(struct early_suspend *h)
{
pm_message_t state;
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
mddi_ext_early_suspend);
state.event = PM_EVENT_SUSPEND;
mddi_ext_suspend(mfd->pdev, state);
}
static void mddi_ext_early_resume(struct early_suspend *h)
{
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
mddi_ext_early_suspend);
mddi_ext_resume(mfd->pdev);
}
#endif
static int mddi_ext_remove(struct platform_device *pdev)
{
iounmap(msm_emdh_base);
return 0;
}
static int mddi_ext_register_driver(void)
{
return platform_driver_register(&mddi_ext_driver);
}
static int __init mddi_ext_driver_init(void)
{
int ret;
mddi_ext_clk = clk_get(NULL, "emdh_clk");
if (IS_ERR(mddi_ext_clk)) {
printk(KERN_ERR "can't find emdh_clk\n");
return PTR_ERR(mddi_ext_clk);
}
clk_enable(mddi_ext_clk);
ret = mddi_ext_register_driver();
if (ret) {
clk_disable(mddi_ext_clk);
clk_put(mddi_ext_clk);
printk(KERN_ERR "mddi_ext_register_driver() failed!\n");
return ret;
}
mddi_init();
return ret;
}
module_init(mddi_ext_driver_init);

View file

@ -0,0 +1,91 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
static int mddi_ext_lcd_on(struct platform_device *pdev);
static int mddi_ext_lcd_off(struct platform_device *pdev);
static int mddi_ext_lcd_on(struct platform_device *pdev)
{
return 0;
}
static int mddi_ext_lcd_off(struct platform_device *pdev)
{
return 0;
}
static int __init mddi_ext_lcd_probe(struct platform_device *pdev)
{
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = mddi_ext_lcd_probe,
.driver = {
.name = "extmddi_svga",
},
};
static struct msm_fb_panel_data mddi_ext_lcd_panel_data = {
.panel_info.xres = 800,
.panel_info.yres = 600,
.panel_info.type = EXT_MDDI_PANEL,
.panel_info.pdest = DISPLAY_1,
.panel_info.wait_cycle = 0,
.panel_info.bpp = 18,
.panel_info.fb_num = 2,
.panel_info.clk_rate = 122880000,
.panel_info.clk_min = 120000000,
.panel_info.clk_max = 125000000,
.on = mddi_ext_lcd_on,
.off = mddi_ext_lcd_off,
};
static struct platform_device this_device = {
.name = "extmddi_svga",
.id = 0,
.dev = {
.platform_data = &mddi_ext_lcd_panel_data,
}
};
static int __init mddi_ext_lcd_init(void)
{
int ret;
struct msm_panel_info *pinfo;
ret = platform_driver_register(&this_driver);
if (!ret) {
pinfo = &mddi_ext_lcd_panel_data.panel_info;
pinfo->lcd.vsync_enable = FALSE;
pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
}
return ret;
}
module_init(mddi_ext_lcd_init);

View file

@ -0,0 +1,114 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
static int prism_lcd_on(struct platform_device *pdev);
static int prism_lcd_off(struct platform_device *pdev);
static int prism_lcd_on(struct platform_device *pdev)
{
/* Set the MDP pixel data attributes for Primary Display */
mddi_host_write_pix_attr_reg(0x00C3);
return 0;
}
static int prism_lcd_off(struct platform_device *pdev)
{
return 0;
}
static int __init prism_probe(struct platform_device *pdev)
{
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = prism_probe,
.driver = {
.name = "mddi_prism_wvga",
},
};
static struct msm_fb_panel_data prism_panel_data = {
.on = prism_lcd_on,
.off = prism_lcd_off,
};
static struct platform_device this_device = {
.name = "mddi_prism_wvga",
.id = 0,
.dev = {
.platform_data = &prism_panel_data,
}
};
static int __init prism_init(void)
{
int ret;
struct msm_panel_info *pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
u32 id;
ret = msm_fb_detect_client("mddi_prism_wvga");
if (ret == -ENODEV)
return 0;
if (ret) {
id = mddi_get_client_id();
if (((id >> 16) != 0x4474) || ((id & 0xffff) == 0x8960))
return 0;
}
#endif
ret = platform_driver_register(&this_driver);
if (!ret) {
pinfo = &prism_panel_data.panel_info;
pinfo->xres = 800;
pinfo->yres = 480;
pinfo->type = MDDI_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
pinfo->wait_cycle = 0;
pinfo->bpp = 18;
pinfo->fb_num = 2;
pinfo->clk_rate = 153600000;
pinfo->clk_min = 150000000;
pinfo->clk_max = 160000000;
pinfo->lcd.vsync_enable = TRUE;
pinfo->lcd.refx100 = 6050;
pinfo->lcd.v_back_porch = 23;
pinfo->lcd.v_front_porch = 20;
pinfo->lcd.v_pulse_width = 105;
pinfo->lcd.hw_vsync_mode = TRUE;
pinfo->lcd.vsync_notifier_period = 0;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
}
return ret;
}
module_init(prism_init);

View file

@ -0,0 +1,892 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
#define SHARP_QVGA_PRIM 1
#define SHARP_128X128_SECD 2
extern uint32 mddi_host_core_version;
static boolean mddi_debug_prim_wait = FALSE;
static boolean mddi_sharp_vsync_wake = TRUE;
static boolean mddi_sharp_monitor_refresh_value = TRUE;
static boolean mddi_sharp_report_refresh_measurements = FALSE;
static uint32 mddi_sharp_rows_per_second = 13830; /* 5200000/376 */
static uint32 mddi_sharp_rows_per_refresh = 338;
static uint32 mddi_sharp_usecs_per_refresh = 24440; /* (376+338)/5200000 */
static boolean mddi_sharp_debug_60hz_refresh = FALSE;
extern mddi_gpio_info_type mddi_gpio;
extern boolean mddi_vsync_detect_enabled;
static msm_fb_vsync_handler_type mddi_sharp_vsync_handler;
static void *mddi_sharp_vsync_handler_arg;
static uint16 mddi_sharp_vsync_attempts;
static void mddi_sharp_prim_lcd_init(void);
static void mddi_sharp_sub_lcd_init(void);
static void mddi_sharp_lcd_set_backlight(struct msm_fb_data_type *mfd);
static void mddi_sharp_vsync_set_handler(msm_fb_vsync_handler_type handler,
void *);
static void mddi_sharp_lcd_vsync_detected(boolean detected);
static struct msm_panel_common_pdata *mddi_sharp_pdata;
#define REG_SYSCTL 0x0000
#define REG_INTR 0x0006
#define REG_CLKCNF 0x000C
#define REG_CLKDIV1 0x000E
#define REG_CLKDIV2 0x0010
#define REG_GIOD 0x0040
#define REG_GIOA 0x0042
#define REG_AGM 0x010A
#define REG_FLFT 0x0110
#define REG_FRGT 0x0112
#define REG_FTOP 0x0114
#define REG_FBTM 0x0116
#define REG_FSTRX 0x0118
#define REG_FSTRY 0x011A
#define REG_VRAM 0x0202
#define REG_SSDCTL 0x0330
#define REG_SSD0 0x0332
#define REG_PSTCTL1 0x0400
#define REG_PSTCTL2 0x0402
#define REG_PTGCTL 0x042A
#define REG_PTHP 0x042C
#define REG_PTHB 0x042E
#define REG_PTHW 0x0430
#define REG_PTHF 0x0432
#define REG_PTVP 0x0434
#define REG_PTVB 0x0436
#define REG_PTVW 0x0438
#define REG_PTVF 0x043A
#define REG_VBLKS 0x0458
#define REG_VBLKE 0x045A
#define REG_SUBCTL 0x0700
#define REG_SUBTCMD 0x0702
#define REG_SUBTCMDD 0x0704
#define REG_REVBYTE 0x0A02
#define REG_REVCNT 0x0A04
#define REG_REVATTR 0x0A06
#define REG_REVFMT 0x0A08
#define SHARP_SUB_UNKNOWN 0xffffffff
#define SHARP_SUB_HYNIX 1
#define SHARP_SUB_ROHM 2
static uint32 sharp_subpanel_type = SHARP_SUB_UNKNOWN;
static void sub_through_write(int sub_rs, uint32 sub_data)
{
mddi_queue_register_write(REG_SUBTCMDD, sub_data, FALSE, 0);
/* CS=1,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, FALSE, 0);
/* CS=0,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0);
/* CS=0,RD=1,WE=0,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x0004 | sub_rs, FALSE, 0);
/* CS=0,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0);
/* CS=1,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, TRUE, 0);
}
static uint32 sub_through_read(int sub_rs)
{
uint32 sub_data;
/* CS=1,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, FALSE, 0);
/* CS=0,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0);
/* CS=0,RD=1,WE=0,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x0002 | sub_rs, TRUE, 0);
mddi_queue_register_read(REG_SUBTCMDD, &sub_data, TRUE, 0);
/* CS=0,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0);
/* CS=1,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, TRUE, 0);
return sub_data;
}
static void serigo(uint32 ssd)
{
uint32 ssdctl;
mddi_queue_register_read(REG_SSDCTL, &ssdctl, TRUE, 0);
ssdctl = ((ssdctl & 0xE7) | 0x02);
mddi_queue_register_write(REG_SSD0, ssd, FALSE, 0);
mddi_queue_register_write(REG_SSDCTL, ssdctl, TRUE, 0);
do {
mddi_queue_register_read(REG_SSDCTL, &ssdctl, TRUE, 0);
} while ((ssdctl & 0x0002) != 0);
if (mddi_debug_prim_wait)
mddi_wait(2);
}
static void mddi_sharp_lcd_powerdown(void)
{
serigo(0x0131);
serigo(0x0300);
mddi_wait(40);
serigo(0x0135);
mddi_wait(20);
serigo(0x2122);
mddi_wait(20);
serigo(0x0201);
mddi_wait(20);
serigo(0x2100);
mddi_wait(20);
serigo(0x2000);
mddi_wait(20);
mddi_queue_register_write(REG_PSTCTL1, 0x1, TRUE, 0);
mddi_wait(100);
mddi_queue_register_write(REG_PSTCTL1, 0x0, TRUE, 0);
mddi_wait(2);
mddi_queue_register_write(REG_SYSCTL, 0x1, TRUE, 0);
mddi_wait(2);
mddi_queue_register_write(REG_CLKDIV1, 0x3, TRUE, 0);
mddi_wait(2);
mddi_queue_register_write(REG_SSDCTL, 0x0000, TRUE, 0); /* SSDRESET */
mddi_queue_register_write(REG_SYSCTL, 0x0, TRUE, 0);
mddi_wait(2);
}
static void mddi_sharp_lcd_set_backlight(struct msm_fb_data_type *mfd)
{
uint32 regdata;
int32 level;
int max = mfd->panel_info.bl_max;
int min = mfd->panel_info.bl_min;
if (mddi_sharp_pdata && mddi_sharp_pdata->backlight_level) {
level = mddi_sharp_pdata->backlight_level(mfd->bl_level,
max,
min);
if (level < 0)
return;
/* use Rodem GPIO(2:0) to give 8 levels of backlight (7-0) */
/* Set lower 3 GPIOs as Outputs (set to 0) */
mddi_queue_register_read(REG_GIOA, &regdata, TRUE, 0);
mddi_queue_register_write(REG_GIOA, regdata & 0xfff8, TRUE, 0);
/* Set lower 3 GPIOs as level */
mddi_queue_register_read(REG_GIOD, &regdata, TRUE, 0);
mddi_queue_register_write(REG_GIOD,
(regdata & 0xfff8) | (0x07 & level), TRUE, 0);
}
}
static void mddi_sharp_prim_lcd_init(void)
{
mddi_queue_register_write(REG_SYSCTL, 0x4000, TRUE, 0);
mddi_wait(1);
mddi_queue_register_write(REG_SYSCTL, 0x0000, TRUE, 0);
mddi_wait(5);
mddi_queue_register_write(REG_SYSCTL, 0x0001, FALSE, 0);
mddi_queue_register_write(REG_CLKDIV1, 0x000b, FALSE, 0);
/* new reg write below */
if (mddi_sharp_debug_60hz_refresh)
mddi_queue_register_write(REG_CLKCNF, 0x070d, FALSE, 0);
else
mddi_queue_register_write(REG_CLKCNF, 0x0708, FALSE, 0);
mddi_queue_register_write(REG_SYSCTL, 0x0201, FALSE, 0);
mddi_queue_register_write(REG_PTGCTL, 0x0010, FALSE, 0);
mddi_queue_register_write(REG_PTHP, 4, FALSE, 0);
mddi_queue_register_write(REG_PTHB, 40, FALSE, 0);
mddi_queue_register_write(REG_PTHW, 240, FALSE, 0);
if (mddi_sharp_debug_60hz_refresh)
mddi_queue_register_write(REG_PTHF, 12, FALSE, 0);
else
mddi_queue_register_write(REG_PTHF, 92, FALSE, 0);
mddi_wait(1);
mddi_queue_register_write(REG_PTVP, 1, FALSE, 0);
mddi_queue_register_write(REG_PTVB, 2, FALSE, 0);
mddi_queue_register_write(REG_PTVW, 320, FALSE, 0);
mddi_queue_register_write(REG_PTVF, 15, FALSE, 0);
mddi_wait(1);
/* vram_color set REG_AGM???? */
mddi_queue_register_write(REG_AGM, 0x0000, TRUE, 0);
mddi_queue_register_write(REG_SSDCTL, 0x0000, FALSE, 0);
mddi_queue_register_write(REG_SSDCTL, 0x0001, TRUE, 0);
mddi_wait(1);
mddi_queue_register_write(REG_PSTCTL1, 0x0001, TRUE, 0);
mddi_wait(10);
serigo(0x0701);
/* software reset */
mddi_wait(1);
/* Wait over 50us */
serigo(0x0400);
/* DCLK~ACHSYNC~ACVSYNC polarity setting */
serigo(0x2900);
/* EEPROM start read address setting */
serigo(0x2606);
/* EEPROM start read register setting */
mddi_wait(20);
/* Wait over 20ms */
serigo(0x0503);
/* Horizontal timing setting */
serigo(0x062C);
/* Veritical timing setting */
serigo(0x2001);
/* power initialize setting(VDC2) */
mddi_wait(20);
/* Wait over 20ms */
serigo(0x2120);
/* Initialize power setting(CPS) */
mddi_wait(20);
/* Wait over 20ms */
serigo(0x2130);
/* Initialize power setting(CPS) */
mddi_wait(20);
/* Wait over 20ms */
serigo(0x2132);
/* Initialize power setting(CPS) */
mddi_wait(10);
/* Wait over 10ms */
serigo(0x2133);
/* Initialize power setting(CPS) */
mddi_wait(20);
/* Wait over 20ms */
serigo(0x0200);
/* Panel initialize release(INIT) */
mddi_wait(1);
/* Wait over 1ms */
serigo(0x0131);
/* Panel setting(CPS) */
mddi_wait(1);
/* Wait over 1ms */
mddi_queue_register_write(REG_PSTCTL1, 0x0003, TRUE, 0);
/* if (FFA LCD is upside down) -> serigo(0x0100); */
serigo(0x0130);
/* Black mask release(display ON) */
mddi_wait(1);
/* Wait over 1ms */
if (mddi_sharp_vsync_wake) {
mddi_queue_register_write(REG_VBLKS, 0x1001, TRUE, 0);
mddi_queue_register_write(REG_VBLKE, 0x1002, TRUE, 0);
}
/* Set the MDP pixel data attributes for Primary Display */
mddi_host_write_pix_attr_reg(0x00C3);
return;
}
void mddi_sharp_sub_lcd_init(void)
{
mddi_queue_register_write(REG_SYSCTL, 0x4000, FALSE, 0);
mddi_queue_register_write(REG_SYSCTL, 0x0000, TRUE, 0);
mddi_wait(100);
mddi_queue_register_write(REG_SYSCTL, 0x0001, FALSE, 0);
mddi_queue_register_write(REG_CLKDIV1, 0x000b, FALSE, 0);
mddi_queue_register_write(REG_CLKCNF, 0x0708, FALSE, 0);
mddi_queue_register_write(REG_SYSCTL, 0x0201, FALSE, 0);
mddi_queue_register_write(REG_PTGCTL, 0x0010, FALSE, 0);
mddi_queue_register_write(REG_PTHP, 4, FALSE, 0);
mddi_queue_register_write(REG_PTHB, 40, FALSE, 0);
mddi_queue_register_write(REG_PTHW, 128, FALSE, 0);
mddi_queue_register_write(REG_PTHF, 92, FALSE, 0);
mddi_queue_register_write(REG_PTVP, 1, FALSE, 0);
mddi_queue_register_write(REG_PTVB, 2, FALSE, 0);
mddi_queue_register_write(REG_PTVW, 128, FALSE, 0);
mddi_queue_register_write(REG_PTVF, 15, FALSE, 0);
/* Now the sub display..... */
/* Reset High */
mddi_queue_register_write(REG_SUBCTL, 0x0200, FALSE, 0);
/* CS=1,RD=1,WE=1,RS=1 */
mddi_queue_register_write(REG_SUBTCMD, 0x000f, TRUE, 0);
mddi_wait(1);
/* Wait 5us */
if (sharp_subpanel_type == SHARP_SUB_UNKNOWN) {
uint32 data;
sub_through_write(1, 0x05);
sub_through_write(1, 0x6A);
sub_through_write(1, 0x1D);
sub_through_write(1, 0x05);
data = sub_through_read(1);
if (data == 0x6A) {
sharp_subpanel_type = SHARP_SUB_HYNIX;
} else {
sub_through_write(0, 0x36);
sub_through_write(1, 0xA8);
sub_through_write(0, 0x09);
data = sub_through_read(1);
data = sub_through_read(1);
if (data == 0x54) {
sub_through_write(0, 0x36);
sub_through_write(1, 0x00);
sharp_subpanel_type = SHARP_SUB_ROHM;
}
}
}
if (sharp_subpanel_type == SHARP_SUB_HYNIX) {
sub_through_write(1, 0x00); /* Display setting 1 */
sub_through_write(1, 0x04);
sub_through_write(1, 0x01);
sub_through_write(1, 0x05);
sub_through_write(1, 0x0280);
sub_through_write(1, 0x0301);
sub_through_write(1, 0x0402);
sub_through_write(1, 0x0500);
sub_through_write(1, 0x0681);
sub_through_write(1, 0x077F);
sub_through_write(1, 0x08C0);
sub_through_write(1, 0x0905);
sub_through_write(1, 0x0A02);
sub_through_write(1, 0x0B00);
sub_through_write(1, 0x0C00);
sub_through_write(1, 0x0D00);
sub_through_write(1, 0x0E00);
sub_through_write(1, 0x0F00);
sub_through_write(1, 0x100B); /* Display setting 2 */
sub_through_write(1, 0x1103);
sub_through_write(1, 0x1237);
sub_through_write(1, 0x1300);
sub_through_write(1, 0x1400);
sub_through_write(1, 0x1500);
sub_through_write(1, 0x1605);
sub_through_write(1, 0x1700);
sub_through_write(1, 0x1800);
sub_through_write(1, 0x192E);
sub_through_write(1, 0x1A00);
sub_through_write(1, 0x1B00);
sub_through_write(1, 0x1C00);
sub_through_write(1, 0x151A); /* Power setting */
sub_through_write(1, 0x2002); /* Gradation Palette setting */
sub_through_write(1, 0x2107);
sub_through_write(1, 0x220C);
sub_through_write(1, 0x2310);
sub_through_write(1, 0x2414);
sub_through_write(1, 0x2518);
sub_through_write(1, 0x261C);
sub_through_write(1, 0x2720);
sub_through_write(1, 0x2824);
sub_through_write(1, 0x2928);
sub_through_write(1, 0x2A2B);
sub_through_write(1, 0x2B2E);
sub_through_write(1, 0x2C31);
sub_through_write(1, 0x2D34);
sub_through_write(1, 0x2E37);
sub_through_write(1, 0x2F3A);
sub_through_write(1, 0x303C);
sub_through_write(1, 0x313E);
sub_through_write(1, 0x323F);
sub_through_write(1, 0x3340);
sub_through_write(1, 0x3441);
sub_through_write(1, 0x3543);
sub_through_write(1, 0x3646);
sub_through_write(1, 0x3749);
sub_through_write(1, 0x384C);
sub_through_write(1, 0x394F);
sub_through_write(1, 0x3A52);
sub_through_write(1, 0x3B59);
sub_through_write(1, 0x3C60);
sub_through_write(1, 0x3D67);
sub_through_write(1, 0x3E6E);
sub_through_write(1, 0x3F7F);
sub_through_write(1, 0x4001);
sub_through_write(1, 0x4107);
sub_through_write(1, 0x420C);
sub_through_write(1, 0x4310);
sub_through_write(1, 0x4414);
sub_through_write(1, 0x4518);
sub_through_write(1, 0x461C);
sub_through_write(1, 0x4720);
sub_through_write(1, 0x4824);
sub_through_write(1, 0x4928);
sub_through_write(1, 0x4A2B);
sub_through_write(1, 0x4B2E);
sub_through_write(1, 0x4C31);
sub_through_write(1, 0x4D34);
sub_through_write(1, 0x4E37);
sub_through_write(1, 0x4F3A);
sub_through_write(1, 0x503C);
sub_through_write(1, 0x513E);
sub_through_write(1, 0x523F);
sub_through_write(1, 0x5340);
sub_through_write(1, 0x5441);
sub_through_write(1, 0x5543);
sub_through_write(1, 0x5646);
sub_through_write(1, 0x5749);
sub_through_write(1, 0x584C);
sub_through_write(1, 0x594F);
sub_through_write(1, 0x5A52);
sub_through_write(1, 0x5B59);
sub_through_write(1, 0x5C60);
sub_through_write(1, 0x5D67);
sub_through_write(1, 0x5E6E);
sub_through_write(1, 0x5F7E);
sub_through_write(1, 0x6000);
sub_through_write(1, 0x6107);
sub_through_write(1, 0x620C);
sub_through_write(1, 0x6310);
sub_through_write(1, 0x6414);
sub_through_write(1, 0x6518);
sub_through_write(1, 0x661C);
sub_through_write(1, 0x6720);
sub_through_write(1, 0x6824);
sub_through_write(1, 0x6928);
sub_through_write(1, 0x6A2B);
sub_through_write(1, 0x6B2E);
sub_through_write(1, 0x6C31);
sub_through_write(1, 0x6D34);
sub_through_write(1, 0x6E37);
sub_through_write(1, 0x6F3A);
sub_through_write(1, 0x703C);
sub_through_write(1, 0x713E);
sub_through_write(1, 0x723F);
sub_through_write(1, 0x7340);
sub_through_write(1, 0x7441);
sub_through_write(1, 0x7543);
sub_through_write(1, 0x7646);
sub_through_write(1, 0x7749);
sub_through_write(1, 0x784C);
sub_through_write(1, 0x794F);
sub_through_write(1, 0x7A52);
sub_through_write(1, 0x7B59);
sub_through_write(1, 0x7C60);
sub_through_write(1, 0x7D67);
sub_through_write(1, 0x7E6E);
sub_through_write(1, 0x7F7D);
sub_through_write(1, 0x1851); /* Display on */
mddi_queue_register_write(REG_AGM, 0x0000, TRUE, 0);
/* 1 pixel / 1 post clock */
mddi_queue_register_write(REG_CLKDIV2, 0x3b00, FALSE, 0);
/* SUB LCD select */
mddi_queue_register_write(REG_PSTCTL2, 0x0080, FALSE, 0);
/* RS=0,command initiate number=0,select master mode */
mddi_queue_register_write(REG_SUBCTL, 0x0202, FALSE, 0);
/* Sub LCD Data transform start */
mddi_queue_register_write(REG_PSTCTL1, 0x0003, FALSE, 0);
} else if (sharp_subpanel_type == SHARP_SUB_ROHM) {
sub_through_write(0, 0x01); /* Display setting */
sub_through_write(1, 0x00);
mddi_wait(1);
/* Wait 100us <----- ******* Update 2005/01/24 */
sub_through_write(0, 0xB6);
sub_through_write(1, 0x0C);
sub_through_write(1, 0x4A);
sub_through_write(1, 0x20);
sub_through_write(0, 0x3A);
sub_through_write(1, 0x05);
sub_through_write(0, 0xB7);
sub_through_write(1, 0x01);
sub_through_write(0, 0xBA);
sub_through_write(1, 0x20);
sub_through_write(1, 0x02);
sub_through_write(0, 0x25);
sub_through_write(1, 0x4F);
sub_through_write(0, 0xBB);
sub_through_write(1, 0x00);
sub_through_write(0, 0x36);
sub_through_write(1, 0x00);
sub_through_write(0, 0xB1);
sub_through_write(1, 0x05);
sub_through_write(0, 0xBE);
sub_through_write(1, 0x80);
sub_through_write(0, 0x26);
sub_through_write(1, 0x01);
sub_through_write(0, 0x2A);
sub_through_write(1, 0x02);
sub_through_write(1, 0x81);
sub_through_write(0, 0x2B);
sub_through_write(1, 0x00);
sub_through_write(1, 0x7F);
sub_through_write(0, 0x2C);
sub_through_write(0, 0x11); /* Sleep mode off */
mddi_wait(1);
/* Wait 100 ms <----- ******* Update 2005/01/24 */
sub_through_write(0, 0x29); /* Display on */
sub_through_write(0, 0xB3);
sub_through_write(1, 0x20);
sub_through_write(1, 0xAA);
sub_through_write(1, 0xA0);
sub_through_write(1, 0x20);
sub_through_write(1, 0x30);
sub_through_write(1, 0xA6);
sub_through_write(1, 0xFF);
sub_through_write(1, 0x9A);
sub_through_write(1, 0x9F);
sub_through_write(1, 0xAF);
sub_through_write(1, 0xBC);
sub_through_write(1, 0xCF);
sub_through_write(1, 0xDF);
sub_through_write(1, 0x20);
sub_through_write(1, 0x9C);
sub_through_write(1, 0x8A);
sub_through_write(0, 0x002C); /* Display on */
/* 1 pixel / 2 post clock */
mddi_queue_register_write(REG_CLKDIV2, 0x7b00, FALSE, 0);
/* SUB LCD select */
mddi_queue_register_write(REG_PSTCTL2, 0x0080, FALSE, 0);
/* RS=1,command initiate number=0,select master mode */
mddi_queue_register_write(REG_SUBCTL, 0x0242, FALSE, 0);
/* Sub LCD Data transform start */
mddi_queue_register_write(REG_PSTCTL1, 0x0003, FALSE, 0);
}
/* Set the MDP pixel data attributes for Sub Display */
mddi_host_write_pix_attr_reg(0x00C0);
}
void mddi_sharp_lcd_vsync_detected(boolean detected)
{
/* static timetick_type start_time = 0; */
static struct timeval start_time;
static boolean first_time = TRUE;
/* uint32 mdp_cnt_val = 0; */
/* timetick_type elapsed_us; */
struct timeval now;
uint32 elapsed_us;
uint32 num_vsyncs;
if ((detected) || (mddi_sharp_vsync_attempts > 5)) {
if ((detected) && (mddi_sharp_monitor_refresh_value)) {
/* if (start_time != 0) */
if (!first_time) {
jiffies_to_timeval(jiffies, &now);
elapsed_us =
(now.tv_sec - start_time.tv_sec) * 1000000 +
now.tv_usec - start_time.tv_usec;
/*
* LCD is configured for a refresh every usecs,
* so to determine the number of vsyncs that
* have occurred since the last measurement add
* half that to the time difference and divide
* by the refresh rate.
*/
num_vsyncs = (elapsed_us +
(mddi_sharp_usecs_per_refresh >>
1)) /
mddi_sharp_usecs_per_refresh;
/*
* LCD is configured for * hsyncs (rows) per
* refresh cycle. Calculate new rows_per_second
* value based upon these new measurements.
* MDP can update with this new value.
*/
mddi_sharp_rows_per_second =
(mddi_sharp_rows_per_refresh * 1000 *
num_vsyncs) / (elapsed_us / 1000);
}
/* start_time = timetick_get(); */
first_time = FALSE;
jiffies_to_timeval(jiffies, &start_time);
if (mddi_sharp_report_refresh_measurements) {
/* mdp_cnt_val = MDP_LINE_COUNT; */
}
}
/* if detected = TRUE, client initiated wakeup was detected */
if (mddi_sharp_vsync_handler != NULL) {
(*mddi_sharp_vsync_handler)
(mddi_sharp_vsync_handler_arg);
mddi_sharp_vsync_handler = NULL;
}
mddi_vsync_detect_enabled = FALSE;
mddi_sharp_vsync_attempts = 0;
/* need to clear this vsync wakeup */
if (!mddi_queue_register_write_int(REG_INTR, 0x0000)) {
MDDI_MSG_ERR("Vsync interrupt clear failed!\n");
}
if (!detected) {
/* give up after 5 failed attempts but show error */
MDDI_MSG_NOTICE("Vsync detection failed!\n");
} else if ((mddi_sharp_monitor_refresh_value) &&
(mddi_sharp_report_refresh_measurements)) {
MDDI_MSG_NOTICE(" Lines Per Second=%d!\n",
mddi_sharp_rows_per_second);
}
} else
/* if detected = FALSE, we woke up from hibernation, but did not
* detect client initiated wakeup.
*/
mddi_sharp_vsync_attempts++;
}
/* ISR to be executed */
void mddi_sharp_vsync_set_handler(msm_fb_vsync_handler_type handler, void *arg)
{
boolean error = FALSE;
unsigned long flags;
/* Disable interrupts */
spin_lock_irqsave(&mddi_host_spin_lock, flags);
/* INTLOCK(); */
if (mddi_sharp_vsync_handler != NULL)
error = TRUE;
/* Register the handler for this particular GROUP interrupt source */
mddi_sharp_vsync_handler = handler;
mddi_sharp_vsync_handler_arg = arg;
/* Restore interrupts */
spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
/* INTFREE(); */
if (error)
MDDI_MSG_ERR("MDDI: Previous Vsync handler never called\n");
/* Enable the vsync wakeup */
mddi_queue_register_write(REG_INTR, 0x8100, FALSE, 0);
mddi_sharp_vsync_attempts = 1;
mddi_vsync_detect_enabled = TRUE;
} /* mddi_sharp_vsync_set_handler */
static int mddi_sharp_lcd_on(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (mfd->panel.id == SHARP_QVGA_PRIM)
mddi_sharp_prim_lcd_init();
else
mddi_sharp_sub_lcd_init();
return 0;
}
static int mddi_sharp_lcd_off(struct platform_device *pdev)
{
mddi_sharp_lcd_powerdown();
return 0;
}
static int __init mddi_sharp_probe(struct platform_device *pdev)
{
if (pdev->id == 0) {
mddi_sharp_pdata = pdev->dev.platform_data;
return 0;
}
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = mddi_sharp_probe,
.driver = {
.name = "mddi_sharp_qvga",
},
};
static struct msm_fb_panel_data mddi_sharp_panel_data0 = {
.on = mddi_sharp_lcd_on,
.off = mddi_sharp_lcd_off,
.set_backlight = mddi_sharp_lcd_set_backlight,
.set_vsync_notifier = mddi_sharp_vsync_set_handler,
};
static struct platform_device this_device_0 = {
.name = "mddi_sharp_qvga",
.id = SHARP_QVGA_PRIM,
.dev = {
.platform_data = &mddi_sharp_panel_data0,
}
};
static struct msm_fb_panel_data mddi_sharp_panel_data1 = {
.on = mddi_sharp_lcd_on,
.off = mddi_sharp_lcd_off,
};
static struct platform_device this_device_1 = {
.name = "mddi_sharp_qvga",
.id = SHARP_128X128_SECD,
.dev = {
.platform_data = &mddi_sharp_panel_data1,
}
};
static int __init mddi_sharp_init(void)
{
int ret;
struct msm_panel_info *pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
u32 id;
ret = msm_fb_detect_client("mddi_sharp_qvga");
if (ret == -ENODEV)
return 0;
if (ret) {
id = mddi_get_client_id();
if (((id >> 16) != 0x0) || ((id & 0xffff) != 0x8835))
return 0;
}
#endif
if (mddi_host_core_version > 8) {
/* can use faster refresh with newer hw revisions */
mddi_sharp_debug_60hz_refresh = TRUE;
/* Timing variables for tracking vsync */
/* dot_clock = 6.00MHz
* horizontal count = 296
* vertical count = 338
* refresh rate = 6000000/(296+338) = 60Hz
*/
mddi_sharp_rows_per_second = 20270; /* 6000000/296 */
mddi_sharp_rows_per_refresh = 338;
mddi_sharp_usecs_per_refresh = 16674; /* (296+338)/6000000 */
} else {
/* Timing variables for tracking vsync */
/* dot_clock = 5.20MHz
* horizontal count = 376
* vertical count = 338
* refresh rate = 5200000/(376+338) = 41Hz
*/
mddi_sharp_rows_per_second = 13830; /* 5200000/376 */
mddi_sharp_rows_per_refresh = 338;
mddi_sharp_usecs_per_refresh = 24440; /* (376+338)/5200000 */
}
ret = platform_driver_register(&this_driver);
if (!ret) {
pinfo = &mddi_sharp_panel_data0.panel_info;
pinfo->xres = 240;
pinfo->yres = 320;
pinfo->type = MDDI_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
pinfo->wait_cycle = 0;
pinfo->bpp = 18;
pinfo->fb_num = 2;
pinfo->clk_rate = 122880000;
pinfo->clk_min = 120000000;
pinfo->clk_max = 125000000;
pinfo->lcd.vsync_enable = TRUE;
pinfo->lcd.refx100 =
(mddi_sharp_rows_per_second * 100) /
mddi_sharp_rows_per_refresh;
pinfo->lcd.v_back_porch = 12;
pinfo->lcd.v_front_porch = 6;
pinfo->lcd.v_pulse_width = 0;
pinfo->lcd.hw_vsync_mode = FALSE;
pinfo->lcd.vsync_notifier_period = (1 * HZ);
pinfo->bl_max = 7;
pinfo->bl_min = 1;
ret = platform_device_register(&this_device_0);
if (ret)
platform_driver_unregister(&this_driver);
pinfo = &mddi_sharp_panel_data1.panel_info;
pinfo->xres = 128;
pinfo->yres = 128;
pinfo->type = MDDI_PANEL;
pinfo->pdest = DISPLAY_2;
pinfo->mddi.vdopkt = 0x400;
pinfo->wait_cycle = 0;
pinfo->bpp = 18;
pinfo->clk_rate = 122880000;
pinfo->clk_min = 120000000;
pinfo->clk_max = 125000000;
pinfo->fb_num = 2;
ret = platform_device_register(&this_device_1);
if (ret) {
platform_device_unregister(&this_device_0);
platform_driver_unregister(&this_driver);
}
}
if (!ret)
mddi_lcd.vsync_detected = mddi_sharp_lcd_vsync_detected;
return ret;
}
module_init(mddi_sharp_init);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,52 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MDDI_TOSHIBA_H
#define MDDI_TOSHIBA_H
#define TOSHIBA_VGA_PRIM 1
#define TOSHIBA_VGA_SECD 2
#define LCD_TOSHIBA_2P4_VGA 0
#define LCD_TOSHIBA_2P4_WVGA 1
#define LCD_TOSHIBA_2P4_WVGA_PT 2
#define LCD_SHARP_2P4_VGA 3
#define GPIO_BLOCK_BASE 0x150000
#define SYSTEM_BLOCK2_BASE 0x170000
#define GPIODIR (GPIO_BLOCK_BASE|0x04)
#define GPIOSEL (SYSTEM_BLOCK2_BASE|0x00)
#define GPIOPC (GPIO_BLOCK_BASE|0x28)
#define GPIODATA (GPIO_BLOCK_BASE|0x00)
#define write_client_reg(__X, __Y, __Z) {\
mddi_queue_register_write(__X, __Y, TRUE, 0);\
}
#endif /* MDDI_TOSHIBA_H */

View file

@ -0,0 +1,136 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
#include "mddi_toshiba.h"
static uint32 read_client_reg(uint32 addr)
{
uint32 val;
mddi_queue_register_read(addr, &val, TRUE, 0);
return val;
}
static uint32 toshiba_lcd_gpio_read(void)
{
uint32 val;
write_client_reg(GPIODIR, 0x0000000C, TRUE);
write_client_reg(GPIOSEL, 0x00000000, TRUE);
write_client_reg(GPIOSEL, 0x00000000, TRUE);
write_client_reg(GPIOPC, 0x03CF00C0, TRUE);
val = read_client_reg(GPIODATA) & 0x2C0;
return val;
}
static u32 mddi_toshiba_panel_detect(void)
{
mddi_host_type host_idx = MDDI_HOST_PRIM;
uint32 lcd_gpio;
u32 mddi_toshiba_lcd = LCD_TOSHIBA_2P4_VGA;
/* Toshiba display requires larger drive_lo value */
mddi_host_reg_out(DRIVE_LO, 0x0050);
lcd_gpio = toshiba_lcd_gpio_read();
switch (lcd_gpio) {
case 0x0080:
mddi_toshiba_lcd = LCD_SHARP_2P4_VGA;
break;
case 0x00C0:
default:
mddi_toshiba_lcd = LCD_TOSHIBA_2P4_VGA;
break;
}
return mddi_toshiba_lcd;
}
static int __init mddi_toshiba_vga_init(void)
{
int ret;
struct msm_panel_info pinfo;
u32 panel;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
u32 id;
ret = msm_fb_detect_client("mddi_toshiba_vga");
if (ret == -ENODEV)
return 0;
if (ret) {
id = mddi_get_client_id();
if ((id >> 16) != 0xD263)
return 0;
}
#endif
panel = mddi_toshiba_panel_detect();
pinfo.xres = 480;
pinfo.yres = 640;
pinfo.type = MDDI_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.lcd.vsync_enable = TRUE;
pinfo.lcd.refx100 = 6118;
pinfo.lcd.v_back_porch = 6;
pinfo.lcd.v_front_porch = 0;
pinfo.lcd.v_pulse_width = 0;
pinfo.lcd.hw_vsync_mode = FALSE;
pinfo.lcd.vsync_notifier_period = (1 * HZ);
pinfo.bl_max = 99;
pinfo.bl_min = 1;
pinfo.clk_rate = 122880000;
pinfo.clk_min = 120000000;
pinfo.clk_max = 200000000;
pinfo.fb_num = 2;
ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM, panel);
if (ret) {
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
pinfo.xres = 176;
pinfo.yres = 220;
pinfo.type = MDDI_PANEL;
pinfo.pdest = DISPLAY_2;
pinfo.mddi.vdopkt = 0x400;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.clk_rate = 122880000;
pinfo.clk_min = 120000000;
pinfo.clk_max = 200000000;
pinfo.fb_num = 2;
ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_SECD, panel);
if (ret)
printk(KERN_WARNING
"%s: failed to register device!\n", __func__);
return ret;
}
module_init(mddi_toshiba_vga_init);

View file

@ -0,0 +1,63 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddi_toshiba.h"
static int __init mddi_toshiba_wvga_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
if (msm_fb_detect_client("mddi_toshiba_wvga"))
return 0;
#endif
pinfo.xres = 800;
pinfo.yres = 480;
pinfo.pdest = DISPLAY_2;
pinfo.type = MDDI_PANEL;
pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.lcd.vsync_enable = TRUE;
pinfo.lcd.refx100 = 6118;
pinfo.lcd.v_back_porch = 6;
pinfo.lcd.v_front_porch = 0;
pinfo.lcd.v_pulse_width = 0;
pinfo.lcd.hw_vsync_mode = FALSE;
pinfo.lcd.vsync_notifier_period = (1 * HZ);
pinfo.bl_max = 4;
pinfo.bl_min = 1;
pinfo.clk_rate = 192000000;
pinfo.clk_min = 190000000;
pinfo.clk_max = 200000000;
pinfo.fb_num = 2;
ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM,
LCD_TOSHIBA_2P4_WVGA);
if (ret) {
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
return ret;
}
module_init(mddi_toshiba_wvga_init);

View file

@ -0,0 +1,64 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
#include "mddi_toshiba.h"
static int __init mddi_toshiba_wvga_pt_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
uint id;
ret = msm_fb_detect_client("mddi_toshiba_wvga_pt");
if (ret == -ENODEV)
return 0;
if (ret) {
id = mddi_get_client_id();
if (id != 0xd2638722)
return 0;
}
#endif
pinfo.xres = 480;
pinfo.yres = 800;
pinfo.type = MDDI_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.lcd.vsync_enable = FALSE;
pinfo.bl_max = 15;
pinfo.bl_min = 1;
pinfo.clk_rate = 192000000;
pinfo.clk_min = 190000000;
pinfo.clk_max = 200000000;
pinfo.fb_num = 2;
ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM,
LCD_TOSHIBA_2P4_WVGA_PT);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(mddi_toshiba_wvga_pt_init);

View file

@ -0,0 +1,377 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
#include <linux/clk.h>
#include <mach/clk.h>
struct semaphore mddi_host_mutex;
struct clk *mddi_io_clk;
static boolean mddi_host_powered = FALSE;
static boolean mddi_host_initialized = FALSE;
extern uint32 *mddi_reg_read_value_ptr;
mddi_lcd_func_type mddi_lcd;
extern mddi_client_capability_type mddi_client_capability_pkt;
#ifdef FEATURE_MDDI_HITACHI
extern void mddi_hitachi_window_adjust(uint16 x1,
uint16 x2, uint16 y1, uint16 y2);
#endif
extern void mddi_toshiba_lcd_init(void);
#ifdef FEATURE_MDDI_S6D0142
extern void mddi_s6d0142_lcd_init(void);
extern void mddi_s6d0142_window_adjust(uint16 x1,
uint16 x2,
uint16 y1,
uint16 y2,
mddi_llist_done_cb_type done_cb);
#endif
void mddi_init(void)
{
if (mddi_host_initialized)
return;
mddi_host_initialized = TRUE;
init_MUTEX(&mddi_host_mutex);
if (!mddi_host_powered) {
down(&mddi_host_mutex);
mddi_host_init(MDDI_HOST_PRIM);
mddi_host_powered = TRUE;
up(&mddi_host_mutex);
mdelay(10);
}
}
int mddi_host_register_read(uint32 reg_addr,
uint32 *reg_value_ptr, boolean wait, mddi_host_type host) {
mddi_linked_list_type *curr_llist_ptr;
mddi_register_access_packet_type *regacc_pkt_ptr;
uint16 curr_llist_idx;
int ret = 0;
if (in_interrupt())
MDDI_MSG_CRIT("Called from ISR context\n");
if (!mddi_host_powered) {
MDDI_MSG_ERR("MDDI powered down!\n");
mddi_init();
}
down(&mddi_host_mutex);
mddi_reg_read_value_ptr = reg_value_ptr;
curr_llist_idx = mddi_get_reg_read_llist_item(host, TRUE);
if (curr_llist_idx == UNASSIGNED_INDEX) {
up(&mddi_host_mutex);
/* need to change this to some sort of wait */
MDDI_MSG_ERR("Attempting to queue up more than 1 reg read\n");
return -EINVAL;
}
curr_llist_ptr = &llist_extern[host][curr_llist_idx];
curr_llist_ptr->link_controller_flags = 0x11;
curr_llist_ptr->packet_header_count = 14;
curr_llist_ptr->packet_data_count = 0;
curr_llist_ptr->next_packet_pointer = NULL;
curr_llist_ptr->packet_data_pointer = NULL;
curr_llist_ptr->reserved = 0;
regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count;
regacc_pkt_ptr->packet_type = 146; /* register access packet */
regacc_pkt_ptr->bClient_ID = 0;
regacc_pkt_ptr->read_write_info = 0x8001;
regacc_pkt_ptr->register_address = reg_addr;
/* now adjust pointers */
mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait,
NULL, host);
/* need to check if we can write the pointer or not */
up(&mddi_host_mutex);
if (wait) {
int wait_ret;
mddi_linked_list_notify_type *llist_notify_ptr;
llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx];
wait_ret = wait_for_completion_timeout(
&(llist_notify_ptr->done_comp), 5 * HZ);
if (wait_ret <= 0)
ret = -EBUSY;
if (wait_ret < 0)
printk(KERN_ERR "%s: failed to wait for completion!\n",
__func__);
else if (!wait_ret)
printk(KERN_ERR "%s: Timed out waiting!\n", __func__);
}
MDDI_MSG_DEBUG("Reg Read value=0x%x\n", *reg_value_ptr);
return ret;
} /* mddi_host_register_read */
int mddi_host_register_write(uint32 reg_addr,
uint32 reg_val, enum mddi_data_packet_size_type packet_size,
boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host) {
mddi_linked_list_type *curr_llist_ptr;
mddi_linked_list_type *curr_llist_dma_ptr;
mddi_register_access_packet_type *regacc_pkt_ptr;
uint16 curr_llist_idx;
int ret = 0;
if (in_interrupt())
MDDI_MSG_CRIT("Called from ISR context\n");
if (!mddi_host_powered) {
MDDI_MSG_ERR("MDDI powered down!\n");
mddi_init();
}
down(&mddi_host_mutex);
curr_llist_idx = mddi_get_next_free_llist_item(host, TRUE);
curr_llist_ptr = &llist_extern[host][curr_llist_idx];
curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx];
curr_llist_ptr->link_controller_flags = 1;
curr_llist_ptr->packet_header_count = 14;
curr_llist_ptr->packet_data_count = 4;
curr_llist_ptr->next_packet_pointer = NULL;
curr_llist_ptr->reserved = 0;
regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count +
(uint16)packet_size;
regacc_pkt_ptr->packet_type = 146; /* register access packet */
regacc_pkt_ptr->bClient_ID = 0;
regacc_pkt_ptr->read_write_info = 0x0001;
regacc_pkt_ptr->register_address = reg_addr;
regacc_pkt_ptr->register_data_list = reg_val;
MDDI_MSG_DEBUG("Reg Access write reg=0x%x, value=0x%x\n",
regacc_pkt_ptr->register_address,
regacc_pkt_ptr->register_data_list);
regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt;
curr_llist_ptr->packet_data_pointer =
(void *)(&regacc_pkt_ptr->register_data_list);
/* now adjust pointers */
mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait,
done_cb, host);
up(&mddi_host_mutex);
if (wait) {
int wait_ret;
mddi_linked_list_notify_type *llist_notify_ptr;
llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx];
wait_ret = wait_for_completion_timeout(
&(llist_notify_ptr->done_comp), 5 * HZ);
if (wait_ret <= 0)
ret = -EBUSY;
if (wait_ret < 0)
printk(KERN_ERR "%s: failed to wait for completion!\n",
__func__);
else if (!wait_ret)
printk(KERN_ERR "%s: Timed out waiting!\n", __func__);
}
return ret;
} /* mddi_host_register_write */
boolean mddi_host_register_read_int
(uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host) {
mddi_linked_list_type *curr_llist_ptr;
mddi_register_access_packet_type *regacc_pkt_ptr;
uint16 curr_llist_idx;
if (!in_interrupt())
MDDI_MSG_CRIT("Called from TASK context\n");
if (!mddi_host_powered) {
MDDI_MSG_ERR("MDDI powered down!\n");
return FALSE;
}
if (down_trylock(&mddi_host_mutex) != 0)
return FALSE;
mddi_reg_read_value_ptr = reg_value_ptr;
curr_llist_idx = mddi_get_reg_read_llist_item(host, FALSE);
if (curr_llist_idx == UNASSIGNED_INDEX) {
up(&mddi_host_mutex);
return FALSE;
}
curr_llist_ptr = &llist_extern[host][curr_llist_idx];
curr_llist_ptr->link_controller_flags = 0x11;
curr_llist_ptr->packet_header_count = 14;
curr_llist_ptr->packet_data_count = 0;
curr_llist_ptr->next_packet_pointer = NULL;
curr_llist_ptr->packet_data_pointer = NULL;
curr_llist_ptr->reserved = 0;
regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count;
regacc_pkt_ptr->packet_type = 146; /* register access packet */
regacc_pkt_ptr->bClient_ID = 0;
regacc_pkt_ptr->read_write_info = 0x8001;
regacc_pkt_ptr->register_address = reg_addr;
/* now adjust pointers */
mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE,
NULL, host);
/* need to check if we can write the pointer or not */
up(&mddi_host_mutex);
return TRUE;
} /* mddi_host_register_read */
boolean mddi_host_register_write_int
(uint32 reg_addr,
uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host) {
mddi_linked_list_type *curr_llist_ptr;
mddi_linked_list_type *curr_llist_dma_ptr;
mddi_register_access_packet_type *regacc_pkt_ptr;
uint16 curr_llist_idx;
if (!in_interrupt())
MDDI_MSG_CRIT("Called from TASK context\n");
if (!mddi_host_powered) {
MDDI_MSG_ERR("MDDI powered down!\n");
return FALSE;
}
if (down_trylock(&mddi_host_mutex) != 0)
return FALSE;
curr_llist_idx = mddi_get_next_free_llist_item(host, FALSE);
if (curr_llist_idx == UNASSIGNED_INDEX) {
up(&mddi_host_mutex);
return FALSE;
}
curr_llist_ptr = &llist_extern[host][curr_llist_idx];
curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx];
curr_llist_ptr->link_controller_flags = 1;
curr_llist_ptr->packet_header_count = 14;
curr_llist_ptr->packet_data_count = 4;
curr_llist_ptr->next_packet_pointer = NULL;
curr_llist_ptr->reserved = 0;
regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count + 4;
regacc_pkt_ptr->packet_type = 146; /* register access packet */
regacc_pkt_ptr->bClient_ID = 0;
regacc_pkt_ptr->read_write_info = 0x0001;
regacc_pkt_ptr->register_address = reg_addr;
regacc_pkt_ptr->register_data_list = reg_val;
regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt;
curr_llist_ptr->packet_data_pointer =
(void *)(&(regacc_pkt_ptr->register_data_list));
/* now adjust pointers */
mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE,
done_cb, host);
up(&mddi_host_mutex);
return TRUE;
} /* mddi_host_register_write */
void mddi_wait(uint16 time_ms)
{
mdelay(time_ms);
}
void mddi_client_lcd_vsync_detected(boolean detected)
{
if (mddi_lcd.vsync_detected)
(*mddi_lcd.vsync_detected) (detected);
}
/* extended version of function includes done callback */
void mddi_window_adjust_ext(struct msm_fb_data_type *mfd,
uint16 x1,
uint16 x2,
uint16 y1,
uint16 y2, mddi_llist_done_cb_type done_cb)
{
#ifdef FEATURE_MDDI_HITACHI
if (mfd->panel.id == HITACHI)
mddi_hitachi_window_adjust(x1, x2, y1, y2);
#elif defined(FEATURE_MDDI_S6D0142)
if (mfd->panel.id == MDDI_LCD_S6D0142)
mddi_s6d0142_window_adjust(x1, x2, y1, y2, done_cb);
#else
/* Do nothing then... except avoid lint/compiler warnings */
(void)x1;
(void)x2;
(void)y1;
(void)y2;
(void)done_cb;
#endif
}
void mddi_window_adjust(struct msm_fb_data_type *mfd,
uint16 x1, uint16 x2, uint16 y1, uint16 y2)
{
mddi_window_adjust_ext(mfd, x1, x2, y1, y2, NULL);
}

View file

@ -0,0 +1,225 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MDDIHOST_H
#define MDDIHOST_H
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include "linux/proc_fs.h"
#include <linux/types.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/types.h>
#include <linux/dma-mapping.h>
#include "msm_fb_panel.h"
#undef FEATURE_MDDI_MC4
#undef FEATURE_MDDI_S6D0142
#undef FEATURE_MDDI_HITACHI
#define FEATURE_MDDI_SHARP
#define FEATURE_MDDI_TOSHIBA
#undef FEATURE_MDDI_E751
#define FEATURE_MDDI_CORONA
#define FEATURE_MDDI_PRISM
#define T_MSM7500
typedef enum {
format_16bpp,
format_18bpp,
format_24bpp
} mddi_video_format;
typedef enum {
MDDI_LCD_NONE = 0,
MDDI_LCD_MC4,
MDDI_LCD_S6D0142,
MDDI_LCD_SHARP,
MDDI_LCD_E751,
MDDI_LCD_CORONA,
MDDI_LCD_HITACHI,
MDDI_LCD_TOSHIBA,
MDDI_LCD_PRISM,
MDDI_LCD_TP2,
MDDI_NUM_LCD_TYPES,
MDDI_LCD_DEFAULT = MDDI_LCD_TOSHIBA
} mddi_lcd_type;
typedef enum {
MDDI_HOST_PRIM = 0,
MDDI_HOST_EXT,
MDDI_NUM_HOST_CORES
} mddi_host_type;
typedef enum {
MDDI_DRIVER_RESET, /* host core registers have not been written. */
MDDI_DRIVER_DISABLED, /* registers written, interrupts disabled. */
MDDI_DRIVER_ENABLED /* registers written, interrupts enabled. */
} mddi_host_driver_state_type;
typedef enum {
MDDI_GPIO_INT_0 = 0,
MDDI_GPIO_INT_1,
MDDI_GPIO_INT_2,
MDDI_GPIO_INT_3,
MDDI_GPIO_INT_4,
MDDI_GPIO_INT_5,
MDDI_GPIO_INT_6,
MDDI_GPIO_INT_7,
MDDI_GPIO_INT_8,
MDDI_GPIO_INT_9,
MDDI_GPIO_INT_10,
MDDI_GPIO_INT_11,
MDDI_GPIO_INT_12,
MDDI_GPIO_INT_13,
MDDI_GPIO_INT_14,
MDDI_GPIO_INT_15,
MDDI_GPIO_NUM_INTS
} mddi_gpio_int_type;
enum mddi_data_packet_size_type {
MDDI_DATA_PACKET_4_BYTES = 4,
MDDI_DATA_PACKET_8_BYTES = 8,
MDDI_DATA_PACKET_12_BYTES = 12,
MDDI_DATA_PACKET_16_BYTES = 16,
MDDI_DATA_PACKET_24_BYTES = 24
};
typedef struct {
uint32 addr;
uint32 value;
} mddi_reg_write_type;
boolean mddi_vsync_set_handler(msm_fb_vsync_handler_type handler, void *arg);
typedef void (*mddi_llist_done_cb_type) (void);
typedef void (*mddi_rev_handler_type) (void *);
boolean mddi_set_rev_handler(mddi_rev_handler_type handler, uint16 pkt_type);
#define MDDI_DEFAULT_PRIM_PIX_ATTR 0xC3
#define MDDI_DEFAULT_SECD_PIX_ATTR 0xC0
typedef int gpio_int_polarity_type;
typedef int gpio_int_handler_type;
typedef struct {
void (*vsync_detected) (boolean);
} mddi_lcd_func_type;
extern mddi_lcd_func_type mddi_lcd;
void mddi_init(void);
void mddi_powerdown(void);
void mddi_host_start_ext_display(void);
void mddi_host_stop_ext_display(void);
extern spinlock_t mddi_host_spin_lock;
#ifdef T_MSM7500
void mddi_reset(void);
#ifdef FEATURE_DUAL_PROC_MODEM_DISPLAY
void mddi_host_switch_proc_control(boolean on);
#endif
#endif
void mddi_host_exit_power_collapse(void);
void mddi_queue_splash_screen
(void *buf_ptr,
boolean clear_area,
int16 src_width,
int16 src_starting_row,
int16 src_starting_column,
int16 num_of_rows,
int16 num_of_columns, int16 dst_starting_row, int16 dst_starting_column);
void mddi_queue_image
(void *buf_ptr,
uint8 stereo_video,
boolean clear_area,
int16 src_width,
int16 src_starting_row,
int16 src_starting_column,
int16 num_of_rows,
int16 num_of_columns, int16 dst_starting_row, int16 dst_starting_column);
int mddi_host_register_read
(uint32 reg_addr,
uint32 *reg_value_ptr, boolean wait, mddi_host_type host_idx);
int mddi_host_register_write
(uint32 reg_addr, uint32 reg_val,
enum mddi_data_packet_size_type packet_size,
boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host);
boolean mddi_host_register_write_int
(uint32 reg_addr,
uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host);
boolean mddi_host_register_read_int
(uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host_idx);
void mddi_queue_register_write_static
(uint32 reg_addr,
uint32 reg_val, boolean wait, mddi_llist_done_cb_type done_cb);
void mddi_queue_static_window_adjust
(const mddi_reg_write_type *reg_write,
uint16 num_writes, mddi_llist_done_cb_type done_cb);
#define mddi_queue_register_read(reg, val_ptr, wait, sig) \
mddi_host_register_read(reg, val_ptr, wait, MDDI_HOST_PRIM)
#define mddi_queue_register_write(reg, val, wait, sig) \
mddi_host_register_write(reg, val, MDDI_DATA_PACKET_4_BYTES,\
wait, NULL, MDDI_HOST_PRIM)
#define mddi_queue_register_write_extn(reg, val, pkt_size, wait, sig) \
mddi_host_register_write(reg, val, pkt_size, \
wait, NULL, MDDI_HOST_PRIM)
#define mddi_queue_register_write_int(reg, val) \
mddi_host_register_write_int(reg, val, NULL, MDDI_HOST_PRIM)
#define mddi_queue_register_read_int(reg, val_ptr) \
mddi_host_register_read_int(reg, val_ptr, MDDI_HOST_PRIM)
#define mddi_queue_register_writes(reg_ptr, val, wait, sig) \
mddi_host_register_writes(reg_ptr, val, wait, sig, MDDI_HOST_PRIM)
void mddi_wait(uint16 time_ms);
void mddi_assign_max_pkt_dimensions(uint16 image_cols,
uint16 image_rows,
uint16 bpp,
uint16 *max_cols, uint16 * max_rows);
uint16 mddi_assign_pkt_height(uint16 pkt_width, uint16 pkt_height, uint16 bpp);
void mddi_queue_reverse_encapsulation(boolean wait);
void mddi_disable(int lock);
#endif /* MDDIHOST_H */

View file

@ -0,0 +1,63 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
#include <linux/clk.h>
#include <mach/clk.h>
extern struct semaphore mddi_host_mutex;
static boolean mddi_host_ext_powered = FALSE;
void mddi_host_start_ext_display(void)
{
down(&mddi_host_mutex);
if (!mddi_host_ext_powered) {
mddi_host_init(MDDI_HOST_EXT);
mddi_host_ext_powered = TRUE;
}
up(&mddi_host_mutex);
}
void mddi_host_stop_ext_display(void)
{
down(&mddi_host_mutex);
if (mddi_host_ext_powered) {
mddi_host_powerdown(MDDI_HOST_EXT);
mddi_host_ext_powered = FALSE;
}
up(&mddi_host_mutex);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,547 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MDDIHOSTI_H
#define MDDIHOSTI_H
#include "msm_fb.h"
#include "mddihost.h"
#include <linux/clk.h>
/* Register offsets in MDDI, applies to both msm_pmdh_base and
* (u32)msm_emdh_base. */
#define MDDI_CMD 0x0000
#define MDDI_VERSION 0x0004
#define MDDI_PRI_PTR 0x0008
#define MDDI_BPS 0x0010
#define MDDI_SPM 0x0014
#define MDDI_INT 0x0018
#define MDDI_INTEN 0x001c
#define MDDI_REV_PTR 0x0020
#define MDDI_REV_SIZE 0x0024
#define MDDI_STAT 0x0028
#define MDDI_REV_RATE_DIV 0x002c
#define MDDI_REV_CRC_ERR 0x0030
#define MDDI_TA1_LEN 0x0034
#define MDDI_TA2_LEN 0x0038
#define MDDI_TEST 0x0040
#define MDDI_REV_PKT_CNT 0x0044
#define MDDI_DRIVE_HI 0x0048
#define MDDI_DRIVE_LO 0x004c
#define MDDI_DISP_WAKE 0x0050
#define MDDI_REV_ENCAP_SZ 0x0054
#define MDDI_RTD_VAL 0x0058
#define MDDI_PAD_CTL 0x0068
#define MDDI_DRIVER_START_CNT 0x006c
#define MDDI_CORE_VER 0x008c
#define MDDI_FIFO_ALLOC 0x0090
#define MDDI_PAD_IO_CTL 0x00a0
#define MDDI_PAD_CAL 0x00a4
extern u32 mddi_msg_level;
/* No longer need to write to clear these registers */
#define xxxx_mddi_host_reg_outm(reg, mask, val) \
do { \
if (host_idx == MDDI_HOST_PRIM) \
mddi_host_reg_outm_pmdh(reg, mask, val); \
else \
mddi_host_reg_outm_emdh(reg, mask, val); \
} while (0)
#define mddi_host_reg_outm(reg, mask, val) \
do { \
unsigned long __addr; \
if (host_idx == MDDI_HOST_PRIM) \
__addr = (u32)msm_pmdh_base + MDDI_##reg; \
else \
__addr = (u32)msm_emdh_base + MDDI_##reg; \
writel((readl(__addr) & ~(mask)) | ((val) & (mask)), __addr); \
} while (0)
#define xxxx_mddi_host_reg_out(reg, val) \
do { \
if (host_idx == MDDI_HOST_PRIM) \
mddi_host_reg_out_pmdh(reg, val); \
else \
mddi_host_reg_out_emdh(reg, val); \
} while (0)
#define mddi_host_reg_out(reg, val) \
do { \
if (host_idx == MDDI_HOST_PRIM) \
writel(val, (u32)msm_pmdh_base + MDDI_##reg); \
else \
writel(val, (u32)msm_emdh_base + MDDI_##reg); \
} while (0)
#define xxxx_mddi_host_reg_in(reg) \
((host_idx) ? \
mddi_host_reg_in_emdh(reg) : mddi_host_reg_in_pmdh(reg));
#define mddi_host_reg_in(reg) \
((host_idx) ? \
readl((u32)msm_emdh_base + MDDI_##reg) : \
readl((u32)msm_pmdh_base + MDDI_##reg)) \
#define xxxx_mddi_host_reg_inm(reg, mask) \
((host_idx) ? \
mddi_host_reg_inm_emdh(reg, mask) : \
mddi_host_reg_inm_pmdh(reg, mask);)
#define mddi_host_reg_inm(reg, mask) \
((host_idx) ? \
readl((u32)msm_emdh_base + MDDI_##reg) & (mask) : \
readl((u32)msm_pmdh_base + MDDI_##reg) & (mask)) \
/* Using non-cacheable pmem, so do nothing */
#define mddi_invalidate_cache_lines(addr_start, num_bytes)
/*
* Using non-cacheable pmem, so do nothing with cache
* but, ensure write goes out to memory
*/
#define mddi_flush_cache_lines(addr_start, num_bytes) \
(void) addr_start; \
(void) num_bytes; \
memory_barrier()
/* Since this translates to Remote Procedure Calls to check on clock status
* just use a local variable to keep track of io_clock */
#define MDDI_HOST_IS_IO_CLOCK_ON mddi_host_io_clock_on
#define MDDI_HOST_ENABLE_IO_CLOCK
#define MDDI_HOST_DISABLE_IO_CLOCK
#define MDDI_HOST_IS_HCLK_ON mddi_host_hclk_on
#define MDDI_HOST_ENABLE_HCLK
#define MDDI_HOST_DISABLE_HCLK
#define FEATURE_MDDI_HOST_IO_CLOCK_CONTROL_DISABLE
#define FEATURE_MDDI_HOST_HCLK_CONTROL_DISABLE
#define TRAMP_MDDI_HOST_ISR TRAMP_MDDI_PRI_ISR
#define TRAMP_MDDI_HOST_EXT_ISR TRAMP_MDDI_EXT_ISR
#define MDP_LINE_COUNT_BMSK 0x3ff
#define MDP_SYNC_STATUS 0x000c
#define MDP_LINE_COUNT \
(readl(msm_mdp_base + MDP_SYNC_STATUS) & MDP_LINE_COUNT_BMSK)
/* MDP sends 256 pixel packets, so lower value hibernates more without
* significantly increasing latency of waiting for next subframe */
#define MDDI_HOST_BYTES_PER_SUBFRAME 0x3C00
#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40)
#define MDDI_HOST_TA2_LEN 0x001a
#define MDDI_HOST_REV_RATE_DIV 0x0004
#else
#define MDDI_HOST_TA2_LEN 0x000c
#define MDDI_HOST_REV_RATE_DIV 0x0002
#endif
#define MDDI_MSG_EMERG(msg, ...) \
if (mddi_msg_level > 0) \
printk(KERN_EMERG msg, ## __VA_ARGS__);
#define MDDI_MSG_ALERT(msg, ...) \
if (mddi_msg_level > 1) \
printk(KERN_ALERT msg, ## __VA_ARGS__);
#define MDDI_MSG_CRIT(msg, ...) \
if (mddi_msg_level > 2) \
printk(KERN_CRIT msg, ## __VA_ARGS__);
#define MDDI_MSG_ERR(msg, ...) \
if (mddi_msg_level > 3) \
printk(KERN_ERR msg, ## __VA_ARGS__);
#define MDDI_MSG_WARNING(msg, ...) \
if (mddi_msg_level > 4) \
printk(KERN_WARNING msg, ## __VA_ARGS__);
#define MDDI_MSG_NOTICE(msg, ...) \
if (mddi_msg_level > 5) \
printk(KERN_NOTICE msg, ## __VA_ARGS__);
#define MDDI_MSG_INFO(msg, ...) \
if (mddi_msg_level > 6) \
printk(KERN_INFO msg, ## __VA_ARGS__);
#define MDDI_MSG_DEBUG(msg, ...) \
if (mddi_msg_level > 7) \
printk(KERN_DEBUG msg, ## __VA_ARGS__);
#define GCC_PACKED __attribute__((packed))
typedef struct GCC_PACKED {
uint16 packet_length;
/* total # of bytes in the packet not including
the packet_length field. */
uint16 packet_type;
/* A Packet Type of 70 identifies the packet as
a Client status Packet. */
uint16 bClient_ID;
/* This field is reserved for future use and shall
be set to zero. */
} mddi_rev_packet_type;
typedef struct GCC_PACKED {
uint16 packet_length;
/* total # of bytes in the packet not including
the packet_length field. */
uint16 packet_type;
/* A Packet Type of 70 identifies the packet as
a Client status Packet. */
uint16 bClient_ID;
/* This field is reserved for future use and shall
be set to zero. */
uint16 reverse_link_request;
/* 16 bit unsigned integer with number of bytes client
needs in the * reverse encapsulation message
to transmit data. */
uint8 crc_error_count;
uint8 capability_change;
uint16 graphics_busy_flags;
uint16 parameter_CRC;
/* 16-bit CRC of all the bytes in the packet
including Packet Length. */
} mddi_client_status_type;
typedef struct GCC_PACKED {
uint16 packet_length;
/* total # of bytes in the packet not including
the packet_length field. */
uint16 packet_type;
/* A Packet Type of 66 identifies the packet as
a Client Capability Packet. */
uint16 bClient_ID;
/* This field is reserved for future use and
shall be set to zero. */
uint16 Protocol_Version;
uint16 Minimum_Protocol_Version;
uint16 Data_Rate_Capability;
uint8 Interface_Type_Capability;
uint8 Number_of_Alt_Displays;
uint16 PostCal_Data_Rate;
uint16 Bitmap_Width;
uint16 Bitmap_Height;
uint16 Display_Window_Width;
uint16 Display_Window_Height;
uint32 Color_Map_Size;
uint16 Color_Map_RGB_Width;
uint16 RGB_Capability;
uint8 Monochrome_Capability;
uint8 Reserved_1;
uint16 Y_Cb_Cr_Capability;
uint16 Bayer_Capability;
uint16 Alpha_Cursor_Image_Planes;
uint32 Client_Feature_Capability_Indicators;
uint8 Maximum_Video_Frame_Rate_Capability;
uint8 Minimum_Video_Frame_Rate_Capability;
uint16 Minimum_Sub_frame_Rate;
uint16 Audio_Buffer_Depth;
uint16 Audio_Channel_Capability;
uint16 Audio_Sample_Rate_Capability;
uint8 Audio_Sample_Resolution;
uint8 Mic_Audio_Sample_Resolution;
uint16 Mic_Sample_Rate_Capability;
uint8 Keyboard_Data_Format;
uint8 pointing_device_data_format;
uint16 content_protection_type;
uint16 Mfr_Name;
uint16 Product_Code;
uint16 Reserved_3;
uint32 Serial_Number;
uint8 Week_of_Manufacture;
uint8 Year_of_Manufacture;
uint16 parameter_CRC;
/* 16-bit CRC of all the bytes in the packet including Packet Length. */
} mddi_client_capability_type;
typedef struct GCC_PACKED {
uint16 packet_length;
/* total # of bytes in the packet not including the packet_length field. */
uint16 packet_type;
/* A Packet Type of 16 identifies the packet as a Video Stream Packet. */
uint16 bClient_ID;
/* This field is reserved for future use and shall be set to zero. */
uint16 video_data_format_descriptor;
/* format of each pixel in the Pixel Data in the present stream in the
* present packet.
* If bits [15:13] = 000 monochrome
* If bits [15:13] = 001 color pixels (palette).
* If bits [15:13] = 010 color pixels in raw RGB
* If bits [15:13] = 011 data in 4:2:2 Y Cb Cr format
* If bits [15:13] = 100 Bayer pixels
*/
uint16 pixel_data_attributes;
/* interpreted as follows:
* Bits [1:0] = 11 pixel data is displayed to both eyes
* Bits [1:0] = 10 pixel data is routed to the left eye only.
* Bits [1:0] = 01 pixel data is routed to the right eye only.
* Bits [1:0] = 00 pixel data is routed to the alternate display.
* Bit 2 is 0 Pixel Data is in the standard progressive format.
* Bit 2 is 1 Pixel Data is in interlace format.
* Bit 3 is 0 Pixel Data is in the standard progressive format.
* Bit 3 is 1 Pixel Data is in alternate pixel format.
* Bit 4 is 0 Pixel Data is to or from the display frame buffer.
* Bit 4 is 1 Pixel Data is to or from the camera.
* Bit 5 is 0 pixel data contains the next consecutive row of pixels.
* Bit 5 is 1 X Left Edge, Y Top Edge, X Right Edge, Y Bottom Edge,
* X Start, and Y Start parameters are not defined and
* shall be ignored by the client.
* Bits [7:6] = 01 Pixel data is written to the offline image buffer.
* Bits [7:6] = 00 Pixel data is written to the buffer to refresh display.
* Bits [7:6] = 11 Pixel data is written to all image buffers.
* Bits [7:6] = 10 Invalid. Reserved for future use.
* Bits 8 through 11 alternate display number.
* Bits 12 through 14 are reserved for future use and shall be set to zero.
* Bit 15 is 1 the row of pixels is the last row of pixels in a frame.
*/
uint16 x_left_edge;
uint16 y_top_edge;
/* X,Y coordinate of the top left edge of the screen window */
uint16 x_right_edge;
uint16 y_bottom_edge;
/* X,Y coordinate of the bottom right edge of the window being updated. */
uint16 x_start;
uint16 y_start;
/* (X Start, Y Start) is the first pixel in the Pixel Data field below. */
uint16 pixel_count;
/* number of pixels in the Pixel Data field below. */
uint16 parameter_CRC;
/* 16-bit CRC of all bytes from the Packet Length to the Pixel Count. */
uint16 reserved;
/* 16-bit variable to make structure align on 4 byte boundary */
} mddi_video_stream_packet_type;
typedef struct GCC_PACKED {
uint16 packet_length;
/* total # of bytes in the packet not including the packet_length field. */
uint16 packet_type;
/* A Packet Type of 146 identifies the packet as a Register Access Packet. */
uint16 bClient_ID;
/* This field is reserved for future use and shall be set to zero. */
uint16 read_write_info;
/* Bits 13:0 a 14-bit unsigned integer that specifies the number of
* 32-bit Register Data List items to be transferred in the
* Register Data List field.
* Bits[15:14] = 00 Write to register(s);
* Bits[15:14] = 10 Read from register(s);
* Bits[15:14] = 11 Response to a Read.
* Bits[15:14] = 01 this value is reserved for future use. */
uint32 register_address;
/* the register address that is to be written to or read from. */
uint16 parameter_CRC;
/* 16-bit CRC of all bytes from the Packet Length to the Register Address. */
uint32 register_data_list;
/* list of 4-byte register data values for/from client registers */
} mddi_register_access_packet_type;
typedef union GCC_PACKED {
mddi_video_stream_packet_type video_pkt;
mddi_register_access_packet_type register_pkt;
/* add 48 byte pad to ensure 64 byte llist struct, that can be
* manipulated easily with cache */
uint32 alignment_pad[12]; /* 48 bytes */
} mddi_packet_header_type;
typedef struct GCC_PACKED mddi_host_llist_struct {
uint16 link_controller_flags;
uint16 packet_header_count;
uint16 packet_data_count;
void *packet_data_pointer;
struct mddi_host_llist_struct *next_packet_pointer;
uint16 reserved;
mddi_packet_header_type packet_header;
} mddi_linked_list_type;
typedef struct {
struct completion done_comp;
mddi_llist_done_cb_type done_cb;
uint16 next_idx;
boolean waiting;
boolean in_use;
} mddi_linked_list_notify_type;
#define MDDI_LLIST_POOL_SIZE 0x1000
#define MDDI_MAX_NUM_LLIST_ITEMS (MDDI_LLIST_POOL_SIZE / \
sizeof(mddi_linked_list_type))
#define UNASSIGNED_INDEX MDDI_MAX_NUM_LLIST_ITEMS
#define MDDI_FIRST_DYNAMIC_LLIST_IDX 0
/* Static llist items can be used for applications that frequently send
* the same set of packets using the linked list interface. */
/* Here we configure for 6 static linked list items:
* The 1st is used for a the adaptive backlight setting.
* and the remaining 5 are used for sending window adjustments for
* MDDI clients that need windowing info sent separate from video
* packets. */
#define MDDI_NUM_STATIC_ABL_ITEMS 1
#define MDDI_NUM_STATIC_WINDOW_ITEMS 5
#define MDDI_NUM_STATIC_LLIST_ITEMS (MDDI_NUM_STATIC_ABL_ITEMS + \
MDDI_NUM_STATIC_WINDOW_ITEMS)
#define MDDI_NUM_DYNAMIC_LLIST_ITEMS (MDDI_MAX_NUM_LLIST_ITEMS - \
MDDI_NUM_STATIC_LLIST_ITEMS)
#define MDDI_FIRST_STATIC_LLIST_IDX MDDI_NUM_DYNAMIC_LLIST_ITEMS
#define MDDI_FIRST_STATIC_ABL_IDX MDDI_FIRST_STATIC_LLIST_IDX
#define MDDI_FIRST_STATIC_WINDOW_IDX (MDDI_FIRST_STATIC_LLIST_IDX + \
MDDI_NUM_STATIC_ABL_ITEMS)
/* GPIO registers */
#define VSYNC_WAKEUP_REG 0x80
#define GPIO_REG 0x81
#define GPIO_OUTPUT_REG 0x82
#define GPIO_INTERRUPT_REG 0x83
#define GPIO_INTERRUPT_ENABLE_REG 0x84
#define GPIO_POLARITY_REG 0x85
/* Interrupt Bits */
#define MDDI_INT_PRI_PTR_READ 0x0001
#define MDDI_INT_SEC_PTR_READ 0x0002
#define MDDI_INT_REV_DATA_AVAIL 0x0004
#define MDDI_INT_DISP_REQ 0x0008
#define MDDI_INT_PRI_UNDERFLOW 0x0010
#define MDDI_INT_SEC_UNDERFLOW 0x0020
#define MDDI_INT_REV_OVERFLOW 0x0040
#define MDDI_INT_CRC_ERROR 0x0080
#define MDDI_INT_MDDI_IN 0x0100
#define MDDI_INT_PRI_OVERWRITE 0x0200
#define MDDI_INT_SEC_OVERWRITE 0x0400
#define MDDI_INT_REV_OVERWRITE 0x0800
#define MDDI_INT_DMA_FAILURE 0x1000
#define MDDI_INT_LINK_ACTIVE 0x2000
#define MDDI_INT_IN_HIBERNATION 0x4000
#define MDDI_INT_PRI_LINK_LIST_DONE 0x8000
#define MDDI_INT_SEC_LINK_LIST_DONE 0x10000
#define MDDI_INT_NO_CMD_PKTS_PEND 0x20000
#define MDDI_INT_RTD_FAILURE 0x40000
#define MDDI_INT_ERROR_CONDITIONS ( \
MDDI_INT_PRI_UNDERFLOW | MDDI_INT_SEC_UNDERFLOW | \
MDDI_INT_REV_OVERFLOW | MDDI_INT_CRC_ERROR | \
MDDI_INT_PRI_OVERWRITE | MDDI_INT_SEC_OVERWRITE | \
MDDI_INT_RTD_FAILURE | \
MDDI_INT_REV_OVERWRITE | MDDI_INT_DMA_FAILURE)
#define MDDI_INT_LINK_STATE_CHANGES ( \
MDDI_INT_LINK_ACTIVE | MDDI_INT_IN_HIBERNATION)
/* Status Bits */
#define MDDI_STAT_LINK_ACTIVE 0x0001
#define MDDI_STAT_NEW_REV_PTR 0x0002
#define MDDI_STAT_NEW_PRI_PTR 0x0004
#define MDDI_STAT_NEW_SEC_PTR 0x0008
#define MDDI_STAT_IN_HIBERNATION 0x0010
#define MDDI_STAT_PRI_LINK_LIST_DONE 0x0020
#define MDDI_STAT_SEC_LINK_LIST_DONE 0x0040
#define MDDI_STAT_PENDING_TIMING_PKT 0x0080
#define MDDI_STAT_PENDING_REV_ENCAP 0x0100
#define MDDI_STAT_PENDING_POWERDOWN 0x0200
#define MDDI_STAT_RTD_MEAS_FAIL 0x0800
#define MDDI_STAT_CLIENT_WAKEUP_REQ 0x1000
/* Command Bits */
#define MDDI_CMD_POWERDOWN 0x0100
#define MDDI_CMD_POWERUP 0x0200
#define MDDI_CMD_HIBERNATE 0x0300
#define MDDI_CMD_RESET 0x0400
#define MDDI_CMD_DISP_IGNORE 0x0501
#define MDDI_CMD_DISP_LISTEN 0x0500
#define MDDI_CMD_SEND_REV_ENCAP 0x0600
#define MDDI_CMD_GET_CLIENT_CAP 0x0601
#define MDDI_CMD_GET_CLIENT_STATUS 0x0602
#define MDDI_CMD_SEND_RTD 0x0700
#define MDDI_CMD_LINK_ACTIVE 0x0900
#define MDDI_CMD_PERIODIC_REV_ENCAP 0x0A00
extern void mddi_host_init(mddi_host_type host);
extern void mddi_host_powerdown(mddi_host_type host);
extern uint16 mddi_get_next_free_llist_item(mddi_host_type host, boolean wait);
extern uint16 mddi_get_reg_read_llist_item(mddi_host_type host, boolean wait);
extern void mddi_queue_forward_packets(uint16 first_llist_idx,
uint16 last_llist_idx,
boolean wait,
mddi_llist_done_cb_type llist_done_cb,
mddi_host_type host);
extern void mddi_host_write_pix_attr_reg(uint32 value);
extern void mddi_client_lcd_gpio_poll(uint32 poll_reg_val);
extern void mddi_client_lcd_vsync_detected(boolean detected);
extern void mddi_host_disable_hibernation(boolean disable);
extern mddi_linked_list_type *llist_extern[];
extern mddi_linked_list_type *llist_dma_extern[];
extern mddi_linked_list_notify_type *llist_extern_notify[];
extern struct timer_list mddi_host_timer;
typedef struct {
uint16 transmitting_start_idx;
uint16 transmitting_end_idx;
uint16 waiting_start_idx;
uint16 waiting_end_idx;
uint16 reg_read_idx;
uint16 next_free_idx;
boolean reg_read_waiting;
} mddi_llist_info_type;
extern mddi_llist_info_type mddi_llist;
#define MDDI_GPIO_DEFAULT_POLLING_INTERVAL 200
typedef struct {
uint32 polling_reg;
uint32 polling_val;
uint32 polling_interval;
boolean polling_enabled;
} mddi_gpio_info_type;
uint32 mddi_get_client_id(void);
void mddi_mhctl_remove(mddi_host_type host_idx);
void mddi_host_timer_service(unsigned long data);
#endif /* MDDIHOSTI_H */

1113
drivers/staging/msm/mdp.c Normal file

File diff suppressed because it is too large Load diff

695
drivers/staging/msm/mdp.h Normal file
View file

@ -0,0 +1,695 @@
/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MDP_H
#define MDP_H
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/hrtimer.h>
#include "msm_mdp.h"
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include "msm_fb_panel.h"
#ifdef CONFIG_MDP_PPP_ASYNC_OP
#include "mdp_ppp_dq.h"
#endif
#ifdef BIT
#undef BIT
#endif
#define BIT(x) (1<<(x))
#define MDPOP_NOP 0
#define MDPOP_LR BIT(0) /* left to right flip */
#define MDPOP_UD BIT(1) /* up and down flip */
#define MDPOP_ROT90 BIT(2) /* rotate image to 90 degree */
#define MDPOP_ROT180 (MDPOP_UD|MDPOP_LR)
#define MDPOP_ROT270 (MDPOP_ROT90|MDPOP_UD|MDPOP_LR)
#define MDPOP_ASCALE BIT(7)
#define MDPOP_ALPHAB BIT(8) /* enable alpha blending */
#define MDPOP_TRANSP BIT(9) /* enable transparency */
#define MDPOP_DITHER BIT(10) /* enable dither */
#define MDPOP_SHARPENING BIT(11) /* enable sharpening */
#define MDPOP_BLUR BIT(12) /* enable blur */
#define MDPOP_FG_PM_ALPHA BIT(13)
struct mdp_table_entry {
uint32_t reg;
uint32_t val;
};
extern struct mdp_ccs mdp_ccs_yuv2rgb ;
extern struct mdp_ccs mdp_ccs_rgb2yuv ;
/*
* MDP Image Structure
*/
typedef struct mdpImg_ {
uint32 imgType; /* Image type */
uint32 *bmy_addr; /* bitmap or y addr */
uint32 *cbcr_addr; /* cbcr addr */
uint32 width; /* image width */
uint32 mdpOp; /* image opertion (rotation,flip up/down, alpha/tp) */
uint32 tpVal; /* transparency color */
uint32 alpha; /* alpha percentage 0%(0x0) ~ 100%(0x100) */
int sp_value; /* sharpening strength */
} MDPIMG;
#ifdef CONFIG_MDP_PPP_ASYNC_OP
#define MDP_OUTP(addr, data) mdp_ppp_outdw((uint32_t)(addr), \
(uint32_t)(data))
#else
#define MDP_OUTP(addr, data) outpdw((addr), (data))
#endif
#define MDP_KTIME2USEC(kt) (kt.tv.sec*1000000 + kt.tv.nsec/1000)
#define MDP_BASE msm_mdp_base
typedef enum {
MDP_BC_SCALE_POINT2_POINT4,
MDP_BC_SCALE_POINT4_POINT6,
MDP_BC_SCALE_POINT6_POINT8,
MDP_BC_SCALE_POINT8_1,
MDP_BC_SCALE_UP,
MDP_PR_SCALE_POINT2_POINT4,
MDP_PR_SCALE_POINT4_POINT6,
MDP_PR_SCALE_POINT6_POINT8,
MDP_PR_SCALE_POINT8_1,
MDP_PR_SCALE_UP,
MDP_SCALE_BLUR,
MDP_INIT_SCALE
} MDP_SCALE_MODE;
typedef enum {
MDP_BLOCK_POWER_OFF,
MDP_BLOCK_POWER_ON
} MDP_BLOCK_POWER_STATE;
typedef enum {
MDP_MASTER_BLOCK,
MDP_CMD_BLOCK,
MDP_PPP_BLOCK,
MDP_DMA2_BLOCK,
MDP_DMA3_BLOCK,
MDP_DMA_S_BLOCK,
MDP_DMA_E_BLOCK,
MDP_OVERLAY0_BLOCK,
MDP_OVERLAY1_BLOCK,
MDP_MAX_BLOCK
} MDP_BLOCK_TYPE;
/* Let's keep Q Factor power of 2 for optimization */
#define MDP_SCALE_Q_FACTOR 512
#ifdef CONFIG_FB_MSM_MDP31
#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*8)
#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/8)
#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*8)
#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/8)
#else
#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4)
#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4)
#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4)
#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4)
#endif
/* SHIM Q Factor */
#define PHI_Q_FACTOR 29
#define PQF_PLUS_5 (PHI_Q_FACTOR + 5) /* due to 32 phases */
#define PQF_PLUS_4 (PHI_Q_FACTOR + 4)
#define PQF_PLUS_2 (PHI_Q_FACTOR + 2) /* to get 4.0 */
#define PQF_MINUS_2 (PHI_Q_FACTOR - 2) /* to get 0.25 */
#define PQF_PLUS_5_PLUS_2 (PQF_PLUS_5 + 2)
#define PQF_PLUS_5_MINUS_2 (PQF_PLUS_5 - 2)
#define MDP_CONVTP(tpVal) (((tpVal&0xF800)<<8)|((tpVal&0x7E0)<<5)|((tpVal&0x1F)<<3))
#define MDPOP_ROTATION (MDPOP_ROT90|MDPOP_LR|MDPOP_UD)
#define MDP_CHKBIT(val, bit) ((bit) == ((val) & (bit)))
/* overlay interface API defines */
typedef enum {
MORE_IBUF,
FINAL_IBUF,
COMPLETE_IBUF
} MDP_IBUF_STATE;
struct mdp_dirty_region {
__u32 xoffset; /* source origin in the x-axis */
__u32 yoffset; /* source origin in the y-axis */
__u32 width; /* number of pixels in the x-axis */
__u32 height; /* number of pixels in the y-axis */
};
/*
* MDP extended data types
*/
typedef struct mdp_roi_s {
uint32 x;
uint32 y;
uint32 width;
uint32 height;
int32 lcd_x;
int32 lcd_y;
uint32 dst_width;
uint32 dst_height;
} MDP_ROI;
typedef struct mdp_ibuf_s {
uint8 *buf;
uint32 bpp;
uint32 ibuf_type;
uint32 ibuf_width;
uint32 ibuf_height;
MDP_ROI roi;
MDPIMG mdpImg;
int32 dma_x;
int32 dma_y;
uint32 dma_w;
uint32 dma_h;
uint32 vsync_enable;
uint32 visible_swapped;
} MDPIBUF;
struct mdp_dma_data {
boolean busy;
boolean waiting;
struct mutex ov_mutex;
struct semaphore mutex;
struct completion comp;
};
#define MDP_CMD_DEBUG_ACCESS_BASE (MDP_BASE+0x10000)
#define MDP_DMA2_TERM 0x1
#define MDP_DMA3_TERM 0x2
#define MDP_PPP_TERM 0x4
#define MDP_DMA_S_TERM 0x8
#ifdef CONFIG_FB_MSM_MDP40
#define MDP_DMA_E_TERM 0x10
#define MDP_OVERLAY0_TERM 0x20
#define MDP_OVERLAY1_TERM 0x40
#endif
#define ACTIVE_START_X_EN BIT(31)
#define ACTIVE_START_Y_EN BIT(31)
#define ACTIVE_HIGH 0
#define ACTIVE_LOW 1
#define MDP_DMA_S_DONE BIT(2)
#define LCDC_FRAME_START BIT(15)
#define LCDC_UNDERFLOW BIT(16)
#ifdef CONFIG_FB_MSM_MDP22
#define MDP_DMA_P_DONE BIT(2)
#else
#define MDP_DMA_P_DONE BIT(14)
#endif
#define MDP_PPP_DONE BIT(0)
#define TV_OUT_DMA3_DONE BIT(6)
#define TV_ENC_UNDERRUN BIT(7)
#define TV_OUT_DMA3_START BIT(13)
#define MDP_HIST_DONE BIT(20)
#ifdef CONFIG_FB_MSM_MDP22
#define MDP_ANY_INTR_MASK (MDP_PPP_DONE| \
MDP_DMA_P_DONE| \
TV_ENC_UNDERRUN)
#else
#define MDP_ANY_INTR_MASK (MDP_PPP_DONE| \
MDP_DMA_P_DONE| \
MDP_DMA_S_DONE| \
LCDC_UNDERFLOW| \
MDP_HIST_DONE| \
TV_ENC_UNDERRUN)
#endif
#define MDP_TOP_LUMA 16
#define MDP_TOP_CHROMA 0
#define MDP_BOTTOM_LUMA 19
#define MDP_BOTTOM_CHROMA 3
#define MDP_LEFT_LUMA 22
#define MDP_LEFT_CHROMA 6
#define MDP_RIGHT_LUMA 25
#define MDP_RIGHT_CHROMA 9
#define CLR_G 0x0
#define CLR_B 0x1
#define CLR_R 0x2
#define CLR_ALPHA 0x3
#define CLR_Y CLR_G
#define CLR_CB CLR_B
#define CLR_CR CLR_R
/* from lsb to msb */
#define MDP_GET_PACK_PATTERN(a,x,y,z,bit) (((a)<<(bit*3))|((x)<<(bit*2))|((y)<<bit)|(z))
/*
* 0x0000 0x0004 0x0008 MDP sync config
*/
#ifdef CONFIG_FB_MSM_MDP22
#define MDP_SYNCFG_HGT_LOC 22
#define MDP_SYNCFG_VSYNC_EXT_EN BIT(21)
#define MDP_SYNCFG_VSYNC_INT_EN BIT(20)
#else
#define MDP_SYNCFG_HGT_LOC 21
#define MDP_SYNCFG_VSYNC_EXT_EN BIT(20)
#define MDP_SYNCFG_VSYNC_INT_EN BIT(19)
#define MDP_HW_VSYNC
#endif
/*
* 0x0018 MDP VSYNC THREASH
*/
#define MDP_PRIM_BELOW_LOC 0
#define MDP_PRIM_ABOVE_LOC 8
/*
* MDP_PRIMARY_VSYNC_OUT_CTRL
* 0x0080,84,88 internal vsync pulse config
*/
#define VSYNC_PULSE_EN BIT(31)
#define VSYNC_PULSE_INV BIT(30)
/*
* 0x008c MDP VSYNC CONTROL
*/
#define DISP0_VSYNC_MAP_VSYNC0 0
#define DISP0_VSYNC_MAP_VSYNC1 BIT(0)
#define DISP0_VSYNC_MAP_VSYNC2 BIT(0)|BIT(1)
#define DISP1_VSYNC_MAP_VSYNC0 0
#define DISP1_VSYNC_MAP_VSYNC1 BIT(2)
#define DISP1_VSYNC_MAP_VSYNC2 BIT(2)|BIT(3)
#define PRIMARY_LCD_SYNC_EN BIT(4)
#define PRIMARY_LCD_SYNC_DISABLE 0
#define SECONDARY_LCD_SYNC_EN BIT(5)
#define SECONDARY_LCD_SYNC_DISABLE 0
#define EXTERNAL_LCD_SYNC_EN BIT(6)
#define EXTERNAL_LCD_SYNC_DISABLE 0
/*
* 0x101f0 MDP VSYNC Threshold
*/
#define VSYNC_THRESHOLD_ABOVE_LOC 0
#define VSYNC_THRESHOLD_BELOW_LOC 16
#define VSYNC_ANTI_TEAR_EN BIT(31)
/*
* 0x10004 command config
*/
#define MDP_CMD_DBGBUS_EN BIT(0)
/*
* 0x10124 or 0x101d4PPP source config
*/
#define PPP_SRC_C0G_8BITS (BIT(1)|BIT(0))
#define PPP_SRC_C1B_8BITS (BIT(3)|BIT(2))
#define PPP_SRC_C2R_8BITS (BIT(5)|BIT(4))
#define PPP_SRC_C3A_8BITS (BIT(7)|BIT(6))
#define PPP_SRC_C0G_6BITS BIT(1)
#define PPP_SRC_C1B_6BITS BIT(3)
#define PPP_SRC_C2R_6BITS BIT(5)
#define PPP_SRC_C0G_5BITS BIT(0)
#define PPP_SRC_C1B_5BITS BIT(2)
#define PPP_SRC_C2R_5BITS BIT(4)
#define PPP_SRC_C3_ALPHA_EN BIT(8)
#define PPP_SRC_BPP_INTERLVD_1BYTES 0
#define PPP_SRC_BPP_INTERLVD_2BYTES BIT(9)
#define PPP_SRC_BPP_INTERLVD_3BYTES BIT(10)
#define PPP_SRC_BPP_INTERLVD_4BYTES (BIT(10)|BIT(9))
#define PPP_SRC_BPP_ROI_ODD_X BIT(11)
#define PPP_SRC_BPP_ROI_ODD_Y BIT(12)
#define PPP_SRC_INTERLVD_2COMPONENTS BIT(13)
#define PPP_SRC_INTERLVD_3COMPONENTS BIT(14)
#define PPP_SRC_INTERLVD_4COMPONENTS (BIT(14)|BIT(13))
/*
* RGB666 unpack format
* TIGHT means R6+G6+B6 together
* LOOSE means R6+2 +G6+2+ B6+2 (with MSB)
* or 2+R6 +2+G6 +2+B6 (with LSB)
*/
#define PPP_SRC_UNPACK_TIGHT BIT(17)
#define PPP_SRC_UNPACK_LOOSE 0
#define PPP_SRC_UNPACK_ALIGN_LSB 0
#define PPP_SRC_UNPACK_ALIGN_MSB BIT(18)
#define PPP_SRC_FETCH_PLANES_INTERLVD 0
#define PPP_SRC_FETCH_PLANES_PSEUDOPLNR BIT(20)
#define PPP_SRC_WMV9_MODE BIT(21) /* window media version 9 */
/*
* 0x10138 PPP operation config
*/
#define PPP_OP_SCALE_X_ON BIT(0)
#define PPP_OP_SCALE_Y_ON BIT(1)
#define PPP_OP_CONVERT_RGB2YCBCR 0
#define PPP_OP_CONVERT_YCBCR2RGB BIT(2)
#define PPP_OP_CONVERT_ON BIT(3)
#define PPP_OP_CONVERT_MATRIX_PRIMARY 0
#define PPP_OP_CONVERT_MATRIX_SECONDARY BIT(4)
#define PPP_OP_LUT_C0_ON BIT(5)
#define PPP_OP_LUT_C1_ON BIT(6)
#define PPP_OP_LUT_C2_ON BIT(7)
/* rotate or blend enable */
#define PPP_OP_ROT_ON BIT(8)
#define PPP_OP_ROT_90 BIT(9)
#define PPP_OP_FLIP_LR BIT(10)
#define PPP_OP_FLIP_UD BIT(11)
#define PPP_OP_BLEND_ON BIT(12)
#define PPP_OP_BLEND_SRCPIXEL_ALPHA 0
#define PPP_OP_BLEND_DSTPIXEL_ALPHA BIT(13)
#define PPP_OP_BLEND_CONSTANT_ALPHA BIT(14)
#define PPP_OP_BLEND_SRCPIXEL_TRANSP (BIT(13)|BIT(14))
#define PPP_OP_BLEND_ALPHA_BLEND_NORMAL 0
#define PPP_OP_BLEND_ALPHA_BLEND_REVERSE BIT(15)
#define PPP_OP_DITHER_EN BIT(16)
#define PPP_OP_COLOR_SPACE_RGB 0
#define PPP_OP_COLOR_SPACE_YCBCR BIT(17)
#define PPP_OP_SRC_CHROMA_RGB 0
#define PPP_OP_SRC_CHROMA_H2V1 BIT(18)
#define PPP_OP_SRC_CHROMA_H1V2 BIT(19)
#define PPP_OP_SRC_CHROMA_420 (BIT(18)|BIT(19))
#define PPP_OP_SRC_CHROMA_COSITE 0
#define PPP_OP_SRC_CHROMA_OFFSITE BIT(20)
#define PPP_OP_DST_CHROMA_RGB 0
#define PPP_OP_DST_CHROMA_H2V1 BIT(21)
#define PPP_OP_DST_CHROMA_H1V2 BIT(22)
#define PPP_OP_DST_CHROMA_420 (BIT(21)|BIT(22))
#define PPP_OP_DST_CHROMA_COSITE 0
#define PPP_OP_DST_CHROMA_OFFSITE BIT(23)
#define PPP_BLEND_CALPHA_TRNASP BIT(24)
#define PPP_OP_BG_CHROMA_RGB 0
#define PPP_OP_BG_CHROMA_H2V1 BIT(25)
#define PPP_OP_BG_CHROMA_H1V2 BIT(26)
#define PPP_OP_BG_CHROMA_420 BIT(25)|BIT(26)
#define PPP_OP_BG_CHROMA_SITE_COSITE 0
#define PPP_OP_BG_CHROMA_SITE_OFFSITE BIT(27)
#define PPP_OP_DEINT_EN BIT(29)
#define PPP_BLEND_BG_USE_ALPHA_SEL (1 << 0)
#define PPP_BLEND_BG_ALPHA_REVERSE (1 << 3)
#define PPP_BLEND_BG_SRCPIXEL_ALPHA (0 << 1)
#define PPP_BLEND_BG_DSTPIXEL_ALPHA (1 << 1)
#define PPP_BLEND_BG_CONSTANT_ALPHA (2 << 1)
#define PPP_BLEND_BG_CONST_ALPHA_VAL(x) ((x) << 24)
#define PPP_OP_DST_RGB 0
#define PPP_OP_DST_YCBCR BIT(30)
/*
* 0x10150 PPP destination config
*/
#define PPP_DST_C0G_8BIT (BIT(0)|BIT(1))
#define PPP_DST_C1B_8BIT (BIT(3)|BIT(2))
#define PPP_DST_C2R_8BIT (BIT(5)|BIT(4))
#define PPP_DST_C3A_8BIT (BIT(7)|BIT(6))
#define PPP_DST_C0G_6BIT BIT(1)
#define PPP_DST_C1B_6BIT BIT(3)
#define PPP_DST_C2R_6BIT BIT(5)
#define PPP_DST_C0G_5BIT BIT(0)
#define PPP_DST_C1B_5BIT BIT(2)
#define PPP_DST_C2R_5BIT BIT(4)
#define PPP_DST_C3A_8BIT (BIT(7)|BIT(6))
#define PPP_DST_C3ALPHA_EN BIT(8)
#define PPP_DST_PACKET_CNT_INTERLVD_2ELEM BIT(9)
#define PPP_DST_PACKET_CNT_INTERLVD_3ELEM BIT(10)
#define PPP_DST_PACKET_CNT_INTERLVD_4ELEM (BIT(10)|BIT(9))
#define PPP_DST_PACKET_CNT_INTERLVD_6ELEM (BIT(11)|BIT(9))
#define PPP_DST_PACK_LOOSE 0
#define PPP_DST_PACK_TIGHT BIT(13)
#define PPP_DST_PACK_ALIGN_LSB 0
#define PPP_DST_PACK_ALIGN_MSB BIT(14)
#define PPP_DST_OUT_SEL_AXI 0
#define PPP_DST_OUT_SEL_MDDI BIT(15)
#define PPP_DST_BPP_2BYTES BIT(16)
#define PPP_DST_BPP_3BYTES BIT(17)
#define PPP_DST_BPP_4BYTES (BIT(17)|BIT(16))
#define PPP_DST_PLANE_INTERLVD 0
#define PPP_DST_PLANE_PLANAR BIT(18)
#define PPP_DST_PLANE_PSEUDOPLN BIT(19)
#define PPP_DST_TO_TV BIT(20)
#define PPP_DST_MDDI_PRIMARY 0
#define PPP_DST_MDDI_SECONDARY BIT(21)
#define PPP_DST_MDDI_EXTERNAL BIT(22)
/*
* 0x10180 DMA config
*/
#define DMA_DSTC0G_8BITS (BIT(1)|BIT(0))
#define DMA_DSTC1B_8BITS (BIT(3)|BIT(2))
#define DMA_DSTC2R_8BITS (BIT(5)|BIT(4))
#define DMA_DSTC0G_6BITS BIT(1)
#define DMA_DSTC1B_6BITS BIT(3)
#define DMA_DSTC2R_6BITS BIT(5)
#define DMA_DSTC0G_5BITS BIT(0)
#define DMA_DSTC1B_5BITS BIT(2)
#define DMA_DSTC2R_5BITS BIT(4)
#define DMA_PACK_TIGHT BIT(6)
#define DMA_PACK_LOOSE 0
#define DMA_PACK_ALIGN_LSB 0
/*
* use DMA_PACK_ALIGN_MSB if the upper 6 bits from 8 bits output
* from LCDC block maps into 6 pins out to the panel
*/
#define DMA_PACK_ALIGN_MSB BIT(7)
#define DMA_PACK_PATTERN_RGB \
(MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 2)<<8)
#define DMA_PACK_PATTERN_BGR \
(MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 2)<<8)
#define DMA_OUT_SEL_AHB 0
#define DMA_OUT_SEL_LCDC BIT(20)
#define DMA_IBUF_FORMAT_RGB888 0
#define DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888 BIT(26)
#ifdef CONFIG_FB_MSM_MDP22
#define DMA_OUT_SEL_MDDI BIT(14)
#define DMA_AHBM_LCD_SEL_PRIMARY 0
#define DMA_AHBM_LCD_SEL_SECONDARY BIT(15)
#define DMA_IBUF_C3ALPHA_EN BIT(16)
#define DMA_DITHER_EN BIT(17)
#define DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY 0
#define DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY BIT(18)
#define DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL BIT(19)
#define DMA_IBUF_FORMAT_RGB565 BIT(20)
#define DMA_IBUF_FORMAT_RGB888_OR_ARGB8888 0
#define DMA_IBUF_NONCONTIGUOUS BIT(21)
#else
#define DMA_OUT_SEL_MDDI BIT(19)
#define DMA_AHBM_LCD_SEL_PRIMARY 0
#define DMA_AHBM_LCD_SEL_SECONDARY 0
#define DMA_IBUF_C3ALPHA_EN 0
#define DMA_DITHER_EN BIT(24)
#define DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY 0
#define DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY 0
#define DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL 0
#define DMA_IBUF_FORMAT_RGB565 BIT(25)
#define DMA_IBUF_NONCONTIGUOUS 0
#endif
/*
* MDDI Register
*/
#define MDDI_VDO_PACKET_DESC 0x5666
#ifdef CONFIG_FB_MSM_MDP40
#define MDP_INTR_ENABLE (msm_mdp_base + 0x0050)
#define MDP_INTR_STATUS (msm_mdp_base + 0x0054)
#define MDP_INTR_CLEAR (msm_mdp_base + 0x0058)
#define MDP_EBI2_LCD0 (msm_mdp_base + 0x0060)
#define MDP_EBI2_LCD1 (msm_mdp_base + 0x0064)
#define MDP_EBI2_PORTMAP_MODE (msm_mdp_base + 0x0070)
#define MDP_DMA_P_HIST_INTR_STATUS (msm_mdp_base + 0x95014)
#define MDP_DMA_P_HIST_INTR_CLEAR (msm_mdp_base + 0x95018)
#define MDP_DMA_P_HIST_INTR_ENABLE (msm_mdp_base + 0x9501C)
#else
#define MDP_INTR_ENABLE (msm_mdp_base + 0x0020)
#define MDP_INTR_STATUS (msm_mdp_base + 0x0024)
#define MDP_INTR_CLEAR (msm_mdp_base + 0x0028)
#define MDP_EBI2_LCD0 (msm_mdp_base + 0x003c)
#define MDP_EBI2_LCD1 (msm_mdp_base + 0x0040)
#define MDP_EBI2_PORTMAP_MODE (msm_mdp_base + 0x005c)
#endif
#define MDP_FULL_BYPASS_WORD43 (msm_mdp_base + 0x101ac)
#define MDP_CSC_PFMVn(n) (msm_mdp_base + 0x40400 + 4 * (n))
#define MDP_CSC_PRMVn(n) (msm_mdp_base + 0x40440 + 4 * (n))
#define MDP_CSC_PRE_BV1n(n) (msm_mdp_base + 0x40500 + 4 * (n))
#define MDP_CSC_PRE_BV2n(n) (msm_mdp_base + 0x40540 + 4 * (n))
#define MDP_CSC_POST_BV1n(n) (msm_mdp_base + 0x40580 + 4 * (n))
#define MDP_CSC_POST_BV2n(n) (msm_mdp_base + 0x405c0 + 4 * (n))
#ifdef CONFIG_FB_MSM_MDP31
#define MDP_CSC_PRE_LV1n(n) (msm_mdp_base + 0x40600 + 4 * (n))
#define MDP_CSC_PRE_LV2n(n) (msm_mdp_base + 0x40640 + 4 * (n))
#define MDP_CSC_POST_LV1n(n) (msm_mdp_base + 0x40680 + 4 * (n))
#define MDP_CSC_POST_LV2n(n) (msm_mdp_base + 0x406c0 + 4 * (n))
#define MDP_PPP_SCALE_COEFF_LSBn(n) (msm_mdp_base + 0x50400 + 8 * (n))
#define MDP_PPP_SCALE_COEFF_MSBn(n) (msm_mdp_base + 0x50404 + 8 * (n))
#define SCALE_D0_SET 0
#define SCALE_D1_SET BIT(0)
#define SCALE_D2_SET BIT(1)
#define SCALE_U1_SET (BIT(0)|BIT(1))
#else
#define MDP_CSC_PRE_LV1n(n) (msm_mdp_base + 0x40580 + 4 * (n))
#endif
#define MDP_CURSOR_WIDTH 64
#define MDP_CURSOR_HEIGHT 64
#define MDP_CURSOR_SIZE (MDP_CURSOR_WIDTH*MDP_CURSOR_WIDTH*4)
#define MDP_DMA_P_LUT_C0_EN BIT(0)
#define MDP_DMA_P_LUT_C1_EN BIT(1)
#define MDP_DMA_P_LUT_C2_EN BIT(2)
#define MDP_DMA_P_LUT_POST BIT(4)
void mdp_hw_init(void);
int mdp_ppp_pipe_wait(void);
void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd);
void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state,
boolean isr);
void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty,
boolean sync);
void mdp_dma_pan_update(struct fb_info *info);
void mdp_refresh_screen(unsigned long data);
int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req,
struct file **pp_src, struct file **pp_dest);
void mdp_lcd_update_workqueue_handler(struct work_struct *work);
void mdp_vsync_resync_workqueue_handler(struct work_struct *work);
void mdp_dma2_update(struct msm_fb_data_type *mfd);
void mdp_config_vsync(struct msm_fb_data_type *);
uint32 mdp_get_lcd_line_counter(struct msm_fb_data_type *mfd);
enum hrtimer_restart mdp_dma2_vsync_hrtimer_handler(struct hrtimer *ht);
void mdp_set_scale(MDPIBUF *iBuf,
uint32 dst_roi_width,
uint32 dst_roi_height,
boolean inputRGB, boolean outputRGB, uint32 *pppop_reg_ptr);
void mdp_init_scale_table(void);
void mdp_adjust_start_addr(uint8 **src0,
uint8 **src1,
int v_slice,
int h_slice,
int x,
int y,
uint32 width,
uint32 height, int bpp, MDPIBUF *iBuf, int layer);
void mdp_set_blend_attr(MDPIBUF *iBuf,
uint32 *alpha,
uint32 *tpVal,
uint32 perPixelAlpha, uint32 *pppop_reg_ptr);
int mdp_dma3_on(struct platform_device *pdev);
int mdp_dma3_off(struct platform_device *pdev);
void mdp_dma3_update(struct msm_fb_data_type *mfd);
int mdp_lcdc_on(struct platform_device *pdev);
int mdp_lcdc_off(struct platform_device *pdev);
void mdp_lcdc_update(struct msm_fb_data_type *mfd);
int mdp_hw_cursor_update(struct fb_info *info, struct fb_cursor *cursor);
void mdp_enable_irq(uint32 term);
void mdp_disable_irq(uint32 term);
void mdp_disable_irq_nolock(uint32 term);
uint32_t mdp_get_bytes_per_pixel(uint32_t format);
#ifdef MDP_HW_VSYNC
void mdp_hw_vsync_clk_enable(struct msm_fb_data_type *mfd);
void mdp_hw_vsync_clk_disable(struct msm_fb_data_type *mfd);
#endif
void mdp_dma_s_update(struct msm_fb_data_type *mfd);
/* Added to support flipping */
void mdp_set_offset_info(struct fb_info *info, uint32 address, uint32 interval);
int get_gem_img(struct mdp_img *img, unsigned long *start,
unsigned long *len);
int get_img(struct mdp_img *img, struct fb_info *info,
unsigned long *start, unsigned long *len,
struct file **pp_file);
/*int get_img(struct msmfb_data *img, struct fb_info *info,
unsigned long *start, unsigned long *len, struct file **pp_file);*/
#endif /* MDP_H */

352
drivers/staging/msm/mdp4.h Normal file
View file

@ -0,0 +1,352 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MDP4_H
#define MDP4_H
extern struct mdp_dma_data dma2_data;
extern struct mdp_dma_data dma_s_data;
extern struct mdp_dma_data dma_e_data;
extern struct mdp_histogram mdp_hist;
extern struct completion mdp_hist_comp;
extern boolean mdp_is_in_isr;
extern uint32 mdp_intr_mask;
extern spinlock_t mdp_spin_lock;
#define MDP4_NONBLOCKING /* enable non blocking ioctl */
#define MDP4_OVERLAYPROC0_BASE 0x10000
#define MDP4_OVERLAYPROC1_BASE 0x18000
#define MDP4_VIDEO_BASE 0x20000
#define MDP4_VIDEO_OFF 0x10000
#define MDP4_RGB_BASE 0x40000
#define MDP4_RGB_OFF 0x10000
enum { /* display */
PRIMARY_INTF_SEL,
SECONDARY_INTF_SEL,
EXTERNAL_INTF_SEL
};
enum {
LCDC_RGB_INTF,
DTV_INTF = LCDC_RGB_INTF,
MDDI_LCDC_INTF,
MDDI_INTF,
EBI2_INTF
};
enum {
MDDI_PRIMARY_SET,
MDDI_SECONDARY_SET,
MDDI_EXTERNAL_SET
};
enum {
EBI2_LCD0,
EBI2_LCD1
};
enum {
OVERLAY_MODE_NONE,
OVERLAY_MODE_BLT
};
enum {
OVERLAY_REFRESH_ON_DEMAND,
OVERLAY_REFRESH_VSYNC,
OVERLAY_REFRESH_VSYNC_HALF,
OVERLAY_REFRESH_VSYNC_QUARTER
};
enum {
OVERLAY_FRAMEBUF,
OVERLAY_DIRECTOUT
};
/* system interrupts */
#define INTR_OVERLAY0_DONE BIT(0)
#define INTR_OVERLAY1_DONE BIT(1)
#define INTR_DMA_S_DONE BIT(2)
#define INTR_DMA_E_DONE BIT(3)
#define INTR_DMA_P_DONE BIT(4)
#define INTR_VG1_HISTOGRAM BIT(5)
#define INTR_VG2_HISTOGRAM BIT(6)
#define INTR_PRIMARY_VSYNC BIT(7)
#define INTR_PRIMARY_INTF_UDERRUN BIT(8)
#define INTR_EXTERNAL_VSYNC BIT(9)
#define INTR_EXTERNAL_INTF_UDERRUN BIT(10)
#define INTR_DMA_P_HISTOGRAM BIT(17)
/* histogram interrupts */
#define INTR_HIST_DONE BIT(0)
#define INTR_HIST_RESET_SEQ_DONE BIT(1)
#ifdef CONFIG_FB_MSM_OVERLAY
#define MDP4_ANY_INTR_MASK (INTR_OVERLAY0_DONE)
#else
#define MDP4_ANY_INTR_MASK (INTR_DMA_P_DONE)
#endif
enum {
OVERLAY_PIPE_RGB1,
OVERLAY_PIPE_RGB2,
};
enum {
OVERLAY_PIPE_VG1, /* video/graphic */
OVERLAY_PIPE_VG2
};
enum {
OVERLAY_TYPE_RGB,
OVERLAY_TYPE_VG /* video/graphic */
};
enum {
MDP4_MIXER0,
MDP4_MIXER1
};
#define MDP4_MAX_MIXER 2
enum {
OVERLAY_PLANE_INTERLEAVED,
OVERLAY_PLANE_PLANAR,
OVERLAY_PLANE_PSEUDO_PLANAR
};
enum {
MDP4_MIXER_STAGE_UNUNSED, /* pipe not used */
MDP4_MIXER_STAGE_BASE,
MDP4_MIXER_STAGE0, /* zorder 0 */
MDP4_MIXER_STAGE1, /* zorder 1 */
MDP4_MIXER_STAGE2 /* zorder 2 */
};
#define MDP4_MAX_STAGE 4
enum {
MDP4_FRAME_FORMAT_LINEAR,
MDP4_FRAME_FORMAT_ARGB_TILE,
MDP4_FRAME_FORMAT_VIDEO_SUPERTILE
};
enum {
MDP4_CHROMA_RGB,
MDP4_CHROMA_H2V1,
MDP4_CHROMA_H1V2,
MDP4_CHROMA_420
};
#define MDP4_BLEND_BG_TRANSP_EN BIT(9)
#define MDP4_BLEND_FG_TRANSP_EN BIT(8)
#define MDP4_BLEND_BG_MOD_ALPHA BIT(7)
#define MDP4_BLEND_BG_INV_ALPHA BIT(6)
#define MDP4_BLEND_BG_ALPHA_FG_CONST (0 << 4)
#define MDP4_BLEND_BG_ALPHA_BG_CONST (1 << 4)
#define MDP4_BLEND_BG_ALPHA_FG_PIXEL (2 << 4)
#define MDP4_BLEND_BG_ALPHA_BG_PIXEL (3 << 4)
#define MDP4_BLEND_FG_MOD_ALPHA BIT(3)
#define MDP4_BLEND_FG_INV_ALPHA BIT(2)
#define MDP4_BLEND_FG_ALPHA_FG_CONST (0 << 0)
#define MDP4_BLEND_FG_ALPHA_BG_CONST (1 << 0)
#define MDP4_BLEND_FG_ALPHA_FG_PIXEL (2 << 0)
#define MDP4_BLEND_FG_ALPHA_BG_PIXEL (3 << 0)
#define MDP4_FORMAT_SOLID_FILL BIT(22)
#define MDP4_FORMAT_UNPACK_ALIGN_MSB BIT(18)
#define MDP4_FORMAT_UNPACK_TIGHT BIT(17)
#define MDP4_FORMAT_90_ROTATED BIT(12)
#define MDP4_FORMAT_ALPHA_ENABLE BIT(8)
#define MDP4_OP_DEINT_ODD_REF BIT(19)
#define MDP4_OP_IGC_LUT_EN BIT(16)
#define MDP4_OP_DITHER_EN BIT(15)
#define MDP4_OP_FLIP_UD BIT(14)
#define MDP4_OP_FLIP_LR BIT(13)
#define MDP4_OP_CSC_EN BIT(11)
#define MDP4_OP_SRC_DATA_YCBCR BIT(9)
#define MDP4_OP_SCALEY_FIR (0 << 4)
#define MDP4_OP_SCALEY_MN_PHASE (1 << 4)
#define MDP4_OP_SCALEY_PIXEL_RPT (2 << 4)
#define MDP4_OP_SCALEX_FIR (0 << 2)
#define MDP4_OP_SCALEX_MN_PHASE (1 << 2)
#define MDP4_OP_SCALEX_PIXEL_RPT (2 << 2)
#define MDP4_OP_SCALEY_EN BIT(1)
#define MDP4_OP_SCALEX_EN BIT(0)
#define MDP4_PIPE_PER_MIXER 2
#define MDP4_MAX_PLANE 4
#define MDP4_MAX_VIDEO_PIPE 2
#define MDP4_MAX_RGB_PIPE 2
#define MDP4_MAX_OVERLAY_PIPE 16
struct mdp4_overlay_pipe {
uint32 pipe_type; /* rgb, video/graphic */
uint32 pipe_num;
uint32 pipe_ndx;
uint32 mixer_num; /* which mixer used */
uint32 mixer_stage; /* which stage of mixer used */
uint32 src_format;
uint32 src_width; /* source img width */
uint32 src_height; /* source img height */
uint32 src_w; /* roi */
uint32 src_h; /* roi */
uint32 src_x; /* roi */
uint32 src_y; /* roi */
uint32 dst_w; /* roi */
uint32 dst_h; /* roi */
uint32 dst_x; /* roi */
uint32 dst_y; /* roi */
uint32 op_mode;
uint32 transp;
uint32 blend_op;
uint32 phasex_step;
uint32 phasey_step;
uint32 alpha;
uint32 is_fg; /* control alpha & color key */
uint32 srcp0_addr; /* interleave, luma */
uint32 srcp0_ystride;
uint32 srcp1_addr; /* pseudoplanar, chroma plane */
uint32 srcp1_ystride;
uint32 srcp2_addr; /* planar color 2*/
uint32 srcp2_ystride;
uint32 srcp3_addr; /* alpha/color 3 */
uint32 srcp3_ystride;
uint32 fetch_plane;
uint32 frame_format; /* video */
uint32 chroma_site; /* video */
uint32 chroma_sample; /* video */
uint32 solid_fill;
uint32 vc1_reduce; /* video */
uint32 fatch_planes; /* video */
uint32 unpack_align_msb;/* 0 to LSB, 1 to MSB */
uint32 unpack_tight;/* 0 for loose, 1 for tight */
uint32 unpack_count;/* 0 = 1 component, 1 = 2 component ... */
uint32 rotated_90; /* has been rotated 90 degree */
uint32 bpp; /* byte per pixel */
uint32 alpha_enable;/* source has alpha */
/*
* number of bits for source component,
* 0 = 1 bit, 1 = 2 bits, 2 = 6 bits, 3 = 8 bits
*/
uint32 a_bit; /* component 3, alpha */
uint32 r_bit; /* component 2, R_Cr */
uint32 b_bit; /* component 1, B_Cb */
uint32 g_bit; /* component 0, G_lumz */
/*
* unpack pattern
* A = C3, R = C2, B = C1, G = C0
*/
uint32 element3; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */
uint32 element2; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */
uint32 element1; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */
uint32 element0; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */
struct completion comp;
struct mdp_overlay req_data;
};
void mdp4_sw_reset(unsigned long bits);
void mdp4_display_intf_sel(int output, unsigned long intf);
void mdp4_overlay_cfg(int layer, int blt_mode, int refresh, int direct_out);
void mdp4_ebi2_lcd_setup(int lcd, unsigned long base, int ystride);
void mdp4_mddi_setup(int which, unsigned long id);
unsigned long mdp4_display_status(void);
void mdp4_enable_clk_irq(void);
void mdp4_disable_clk_irq(void);
void mdp4_dma_p_update(struct msm_fb_data_type *mfd);
void mdp4_dma_s_update(struct msm_fb_data_type *mfd);
void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state,
boolean isr);
void mdp4_pipe_kickoff(uint32 pipe, struct msm_fb_data_type *mfd);
int mdp4_lcdc_on(struct platform_device *pdev);
int mdp4_lcdc_off(struct platform_device *pdev);
void mdp4_lcdc_update(struct msm_fb_data_type *mfd);
void mdp4_intr_clear_set(ulong clear, ulong set);
void mdp4_dma_p_cfg(void);
void mdp4_hw_init(void);
void mdp4_isr_read(int);
void mdp4_clear_lcdc(void);
void mdp4_mixer_blend_init(int mixer_num);
void mdp4_vg_qseed_init(int vg_num);
void mdp4_vg_csc_mv_setup(int vp_num);
void mdp4_vg_csc_pre_bv_setup(int vp_num);
void mdp4_vg_csc_post_bv_setup(int vp_num);
void mdp4_vg_csc_pre_lv_setup(int vp_num);
void mdp4_vg_csc_post_lv_setup(int vp_num);
irqreturn_t mdp4_isr(int irq, void *ptr);
void mdp4_overlay_format_to_pipe(uint32 format, struct mdp4_overlay_pipe *pipe);
uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe);
uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe);
uint32 mdp4_overlay_op_mode(struct mdp4_overlay_pipe *pipe);
void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd);
void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe);
void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all);
void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe);
void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe);
void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe);
int mdp4_mixer_stage_can_run(struct mdp4_overlay_pipe *pipe);
void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe);
void mdp4_mddi_overlay(struct msm_fb_data_type *mfd);
int mdp4_overlay_format2type(uint32 format);
int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe);
int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req);
int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req);
int mdp4_overlay_unset(struct fb_info *info, int ndx);
int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req,
struct file **pp_src_file);
struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(void);
void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe);
void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc);
void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe);
int mdp4_overlay_active(int mixer);
void mdp4_overlay0_done_lcdc(void);
void mdp4_overlay0_done_mddi(void);
void mdp4_mddi_overlay_restore(void);
void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
void mdp4_rgb_igc_lut_setup(int num);
void mdp4_vg_igc_lut_setup(int num);
void mdp4_mixer_gc_lut_setup(int mixer_num);
#ifdef CONFIG_DEBUG_FS
int mdp4_debugfs_init(void);
#endif
int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req,
struct file **pp_src_file, struct file **pp_dst_file);
#endif /* MDP_H */

View file

@ -0,0 +1,181 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/hrtimer.h>
#include <linux/clk.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <linux/debugfs.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mdp4.h"
#define MDP4_DEBUG_BUF 128
static char mdp4_debug_buf[MDP4_DEBUG_BUF];
static ulong mdp4_debug_offset;
static ulong mdp4_base_addr;
static int mdp4_offset_set(void *data, u64 val)
{
mdp4_debug_offset = (int)val;
return 0;
}
static int mdp4_offset_get(void *data, u64 *val)
{
*val = (u64)mdp4_debug_offset;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(
mdp4_offset_fops,
mdp4_offset_get,
mdp4_offset_set,
"%llx\n");
static int mdp4_debugfs_open(struct inode *inode, struct file *file)
{
/* non-seekable */
file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
return 0;
}
static int mdp4_debugfs_release(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t mdp4_debugfs_write(
struct file *file,
const char __user *buff,
size_t count,
loff_t *ppos)
{
int cnt;
unsigned int data;
printk(KERN_INFO "%s: offset=%d count=%d *ppos=%d\n",
__func__, (int)mdp4_debug_offset, (int)count, (int)*ppos);
if (count > sizeof(mdp4_debug_buf))
return -EFAULT;
if (copy_from_user(mdp4_debug_buf, buff, count))
return -EFAULT;
mdp4_debug_buf[count] = 0; /* end of string */
cnt = sscanf(mdp4_debug_buf, "%x", &data);
if (cnt < 1) {
printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
return -EINVAL;
}
writel(&data, mdp4_base_addr + mdp4_debug_offset);
return 0;
}
static ssize_t mdp4_debugfs_read(
struct file *file,
char __user *buff,
size_t count,
loff_t *ppos)
{
int len = 0;
unsigned int data;
printk(KERN_INFO "%s: offset=%d count=%d *ppos=%d\n",
__func__, (int)mdp4_debug_offset, (int)count, (int)*ppos);
if (*ppos)
return 0; /* the end */
data = readl(mdp4_base_addr + mdp4_debug_offset);
len = snprintf(mdp4_debug_buf, 4, "%x\n", data);
if (len > 0) {
if (len > count)
len = count;
if (copy_to_user(buff, mdp4_debug_buf, len))
return -EFAULT;
}
printk(KERN_INFO "%s: len=%d\n", __func__, len);
if (len < 0)
return 0;
*ppos += len; /* increase offset */
return len;
}
static const struct file_operations mdp4_debugfs_fops = {
.open = mdp4_debugfs_open,
.release = mdp4_debugfs_release,
.read = mdp4_debugfs_read,
.write = mdp4_debugfs_write,
};
int mdp4_debugfs_init(void)
{
struct dentry *dent = debugfs_create_dir("mdp4", NULL);
if (IS_ERR(dent)) {
printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n",
__FILE__, __LINE__, PTR_ERR(dent));
return -1;
}
if (debugfs_create_file("offset", 0644, dent, 0, &mdp4_offset_fops)
== NULL) {
printk(KERN_ERR "%s(%d): debugfs_create_file: offset fail\n",
__FILE__, __LINE__);
return -1;
}
if (debugfs_create_file("regs", 0644, dent, 0, &mdp4_debugfs_fops)
== NULL) {
printk(KERN_ERR "%s(%d): debugfs_create_file: regs fail\n",
__FILE__, __LINE__);
return -1;
}
mdp4_debug_offset = 0;
mdp4_base_addr = (ulong) msm_mdp_base; /* defined at msm_fb_def.h */
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,313 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mdp4.h"
#ifdef CONFIG_FB_MSM_MDP40
#define LCDC_BASE 0xC0000
#else
#define LCDC_BASE 0xE0000
#endif
int first_pixel_start_x;
int first_pixel_start_y;
static struct mdp4_overlay_pipe *lcdc_pipe;
int mdp_lcdc_on(struct platform_device *pdev)
{
int lcdc_width;
int lcdc_height;
int lcdc_bpp;
int lcdc_border_clr;
int lcdc_underflow_clr;
int lcdc_hsync_skew;
int hsync_period;
int hsync_ctrl;
int vsync_period;
int display_hctl;
int display_v_start;
int display_v_end;
int active_hctl;
int active_h_start;
int active_h_end;
int active_v_start;
int active_v_end;
int ctrl_polarity;
int h_back_porch;
int h_front_porch;
int v_back_porch;
int v_front_porch;
int hsync_pulse_width;
int vsync_pulse_width;
int hsync_polarity;
int vsync_polarity;
int data_en_polarity;
int hsync_start_x;
int hsync_end_x;
uint8 *buf;
int bpp, ptype;
uint32 format;
struct fb_info *fbi;
struct fb_var_screeninfo *var;
struct msm_fb_data_type *mfd;
struct mdp4_overlay_pipe *pipe;
int ret;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
fbi = mfd->fbi;
var = &fbi->var;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
buf += fbi->var.xoffset * bpp +
fbi->var.yoffset * fbi->fix.line_length;
if (bpp == 2)
format = MDP_RGB_565;
else if (bpp == 3)
format = MDP_RGB_888;
else
format = MDP_ARGB_8888;
if (lcdc_pipe == NULL) {
ptype = mdp4_overlay_format2type(format);
pipe = mdp4_overlay_pipe_alloc();
pipe->pipe_type = ptype;
/* use RGB1 pipe */
pipe->pipe_num = OVERLAY_PIPE_RGB1;
pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
pipe->mixer_num = MDP4_MIXER0;
pipe->src_format = format;
mdp4_overlay_format2pipe(pipe);
lcdc_pipe = pipe; /* keep it */
} else {
pipe = lcdc_pipe;
}
pipe->src_height = fbi->var.yres;
pipe->src_width = fbi->var.xres;
pipe->src_h = fbi->var.yres;
pipe->src_w = fbi->var.xres;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->srcp0_addr = (uint32) buf;
pipe->srcp0_ystride = fbi->fix.line_length;
mdp4_overlay_dmap_xy(pipe);
mdp4_overlay_dmap_cfg(mfd, 1);
mdp4_overlay_rgb_setup(pipe);
mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
/*
* LCDC timing setting
*/
h_back_porch = var->left_margin;
h_front_porch = var->right_margin;
v_back_porch = var->upper_margin;
v_front_porch = var->lower_margin;
hsync_pulse_width = var->hsync_len;
vsync_pulse_width = var->vsync_len;
lcdc_border_clr = mfd->panel_info.lcdc.border_clr;
lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
lcdc_width = mfd->panel_info.xres;
lcdc_height = mfd->panel_info.yres;
lcdc_bpp = mfd->panel_info.bpp;
hsync_period =
hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch;
hsync_ctrl = (hsync_period << 16) | hsync_pulse_width;
hsync_start_x = hsync_pulse_width + h_back_porch;
hsync_end_x = hsync_period - h_front_porch - 1;
display_hctl = (hsync_end_x << 16) | hsync_start_x;
vsync_period =
(vsync_pulse_width + v_back_porch + lcdc_height +
v_front_porch) * hsync_period;
display_v_start =
(vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew;
display_v_end =
vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1;
if (lcdc_width != var->xres) {
active_h_start = hsync_start_x + first_pixel_start_x;
active_h_end = active_h_start + var->xres - 1;
active_hctl =
ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start;
} else {
active_hctl = 0;
}
if (lcdc_height != var->yres) {
active_v_start =
display_v_start + first_pixel_start_y * hsync_period;
active_v_end = active_v_start + (var->yres) * hsync_period - 1;
active_v_start |= ACTIVE_START_Y_EN;
} else {
active_v_start = 0;
active_v_end = 0;
}
#ifdef CONFIG_FB_MSM_MDP40
hsync_polarity = 1;
vsync_polarity = 1;
lcdc_underflow_clr |= 0x80000000; /* enable recovery */
#else
hsync_polarity = 0;
vsync_polarity = 0;
#endif
data_en_polarity = 0;
ctrl_polarity =
(data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x4, hsync_ctrl);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x8, vsync_period);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0xc, vsync_pulse_width * hsync_period);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x10, display_hctl);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x14, display_v_start);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x18, display_v_end);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x28, lcdc_border_clr);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x2c, lcdc_underflow_clr);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x30, lcdc_hsync_skew);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x38, ctrl_polarity);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x1c, active_hctl);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x20, active_v_start);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x24, active_v_end);
ret = panel_next_on(pdev);
if (ret == 0) {
/* enable LCDC block */
MDP_OUTP(MDP_BASE + LCDC_BASE, 1);
mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
}
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
return ret;
}
int mdp_lcdc_off(struct platform_device *pdev)
{
int ret = 0;
struct mdp4_overlay_pipe *pipe;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + LCDC_BASE, 0);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
ret = panel_next_off(pdev);
/* delay to make sure the last frame finishes */
mdelay(100);
/* dis-engage rgb0 from mixer */
pipe = lcdc_pipe;
mdp4_mixer_stage_down(pipe);
return ret;
}
/*
* mdp4_overlay0_done_lcdc: called from isr
*/
void mdp4_overlay0_done_lcdc()
{
complete(&lcdc_pipe->comp);
}
void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd)
{
struct fb_info *fbi = mfd->fbi;
uint8 *buf;
int bpp;
unsigned long flag;
struct mdp4_overlay_pipe *pipe;
if (!mfd->panel_power_on)
return;
/* no need to power on cmd block since it's lcdc mode */
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
buf += fbi->var.xoffset * bpp +
fbi->var.yoffset * fbi->fix.line_length;
mutex_lock(&mfd->dma->ov_mutex);
pipe = lcdc_pipe;
pipe->srcp0_addr = (uint32) buf;
mdp4_overlay_rgb_setup(pipe);
mdp4_overlay_reg_flush(pipe, 1); /* rgb1 and mixer0 */
/* enable irq */
spin_lock_irqsave(&mdp_spin_lock, flag);
mdp_enable_irq(MDP_OVERLAY0_TERM);
INIT_COMPLETION(lcdc_pipe->comp);
mfd->dma->waiting = TRUE;
outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
mdp_intr_mask |= INTR_OVERLAY0_DONE;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
wait_for_completion_killable(&lcdc_pipe->comp);
mdp_disable_irq(MDP_OVERLAY0_TERM);
mutex_unlock(&mfd->dma->ov_mutex);
}

View file

@ -0,0 +1,254 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mdp4.h"
static struct mdp4_overlay_pipe *mddi_pipe;
static struct mdp4_overlay_pipe *pending_pipe;
static struct msm_fb_data_type *mddi_mfd;
#define WHOLESCREEN
void mdp4_overlay_update_lcd(struct msm_fb_data_type *mfd)
{
MDPIBUF *iBuf = &mfd->ibuf;
uint8 *src;
int bpp, ptype;
uint32 format;
uint32 mddi_ld_param;
uint16 mddi_vdo_packet_reg;
struct mdp4_overlay_pipe *pipe;
if (mfd->key != MFD_KEY)
return;
mddi_mfd = mfd; /* keep it */
bpp = iBuf->bpp;
if (bpp == 2)
format = MDP_RGB_565;
else if (bpp == 3)
format = MDP_RGB_888;
else
format = MDP_ARGB_8888;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
if (mddi_pipe == NULL) {
ptype = mdp4_overlay_format2type(format);
pipe = mdp4_overlay_pipe_alloc();
pipe->pipe_type = ptype;
/* use RGB1 pipe */
pipe->pipe_num = OVERLAY_PIPE_RGB1;
pipe->mixer_num = MDP4_MIXER0;
pipe->src_format = format;
mdp4_overlay_format2pipe(pipe);
mddi_pipe = pipe; /* keep it */
mddi_ld_param = 0;
mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
if (mfd->panel_info.type == MDDI_PANEL) {
if (mfd->panel_info.pdest == DISPLAY_1)
mddi_ld_param = 0;
else
mddi_ld_param = 1;
} else {
mddi_ld_param = 2;
}
MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param);
MDP_OUTP(MDP_BASE + 0x00094,
(MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
} else {
pipe = mddi_pipe;
}
src = (uint8 *) iBuf->buf;
#ifdef WHOLESCREEN
{
struct fb_info *fbi;
fbi = mfd->fbi;
pipe->src_height = fbi->var.yres;
pipe->src_width = fbi->var.xres;
pipe->src_h = fbi->var.yres;
pipe->src_w = fbi->var.xres;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->dst_h = fbi->var.yres;
pipe->dst_w = fbi->var.xres;
pipe->dst_y = 0;
pipe->dst_x = 0;
pipe->srcp0_addr = (uint32)src;
pipe->srcp0_ystride = fbi->var.xres_virtual * bpp;
}
#else
if (mdp4_overlay_active(MDP4_MIXER0)) {
struct fb_info *fbi;
fbi = mfd->fbi;
pipe->src_height = fbi->var.yres;
pipe->src_width = fbi->var.xres;
pipe->src_h = fbi->var.yres;
pipe->src_w = fbi->var.xres;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->dst_h = fbi->var.yres;
pipe->dst_w = fbi->var.xres;
pipe->dst_y = 0;
pipe->dst_x = 0;
pipe->srcp0_addr = (uint32) src;
pipe->srcp0_ystride = fbi->var.xres_virtual * bpp;
} else {
/* starting input address */
src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) * bpp;
pipe->src_height = iBuf->dma_h;
pipe->src_width = iBuf->dma_w;
pipe->src_h = iBuf->dma_h;
pipe->src_w = iBuf->dma_w;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->dst_h = iBuf->dma_h;
pipe->dst_w = iBuf->dma_w;
pipe->dst_y = iBuf->dma_y;
pipe->dst_x = iBuf->dma_x;
pipe->srcp0_addr = (uint32) src;
pipe->srcp0_ystride = iBuf->ibuf_width * bpp;
}
#endif
pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
mdp4_overlay_rgb_setup(pipe);
mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_dmap_xy(pipe);
mdp4_overlay_dmap_cfg(mfd, 0);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
/*
* mdp4_overlay0_done_mddi: called from isr
*/
void mdp4_overlay0_done_mddi()
{
if (pending_pipe)
complete(&pending_pipe->comp);
}
void mdp4_mddi_overlay_restore(void)
{
/* mutex holded by caller */
mdp4_overlay_update_lcd(mddi_mfd);
mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe);
}
void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
#ifdef MDP4_NONBLOCKING
unsigned long flag;
spin_lock_irqsave(&mdp_spin_lock, flag);
if (mfd->dma->busy == TRUE) {
INIT_COMPLETION(pipe->comp);
pending_pipe = pipe;
}
spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (pending_pipe != NULL) {
/* wait until DMA finishes the current job */
wait_for_completion_killable(&pipe->comp);
pending_pipe = NULL;
}
down(&mfd->sem);
mdp_enable_irq(MDP_OVERLAY0_TERM);
mfd->dma->busy = TRUE;
/* start OVERLAY pipe */
mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
up(&mfd->sem);
#else
down(&mfd->sem);
mdp_enable_irq(MDP_OVERLAY0_TERM);
mfd->dma->busy = TRUE;
INIT_COMPLETION(pipe->comp);
pending_pipe = pipe;
/* start OVERLAY pipe */
mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
up(&mfd->sem);
/* wait until DMA finishes the current job */
wait_for_completion_killable(&pipe->comp);
mdp_disable_irq(MDP_OVERLAY0_TERM);
#endif
}
void mdp4_mddi_overlay(struct msm_fb_data_type *mfd)
{
mutex_lock(&mfd->dma->ov_mutex);
if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
mdp4_overlay_update_lcd(mfd);
mdp4_mddi_overlay_kickoff(mfd, mddi_pipe);
/* signal if pan function is waiting for the update completion */
if (mfd->pan_waiting) {
mfd->pan_waiting = FALSE;
complete(&mfd->pan_comp);
}
}
mutex_unlock(&mfd->dma->ov_mutex);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,104 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
static int cursor_enabled;
int 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 fb_image *img = &cursor->image;
int calpha_en, transp_en;
int alpha;
int ret = 0;
if ((img->width > MDP_CURSOR_WIDTH) ||
(img->height > MDP_CURSOR_HEIGHT) ||
(img->depth != 32))
return -EINVAL;
if (cursor->set & FB_CUR_SETPOS)
MDP_OUTP(MDP_BASE + 0x9004c, (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 = 0x2; /* xrgb */
else
calpha_en = 0x1; /* argb */
MDP_OUTP(MDP_BASE + 0x90044, (img->height << 16) | img->width);
MDP_OUTP(MDP_BASE + 0x90048, mfd->cursor_buf_phys);
/* order the writes the cursor_buf before updating the
* hardware */
// dma_coherent_pre_ops();
MDP_OUTP(MDP_BASE + 0x90060,
(transp_en << 3) | (calpha_en << 1) |
(inp32(MDP_BASE + 0x90060) & 0x1));
#ifdef CONFIG_FB_MSM_MDP40
MDP_OUTP(MDP_BASE + 0x90064, (alpha << 24));
MDP_OUTP(MDP_BASE + 0x90068, (0xffffff & img->bg_color));
MDP_OUTP(MDP_BASE + 0x9006C, (0xffffff & img->bg_color));
#else
MDP_OUTP(MDP_BASE + 0x90064,
(alpha << 24) | (0xffffff & img->bg_color));
MDP_OUTP(MDP_BASE + 0x90068, 0);
#endif
}
if ((cursor->enable) && (!cursor_enabled)) {
cursor_enabled = 1;
MDP_OUTP(MDP_BASE + 0x90060, inp32(MDP_BASE + 0x90060) | 0x1);
} else if ((!cursor->enable) && (cursor_enabled)) {
cursor_enabled = 0;
MDP_OUTP(MDP_BASE + 0x90060,
inp32(MDP_BASE + 0x90060) & (~0x1));
}
return 0;
}

View file

@ -0,0 +1,561 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mddihost.h"
static uint32 mdp_last_dma2_update_width;
static uint32 mdp_last_dma2_update_height;
static uint32 mdp_curr_dma2_update_width;
static uint32 mdp_curr_dma2_update_height;
ktime_t mdp_dma2_last_update_time = { 0 };
int mdp_lcd_rd_cnt_offset_slow = 20;
int mdp_lcd_rd_cnt_offset_fast = 20;
int mdp_vsync_usec_wait_line_too_short = 5;
uint32 mdp_dma2_update_time_in_usec;
uint32 mdp_total_vdopkts;
extern u32 msm_fb_debug_enabled;
extern struct workqueue_struct *mdp_dma_wq;
int vsync_start_y_adjust = 4;
static void mdp_dma2_update_lcd(struct msm_fb_data_type *mfd)
{
MDPIBUF *iBuf = &mfd->ibuf;
int mddi_dest = FALSE;
uint32 outBpp = iBuf->bpp;
uint32 dma2_cfg_reg;
uint8 *src;
uint32 mddi_ld_param;
uint16 mddi_vdo_packet_reg;
struct msm_fb_panel_data *pdata =
(struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
uint32 ystride = mfd->fbi->fix.line_length;
dma2_cfg_reg = DMA_PACK_TIGHT | DMA_PACK_ALIGN_LSB |
DMA_OUT_SEL_AHB | DMA_IBUF_NONCONTIGUOUS;
#ifdef CONFIG_FB_MSM_MDP30
/*
* Software workaround: On 7x25/7x27, the MDP will not
* respond if dma_w is 1 pixel. Set the update width to
* 2 pixels and adjust the x offset if needed.
*/
if (iBuf->dma_w == 1) {
iBuf->dma_w = 2;
if (iBuf->dma_x == (iBuf->ibuf_width - 2))
iBuf->dma_x--;
}
#endif
if (mfd->fb_imgType == MDP_BGR_565)
dma2_cfg_reg |= DMA_PACK_PATTERN_BGR;
else
dma2_cfg_reg |= DMA_PACK_PATTERN_RGB;
if (outBpp == 4)
dma2_cfg_reg |= DMA_IBUF_C3ALPHA_EN;
if (outBpp == 2)
dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
mddi_ld_param = 0;
mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
if ((mfd->panel_info.type == MDDI_PANEL) ||
(mfd->panel_info.type == EXT_MDDI_PANEL)) {
dma2_cfg_reg |= DMA_OUT_SEL_MDDI;
mddi_dest = TRUE;
if (mfd->panel_info.type == MDDI_PANEL) {
mdp_total_vdopkts++;
if (mfd->panel_info.pdest == DISPLAY_1) {
dma2_cfg_reg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY;
mddi_ld_param = 0;
#ifdef MDDI_HOST_WINDOW_WORKAROUND
mddi_window_adjust(mfd, iBuf->dma_x,
iBuf->dma_w - 1, iBuf->dma_y,
iBuf->dma_h - 1);
#endif
} else {
dma2_cfg_reg |=
DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY;
mddi_ld_param = 1;
#ifdef MDDI_HOST_WINDOW_WORKAROUND
mddi_window_adjust(mfd, iBuf->dma_x,
iBuf->dma_w - 1, iBuf->dma_y,
iBuf->dma_h - 1);
#endif
}
} else {
dma2_cfg_reg |= DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL;
mddi_ld_param = 2;
}
} else {
if (mfd->panel_info.pdest == DISPLAY_1) {
dma2_cfg_reg |= DMA_AHBM_LCD_SEL_PRIMARY;
outp32(MDP_EBI2_LCD0, mfd->data_port_phys);
} else {
dma2_cfg_reg |= DMA_AHBM_LCD_SEL_SECONDARY;
outp32(MDP_EBI2_LCD1, mfd->data_port_phys);
}
}
dma2_cfg_reg |= DMA_DITHER_EN;
src = (uint8 *) iBuf->buf;
/* starting input address */
src += iBuf->dma_x * outBpp + iBuf->dma_y * ystride;
mdp_curr_dma2_update_width = iBuf->dma_w;
mdp_curr_dma2_update_height = iBuf->dma_h;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
#ifdef CONFIG_FB_MSM_MDP22
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0184,
(iBuf->dma_h << 16 | iBuf->dma_w));
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0188, src);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x018C, ystride);
#else
MDP_OUTP(MDP_BASE + 0x90004, (iBuf->dma_h << 16 | iBuf->dma_w));
MDP_OUTP(MDP_BASE + 0x90008, src);
MDP_OUTP(MDP_BASE + 0x9000c, ystride);
#endif
if (mfd->panel_info.bpp == 18) {
dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */
DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
} else {
dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */
DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
}
if (mddi_dest) {
#ifdef CONFIG_FB_MSM_MDP22
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0194,
(iBuf->dma_y << 16) | iBuf->dma_x);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01a0, mddi_ld_param);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4,
(MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
#else
MDP_OUTP(MDP_BASE + 0x90010, (iBuf->dma_y << 16) | iBuf->dma_x);
MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param);
MDP_OUTP(MDP_BASE + 0x00094,
(MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
#endif
} else {
/* setting EBI2 LCDC write window */
pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w,
iBuf->dma_h);
}
/* dma2 config register */
#ifdef MDP_HW_VSYNC
MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
if ((mfd->use_mdp_vsync) &&
(mfd->ibuf.vsync_enable) && (mfd->panel_info.lcd.vsync_enable)) {
uint32 start_y;
if (vsync_start_y_adjust <= iBuf->dma_y)
start_y = iBuf->dma_y - vsync_start_y_adjust;
else
start_y =
(mfd->total_lcd_lines - 1) - (vsync_start_y_adjust -
iBuf->dma_y);
/*
* MDP VSYNC clock must be On by now so, we don't have to
* re-enable it
*/
MDP_OUTP(MDP_BASE + 0x210, start_y);
MDP_OUTP(MDP_BASE + 0x20c, 1); /* enable prim vsync */
} else {
MDP_OUTP(MDP_BASE + 0x20c, 0); /* disable prim vsync */
}
#else
#ifdef CONFIG_FB_MSM_MDP22
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0180, dma2_cfg_reg);
#else
MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
#endif
#endif /* MDP_HW_VSYNC */
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
static ktime_t vt = { 0 };
int mdp_usec_diff_threshold = 100;
int mdp_expected_usec_wait;
enum hrtimer_restart mdp_dma2_vsync_hrtimer_handler(struct hrtimer *ht)
{
struct msm_fb_data_type *mfd = NULL;
mfd = container_of(ht, struct msm_fb_data_type, dma_hrtimer);
mdp_pipe_kickoff(MDP_DMA2_TERM, mfd);
if (msm_fb_debug_enabled) {
ktime_t t;
int usec_diff;
int actual_wait;
t = ktime_get_real();
actual_wait =
(t.tv.sec - vt.tv.sec) * 1000000 + (t.tv.nsec -
vt.tv.nsec) / 1000;
usec_diff = actual_wait - mdp_expected_usec_wait;
if ((mdp_usec_diff_threshold < usec_diff) || (usec_diff < 0))
MSM_FB_DEBUG
("HRT Diff = %d usec Exp=%d usec Act=%d usec\n",
usec_diff, mdp_expected_usec_wait, actual_wait);
}
return HRTIMER_NORESTART;
}
static void mdp_dma_schedule(struct msm_fb_data_type *mfd, uint32 term)
{
/*
* dma2 configure VSYNC block
* vsync supported on Primary LCD only for now
*/
int32 mdp_lcd_rd_cnt;
uint32 usec_wait_time;
uint32 start_y;
/*
* ToDo: if we can move HRT timer callback to workqueue, we can
* move DMA2 power on under mdp_pipe_kickoff().
* This will save a power for hrt time wait.
* However if the latency for context switch (hrt irq -> workqueue)
* is too big, we will miss the vsync timing.
*/
if (term == MDP_DMA2_TERM)
mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp_dma2_update_time_in_usec =
MDP_KTIME2USEC(mdp_dma2_last_update_time);
if ((!mfd->ibuf.vsync_enable) || (!mfd->panel_info.lcd.vsync_enable)
|| (mfd->use_mdp_vsync)) {
mdp_pipe_kickoff(term, mfd);
return;
}
/* SW vsync logic starts here */
/* get current rd counter */
mdp_lcd_rd_cnt = mdp_get_lcd_line_counter(mfd);
if (mdp_dma2_update_time_in_usec != 0) {
uint32 num, den;
/*
* roi width boundary calculation to know the size of pixel
* width that MDP can send faster or slower than LCD read
* pointer
*/
num = mdp_last_dma2_update_width * mdp_last_dma2_update_height;
den =
(((mfd->panel_info.lcd.refx100 * mfd->total_lcd_lines) /
1000) * (mdp_dma2_update_time_in_usec / 100)) / 1000;
if (den == 0)
mfd->vsync_width_boundary[mdp_last_dma2_update_width] =
mfd->panel_info.xres + 1;
else
mfd->vsync_width_boundary[mdp_last_dma2_update_width] =
(int)(num / den);
}
if (mfd->vsync_width_boundary[mdp_last_dma2_update_width] >
mdp_curr_dma2_update_width) {
/* MDP wrp is faster than LCD rdp */
mdp_lcd_rd_cnt += mdp_lcd_rd_cnt_offset_fast;
} else {
/* MDP wrp is slower than LCD rdp */
mdp_lcd_rd_cnt -= mdp_lcd_rd_cnt_offset_slow;
}
if (mdp_lcd_rd_cnt < 0)
mdp_lcd_rd_cnt = mfd->total_lcd_lines + mdp_lcd_rd_cnt;
else if (mdp_lcd_rd_cnt > mfd->total_lcd_lines)
mdp_lcd_rd_cnt = mdp_lcd_rd_cnt - mfd->total_lcd_lines - 1;
/* get wrt pointer position */
start_y = mfd->ibuf.dma_y;
/* measure line difference between start_y and rd counter */
if (start_y > mdp_lcd_rd_cnt) {
/*
* *100 for lcd_ref_hzx100 was already multiplied by 100
* *1000000 is for usec conversion
*/
if ((start_y - mdp_lcd_rd_cnt) <=
mdp_vsync_usec_wait_line_too_short)
usec_wait_time = 0;
else
usec_wait_time =
((start_y -
mdp_lcd_rd_cnt) * 1000000) /
((mfd->total_lcd_lines *
mfd->panel_info.lcd.refx100) / 100);
} else {
if ((start_y + (mfd->total_lcd_lines - mdp_lcd_rd_cnt)) <=
mdp_vsync_usec_wait_line_too_short)
usec_wait_time = 0;
else
usec_wait_time =
((start_y +
(mfd->total_lcd_lines -
mdp_lcd_rd_cnt)) * 1000000) /
((mfd->total_lcd_lines *
mfd->panel_info.lcd.refx100) / 100);
}
mdp_last_dma2_update_width = mdp_curr_dma2_update_width;
mdp_last_dma2_update_height = mdp_curr_dma2_update_height;
if (usec_wait_time == 0) {
mdp_pipe_kickoff(term, mfd);
} else {
ktime_t wait_time;
wait_time.tv.sec = 0;
wait_time.tv.nsec = usec_wait_time * 1000;
if (msm_fb_debug_enabled) {
vt = ktime_get_real();
mdp_expected_usec_wait = usec_wait_time;
}
hrtimer_start(&mfd->dma_hrtimer, wait_time, HRTIMER_MODE_REL);
}
}
#ifdef MDDI_HOST_WINDOW_WORKAROUND
void mdp_dma2_update(struct msm_fb_data_type *mfd)
{
MDPIBUF *iBuf;
uint32 upper_height;
if (mfd->panel.type == EXT_MDDI_PANEL) {
mdp_dma2_update_sub(mfd);
return;
}
iBuf = &mfd->ibuf;
upper_height =
(uint32) mddi_assign_pkt_height((uint16) iBuf->dma_w,
(uint16) iBuf->dma_h, 18);
if (upper_height >= iBuf->dma_h) {
mdp_dma2_update_sub(mfd);
} else {
MDPIBUF lower_height;
/* sending the upper region first */
lower_height = iBuf->dma_h - upper_height;
iBuf->dma_h = upper_height;
mdp_dma2_update_sub(mfd);
/* sending the lower region second */
iBuf->dma_h = lower_height;
iBuf->dma_y += lower_height;
iBuf->vsync_enable = FALSE;
mdp_dma2_update_sub(mfd);
}
}
void mdp_dma2_update_sub(struct msm_fb_data_type *mfd)
#else
void mdp_dma2_update(struct msm_fb_data_type *mfd)
#endif
{
down(&mfd->dma->mutex);
if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
down(&mfd->sem);
mfd->ibuf_flushed = TRUE;
mdp_dma2_update_lcd(mfd);
mdp_enable_irq(MDP_DMA2_TERM);
mfd->dma->busy = TRUE;
INIT_COMPLETION(mfd->dma->comp);
/* schedule DMA to start */
mdp_dma_schedule(mfd, MDP_DMA2_TERM);
up(&mfd->sem);
/* wait until DMA finishes the current job */
wait_for_completion_killable(&mfd->dma->comp);
mdp_disable_irq(MDP_DMA2_TERM);
/* signal if pan function is waiting for the update completion */
if (mfd->pan_waiting) {
mfd->pan_waiting = FALSE;
complete(&mfd->pan_comp);
}
}
up(&mfd->dma->mutex);
}
void mdp_lcd_update_workqueue_handler(struct work_struct *work)
{
struct msm_fb_data_type *mfd = NULL;
mfd = container_of(work, struct msm_fb_data_type, dma_update_worker);
if (mfd)
mfd->dma_fnc(mfd);
}
void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty,
boolean sync)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
MDPIBUF *iBuf;
int bpp = info->var.bits_per_pixel / 8;
down(&mfd->sem);
iBuf = &mfd->ibuf;
iBuf->buf = (uint8 *) info->fix.smem_start;
iBuf->buf += info->var.xoffset * bpp +
info->var.yoffset * info->fix.line_length;
iBuf->ibuf_width = info->var.xres_virtual;
iBuf->bpp = bpp;
iBuf->vsync_enable = sync;
if (dirty) {
/*
* ToDo: dirty region check inside var.xoffset+xres
* <-> var.yoffset+yres
*/
iBuf->dma_x = dirty->xoffset % info->var.xres;
iBuf->dma_y = dirty->yoffset % info->var.yres;
iBuf->dma_w = dirty->width;
iBuf->dma_h = dirty->height;
} else {
iBuf->dma_x = 0;
iBuf->dma_y = 0;
iBuf->dma_w = info->var.xres;
iBuf->dma_h = info->var.yres;
}
mfd->ibuf_flushed = FALSE;
up(&mfd->sem);
}
void mdp_set_offset_info(struct fb_info *info, uint32 addr, uint32 sync)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
MDPIBUF *iBuf;
int bpp = info->var.bits_per_pixel / 8;
down(&mfd->sem);
iBuf = &mfd->ibuf;
iBuf->ibuf_width = info->var.xres_virtual;
iBuf->bpp = bpp;
iBuf->vsync_enable = sync;
iBuf->dma_x = 0;
iBuf->dma_y = 0;
iBuf->dma_w = info->var.xres;
iBuf->dma_h = info->var.yres;
iBuf->buf = (uint8 *) addr;
mfd->ibuf_flushed = FALSE;
up(&mfd->sem);
}
void mdp_dma_pan_update(struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
MDPIBUF *iBuf;
iBuf = &mfd->ibuf;
if (mfd->sw_currently_refreshing) {
/* we need to wait for the pending update */
mfd->pan_waiting = TRUE;
if (!mfd->ibuf_flushed) {
wait_for_completion_killable(&mfd->pan_comp);
}
/* waiting for this update to complete */
mfd->pan_waiting = TRUE;
wait_for_completion_killable(&mfd->pan_comp);
} else
mfd->dma_fnc(mfd);
}
void mdp_refresh_screen(unsigned long data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
if ((mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) {
init_timer(&mfd->refresh_timer);
mfd->refresh_timer.function = mdp_refresh_screen;
mfd->refresh_timer.data = data;
if (mfd->dma->busy)
/* come back in 1 msec */
mfd->refresh_timer.expires = jiffies + (HZ / 1000);
else
mfd->refresh_timer.expires =
jiffies + mfd->refresh_timer_duration;
add_timer(&mfd->refresh_timer);
if (!mfd->dma->busy) {
if (!queue_work(mdp_dma_wq, &mfd->dma_update_worker)) {
MSM_FB_DEBUG("mdp_dma: can't queue_work! -> \
MDP/MDDI/LCD clock speed needs to be increased\n");
}
}
} else {
if (!mfd->hw_refresh)
complete(&mfd->refresher_comp);
}
}

View file

@ -0,0 +1,379 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mdp4.h"
#ifdef CONFIG_FB_MSM_MDP40
#define LCDC_BASE 0xC0000
#define DTV_BASE 0xD0000
#define DMA_E_BASE 0xB0000
#else
#define LCDC_BASE 0xE0000
#endif
#define DMA_P_BASE 0x90000
extern spinlock_t mdp_spin_lock;
#ifndef CONFIG_FB_MSM_MDP40
extern uint32 mdp_intr_mask;
#endif
int first_pixel_start_x;
int first_pixel_start_y;
int mdp_lcdc_on(struct platform_device *pdev)
{
int lcdc_width;
int lcdc_height;
int lcdc_bpp;
int lcdc_border_clr;
int lcdc_underflow_clr;
int lcdc_hsync_skew;
int hsync_period;
int hsync_ctrl;
int vsync_period;
int display_hctl;
int display_v_start;
int display_v_end;
int active_hctl;
int active_h_start;
int active_h_end;
int active_v_start;
int active_v_end;
int ctrl_polarity;
int h_back_porch;
int h_front_porch;
int v_back_porch;
int v_front_porch;
int hsync_pulse_width;
int vsync_pulse_width;
int hsync_polarity;
int vsync_polarity;
int data_en_polarity;
int hsync_start_x;
int hsync_end_x;
uint8 *buf;
int bpp;
uint32 dma2_cfg_reg;
struct fb_info *fbi;
struct fb_var_screeninfo *var;
struct msm_fb_data_type *mfd;
uint32 dma_base;
uint32 timer_base = LCDC_BASE;
uint32 block = MDP_DMA2_BLOCK;
int ret;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
fbi = mfd->fbi;
var = &fbi->var;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
buf += fbi->var.xoffset * bpp + fbi->var.yoffset * fbi->fix.line_length;
dma2_cfg_reg = DMA_PACK_ALIGN_LSB | DMA_DITHER_EN | DMA_OUT_SEL_LCDC;
if (mfd->fb_imgType == MDP_BGR_565)
dma2_cfg_reg |= DMA_PACK_PATTERN_BGR;
else
dma2_cfg_reg |= DMA_PACK_PATTERN_RGB;
if (bpp == 2)
dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
else if (bpp == 3)
dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB888;
else
dma2_cfg_reg |= DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888;
switch (mfd->panel_info.bpp) {
case 24:
dma2_cfg_reg |= DMA_DSTC0G_8BITS |
DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS;
break;
case 18:
dma2_cfg_reg |= DMA_DSTC0G_6BITS |
DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
break;
case 16:
dma2_cfg_reg |= DMA_DSTC0G_6BITS |
DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
break;
default:
printk(KERN_ERR "mdp lcdc can't support format %d bpp!\n",
mfd->panel_info.bpp);
return -ENODEV;
}
/* DMA register config */
dma_base = DMA_P_BASE;
#ifdef CONFIG_FB_MSM_MDP40
if (mfd->panel.type == HDMI_PANEL)
dma_base = DMA_E_BASE;
#endif
/* starting address */
MDP_OUTP(MDP_BASE + dma_base + 0x8, (uint32) buf);
/* active window width and height */
MDP_OUTP(MDP_BASE + dma_base + 0x4, ((fbi->var.yres) << 16) |
(fbi->var.xres));
/* buffer ystride */
MDP_OUTP(MDP_BASE + dma_base + 0xc, fbi->fix.line_length);
/* x/y coordinate = always 0 for lcdc */
MDP_OUTP(MDP_BASE + dma_base + 0x10, 0);
/* dma config */
MDP_OUTP(MDP_BASE + dma_base, dma2_cfg_reg);
/*
* LCDC timing setting
*/
h_back_porch = var->left_margin;
h_front_porch = var->right_margin;
v_back_porch = var->upper_margin;
v_front_porch = var->lower_margin;
hsync_pulse_width = var->hsync_len;
vsync_pulse_width = var->vsync_len;
lcdc_border_clr = mfd->panel_info.lcdc.border_clr;
lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
lcdc_width = mfd->panel_info.xres;
lcdc_height = mfd->panel_info.yres;
lcdc_bpp = mfd->panel_info.bpp;
hsync_period =
hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch;
hsync_ctrl = (hsync_period << 16) | hsync_pulse_width;
hsync_start_x = hsync_pulse_width + h_back_porch;
hsync_end_x = hsync_period - h_front_porch - 1;
display_hctl = (hsync_end_x << 16) | hsync_start_x;
vsync_period =
(vsync_pulse_width + v_back_porch + lcdc_height +
v_front_porch) * hsync_period;
display_v_start =
(vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew;
display_v_end =
vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1;
if (lcdc_width != var->xres) {
active_h_start = hsync_start_x + first_pixel_start_x;
active_h_end = active_h_start + var->xres - 1;
active_hctl =
ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start;
} else {
active_hctl = 0;
}
if (lcdc_height != var->yres) {
active_v_start =
display_v_start + first_pixel_start_y * hsync_period;
active_v_end = active_v_start + (var->yres) * hsync_period - 1;
active_v_start |= ACTIVE_START_Y_EN;
} else {
active_v_start = 0;
active_v_end = 0;
}
#ifdef CONFIG_FB_MSM_MDP40
if (mfd->panel.type == HDMI_PANEL) {
block = MDP_DMA_E_BLOCK;
timer_base = DTV_BASE;
hsync_polarity = 0;
vsync_polarity = 0;
} else {
hsync_polarity = 1;
vsync_polarity = 1;
}
lcdc_underflow_clr |= 0x80000000; /* enable recovery */
#else
hsync_polarity = 0;
vsync_polarity = 0;
#endif
data_en_polarity = 0;
ctrl_polarity =
(data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity);
MDP_OUTP(MDP_BASE + timer_base + 0x4, hsync_ctrl);
MDP_OUTP(MDP_BASE + timer_base + 0x8, vsync_period);
MDP_OUTP(MDP_BASE + timer_base + 0xc, vsync_pulse_width * hsync_period);
if (timer_base == LCDC_BASE) {
MDP_OUTP(MDP_BASE + timer_base + 0x10, display_hctl);
MDP_OUTP(MDP_BASE + timer_base + 0x14, display_v_start);
MDP_OUTP(MDP_BASE + timer_base + 0x18, display_v_end);
MDP_OUTP(MDP_BASE + timer_base + 0x28, lcdc_border_clr);
MDP_OUTP(MDP_BASE + timer_base + 0x2c, lcdc_underflow_clr);
MDP_OUTP(MDP_BASE + timer_base + 0x30, lcdc_hsync_skew);
MDP_OUTP(MDP_BASE + timer_base + 0x38, ctrl_polarity);
MDP_OUTP(MDP_BASE + timer_base + 0x1c, active_hctl);
MDP_OUTP(MDP_BASE + timer_base + 0x20, active_v_start);
MDP_OUTP(MDP_BASE + timer_base + 0x24, active_v_end);
} else {
MDP_OUTP(MDP_BASE + timer_base + 0x18, display_hctl);
MDP_OUTP(MDP_BASE + timer_base + 0x1c, display_v_start);
MDP_OUTP(MDP_BASE + timer_base + 0x20, display_v_end);
MDP_OUTP(MDP_BASE + timer_base + 0x40, lcdc_border_clr);
MDP_OUTP(MDP_BASE + timer_base + 0x44, lcdc_underflow_clr);
MDP_OUTP(MDP_BASE + timer_base + 0x48, lcdc_hsync_skew);
MDP_OUTP(MDP_BASE + timer_base + 0x50, ctrl_polarity);
MDP_OUTP(MDP_BASE + timer_base + 0x2c, active_hctl);
MDP_OUTP(MDP_BASE + timer_base + 0x30, active_v_start);
MDP_OUTP(MDP_BASE + timer_base + 0x38, active_v_end);
}
ret = panel_next_on(pdev);
if (ret == 0) {
/* enable LCDC block */
MDP_OUTP(MDP_BASE + timer_base, 1);
mdp_pipe_ctrl(block, MDP_BLOCK_POWER_ON, FALSE);
}
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
return ret;
}
int mdp_lcdc_off(struct platform_device *pdev)
{
int ret = 0;
struct msm_fb_data_type *mfd;
uint32 timer_base = LCDC_BASE;
uint32 block = MDP_DMA2_BLOCK;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
#ifdef CONFIG_FB_MSM_MDP40
if (mfd->panel.type == HDMI_PANEL) {
block = MDP_DMA_E_BLOCK;
timer_base = DTV_BASE;
}
#endif
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + timer_base, 0);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_pipe_ctrl(block, MDP_BLOCK_POWER_OFF, FALSE);
ret = panel_next_off(pdev);
/* delay to make sure the last frame finishes */
mdelay(100);
return ret;
}
void mdp_lcdc_update(struct msm_fb_data_type *mfd)
{
struct fb_info *fbi = mfd->fbi;
uint8 *buf;
int bpp;
unsigned long flag;
uint32 dma_base;
int irq_block = MDP_DMA2_TERM;
#ifdef CONFIG_FB_MSM_MDP40
int intr = INTR_DMA_P_DONE;
#endif
if (!mfd->panel_power_on)
return;
/* no need to power on cmd block since it's lcdc mode */
if (!mfd->ibuf.visible_swapped) {
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
buf += fbi->var.xoffset * bpp +
fbi->var.yoffset * fbi->fix.line_length;
} else {
/* we've done something to update the pointer. */
bpp = mfd->ibuf.bpp;
buf = mfd->ibuf.buf;
}
dma_base = DMA_P_BASE;
#ifdef CONFIG_FB_MSM_MDP40
if (mfd->panel.type == HDMI_PANEL) {
intr = INTR_DMA_E_DONE;
irq_block = MDP_DMA_E_TERM;
dma_base = DMA_E_BASE;
}
#endif
/* starting address */
MDP_OUTP(MDP_BASE + dma_base + 0x8, (uint32) buf);
/* enable LCDC irq */
spin_lock_irqsave(&mdp_spin_lock, flag);
mdp_enable_irq(irq_block);
INIT_COMPLETION(mfd->dma->comp);
mfd->dma->waiting = TRUE;
#ifdef CONFIG_FB_MSM_MDP40
outp32(MDP_INTR_CLEAR, intr);
mdp_intr_mask |= intr;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
#else
outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
mdp_intr_mask |= LCDC_FRAME_START;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
#endif
spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (mfd->ibuf.vsync_enable)
wait_for_completion_killable(&mfd->dma->comp);
mdp_disable_irq(irq_block);
}

View file

@ -0,0 +1,139 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
static void mdp_dma_s_update_lcd(struct msm_fb_data_type *mfd)
{
MDPIBUF *iBuf = &mfd->ibuf;
int mddi_dest = FALSE;
uint32 outBpp = iBuf->bpp;
uint32 dma_s_cfg_reg;
uint8 *src;
struct msm_fb_panel_data *pdata =
(struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
dma_s_cfg_reg = DMA_PACK_TIGHT | DMA_PACK_ALIGN_LSB |
DMA_OUT_SEL_AHB | DMA_IBUF_NONCONTIGUOUS;
if (mfd->fb_imgType == MDP_BGR_565)
dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR;
else
dma_s_cfg_reg |= DMA_PACK_PATTERN_RGB;
if (outBpp == 4)
dma_s_cfg_reg |= DMA_IBUF_C3ALPHA_EN;
if (outBpp == 2)
dma_s_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
if (mfd->panel_info.pdest != DISPLAY_2) {
printk(KERN_ERR "error: non-secondary type through dma_s!\n");
return;
}
if (mfd->panel_info.type == MDDI_PANEL) {
dma_s_cfg_reg |= DMA_OUT_SEL_MDDI;
mddi_dest = TRUE;
} else {
dma_s_cfg_reg |= DMA_AHBM_LCD_SEL_SECONDARY;
outp32(MDP_EBI2_LCD1, mfd->data_port_phys);
}
dma_s_cfg_reg |= DMA_DITHER_EN;
src = (uint8 *) iBuf->buf;
/* starting input address */
src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) * outBpp;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
/* PIXELSIZE */
MDP_OUTP(MDP_BASE + 0xa0004, (iBuf->dma_h << 16 | iBuf->dma_w));
MDP_OUTP(MDP_BASE + 0xa0008, src); /* ibuf address */
MDP_OUTP(MDP_BASE + 0xa000c, iBuf->ibuf_width * outBpp);/* ystride */
if (mfd->panel_info.bpp == 18) {
dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */
DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
} else {
dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */
DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
}
if (mddi_dest) {
MDP_OUTP(MDP_BASE + 0xa0010, (iBuf->dma_y << 16) | iBuf->dma_x);
MDP_OUTP(MDP_BASE + 0x00090, 1);
MDP_OUTP(MDP_BASE + 0x00094,
(MDDI_VDO_PACKET_DESC << 16) |
mfd->panel_info.mddi.vdopkt);
} else {
/* setting LCDC write window */
pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w,
iBuf->dma_h);
}
MDP_OUTP(MDP_BASE + 0xa0000, dma_s_cfg_reg);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd);
}
void mdp_dma_s_update(struct msm_fb_data_type *mfd)
{
down(&mfd->dma->mutex);
if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
down(&mfd->sem);
mdp_enable_irq(MDP_DMA_S_TERM);
mfd->dma->busy = TRUE;
INIT_COMPLETION(mfd->dma->comp);
mfd->ibuf_flushed = TRUE;
mdp_dma_s_update_lcd(mfd);
up(&mfd->sem);
/* wait until DMA finishes the current job */
wait_for_completion_killable(&mfd->dma->comp);
mdp_disable_irq(MDP_DMA_S_TERM);
/* signal if pan function is waiting for the update completion */
if (mfd->pan_waiting) {
mfd->pan_waiting = FALSE;
complete(&mfd->pan_comp);
}
}
up(&mfd->dma->mutex);
}

View file

@ -0,0 +1,142 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
extern spinlock_t mdp_spin_lock;
extern uint32 mdp_intr_mask;
int mdp_dma3_on(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct fb_info *fbi;
uint8 *buf;
int bpp;
int ret = 0;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
fbi = mfd->fbi;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
buf += fbi->var.xoffset * bpp +
fbi->var.yoffset * fbi->fix.line_length;
/* starting address[31..8] of Video frame buffer is CS0 */
MDP_OUTP(MDP_BASE + 0xC0008, (uint32) buf >> 3);
mdp_pipe_ctrl(MDP_DMA3_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + 0xC0004, 0x4c60674); /* flicker filter enabled */
MDP_OUTP(MDP_BASE + 0xC0010, 0x20); /* sobel treshold */
MDP_OUTP(MDP_BASE + 0xC0018, 0xeb0010); /* Y Max, Y min */
MDP_OUTP(MDP_BASE + 0xC001C, 0xf00010); /* Cb Max, Cb min */
MDP_OUTP(MDP_BASE + 0xC0020, 0xf00010); /* Cb Max, Cb min */
MDP_OUTP(MDP_BASE + 0xC000C, 0x67686970); /* add a few chars for CC */
MDP_OUTP(MDP_BASE + 0xC0000, 0x1); /* MDP tv out enable */
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
ret = panel_next_on(pdev);
return ret;
}
int mdp_dma3_off(struct platform_device *pdev)
{
int ret = 0;
ret = panel_next_off(pdev);
if (ret)
return ret;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + 0xC0000, 0x0);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_pipe_ctrl(MDP_DMA3_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
/* delay to make sure the last frame finishes */
mdelay(100);
return ret;
}
void mdp_dma3_update(struct msm_fb_data_type *mfd)
{
struct fb_info *fbi = mfd->fbi;
uint8 *buf;
int bpp;
unsigned long flag;
if (!mfd->panel_power_on)
return;
/* no need to power on cmd block since dma3 is running */
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
buf += fbi->var.xoffset * bpp +
fbi->var.yoffset * fbi->fix.line_length;
MDP_OUTP(MDP_BASE + 0xC0008, (uint32) buf >> 3);
spin_lock_irqsave(&mdp_spin_lock, flag);
mdp_enable_irq(MDP_DMA3_TERM);
INIT_COMPLETION(mfd->dma->comp);
mfd->dma->waiting = TRUE;
outp32(MDP_INTR_CLEAR, TV_OUT_DMA3_START);
mdp_intr_mask |= TV_OUT_DMA3_START;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
wait_for_completion_killable(&mfd->dma->comp);
mdp_disable_irq(MDP_DMA3_TERM);
}

View file

@ -0,0 +1,720 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "mdp.h"
/* mdp primary csc limit vector */
uint32 mdp_plv[] = { 0x10, 0xeb, 0x10, 0xf0 };
/* Color Coefficient matrix for YUV -> RGB */
struct mdp_ccs mdp_ccs_yuv2rgb = {
MDP_CCS_YUV2RGB,
{
0x254,
0x000,
0x331,
0x254,
0xff38,
0xfe61,
0x254,
0x409,
0x000,
},
{
#ifdef CONFIG_FB_MSM_MDP31
0x1f0,
0x180,
0x180
#else
0x10,
0x80,
0x80
#endif
}
};
/* Color Coefficient matrix for RGB -> YUV */
struct mdp_ccs mdp_ccs_rgb2yuv = {
MDP_CCS_RGB2YUV,
{
0x83,
0x102,
0x32,
0xffb5,
0xff6c,
0xe1,
0xe1,
0xff45,
0xffdc,
},
#ifdef CONFIG_FB_MSM_MDP31
{
0x10,
0x80,
0x80
}
#endif
};
static void mdp_load_lut_param(void)
{
outpdw(MDP_BASE + 0x40800, 0x0);
outpdw(MDP_BASE + 0x40804, 0x151515);
outpdw(MDP_BASE + 0x40808, 0x1d1d1d);
outpdw(MDP_BASE + 0x4080c, 0x232323);
outpdw(MDP_BASE + 0x40810, 0x272727);
outpdw(MDP_BASE + 0x40814, 0x2b2b2b);
outpdw(MDP_BASE + 0x40818, 0x2f2f2f);
outpdw(MDP_BASE + 0x4081c, 0x333333);
outpdw(MDP_BASE + 0x40820, 0x363636);
outpdw(MDP_BASE + 0x40824, 0x393939);
outpdw(MDP_BASE + 0x40828, 0x3b3b3b);
outpdw(MDP_BASE + 0x4082c, 0x3e3e3e);
outpdw(MDP_BASE + 0x40830, 0x404040);
outpdw(MDP_BASE + 0x40834, 0x434343);
outpdw(MDP_BASE + 0x40838, 0x454545);
outpdw(MDP_BASE + 0x4083c, 0x474747);
outpdw(MDP_BASE + 0x40840, 0x494949);
outpdw(MDP_BASE + 0x40844, 0x4b4b4b);
outpdw(MDP_BASE + 0x40848, 0x4d4d4d);
outpdw(MDP_BASE + 0x4084c, 0x4f4f4f);
outpdw(MDP_BASE + 0x40850, 0x515151);
outpdw(MDP_BASE + 0x40854, 0x535353);
outpdw(MDP_BASE + 0x40858, 0x555555);
outpdw(MDP_BASE + 0x4085c, 0x565656);
outpdw(MDP_BASE + 0x40860, 0x585858);
outpdw(MDP_BASE + 0x40864, 0x5a5a5a);
outpdw(MDP_BASE + 0x40868, 0x5b5b5b);
outpdw(MDP_BASE + 0x4086c, 0x5d5d5d);
outpdw(MDP_BASE + 0x40870, 0x5e5e5e);
outpdw(MDP_BASE + 0x40874, 0x606060);
outpdw(MDP_BASE + 0x40878, 0x616161);
outpdw(MDP_BASE + 0x4087c, 0x636363);
outpdw(MDP_BASE + 0x40880, 0x646464);
outpdw(MDP_BASE + 0x40884, 0x666666);
outpdw(MDP_BASE + 0x40888, 0x676767);
outpdw(MDP_BASE + 0x4088c, 0x686868);
outpdw(MDP_BASE + 0x40890, 0x6a6a6a);
outpdw(MDP_BASE + 0x40894, 0x6b6b6b);
outpdw(MDP_BASE + 0x40898, 0x6c6c6c);
outpdw(MDP_BASE + 0x4089c, 0x6e6e6e);
outpdw(MDP_BASE + 0x408a0, 0x6f6f6f);
outpdw(MDP_BASE + 0x408a4, 0x707070);
outpdw(MDP_BASE + 0x408a8, 0x717171);
outpdw(MDP_BASE + 0x408ac, 0x727272);
outpdw(MDP_BASE + 0x408b0, 0x747474);
outpdw(MDP_BASE + 0x408b4, 0x757575);
outpdw(MDP_BASE + 0x408b8, 0x767676);
outpdw(MDP_BASE + 0x408bc, 0x777777);
outpdw(MDP_BASE + 0x408c0, 0x787878);
outpdw(MDP_BASE + 0x408c4, 0x797979);
outpdw(MDP_BASE + 0x408c8, 0x7a7a7a);
outpdw(MDP_BASE + 0x408cc, 0x7c7c7c);
outpdw(MDP_BASE + 0x408d0, 0x7d7d7d);
outpdw(MDP_BASE + 0x408d4, 0x7e7e7e);
outpdw(MDP_BASE + 0x408d8, 0x7f7f7f);
outpdw(MDP_BASE + 0x408dc, 0x808080);
outpdw(MDP_BASE + 0x408e0, 0x818181);
outpdw(MDP_BASE + 0x408e4, 0x828282);
outpdw(MDP_BASE + 0x408e8, 0x838383);
outpdw(MDP_BASE + 0x408ec, 0x848484);
outpdw(MDP_BASE + 0x408f0, 0x858585);
outpdw(MDP_BASE + 0x408f4, 0x868686);
outpdw(MDP_BASE + 0x408f8, 0x878787);
outpdw(MDP_BASE + 0x408fc, 0x888888);
outpdw(MDP_BASE + 0x40900, 0x898989);
outpdw(MDP_BASE + 0x40904, 0x8a8a8a);
outpdw(MDP_BASE + 0x40908, 0x8b8b8b);
outpdw(MDP_BASE + 0x4090c, 0x8c8c8c);
outpdw(MDP_BASE + 0x40910, 0x8d8d8d);
outpdw(MDP_BASE + 0x40914, 0x8e8e8e);
outpdw(MDP_BASE + 0x40918, 0x8f8f8f);
outpdw(MDP_BASE + 0x4091c, 0x8f8f8f);
outpdw(MDP_BASE + 0x40920, 0x909090);
outpdw(MDP_BASE + 0x40924, 0x919191);
outpdw(MDP_BASE + 0x40928, 0x929292);
outpdw(MDP_BASE + 0x4092c, 0x939393);
outpdw(MDP_BASE + 0x40930, 0x949494);
outpdw(MDP_BASE + 0x40934, 0x959595);
outpdw(MDP_BASE + 0x40938, 0x969696);
outpdw(MDP_BASE + 0x4093c, 0x969696);
outpdw(MDP_BASE + 0x40940, 0x979797);
outpdw(MDP_BASE + 0x40944, 0x989898);
outpdw(MDP_BASE + 0x40948, 0x999999);
outpdw(MDP_BASE + 0x4094c, 0x9a9a9a);
outpdw(MDP_BASE + 0x40950, 0x9b9b9b);
outpdw(MDP_BASE + 0x40954, 0x9c9c9c);
outpdw(MDP_BASE + 0x40958, 0x9c9c9c);
outpdw(MDP_BASE + 0x4095c, 0x9d9d9d);
outpdw(MDP_BASE + 0x40960, 0x9e9e9e);
outpdw(MDP_BASE + 0x40964, 0x9f9f9f);
outpdw(MDP_BASE + 0x40968, 0xa0a0a0);
outpdw(MDP_BASE + 0x4096c, 0xa0a0a0);
outpdw(MDP_BASE + 0x40970, 0xa1a1a1);
outpdw(MDP_BASE + 0x40974, 0xa2a2a2);
outpdw(MDP_BASE + 0x40978, 0xa3a3a3);
outpdw(MDP_BASE + 0x4097c, 0xa4a4a4);
outpdw(MDP_BASE + 0x40980, 0xa4a4a4);
outpdw(MDP_BASE + 0x40984, 0xa5a5a5);
outpdw(MDP_BASE + 0x40988, 0xa6a6a6);
outpdw(MDP_BASE + 0x4098c, 0xa7a7a7);
outpdw(MDP_BASE + 0x40990, 0xa7a7a7);
outpdw(MDP_BASE + 0x40994, 0xa8a8a8);
outpdw(MDP_BASE + 0x40998, 0xa9a9a9);
outpdw(MDP_BASE + 0x4099c, 0xaaaaaa);
outpdw(MDP_BASE + 0x409a0, 0xaaaaaa);
outpdw(MDP_BASE + 0x409a4, 0xababab);
outpdw(MDP_BASE + 0x409a8, 0xacacac);
outpdw(MDP_BASE + 0x409ac, 0xadadad);
outpdw(MDP_BASE + 0x409b0, 0xadadad);
outpdw(MDP_BASE + 0x409b4, 0xaeaeae);
outpdw(MDP_BASE + 0x409b8, 0xafafaf);
outpdw(MDP_BASE + 0x409bc, 0xafafaf);
outpdw(MDP_BASE + 0x409c0, 0xb0b0b0);
outpdw(MDP_BASE + 0x409c4, 0xb1b1b1);
outpdw(MDP_BASE + 0x409c8, 0xb2b2b2);
outpdw(MDP_BASE + 0x409cc, 0xb2b2b2);
outpdw(MDP_BASE + 0x409d0, 0xb3b3b3);
outpdw(MDP_BASE + 0x409d4, 0xb4b4b4);
outpdw(MDP_BASE + 0x409d8, 0xb4b4b4);
outpdw(MDP_BASE + 0x409dc, 0xb5b5b5);
outpdw(MDP_BASE + 0x409e0, 0xb6b6b6);
outpdw(MDP_BASE + 0x409e4, 0xb6b6b6);
outpdw(MDP_BASE + 0x409e8, 0xb7b7b7);
outpdw(MDP_BASE + 0x409ec, 0xb8b8b8);
outpdw(MDP_BASE + 0x409f0, 0xb8b8b8);
outpdw(MDP_BASE + 0x409f4, 0xb9b9b9);
outpdw(MDP_BASE + 0x409f8, 0xbababa);
outpdw(MDP_BASE + 0x409fc, 0xbababa);
outpdw(MDP_BASE + 0x40a00, 0xbbbbbb);
outpdw(MDP_BASE + 0x40a04, 0xbcbcbc);
outpdw(MDP_BASE + 0x40a08, 0xbcbcbc);
outpdw(MDP_BASE + 0x40a0c, 0xbdbdbd);
outpdw(MDP_BASE + 0x40a10, 0xbebebe);
outpdw(MDP_BASE + 0x40a14, 0xbebebe);
outpdw(MDP_BASE + 0x40a18, 0xbfbfbf);
outpdw(MDP_BASE + 0x40a1c, 0xc0c0c0);
outpdw(MDP_BASE + 0x40a20, 0xc0c0c0);
outpdw(MDP_BASE + 0x40a24, 0xc1c1c1);
outpdw(MDP_BASE + 0x40a28, 0xc1c1c1);
outpdw(MDP_BASE + 0x40a2c, 0xc2c2c2);
outpdw(MDP_BASE + 0x40a30, 0xc3c3c3);
outpdw(MDP_BASE + 0x40a34, 0xc3c3c3);
outpdw(MDP_BASE + 0x40a38, 0xc4c4c4);
outpdw(MDP_BASE + 0x40a3c, 0xc5c5c5);
outpdw(MDP_BASE + 0x40a40, 0xc5c5c5);
outpdw(MDP_BASE + 0x40a44, 0xc6c6c6);
outpdw(MDP_BASE + 0x40a48, 0xc6c6c6);
outpdw(MDP_BASE + 0x40a4c, 0xc7c7c7);
outpdw(MDP_BASE + 0x40a50, 0xc8c8c8);
outpdw(MDP_BASE + 0x40a54, 0xc8c8c8);
outpdw(MDP_BASE + 0x40a58, 0xc9c9c9);
outpdw(MDP_BASE + 0x40a5c, 0xc9c9c9);
outpdw(MDP_BASE + 0x40a60, 0xcacaca);
outpdw(MDP_BASE + 0x40a64, 0xcbcbcb);
outpdw(MDP_BASE + 0x40a68, 0xcbcbcb);
outpdw(MDP_BASE + 0x40a6c, 0xcccccc);
outpdw(MDP_BASE + 0x40a70, 0xcccccc);
outpdw(MDP_BASE + 0x40a74, 0xcdcdcd);
outpdw(MDP_BASE + 0x40a78, 0xcecece);
outpdw(MDP_BASE + 0x40a7c, 0xcecece);
outpdw(MDP_BASE + 0x40a80, 0xcfcfcf);
outpdw(MDP_BASE + 0x40a84, 0xcfcfcf);
outpdw(MDP_BASE + 0x40a88, 0xd0d0d0);
outpdw(MDP_BASE + 0x40a8c, 0xd0d0d0);
outpdw(MDP_BASE + 0x40a90, 0xd1d1d1);
outpdw(MDP_BASE + 0x40a94, 0xd2d2d2);
outpdw(MDP_BASE + 0x40a98, 0xd2d2d2);
outpdw(MDP_BASE + 0x40a9c, 0xd3d3d3);
outpdw(MDP_BASE + 0x40aa0, 0xd3d3d3);
outpdw(MDP_BASE + 0x40aa4, 0xd4d4d4);
outpdw(MDP_BASE + 0x40aa8, 0xd4d4d4);
outpdw(MDP_BASE + 0x40aac, 0xd5d5d5);
outpdw(MDP_BASE + 0x40ab0, 0xd6d6d6);
outpdw(MDP_BASE + 0x40ab4, 0xd6d6d6);
outpdw(MDP_BASE + 0x40ab8, 0xd7d7d7);
outpdw(MDP_BASE + 0x40abc, 0xd7d7d7);
outpdw(MDP_BASE + 0x40ac0, 0xd8d8d8);
outpdw(MDP_BASE + 0x40ac4, 0xd8d8d8);
outpdw(MDP_BASE + 0x40ac8, 0xd9d9d9);
outpdw(MDP_BASE + 0x40acc, 0xd9d9d9);
outpdw(MDP_BASE + 0x40ad0, 0xdadada);
outpdw(MDP_BASE + 0x40ad4, 0xdbdbdb);
outpdw(MDP_BASE + 0x40ad8, 0xdbdbdb);
outpdw(MDP_BASE + 0x40adc, 0xdcdcdc);
outpdw(MDP_BASE + 0x40ae0, 0xdcdcdc);
outpdw(MDP_BASE + 0x40ae4, 0xdddddd);
outpdw(MDP_BASE + 0x40ae8, 0xdddddd);
outpdw(MDP_BASE + 0x40aec, 0xdedede);
outpdw(MDP_BASE + 0x40af0, 0xdedede);
outpdw(MDP_BASE + 0x40af4, 0xdfdfdf);
outpdw(MDP_BASE + 0x40af8, 0xdfdfdf);
outpdw(MDP_BASE + 0x40afc, 0xe0e0e0);
outpdw(MDP_BASE + 0x40b00, 0xe0e0e0);
outpdw(MDP_BASE + 0x40b04, 0xe1e1e1);
outpdw(MDP_BASE + 0x40b08, 0xe1e1e1);
outpdw(MDP_BASE + 0x40b0c, 0xe2e2e2);
outpdw(MDP_BASE + 0x40b10, 0xe3e3e3);
outpdw(MDP_BASE + 0x40b14, 0xe3e3e3);
outpdw(MDP_BASE + 0x40b18, 0xe4e4e4);
outpdw(MDP_BASE + 0x40b1c, 0xe4e4e4);
outpdw(MDP_BASE + 0x40b20, 0xe5e5e5);
outpdw(MDP_BASE + 0x40b24, 0xe5e5e5);
outpdw(MDP_BASE + 0x40b28, 0xe6e6e6);
outpdw(MDP_BASE + 0x40b2c, 0xe6e6e6);
outpdw(MDP_BASE + 0x40b30, 0xe7e7e7);
outpdw(MDP_BASE + 0x40b34, 0xe7e7e7);
outpdw(MDP_BASE + 0x40b38, 0xe8e8e8);
outpdw(MDP_BASE + 0x40b3c, 0xe8e8e8);
outpdw(MDP_BASE + 0x40b40, 0xe9e9e9);
outpdw(MDP_BASE + 0x40b44, 0xe9e9e9);
outpdw(MDP_BASE + 0x40b48, 0xeaeaea);
outpdw(MDP_BASE + 0x40b4c, 0xeaeaea);
outpdw(MDP_BASE + 0x40b50, 0xebebeb);
outpdw(MDP_BASE + 0x40b54, 0xebebeb);
outpdw(MDP_BASE + 0x40b58, 0xececec);
outpdw(MDP_BASE + 0x40b5c, 0xececec);
outpdw(MDP_BASE + 0x40b60, 0xededed);
outpdw(MDP_BASE + 0x40b64, 0xededed);
outpdw(MDP_BASE + 0x40b68, 0xeeeeee);
outpdw(MDP_BASE + 0x40b6c, 0xeeeeee);
outpdw(MDP_BASE + 0x40b70, 0xefefef);
outpdw(MDP_BASE + 0x40b74, 0xefefef);
outpdw(MDP_BASE + 0x40b78, 0xf0f0f0);
outpdw(MDP_BASE + 0x40b7c, 0xf0f0f0);
outpdw(MDP_BASE + 0x40b80, 0xf1f1f1);
outpdw(MDP_BASE + 0x40b84, 0xf1f1f1);
outpdw(MDP_BASE + 0x40b88, 0xf2f2f2);
outpdw(MDP_BASE + 0x40b8c, 0xf2f2f2);
outpdw(MDP_BASE + 0x40b90, 0xf2f2f2);
outpdw(MDP_BASE + 0x40b94, 0xf3f3f3);
outpdw(MDP_BASE + 0x40b98, 0xf3f3f3);
outpdw(MDP_BASE + 0x40b9c, 0xf4f4f4);
outpdw(MDP_BASE + 0x40ba0, 0xf4f4f4);
outpdw(MDP_BASE + 0x40ba4, 0xf5f5f5);
outpdw(MDP_BASE + 0x40ba8, 0xf5f5f5);
outpdw(MDP_BASE + 0x40bac, 0xf6f6f6);
outpdw(MDP_BASE + 0x40bb0, 0xf6f6f6);
outpdw(MDP_BASE + 0x40bb4, 0xf7f7f7);
outpdw(MDP_BASE + 0x40bb8, 0xf7f7f7);
outpdw(MDP_BASE + 0x40bbc, 0xf8f8f8);
outpdw(MDP_BASE + 0x40bc0, 0xf8f8f8);
outpdw(MDP_BASE + 0x40bc4, 0xf9f9f9);
outpdw(MDP_BASE + 0x40bc8, 0xf9f9f9);
outpdw(MDP_BASE + 0x40bcc, 0xfafafa);
outpdw(MDP_BASE + 0x40bd0, 0xfafafa);
outpdw(MDP_BASE + 0x40bd4, 0xfafafa);
outpdw(MDP_BASE + 0x40bd8, 0xfbfbfb);
outpdw(MDP_BASE + 0x40bdc, 0xfbfbfb);
outpdw(MDP_BASE + 0x40be0, 0xfcfcfc);
outpdw(MDP_BASE + 0x40be4, 0xfcfcfc);
outpdw(MDP_BASE + 0x40be8, 0xfdfdfd);
outpdw(MDP_BASE + 0x40bec, 0xfdfdfd);
outpdw(MDP_BASE + 0x40bf0, 0xfefefe);
outpdw(MDP_BASE + 0x40bf4, 0xfefefe);
outpdw(MDP_BASE + 0x40bf8, 0xffffff);
outpdw(MDP_BASE + 0x40bfc, 0xffffff);
outpdw(MDP_BASE + 0x40c00, 0x0);
outpdw(MDP_BASE + 0x40c04, 0x0);
outpdw(MDP_BASE + 0x40c08, 0x0);
outpdw(MDP_BASE + 0x40c0c, 0x0);
outpdw(MDP_BASE + 0x40c10, 0x0);
outpdw(MDP_BASE + 0x40c14, 0x0);
outpdw(MDP_BASE + 0x40c18, 0x0);
outpdw(MDP_BASE + 0x40c1c, 0x0);
outpdw(MDP_BASE + 0x40c20, 0x0);
outpdw(MDP_BASE + 0x40c24, 0x0);
outpdw(MDP_BASE + 0x40c28, 0x0);
outpdw(MDP_BASE + 0x40c2c, 0x0);
outpdw(MDP_BASE + 0x40c30, 0x0);
outpdw(MDP_BASE + 0x40c34, 0x0);
outpdw(MDP_BASE + 0x40c38, 0x0);
outpdw(MDP_BASE + 0x40c3c, 0x0);
outpdw(MDP_BASE + 0x40c40, 0x10101);
outpdw(MDP_BASE + 0x40c44, 0x10101);
outpdw(MDP_BASE + 0x40c48, 0x10101);
outpdw(MDP_BASE + 0x40c4c, 0x10101);
outpdw(MDP_BASE + 0x40c50, 0x10101);
outpdw(MDP_BASE + 0x40c54, 0x10101);
outpdw(MDP_BASE + 0x40c58, 0x10101);
outpdw(MDP_BASE + 0x40c5c, 0x10101);
outpdw(MDP_BASE + 0x40c60, 0x10101);
outpdw(MDP_BASE + 0x40c64, 0x10101);
outpdw(MDP_BASE + 0x40c68, 0x20202);
outpdw(MDP_BASE + 0x40c6c, 0x20202);
outpdw(MDP_BASE + 0x40c70, 0x20202);
outpdw(MDP_BASE + 0x40c74, 0x20202);
outpdw(MDP_BASE + 0x40c78, 0x20202);
outpdw(MDP_BASE + 0x40c7c, 0x20202);
outpdw(MDP_BASE + 0x40c80, 0x30303);
outpdw(MDP_BASE + 0x40c84, 0x30303);
outpdw(MDP_BASE + 0x40c88, 0x30303);
outpdw(MDP_BASE + 0x40c8c, 0x30303);
outpdw(MDP_BASE + 0x40c90, 0x30303);
outpdw(MDP_BASE + 0x40c94, 0x40404);
outpdw(MDP_BASE + 0x40c98, 0x40404);
outpdw(MDP_BASE + 0x40c9c, 0x40404);
outpdw(MDP_BASE + 0x40ca0, 0x40404);
outpdw(MDP_BASE + 0x40ca4, 0x40404);
outpdw(MDP_BASE + 0x40ca8, 0x50505);
outpdw(MDP_BASE + 0x40cac, 0x50505);
outpdw(MDP_BASE + 0x40cb0, 0x50505);
outpdw(MDP_BASE + 0x40cb4, 0x50505);
outpdw(MDP_BASE + 0x40cb8, 0x60606);
outpdw(MDP_BASE + 0x40cbc, 0x60606);
outpdw(MDP_BASE + 0x40cc0, 0x60606);
outpdw(MDP_BASE + 0x40cc4, 0x70707);
outpdw(MDP_BASE + 0x40cc8, 0x70707);
outpdw(MDP_BASE + 0x40ccc, 0x70707);
outpdw(MDP_BASE + 0x40cd0, 0x70707);
outpdw(MDP_BASE + 0x40cd4, 0x80808);
outpdw(MDP_BASE + 0x40cd8, 0x80808);
outpdw(MDP_BASE + 0x40cdc, 0x80808);
outpdw(MDP_BASE + 0x40ce0, 0x90909);
outpdw(MDP_BASE + 0x40ce4, 0x90909);
outpdw(MDP_BASE + 0x40ce8, 0xa0a0a);
outpdw(MDP_BASE + 0x40cec, 0xa0a0a);
outpdw(MDP_BASE + 0x40cf0, 0xa0a0a);
outpdw(MDP_BASE + 0x40cf4, 0xb0b0b);
outpdw(MDP_BASE + 0x40cf8, 0xb0b0b);
outpdw(MDP_BASE + 0x40cfc, 0xb0b0b);
outpdw(MDP_BASE + 0x40d00, 0xc0c0c);
outpdw(MDP_BASE + 0x40d04, 0xc0c0c);
outpdw(MDP_BASE + 0x40d08, 0xd0d0d);
outpdw(MDP_BASE + 0x40d0c, 0xd0d0d);
outpdw(MDP_BASE + 0x40d10, 0xe0e0e);
outpdw(MDP_BASE + 0x40d14, 0xe0e0e);
outpdw(MDP_BASE + 0x40d18, 0xe0e0e);
outpdw(MDP_BASE + 0x40d1c, 0xf0f0f);
outpdw(MDP_BASE + 0x40d20, 0xf0f0f);
outpdw(MDP_BASE + 0x40d24, 0x101010);
outpdw(MDP_BASE + 0x40d28, 0x101010);
outpdw(MDP_BASE + 0x40d2c, 0x111111);
outpdw(MDP_BASE + 0x40d30, 0x111111);
outpdw(MDP_BASE + 0x40d34, 0x121212);
outpdw(MDP_BASE + 0x40d38, 0x121212);
outpdw(MDP_BASE + 0x40d3c, 0x131313);
outpdw(MDP_BASE + 0x40d40, 0x131313);
outpdw(MDP_BASE + 0x40d44, 0x141414);
outpdw(MDP_BASE + 0x40d48, 0x151515);
outpdw(MDP_BASE + 0x40d4c, 0x151515);
outpdw(MDP_BASE + 0x40d50, 0x161616);
outpdw(MDP_BASE + 0x40d54, 0x161616);
outpdw(MDP_BASE + 0x40d58, 0x171717);
outpdw(MDP_BASE + 0x40d5c, 0x171717);
outpdw(MDP_BASE + 0x40d60, 0x181818);
outpdw(MDP_BASE + 0x40d64, 0x191919);
outpdw(MDP_BASE + 0x40d68, 0x191919);
outpdw(MDP_BASE + 0x40d6c, 0x1a1a1a);
outpdw(MDP_BASE + 0x40d70, 0x1b1b1b);
outpdw(MDP_BASE + 0x40d74, 0x1b1b1b);
outpdw(MDP_BASE + 0x40d78, 0x1c1c1c);
outpdw(MDP_BASE + 0x40d7c, 0x1c1c1c);
outpdw(MDP_BASE + 0x40d80, 0x1d1d1d);
outpdw(MDP_BASE + 0x40d84, 0x1e1e1e);
outpdw(MDP_BASE + 0x40d88, 0x1f1f1f);
outpdw(MDP_BASE + 0x40d8c, 0x1f1f1f);
outpdw(MDP_BASE + 0x40d90, 0x202020);
outpdw(MDP_BASE + 0x40d94, 0x212121);
outpdw(MDP_BASE + 0x40d98, 0x212121);
outpdw(MDP_BASE + 0x40d9c, 0x222222);
outpdw(MDP_BASE + 0x40da0, 0x232323);
outpdw(MDP_BASE + 0x40da4, 0x242424);
outpdw(MDP_BASE + 0x40da8, 0x242424);
outpdw(MDP_BASE + 0x40dac, 0x252525);
outpdw(MDP_BASE + 0x40db0, 0x262626);
outpdw(MDP_BASE + 0x40db4, 0x272727);
outpdw(MDP_BASE + 0x40db8, 0x272727);
outpdw(MDP_BASE + 0x40dbc, 0x282828);
outpdw(MDP_BASE + 0x40dc0, 0x292929);
outpdw(MDP_BASE + 0x40dc4, 0x2a2a2a);
outpdw(MDP_BASE + 0x40dc8, 0x2b2b2b);
outpdw(MDP_BASE + 0x40dcc, 0x2c2c2c);
outpdw(MDP_BASE + 0x40dd0, 0x2c2c2c);
outpdw(MDP_BASE + 0x40dd4, 0x2d2d2d);
outpdw(MDP_BASE + 0x40dd8, 0x2e2e2e);
outpdw(MDP_BASE + 0x40ddc, 0x2f2f2f);
outpdw(MDP_BASE + 0x40de0, 0x303030);
outpdw(MDP_BASE + 0x40de4, 0x313131);
outpdw(MDP_BASE + 0x40de8, 0x323232);
outpdw(MDP_BASE + 0x40dec, 0x333333);
outpdw(MDP_BASE + 0x40df0, 0x333333);
outpdw(MDP_BASE + 0x40df4, 0x343434);
outpdw(MDP_BASE + 0x40df8, 0x353535);
outpdw(MDP_BASE + 0x40dfc, 0x363636);
outpdw(MDP_BASE + 0x40e00, 0x373737);
outpdw(MDP_BASE + 0x40e04, 0x383838);
outpdw(MDP_BASE + 0x40e08, 0x393939);
outpdw(MDP_BASE + 0x40e0c, 0x3a3a3a);
outpdw(MDP_BASE + 0x40e10, 0x3b3b3b);
outpdw(MDP_BASE + 0x40e14, 0x3c3c3c);
outpdw(MDP_BASE + 0x40e18, 0x3d3d3d);
outpdw(MDP_BASE + 0x40e1c, 0x3e3e3e);
outpdw(MDP_BASE + 0x40e20, 0x3f3f3f);
outpdw(MDP_BASE + 0x40e24, 0x404040);
outpdw(MDP_BASE + 0x40e28, 0x414141);
outpdw(MDP_BASE + 0x40e2c, 0x424242);
outpdw(MDP_BASE + 0x40e30, 0x434343);
outpdw(MDP_BASE + 0x40e34, 0x444444);
outpdw(MDP_BASE + 0x40e38, 0x464646);
outpdw(MDP_BASE + 0x40e3c, 0x474747);
outpdw(MDP_BASE + 0x40e40, 0x484848);
outpdw(MDP_BASE + 0x40e44, 0x494949);
outpdw(MDP_BASE + 0x40e48, 0x4a4a4a);
outpdw(MDP_BASE + 0x40e4c, 0x4b4b4b);
outpdw(MDP_BASE + 0x40e50, 0x4c4c4c);
outpdw(MDP_BASE + 0x40e54, 0x4d4d4d);
outpdw(MDP_BASE + 0x40e58, 0x4f4f4f);
outpdw(MDP_BASE + 0x40e5c, 0x505050);
outpdw(MDP_BASE + 0x40e60, 0x515151);
outpdw(MDP_BASE + 0x40e64, 0x525252);
outpdw(MDP_BASE + 0x40e68, 0x535353);
outpdw(MDP_BASE + 0x40e6c, 0x545454);
outpdw(MDP_BASE + 0x40e70, 0x565656);
outpdw(MDP_BASE + 0x40e74, 0x575757);
outpdw(MDP_BASE + 0x40e78, 0x585858);
outpdw(MDP_BASE + 0x40e7c, 0x595959);
outpdw(MDP_BASE + 0x40e80, 0x5b5b5b);
outpdw(MDP_BASE + 0x40e84, 0x5c5c5c);
outpdw(MDP_BASE + 0x40e88, 0x5d5d5d);
outpdw(MDP_BASE + 0x40e8c, 0x5e5e5e);
outpdw(MDP_BASE + 0x40e90, 0x606060);
outpdw(MDP_BASE + 0x40e94, 0x616161);
outpdw(MDP_BASE + 0x40e98, 0x626262);
outpdw(MDP_BASE + 0x40e9c, 0x646464);
outpdw(MDP_BASE + 0x40ea0, 0x656565);
outpdw(MDP_BASE + 0x40ea4, 0x666666);
outpdw(MDP_BASE + 0x40ea8, 0x686868);
outpdw(MDP_BASE + 0x40eac, 0x696969);
outpdw(MDP_BASE + 0x40eb0, 0x6a6a6a);
outpdw(MDP_BASE + 0x40eb4, 0x6c6c6c);
outpdw(MDP_BASE + 0x40eb8, 0x6d6d6d);
outpdw(MDP_BASE + 0x40ebc, 0x6f6f6f);
outpdw(MDP_BASE + 0x40ec0, 0x707070);
outpdw(MDP_BASE + 0x40ec4, 0x717171);
outpdw(MDP_BASE + 0x40ec8, 0x737373);
outpdw(MDP_BASE + 0x40ecc, 0x747474);
outpdw(MDP_BASE + 0x40ed0, 0x767676);
outpdw(MDP_BASE + 0x40ed4, 0x777777);
outpdw(MDP_BASE + 0x40ed8, 0x797979);
outpdw(MDP_BASE + 0x40edc, 0x7a7a7a);
outpdw(MDP_BASE + 0x40ee0, 0x7c7c7c);
outpdw(MDP_BASE + 0x40ee4, 0x7d7d7d);
outpdw(MDP_BASE + 0x40ee8, 0x7f7f7f);
outpdw(MDP_BASE + 0x40eec, 0x808080);
outpdw(MDP_BASE + 0x40ef0, 0x828282);
outpdw(MDP_BASE + 0x40ef4, 0x838383);
outpdw(MDP_BASE + 0x40ef8, 0x858585);
outpdw(MDP_BASE + 0x40efc, 0x868686);
outpdw(MDP_BASE + 0x40f00, 0x888888);
outpdw(MDP_BASE + 0x40f04, 0x898989);
outpdw(MDP_BASE + 0x40f08, 0x8b8b8b);
outpdw(MDP_BASE + 0x40f0c, 0x8d8d8d);
outpdw(MDP_BASE + 0x40f10, 0x8e8e8e);
outpdw(MDP_BASE + 0x40f14, 0x909090);
outpdw(MDP_BASE + 0x40f18, 0x919191);
outpdw(MDP_BASE + 0x40f1c, 0x939393);
outpdw(MDP_BASE + 0x40f20, 0x959595);
outpdw(MDP_BASE + 0x40f24, 0x969696);
outpdw(MDP_BASE + 0x40f28, 0x989898);
outpdw(MDP_BASE + 0x40f2c, 0x9a9a9a);
outpdw(MDP_BASE + 0x40f30, 0x9b9b9b);
outpdw(MDP_BASE + 0x40f34, 0x9d9d9d);
outpdw(MDP_BASE + 0x40f38, 0x9f9f9f);
outpdw(MDP_BASE + 0x40f3c, 0xa1a1a1);
outpdw(MDP_BASE + 0x40f40, 0xa2a2a2);
outpdw(MDP_BASE + 0x40f44, 0xa4a4a4);
outpdw(MDP_BASE + 0x40f48, 0xa6a6a6);
outpdw(MDP_BASE + 0x40f4c, 0xa7a7a7);
outpdw(MDP_BASE + 0x40f50, 0xa9a9a9);
outpdw(MDP_BASE + 0x40f54, 0xababab);
outpdw(MDP_BASE + 0x40f58, 0xadadad);
outpdw(MDP_BASE + 0x40f5c, 0xafafaf);
outpdw(MDP_BASE + 0x40f60, 0xb0b0b0);
outpdw(MDP_BASE + 0x40f64, 0xb2b2b2);
outpdw(MDP_BASE + 0x40f68, 0xb4b4b4);
outpdw(MDP_BASE + 0x40f6c, 0xb6b6b6);
outpdw(MDP_BASE + 0x40f70, 0xb8b8b8);
outpdw(MDP_BASE + 0x40f74, 0xbababa);
outpdw(MDP_BASE + 0x40f78, 0xbbbbbb);
outpdw(MDP_BASE + 0x40f7c, 0xbdbdbd);
outpdw(MDP_BASE + 0x40f80, 0xbfbfbf);
outpdw(MDP_BASE + 0x40f84, 0xc1c1c1);
outpdw(MDP_BASE + 0x40f88, 0xc3c3c3);
outpdw(MDP_BASE + 0x40f8c, 0xc5c5c5);
outpdw(MDP_BASE + 0x40f90, 0xc7c7c7);
outpdw(MDP_BASE + 0x40f94, 0xc9c9c9);
outpdw(MDP_BASE + 0x40f98, 0xcbcbcb);
outpdw(MDP_BASE + 0x40f9c, 0xcdcdcd);
outpdw(MDP_BASE + 0x40fa0, 0xcfcfcf);
outpdw(MDP_BASE + 0x40fa4, 0xd1d1d1);
outpdw(MDP_BASE + 0x40fa8, 0xd3d3d3);
outpdw(MDP_BASE + 0x40fac, 0xd5d5d5);
outpdw(MDP_BASE + 0x40fb0, 0xd7d7d7);
outpdw(MDP_BASE + 0x40fb4, 0xd9d9d9);
outpdw(MDP_BASE + 0x40fb8, 0xdbdbdb);
outpdw(MDP_BASE + 0x40fbc, 0xdddddd);
outpdw(MDP_BASE + 0x40fc0, 0xdfdfdf);
outpdw(MDP_BASE + 0x40fc4, 0xe1e1e1);
outpdw(MDP_BASE + 0x40fc8, 0xe3e3e3);
outpdw(MDP_BASE + 0x40fcc, 0xe5e5e5);
outpdw(MDP_BASE + 0x40fd0, 0xe7e7e7);
outpdw(MDP_BASE + 0x40fd4, 0xe9e9e9);
outpdw(MDP_BASE + 0x40fd8, 0xebebeb);
outpdw(MDP_BASE + 0x40fdc, 0xeeeeee);
outpdw(MDP_BASE + 0x40fe0, 0xf0f0f0);
outpdw(MDP_BASE + 0x40fe4, 0xf2f2f2);
outpdw(MDP_BASE + 0x40fe8, 0xf4f4f4);
outpdw(MDP_BASE + 0x40fec, 0xf6f6f6);
outpdw(MDP_BASE + 0x40ff0, 0xf8f8f8);
outpdw(MDP_BASE + 0x40ff4, 0xfbfbfb);
outpdw(MDP_BASE + 0x40ff8, 0xfdfdfd);
outpdw(MDP_BASE + 0x40ffc, 0xffffff);
}
#define IRQ_EN_1__MDP_IRQ___M 0x00000800
void mdp_hw_init(void)
{
int i;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
/* debug interface write access */
outpdw(MDP_BASE + 0x60, 1);
outp32(MDP_INTR_ENABLE, MDP_ANY_INTR_MASK);
outp32(MDP_EBI2_PORTMAP_MODE, 0x3);
outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8, 0x0);
outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc, 0x0);
outpdw(MDP_BASE + 0x60, 0x1);
mdp_load_lut_param();
/*
* clear up unused fg/main registers
*/
/* comp.plane 2&3 ystride */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0120, 0x0);
/* unpacked pattern */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x012c, 0x0);
/* unpacked pattern */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0130, 0x0);
/* unpacked pattern */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0134, 0x0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0158, 0x0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x15c, 0x0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0160, 0x0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0170, 0x0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0174, 0x0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x017c, 0x0);
/* comp.plane 2 */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0114, 0x0);
/* comp.plane 3 */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0118, 0x0);
/* clear up unused bg registers */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8, 0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0, 0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc, 0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0, 0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4, 0);
#ifndef CONFIG_FB_MSM_MDP22
MDP_OUTP(MDP_BASE + 0xE0000, 0);
MDP_OUTP(MDP_BASE + 0x100, 0xffffffff);
MDP_OUTP(MDP_BASE + 0x90070, 0);
MDP_OUTP(MDP_BASE + 0x94010, 1);
MDP_OUTP(MDP_BASE + 0x9401c, 2);
#endif
/*
* limit vector
* pre gets applied before color matrix conversion
* post is after ccs
*/
writel(mdp_plv[0], MDP_CSC_PRE_LV1n(0));
writel(mdp_plv[1], MDP_CSC_PRE_LV1n(1));
writel(mdp_plv[2], MDP_CSC_PRE_LV1n(2));
writel(mdp_plv[3], MDP_CSC_PRE_LV1n(3));
#ifdef CONFIG_FB_MSM_MDP31
writel(mdp_plv[2], MDP_CSC_PRE_LV1n(4));
writel(mdp_plv[3], MDP_CSC_PRE_LV1n(5));
writel(0, MDP_CSC_POST_LV1n(0));
writel(0xff, MDP_CSC_POST_LV1n(1));
writel(0, MDP_CSC_POST_LV1n(2));
writel(0xff, MDP_CSC_POST_LV1n(3));
writel(0, MDP_CSC_POST_LV1n(4));
writel(0xff, MDP_CSC_POST_LV1n(5));
writel(0, MDP_CSC_PRE_LV2n(0));
writel(0xff, MDP_CSC_PRE_LV2n(1));
writel(0, MDP_CSC_PRE_LV2n(2));
writel(0xff, MDP_CSC_PRE_LV2n(3));
writel(0, MDP_CSC_PRE_LV2n(4));
writel(0xff, MDP_CSC_PRE_LV2n(5));
writel(mdp_plv[0], MDP_CSC_POST_LV2n(0));
writel(mdp_plv[1], MDP_CSC_POST_LV2n(1));
writel(mdp_plv[2], MDP_CSC_POST_LV2n(2));
writel(mdp_plv[3], MDP_CSC_POST_LV2n(3));
writel(mdp_plv[2], MDP_CSC_POST_LV2n(4));
writel(mdp_plv[3], MDP_CSC_POST_LV2n(5));
#endif
/* primary forward matrix */
for (i = 0; i < MDP_CCS_SIZE; i++)
writel(mdp_ccs_rgb2yuv.ccs[i], MDP_CSC_PFMVn(i));
#ifdef CONFIG_FB_MSM_MDP31
for (i = 0; i < MDP_BV_SIZE; i++)
writel(mdp_ccs_rgb2yuv.bv[i], MDP_CSC_POST_BV2n(i));
writel(0, MDP_CSC_PRE_BV2n(0));
writel(0, MDP_CSC_PRE_BV2n(1));
writel(0, MDP_CSC_PRE_BV2n(2));
#endif
/* primary reverse matrix */
for (i = 0; i < MDP_CCS_SIZE; i++)
writel(mdp_ccs_yuv2rgb.ccs[i], MDP_CSC_PRMVn(i));
for (i = 0; i < MDP_BV_SIZE; i++)
writel(mdp_ccs_yuv2rgb.bv[i], MDP_CSC_PRE_BV1n(i));
#ifdef CONFIG_FB_MSM_MDP31
writel(0, MDP_CSC_POST_BV1n(0));
writel(0, MDP_CSC_POST_BV1n(1));
writel(0, MDP_CSC_POST_BV1n(2));
outpdw(MDP_BASE + 0x30010, 0x03e0);
outpdw(MDP_BASE + 0x30014, 0x0360);
outpdw(MDP_BASE + 0x30018, 0x0120);
outpdw(MDP_BASE + 0x3001c, 0x0140);
#endif
mdp_init_scale_table();
#ifndef CONFIG_FB_MSM_MDP31
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0104,
((16 << 6) << 16) | (16) << 6);
#endif
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,347 @@
/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "mdp.h"
static boolean mdp_ppp_intr_flag = FALSE;
static boolean mdp_ppp_busy_flag = FALSE;
/* Queue to keep track of the completed jobs for cleaning */
static LIST_HEAD(mdp_ppp_djob_clnrq);
static DEFINE_SPINLOCK(mdp_ppp_djob_clnrq_lock);
/* Worker to cleanup Display Jobs */
static struct workqueue_struct *mdp_ppp_djob_clnr;
/* Display Queue (DQ) for MDP PPP Block */
static LIST_HEAD(mdp_ppp_dq);
static DEFINE_SPINLOCK(mdp_ppp_dq_lock);
/* Current Display Job for MDP PPP */
static struct mdp_ppp_djob *curr_djob;
/* Track ret code for the last opeartion */
static int mdp_ppp_ret_code;
inline int mdp_ppp_get_ret_code(void)
{
return mdp_ppp_ret_code;
}
/* Push <Reg, Val> pair into DQ (if available) to later
* program the MDP PPP Block */
inline void mdp_ppp_outdw(uint32_t addr, uint32_t data)
{
if (curr_djob) {
/* get the last node of the list. */
struct mdp_ppp_roi_cmd_set *node =
list_entry(curr_djob->roi_cmd_list.prev,
struct mdp_ppp_roi_cmd_set, node);
/* If a node is already full, create a new one and add it to
* the list (roi_cmd_list).
*/
if (node->ncmds == MDP_PPP_ROI_NODE_SIZE) {
node = kmalloc(sizeof(struct mdp_ppp_roi_cmd_set),
GFP_KERNEL);
if (!node) {
printk(KERN_ERR
"MDP_PPP: not enough memory.\n");
mdp_ppp_ret_code = -EINVAL;
return;
}
/* no ROI commands initially */
node->ncmds = 0;
/* add one node to roi_cmd_list. */
list_add_tail(&node->node, &curr_djob->roi_cmd_list);
}
/* register ROI commands */
node->cmd[node->ncmds].reg = addr;
node->cmd[node->ncmds].val = data;
node->ncmds++;
} else
/* program MDP PPP block now */
outpdw((addr), (data));
}
/* Initialize DQ */
inline void mdp_ppp_dq_init(void)
{
mdp_ppp_djob_clnr = create_singlethread_workqueue("MDPDJobClnrThrd");
}
/* Release resources of a job (DJob). */
static void mdp_ppp_del_djob(struct mdp_ppp_djob *job)
{
struct mdp_ppp_roi_cmd_set *node, *tmp;
/* release mem */
mdp_ppp_put_img(job->p_src_file, job->p_dst_file);
/* release roi_cmd_list */
list_for_each_entry_safe(node, tmp, &job->roi_cmd_list, node) {
list_del(&node->node);
kfree(node);
}
/* release job struct */
kfree(job);
}
/* Worker thread to reclaim resources once a display job is done */
static void mdp_ppp_djob_cleaner(struct work_struct *work)
{
struct mdp_ppp_djob *job;
MDP_PPP_DEBUG_MSG("mdp ppp display job cleaner started \n");
/* cleanup display job */
job = container_of(work, struct mdp_ppp_djob, cleaner.work);
if (likely(work && job))
mdp_ppp_del_djob(job);
}
/* Create a new Display Job (DJob) */
inline struct mdp_ppp_djob *mdp_ppp_new_djob(void)
{
struct mdp_ppp_djob *job;
struct mdp_ppp_roi_cmd_set *node;
/* create a new djob */
job = kmalloc(sizeof(struct mdp_ppp_djob), GFP_KERNEL);
if (!job)
return NULL;
/* add the first node to curr_djob->roi_cmd_list */
node = kmalloc(sizeof(struct mdp_ppp_roi_cmd_set), GFP_KERNEL);
if (!node) {
kfree(job);
return NULL;
}
/* make this current djob container to keep track of the curr djob not
* used in the async path i.e. no sync needed
*
* Should not contain any references from the past djob
*/
BUG_ON(curr_djob);
curr_djob = job;
INIT_LIST_HEAD(&curr_djob->roi_cmd_list);
/* no ROI commands initially */
node->ncmds = 0;
INIT_LIST_HEAD(&node->node);
list_add_tail(&node->node, &curr_djob->roi_cmd_list);
/* register this djob with the djob cleaner
* initializes 'work' data struct
*/
INIT_DELAYED_WORK(&curr_djob->cleaner, mdp_ppp_djob_cleaner);
INIT_LIST_HEAD(&curr_djob->entry);
curr_djob->p_src_file = 0;
curr_djob->p_dst_file = 0;
return job;
}
/* Undo the effect of mdp_ppp_new_djob() */
inline void mdp_ppp_clear_curr_djob(void)
{
if (likely(curr_djob)) {
mdp_ppp_del_djob(curr_djob);
curr_djob = NULL;
}
}
/* Cleanup dirty djobs */
static void mdp_ppp_flush_dirty_djobs(void *cond)
{
unsigned long flags;
struct mdp_ppp_djob *job;
/* Flush the jobs from the djob clnr queue */
while (cond && test_bit(0, (unsigned long *)cond)) {
/* Until we are done with the cleanup queue */
spin_lock_irqsave(&mdp_ppp_djob_clnrq_lock, flags);
if (list_empty(&mdp_ppp_djob_clnrq)) {
spin_unlock_irqrestore(&mdp_ppp_djob_clnrq_lock, flags);
break;
}
MDP_PPP_DEBUG_MSG("flushing djobs ... loop \n");
/* Retrieve the job that needs to be cleaned */
job = list_entry(mdp_ppp_djob_clnrq.next,
struct mdp_ppp_djob, entry);
list_del_init(&job->entry);
spin_unlock_irqrestore(&mdp_ppp_djob_clnrq_lock, flags);
/* Keep mem state coherent */
msm_fb_ensure_mem_coherency_after_dma(job->info, &job->req, 1);
/* Schedule jobs for cleanup
* A seperate worker thread does this */
queue_delayed_work(mdp_ppp_djob_clnr, &job->cleaner,
mdp_timer_duration);
}
}
/* If MDP PPP engine is busy, wait until it is available again */
void mdp_ppp_wait(void)
{
unsigned long flags;
int cond = 1;
/* keep flushing dirty djobs as long as MDP PPP engine is busy */
mdp_ppp_flush_dirty_djobs(&mdp_ppp_busy_flag);
/* block if MDP PPP engine is still busy */
spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
if (test_bit(0, (unsigned long *)&mdp_ppp_busy_flag)) {
/* prepare for the wakeup event */
test_and_set_bit(0, (unsigned long *)&mdp_ppp_waiting);
INIT_COMPLETION(mdp_ppp_comp);
spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
/* block uninterruptibly until available */
MDP_PPP_DEBUG_MSG("waiting for mdp... \n");
wait_for_completion_killable(&mdp_ppp_comp);
/* if MDP PPP engine is still free,
* disable INT_MDP if enabled
*/
spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
if (!test_bit(0, (unsigned long *)&mdp_ppp_busy_flag) &&
test_and_clear_bit(0, (unsigned long *)&mdp_ppp_intr_flag))
mdp_disable_irq(MDP_PPP_TERM);
}
spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
/* flush remaining dirty djobs, if any */
mdp_ppp_flush_dirty_djobs(&cond);
}
/* Program MDP PPP block to process this ROI */
static void mdp_ppp_process_roi(struct list_head *roi_cmd_list)
{
/* program PPP engine with registered ROI commands */
struct mdp_ppp_roi_cmd_set *node;
list_for_each_entry(node, roi_cmd_list, node) {
int i = 0;
for (; i < node->ncmds; i++) {
MDP_PPP_DEBUG_MSG("%d: reg: 0x%x val: 0x%x \n",
i, node->cmd[i].reg, node->cmd[i].val);
outpdw(node->cmd[i].reg, node->cmd[i].val);
}
}
/* kickoff MDP PPP engine */
MDP_PPP_DEBUG_MSG("kicking off mdp \n");
outpdw(MDP_BASE + 0x30, 0x1000);
}
/* Submit this display job to MDP PPP engine */
static void mdp_ppp_dispatch_djob(struct mdp_ppp_djob *job)
{
/* enable INT_MDP if disabled */
if (!test_and_set_bit(0, (unsigned long *)&mdp_ppp_intr_flag))
mdp_enable_irq(MDP_PPP_TERM);
/* turn on PPP and CMD blocks */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
/* process this ROI */
mdp_ppp_process_roi(&job->roi_cmd_list);
}
/* Enqueue this display job to be cleaned up later in "mdp_ppp_djob_done" */
static inline void mdp_ppp_enqueue_djob(struct mdp_ppp_djob *job)
{
unsigned long flags;
spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
list_add_tail(&job->entry, &mdp_ppp_dq);
spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
}
/* First enqueue display job for cleanup and dispatch immediately
* if MDP PPP engine is free */
void mdp_ppp_process_curr_djob(void)
{
/* enqueue djob */
mdp_ppp_enqueue_djob(curr_djob);
/* dispatch now if MDP PPP engine is free */
if (!test_and_set_bit(0, (unsigned long *)&mdp_ppp_busy_flag))
mdp_ppp_dispatch_djob(curr_djob);
/* done with the current djob */
curr_djob = NULL;
}
/* Called from mdp_isr - cleanup finished job and start with next
* if available else set MDP PPP engine free */
void mdp_ppp_djob_done(void)
{
struct mdp_ppp_djob *curr, *next;
unsigned long flags;
/* dequeue current */
spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
curr = list_entry(mdp_ppp_dq.next, struct mdp_ppp_djob, entry);
list_del_init(&curr->entry);
spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
/* cleanup current - enqueue in the djob clnr queue */
spin_lock_irqsave(&mdp_ppp_djob_clnrq_lock, flags);
list_add_tail(&curr->entry, &mdp_ppp_djob_clnrq);
spin_unlock_irqrestore(&mdp_ppp_djob_clnrq_lock, flags);
/* grab next pending */
spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
if (!list_empty(&mdp_ppp_dq)) {
next = list_entry(mdp_ppp_dq.next, struct mdp_ppp_djob,
entry);
spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
/* process next in the queue */
mdp_ppp_process_roi(&next->roi_cmd_list);
} else {
/* no pending display job */
spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
/* turn off PPP and CMD blocks - "in_isr" is TRUE */
mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
/* notify if waiting */
if (test_and_clear_bit(0, (unsigned long *)&mdp_ppp_waiting))
complete(&mdp_ppp_comp);
/* set free */
test_and_clear_bit(0, (unsigned long *)&mdp_ppp_busy_flag);
}
}

View file

@ -0,0 +1,86 @@
/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MDP_PPP_DQ_H
#define MDP_PPP_DQ_H
#include "msm_fb_def.h"
#define MDP_PPP_DEBUG_MSG MSM_FB_DEBUG
/* The maximum number of <Reg,Val> pairs in an mdp_ppp_roi_cmd_set structure (a
* node)
*/
#define MDP_PPP_ROI_NODE_SIZE 32
/* ROI config command (<Reg,Val> pair) for MDP PPP block */
struct mdp_ppp_roi_cmd {
uint32_t reg;
uint32_t val;
};
/* ROI config commands for MDP PPP block are stored in a list of
* mdp_ppp_roi_cmd_set structures (nodes).
*/
struct mdp_ppp_roi_cmd_set {
struct list_head node;
uint32_t ncmds; /* number of commands in this set (node). */
struct mdp_ppp_roi_cmd cmd[MDP_PPP_ROI_NODE_SIZE];
};
/* MDP PPP Display Job (DJob) */
struct mdp_ppp_djob {
struct list_head entry;
/* One ROI per MDP PPP DJob */
struct list_head roi_cmd_list;
struct mdp_blit_req req;
struct fb_info *info;
struct delayed_work cleaner;
struct file *p_src_file, *p_dst_file;
};
extern struct completion mdp_ppp_comp;
extern boolean mdp_ppp_waiting;
extern unsigned long mdp_timer_duration;
unsigned int mdp_ppp_async_op_get(void);
void mdp_ppp_async_op_set(unsigned int flag);
void msm_fb_ensure_mem_coherency_after_dma(struct fb_info *info,
struct mdp_blit_req *req_list, int req_list_count);
void mdp_ppp_put_img(struct file *p_src_file, struct file *p_dst_file);
void mdp_ppp_dq_init(void);
void mdp_ppp_outdw(uint32_t addr, uint32_t data);
struct mdp_ppp_djob *mdp_ppp_new_djob(void);
void mdp_ppp_clear_curr_djob(void);
void mdp_ppp_process_curr_djob(void);
int mdp_ppp_get_ret_code(void);
void mdp_ppp_djob_done(void);
void mdp_ppp_wait(void);
#endif /* MDP_PPP_DQ_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,828 @@
/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include "linux/proc_fs.h"
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <asm/div64.h>
#include "mdp.h"
#include "msm_fb.h"
#define MDP_SCALE_COEFF_NUM 32
#define MDP_SCALE_0P2_TO_0P4_INDEX 0
#define MDP_SCALE_0P4_TO_0P6_INDEX 32
#define MDP_SCALE_0P6_TO_0P8_INDEX 64
#define MDP_SCALE_0P8_TO_8P0_INDEX 96
#define MDP_SCALE_COEFF_MASK 0x3ff
#define MDP_SCALE_PR 0
#define MDP_SCALE_FIR 1
static uint32 mdp_scale_0p8_to_8p0_mode;
static uint32 mdp_scale_0p6_to_0p8_mode;
static uint32 mdp_scale_0p4_to_0p6_mode;
static uint32 mdp_scale_0p2_to_0p4_mode;
/* -------- All scaling range, "pixel repeat" -------- */
static int16 mdp_scale_pixel_repeat_C0[MDP_SCALE_COEFF_NUM] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
static int16 mdp_scale_pixel_repeat_C1[MDP_SCALE_COEFF_NUM] = {
511, 511, 511, 511, 511, 511, 511, 511,
511, 511, 511, 511, 511, 511, 511, 511,
511, 511, 511, 511, 511, 511, 511, 511,
511, 511, 511, 511, 511, 511, 511, 511
};
static int16 mdp_scale_pixel_repeat_C2[MDP_SCALE_COEFF_NUM] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
static int16 mdp_scale_pixel_repeat_C3[MDP_SCALE_COEFF_NUM] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
/* --------------------------- FIR ------------------------------------- */
/* -------- Downscale, ranging from 0.8x to 8.0x of original size -------- */
static int16 mdp_scale_0p8_to_8p0_C0[MDP_SCALE_COEFF_NUM] = {
0, -7, -13, -19, -24, -28, -32, -34, -37, -39,
-40, -41, -41, -41, -40, -40, -38, -37, -35, -33,
-31, -29, -26, -24, -21, -18, -15, -13, -10, -7,
-5, -2
};
static int16 mdp_scale_0p8_to_8p0_C1[MDP_SCALE_COEFF_NUM] = {
511, 507, 501, 494, 485, 475, 463, 450, 436, 422,
405, 388, 370, 352, 333, 314, 293, 274, 253, 233,
213, 193, 172, 152, 133, 113, 95, 77, 60, 43,
28, 13
};
static int16 mdp_scale_0p8_to_8p0_C2[MDP_SCALE_COEFF_NUM] = {
0, 13, 28, 43, 60, 77, 95, 113, 133, 152,
172, 193, 213, 233, 253, 274, 294, 314, 333, 352,
370, 388, 405, 422, 436, 450, 463, 475, 485, 494,
501, 507,
};
static int16 mdp_scale_0p8_to_8p0_C3[MDP_SCALE_COEFF_NUM] = {
0, -2, -5, -7, -10, -13, -15, -18, -21, -24,
-26, -29, -31, -33, -35, -37, -38, -40, -40, -41,
-41, -41, -40, -39, -37, -34, -32, -28, -24, -19,
-13, -7
};
/* -------- Downscale, ranging from 0.6x to 0.8x of original size -------- */
static int16 mdp_scale_0p6_to_0p8_C0[MDP_SCALE_COEFF_NUM] = {
104, 96, 89, 82, 75, 68, 61, 55, 49, 43,
38, 33, 28, 24, 20, 16, 12, 9, 6, 4,
2, 0, -2, -4, -5, -6, -7, -7, -8, -8,
-8, -8
};
static int16 mdp_scale_0p6_to_0p8_C1[MDP_SCALE_COEFF_NUM] = {
303, 303, 302, 300, 298, 296, 293, 289, 286, 281,
276, 270, 265, 258, 252, 245, 238, 230, 223, 214,
206, 197, 189, 180, 172, 163, 154, 145, 137, 128,
120, 112
};
static int16 mdp_scale_0p6_to_0p8_C2[MDP_SCALE_COEFF_NUM] = {
112, 120, 128, 137, 145, 154, 163, 172, 180, 189,
197, 206, 214, 223, 230, 238, 245, 252, 258, 265,
270, 276, 281, 286, 289, 293, 296, 298, 300, 302,
303, 303
};
static int16 mdp_scale_0p6_to_0p8_C3[MDP_SCALE_COEFF_NUM] = {
-8, -8, -8, -8, -7, -7, -6, -5, -4, -2,
0, 2, 4, 6, 9, 12, 16, 20, 24, 28,
33, 38, 43, 49, 55, 61, 68, 75, 82, 89,
96, 104
};
/* -------- Downscale, ranging from 0.4x to 0.6x of original size -------- */
static int16 mdp_scale_0p4_to_0p6_C0[MDP_SCALE_COEFF_NUM] = {
136, 132, 128, 123, 119, 115, 111, 107, 103, 98,
95, 91, 87, 84, 80, 76, 73, 69, 66, 62,
59, 57, 54, 50, 47, 44, 41, 39, 36, 33,
32, 29
};
static int16 mdp_scale_0p4_to_0p6_C1[MDP_SCALE_COEFF_NUM] = {
206, 205, 204, 204, 201, 200, 199, 197, 196, 194,
191, 191, 189, 185, 184, 182, 180, 178, 176, 173,
170, 168, 165, 162, 160, 157, 155, 152, 148, 146,
142, 140
};
static int16 mdp_scale_0p4_to_0p6_C2[MDP_SCALE_COEFF_NUM] = {
140, 142, 146, 148, 152, 155, 157, 160, 162, 165,
168, 170, 173, 176, 178, 180, 182, 184, 185, 189,
191, 191, 194, 196, 197, 199, 200, 201, 204, 204,
205, 206
};
static int16 mdp_scale_0p4_to_0p6_C3[MDP_SCALE_COEFF_NUM] = {
29, 32, 33, 36, 39, 41, 44, 47, 50, 54,
57, 59, 62, 66, 69, 73, 76, 80, 84, 87,
91, 95, 98, 103, 107, 111, 115, 119, 123, 128,
132, 136
};
/* -------- Downscale, ranging from 0.2x to 0.4x of original size -------- */
static int16 mdp_scale_0p2_to_0p4_C0[MDP_SCALE_COEFF_NUM] = {
131, 131, 130, 129, 128, 127, 127, 126, 125, 125,
124, 123, 123, 121, 120, 119, 119, 118, 117, 117,
116, 115, 115, 114, 113, 112, 111, 110, 109, 109,
108, 107
};
static int16 mdp_scale_0p2_to_0p4_C1[MDP_SCALE_COEFF_NUM] = {
141, 140, 140, 140, 140, 139, 138, 138, 138, 137,
137, 137, 136, 137, 137, 137, 136, 136, 136, 135,
135, 135, 134, 134, 134, 134, 134, 133, 133, 132,
132, 132
};
static int16 mdp_scale_0p2_to_0p4_C2[MDP_SCALE_COEFF_NUM] = {
132, 132, 132, 133, 133, 134, 134, 134, 134, 134,
135, 135, 135, 136, 136, 136, 137, 137, 137, 136,
137, 137, 137, 138, 138, 138, 139, 140, 140, 140,
140, 141
};
static int16 mdp_scale_0p2_to_0p4_C3[MDP_SCALE_COEFF_NUM] = {
107, 108, 109, 109, 110, 111, 112, 113, 114, 115,
115, 116, 117, 117, 118, 119, 119, 120, 121, 123,
123, 124, 125, 125, 126, 127, 127, 128, 129, 130,
131, 131
};
static void mdp_update_scale_table(int index, int16 *c0, int16 *c1,
int16 *c2, int16 *c3)
{
int i, val;
for (i = 0; i < MDP_SCALE_COEFF_NUM; i++) {
val =
((MDP_SCALE_COEFF_MASK & c1[i]) << 16) |
(MDP_SCALE_COEFF_MASK & c0[i]);
MDP_OUTP(MDP_PPP_SCALE_COEFF_LSBn(index), val);
val =
((MDP_SCALE_COEFF_MASK & c3[i]) << 16) |
(MDP_SCALE_COEFF_MASK & c2[i]);
MDP_OUTP(MDP_PPP_SCALE_COEFF_MSBn(index), val);
index++;
}
}
void mdp_init_scale_table(void)
{
mdp_scale_0p2_to_0p4_mode = MDP_SCALE_FIR;
mdp_update_scale_table(MDP_SCALE_0P2_TO_0P4_INDEX,
mdp_scale_0p2_to_0p4_C0,
mdp_scale_0p2_to_0p4_C1,
mdp_scale_0p2_to_0p4_C2,
mdp_scale_0p2_to_0p4_C3);
mdp_scale_0p4_to_0p6_mode = MDP_SCALE_FIR;
mdp_update_scale_table(MDP_SCALE_0P4_TO_0P6_INDEX,
mdp_scale_0p4_to_0p6_C0,
mdp_scale_0p4_to_0p6_C1,
mdp_scale_0p4_to_0p6_C2,
mdp_scale_0p4_to_0p6_C3);
mdp_scale_0p6_to_0p8_mode = MDP_SCALE_FIR;
mdp_update_scale_table(MDP_SCALE_0P6_TO_0P8_INDEX,
mdp_scale_0p6_to_0p8_C0,
mdp_scale_0p6_to_0p8_C1,
mdp_scale_0p6_to_0p8_C2,
mdp_scale_0p6_to_0p8_C3);
mdp_scale_0p8_to_8p0_mode = MDP_SCALE_FIR;
mdp_update_scale_table(MDP_SCALE_0P8_TO_8P0_INDEX,
mdp_scale_0p8_to_8p0_C0,
mdp_scale_0p8_to_8p0_C1,
mdp_scale_0p8_to_8p0_C2,
mdp_scale_0p8_to_8p0_C3);
}
static long long mdp_do_div(long long num, long long den)
{
do_div(num, den);
return num;
}
#define SCALER_PHASE_BITS 29
#define HAL_MDP_PHASE_STEP_2P50 0x50000000
#define HAL_MDP_PHASE_STEP_1P66 0x35555555
#define HAL_MDP_PHASE_STEP_1P25 0x28000000
struct phase_val {
int phase_init_x;
int phase_init_y;
int phase_step_x;
int phase_step_y;
};
static void mdp_calc_scaleInitPhase_3p1(uint32 in_w,
uint32 in_h,
uint32 out_w,
uint32 out_h,
boolean is_rotate,
boolean is_pp_x,
boolean is_pp_y, struct phase_val *pval)
{
uint64 dst_ROI_width;
uint64 dst_ROI_height;
uint64 src_ROI_width;
uint64 src_ROI_height;
/*
* phase_step_x, phase_step_y, phase_init_x and phase_init_y
* are represented in fixed-point, unsigned 3.29 format
*/
uint32 phase_step_x = 0;
uint32 phase_step_y = 0;
uint32 phase_init_x = 0;
uint32 phase_init_y = 0;
uint32 yscale_filter_sel, xscale_filter_sel;
uint32 scale_unit_sel_x, scale_unit_sel_y;
uint64 numerator, denominator;
uint64 temp_dim;
src_ROI_width = in_w;
src_ROI_height = in_h;
dst_ROI_width = out_w;
dst_ROI_height = out_h;
/* if there is a 90 degree rotation */
if (is_rotate) {
/* decide whether to use FIR or M/N for scaling */
/* if down-scaling by a factor smaller than 1/4 */
if (src_ROI_width > (4 * dst_ROI_height))
scale_unit_sel_x = 1; /* use M/N scalar */
else
scale_unit_sel_x = 0; /* use FIR scalar */
/* if down-scaling by a factor smaller than 1/4 */
if (src_ROI_height > (4 * dst_ROI_width))
scale_unit_sel_y = 1; /* use M/N scalar */
else
scale_unit_sel_y = 0; /* use FIR scalar */
} else {
/* decide whether to use FIR or M/N for scaling */
if (src_ROI_width > (4 * dst_ROI_width))
scale_unit_sel_x = 1; /* use M/N scalar */
else
scale_unit_sel_x = 0; /* use FIR scalar */
if (src_ROI_height > (4 * dst_ROI_height))
scale_unit_sel_y = 1; /* use M/N scalar */
else
scale_unit_sel_y = 0; /* use FIR scalar */
}
/* if there is a 90 degree rotation */
if (is_rotate) {
/* swap the width and height of dst ROI */
temp_dim = dst_ROI_width;
dst_ROI_width = dst_ROI_height;
dst_ROI_height = temp_dim;
}
/* calculate phase step for the x direction */
/* if destination is only 1 pixel wide, the value of phase_step_x
is unimportant. Assigning phase_step_x to src ROI width
as an arbitrary value. */
if (dst_ROI_width == 1)
phase_step_x = (uint32) ((src_ROI_width) << SCALER_PHASE_BITS);
/* if using FIR scalar */
else if (scale_unit_sel_x == 0) {
/* Calculate the quotient ( src_ROI_width - 1 ) / ( dst_ROI_width - 1)
with u3.29 precision. Quotient is rounded up to the larger
29th decimal point. */
numerator = (src_ROI_width - 1) << SCALER_PHASE_BITS;
denominator = (dst_ROI_width - 1); /* never equals to 0 because of the "( dst_ROI_width == 1 ) case" */
phase_step_x = (uint32) mdp_do_div((numerator + denominator - 1), denominator); /* divide and round up to the larger 29th decimal point. */
}
/* if M/N scalar */
else if (scale_unit_sel_x == 1) {
/* Calculate the quotient ( src_ROI_width ) / ( dst_ROI_width)
with u3.29 precision. Quotient is rounded down to the
smaller 29th decimal point. */
numerator = (src_ROI_width) << SCALER_PHASE_BITS;
denominator = (dst_ROI_width);
phase_step_x = (uint32) mdp_do_div(numerator, denominator);
}
/* calculate phase step for the y direction */
/* if destination is only 1 pixel wide, the value of
phase_step_x is unimportant. Assigning phase_step_x
to src ROI width as an arbitrary value. */
if (dst_ROI_height == 1)
phase_step_y = (uint32) ((src_ROI_height) << SCALER_PHASE_BITS);
/* if FIR scalar */
else if (scale_unit_sel_y == 0) {
/* Calculate the quotient ( src_ROI_height - 1 ) / ( dst_ROI_height - 1)
with u3.29 precision. Quotient is rounded up to the larger
29th decimal point. */
numerator = (src_ROI_height - 1) << SCALER_PHASE_BITS;
denominator = (dst_ROI_height - 1); /* never equals to 0 because of the "( dst_ROI_height == 1 )" case */
phase_step_y = (uint32) mdp_do_div((numerator + denominator - 1), denominator); /* Quotient is rounded up to the larger 29th decimal point. */
}
/* if M/N scalar */
else if (scale_unit_sel_y == 1) {
/* Calculate the quotient ( src_ROI_height ) / ( dst_ROI_height)
with u3.29 precision. Quotient is rounded down to the smaller
29th decimal point. */
numerator = (src_ROI_height) << SCALER_PHASE_BITS;
denominator = (dst_ROI_height);
phase_step_y = (uint32) mdp_do_div(numerator, denominator);
}
/* decide which set of FIR coefficients to use */
if (phase_step_x > HAL_MDP_PHASE_STEP_2P50)
xscale_filter_sel = 0;
else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66)
xscale_filter_sel = 1;
else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25)
xscale_filter_sel = 2;
else
xscale_filter_sel = 3;
if (phase_step_y > HAL_MDP_PHASE_STEP_2P50)
yscale_filter_sel = 0;
else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66)
yscale_filter_sel = 1;
else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25)
yscale_filter_sel = 2;
else
yscale_filter_sel = 3;
/* calculate phase init for the x direction */
/* if using FIR scalar */
if (scale_unit_sel_x == 0) {
if (dst_ROI_width == 1)
phase_init_x =
(uint32) ((src_ROI_width - 1) << SCALER_PHASE_BITS);
else
phase_init_x = 0;
}
/* M over N scalar */
else if (scale_unit_sel_x == 1)
phase_init_x = 0;
/* calculate phase init for the y direction
if using FIR scalar */
if (scale_unit_sel_y == 0) {
if (dst_ROI_height == 1)
phase_init_y =
(uint32) ((src_ROI_height -
1) << SCALER_PHASE_BITS);
else
phase_init_y = 0;
}
/* M over N scalar */
else if (scale_unit_sel_y == 1)
phase_init_y = 0;
/* write registers */
pval->phase_step_x = (uint32) phase_step_x;
pval->phase_step_y = (uint32) phase_step_y;
pval->phase_init_x = (uint32) phase_init_x;
pval->phase_init_y = (uint32) phase_init_y;
return;
}
void mdp_set_scale(MDPIBUF *iBuf,
uint32 dst_roi_width,
uint32 dst_roi_height,
boolean inputRGB, boolean outputRGB, uint32 *pppop_reg_ptr)
{
uint32 dst_roi_width_scale;
uint32 dst_roi_height_scale;
struct phase_val pval;
boolean use_pr;
uint32 ppp_scale_config = 0;
if (!inputRGB)
ppp_scale_config |= BIT(6);
if (iBuf->mdpImg.mdpOp & MDPOP_ASCALE) {
if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) {
dst_roi_width_scale = dst_roi_height;
dst_roi_height_scale = dst_roi_width;
} else {
dst_roi_width_scale = dst_roi_width;
dst_roi_height_scale = dst_roi_height;
}
if ((dst_roi_width_scale != iBuf->roi.width) ||
(dst_roi_height_scale != iBuf->roi.height) ||
(iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) {
*pppop_reg_ptr |=
(PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
mdp_calc_scaleInitPhase_3p1(iBuf->roi.width,
iBuf->roi.height,
dst_roi_width,
dst_roi_height,
iBuf->mdpImg.
mdpOp & MDPOP_ROT90, 1, 1,
&pval);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x013c,
pval.phase_init_x);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0140,
pval.phase_init_y);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0144,
pval.phase_step_x);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0148,
pval.phase_step_y);
use_pr = (inputRGB) && (outputRGB);
/* x-direction */
if ((dst_roi_width_scale == iBuf->roi.width) &&
!(iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) {
*pppop_reg_ptr &= ~PPP_OP_SCALE_X_ON;
} else
if (((dst_roi_width_scale * 10) / iBuf->roi.width) >
8) {
if ((use_pr)
&& (mdp_scale_0p8_to_8p0_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p8_to_8p0_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P8_TO_8P0_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p8_to_8p0_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p8_to_8p0_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P8_TO_8P0_INDEX,
mdp_scale_0p8_to_8p0_C0,
mdp_scale_0p8_to_8p0_C1,
mdp_scale_0p8_to_8p0_C2,
mdp_scale_0p8_to_8p0_C3);
}
ppp_scale_config |= (SCALE_U1_SET << 2);
} else
if (((dst_roi_width_scale * 10) / iBuf->roi.width) >
6) {
if ((use_pr)
&& (mdp_scale_0p6_to_0p8_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p6_to_0p8_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P6_TO_0P8_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p6_to_0p8_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p6_to_0p8_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P6_TO_0P8_INDEX,
mdp_scale_0p6_to_0p8_C0,
mdp_scale_0p6_to_0p8_C1,
mdp_scale_0p6_to_0p8_C2,
mdp_scale_0p6_to_0p8_C3);
}
ppp_scale_config |= (SCALE_D2_SET << 2);
} else
if (((dst_roi_width_scale * 10) / iBuf->roi.width) >
4) {
if ((use_pr)
&& (mdp_scale_0p4_to_0p6_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p4_to_0p6_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P4_TO_0P6_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p4_to_0p6_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p4_to_0p6_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P4_TO_0P6_INDEX,
mdp_scale_0p4_to_0p6_C0,
mdp_scale_0p4_to_0p6_C1,
mdp_scale_0p4_to_0p6_C2,
mdp_scale_0p4_to_0p6_C3);
}
ppp_scale_config |= (SCALE_D1_SET << 2);
} else
if (((dst_roi_width_scale * 4) / iBuf->roi.width) >=
1) {
if ((use_pr)
&& (mdp_scale_0p2_to_0p4_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p2_to_0p4_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P2_TO_0P4_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p2_to_0p4_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p2_to_0p4_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P2_TO_0P4_INDEX,
mdp_scale_0p2_to_0p4_C0,
mdp_scale_0p2_to_0p4_C1,
mdp_scale_0p2_to_0p4_C2,
mdp_scale_0p2_to_0p4_C3);
}
ppp_scale_config |= (SCALE_D0_SET << 2);
} else
ppp_scale_config |= BIT(0);
/* y-direction */
if ((dst_roi_height_scale == iBuf->roi.height) &&
!(iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) {
*pppop_reg_ptr &= ~PPP_OP_SCALE_Y_ON;
} else if (((dst_roi_height_scale * 10) /
iBuf->roi.height) > 8) {
if ((use_pr)
&& (mdp_scale_0p8_to_8p0_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p8_to_8p0_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P8_TO_8P0_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p8_to_8p0_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p8_to_8p0_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P8_TO_8P0_INDEX,
mdp_scale_0p8_to_8p0_C0,
mdp_scale_0p8_to_8p0_C1,
mdp_scale_0p8_to_8p0_C2,
mdp_scale_0p8_to_8p0_C3);
}
ppp_scale_config |= (SCALE_U1_SET << 4);
} else
if (((dst_roi_height_scale * 10) /
iBuf->roi.height) > 6) {
if ((use_pr)
&& (mdp_scale_0p6_to_0p8_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p6_to_0p8_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P6_TO_0P8_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p6_to_0p8_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p6_to_0p8_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P6_TO_0P8_INDEX,
mdp_scale_0p6_to_0p8_C0,
mdp_scale_0p6_to_0p8_C1,
mdp_scale_0p6_to_0p8_C2,
mdp_scale_0p6_to_0p8_C3);
}
ppp_scale_config |= (SCALE_D2_SET << 4);
} else
if (((dst_roi_height_scale * 10) /
iBuf->roi.height) > 4) {
if ((use_pr)
&& (mdp_scale_0p4_to_0p6_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p4_to_0p6_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P4_TO_0P6_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p4_to_0p6_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p4_to_0p6_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P4_TO_0P6_INDEX,
mdp_scale_0p4_to_0p6_C0,
mdp_scale_0p4_to_0p6_C1,
mdp_scale_0p4_to_0p6_C2,
mdp_scale_0p4_to_0p6_C3);
}
ppp_scale_config |= (SCALE_D1_SET << 4);
} else
if (((dst_roi_height_scale * 4) /
iBuf->roi.height) >= 1) {
if ((use_pr)
&& (mdp_scale_0p2_to_0p4_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p2_to_0p4_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P2_TO_0P4_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p2_to_0p4_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p2_to_0p4_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P2_TO_0P4_INDEX,
mdp_scale_0p2_to_0p4_C0,
mdp_scale_0p2_to_0p4_C1,
mdp_scale_0p2_to_0p4_C2,
mdp_scale_0p2_to_0p4_C3);
}
ppp_scale_config |= (SCALE_D0_SET << 4);
} else
ppp_scale_config |= BIT(1);
if (iBuf->mdpImg.mdpOp & MDPOP_SHARPENING) {
ppp_scale_config |= BIT(7);
MDP_OUTP(MDP_BASE + 0x50020,
iBuf->mdpImg.sp_value);
}
MDP_OUTP(MDP_BASE + 0x10230, ppp_scale_config);
} else {
iBuf->mdpImg.mdpOp &= ~(MDPOP_ASCALE);
}
}
}
void mdp_adjust_start_addr(uint8 **src0,
uint8 **src1,
int v_slice,
int h_slice,
int x,
int y,
uint32 width,
uint32 height, int bpp, MDPIBUF *iBuf, int layer)
{
switch (layer) {
case 0:
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0200, (y << 16) | (x));
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0208,
(height << 16) | (width));
break;
case 1:
/* MDP 3.1 HW bug workaround */
if (iBuf->ibuf_type == MDP_YCRYCB_H2V1) {
*src0 += (x + y * width) * bpp;
x = y = 0;
width = iBuf->roi.dst_width;
height = iBuf->roi.dst_height;
}
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0204, (y << 16) | (x));
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x020c,
(height << 16) | (width));
break;
case 2:
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x019c, (y << 16) | (x));
break;
}
}
void mdp_set_blend_attr(MDPIBUF *iBuf,
uint32 *alpha,
uint32 *tpVal,
uint32 perPixelAlpha, uint32 *pppop_reg_ptr)
{
int bg_alpha;
*alpha = iBuf->mdpImg.alpha;
*tpVal = iBuf->mdpImg.tpVal;
if (iBuf->mdpImg.mdpOp & MDPOP_FG_PM_ALPHA) {
*pppop_reg_ptr |= PPP_OP_ROT_ON |
PPP_OP_BLEND_ON | PPP_OP_BLEND_CONSTANT_ALPHA;
bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL |
PPP_BLEND_BG_ALPHA_REVERSE;
if (perPixelAlpha)
bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA;
else
bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA;
outpdw(MDP_BASE + 0x70010, bg_alpha);
if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)
*pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP;
} else if (perPixelAlpha) {
*pppop_reg_ptr |= PPP_OP_ROT_ON |
PPP_OP_BLEND_ON | PPP_OP_BLEND_SRCPIXEL_ALPHA;
} else {
if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
&& (iBuf->mdpImg.alpha == 0xff)) {
iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB);
}
if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
|| (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) {
*pppop_reg_ptr |=
PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
PPP_OP_BLEND_CONSTANT_ALPHA |
PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
}
if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)
*pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP;
}
}

View file

@ -0,0 +1,389 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/hrtimer.h>
#include <linux/vmalloc.h>
#include <linux/clk.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <mach/gpio.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mddihost.h"
#ifdef CONFIG_FB_MSM_MDP40
#define MDP_SYNC_CFG_0 0x100
#define MDP_SYNC_STATUS_0 0x10c
#define MDP_PRIM_VSYNC_OUT_CTRL 0x118
#define MDP_PRIM_VSYNC_INIT_VAL 0x128
#else
#define MDP_SYNC_CFG_0 0x300
#define MDP_SYNC_STATUS_0 0x30c
#define MDP_PRIM_VSYNC_OUT_CTRL 0x318
#define MDP_PRIM_VSYNC_INIT_VAL 0x328
#endif
extern mddi_lcd_type mddi_lcd_idx;
extern spinlock_t mdp_spin_lock;
extern struct workqueue_struct *mdp_vsync_wq;
extern int lcdc_mode;
extern int vsync_mode;
#ifdef MDP_HW_VSYNC
int vsync_above_th = 4;
int vsync_start_th = 1;
int vsync_load_cnt;
struct clk *mdp_vsync_clk;
void mdp_hw_vsync_clk_enable(struct msm_fb_data_type *mfd)
{
if (mfd->use_mdp_vsync)
clk_enable(mdp_vsync_clk);
}
void mdp_hw_vsync_clk_disable(struct msm_fb_data_type *mfd)
{
if (mfd->use_mdp_vsync)
clk_disable(mdp_vsync_clk);
}
#endif
static void mdp_set_vsync(unsigned long data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
struct msm_fb_panel_data *pdata = NULL;
pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
if ((pdata) && (pdata->set_vsync_notifier == NULL))
return;
init_timer(&mfd->vsync_resync_timer);
mfd->vsync_resync_timer.function = mdp_set_vsync;
mfd->vsync_resync_timer.data = data;
mfd->vsync_resync_timer.expires =
jiffies + mfd->panel_info.lcd.vsync_notifier_period;
add_timer(&mfd->vsync_resync_timer);
if ((mfd->panel_info.lcd.vsync_enable) && (mfd->panel_power_on)
&& (!mfd->vsync_handler_pending)) {
mfd->vsync_handler_pending = TRUE;
if (!queue_work(mdp_vsync_wq, &mfd->vsync_resync_worker)) {
MSM_FB_INFO
("mdp_set_vsync: can't queue_work! -> needs to increase vsync_resync_timer_duration\n");
}
} else {
MSM_FB_DEBUG
("mdp_set_vsync failed! EN:%d PWR:%d PENDING:%d\n",
mfd->panel_info.lcd.vsync_enable, mfd->panel_power_on,
mfd->vsync_handler_pending);
}
}
static void mdp_vsync_handler(void *data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
if (mfd->use_mdp_vsync) {
#ifdef MDP_HW_VSYNC
if (mfd->panel_power_on)
MDP_OUTP(MDP_BASE + MDP_SYNC_STATUS_0, vsync_load_cnt);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
#endif
} else {
mfd->last_vsync_timetick = ktime_get_real();
}
mfd->vsync_handler_pending = FALSE;
}
irqreturn_t mdp_hw_vsync_handler_proxy(int irq, void *data)
{
/*
* ToDo: tried enabling/disabling GPIO MDP HW VSYNC interrupt
* but getting inaccurate timing in mdp_vsync_handler()
* disable_irq(MDP_HW_VSYNC_IRQ);
*/
mdp_vsync_handler(data);
return IRQ_HANDLED;
}
#ifdef MDP_HW_VSYNC
static void mdp_set_sync_cfg_0(struct msm_fb_data_type *mfd, int vsync_cnt)
{
unsigned long cfg;
cfg = mfd->total_lcd_lines - 1;
cfg <<= MDP_SYNCFG_HGT_LOC;
if (mfd->panel_info.lcd.hw_vsync_mode)
cfg |= MDP_SYNCFG_VSYNC_EXT_EN;
cfg |= (MDP_SYNCFG_VSYNC_INT_EN | vsync_cnt);
MDP_OUTP(MDP_BASE + MDP_SYNC_CFG_0, cfg);
}
#endif
void mdp_config_vsync(struct msm_fb_data_type *mfd)
{
/* vsync on primary lcd only for now */
if ((mfd->dest != DISPLAY_LCD) || (mfd->panel_info.pdest != DISPLAY_1)
|| (!vsync_mode)) {
goto err_handle;
}
if (mfd->panel_info.lcd.vsync_enable) {
mfd->total_porch_lines = mfd->panel_info.lcd.v_back_porch +
mfd->panel_info.lcd.v_front_porch +
mfd->panel_info.lcd.v_pulse_width;
mfd->total_lcd_lines =
mfd->panel_info.yres + mfd->total_porch_lines;
mfd->lcd_ref_usec_time =
100000000 / mfd->panel_info.lcd.refx100;
mfd->vsync_handler_pending = FALSE;
mfd->last_vsync_timetick.tv.sec = 0;
mfd->last_vsync_timetick.tv.nsec = 0;
#ifdef MDP_HW_VSYNC
if (mdp_vsync_clk == NULL)
mdp_vsync_clk = clk_get(NULL, "mdp_vsync_clk");
if (IS_ERR(mdp_vsync_clk)) {
printk(KERN_ERR "error: can't get mdp_vsync_clk!\n");
mfd->use_mdp_vsync = 0;
} else
mfd->use_mdp_vsync = 1;
if (mfd->use_mdp_vsync) {
uint32 vsync_cnt_cfg, vsync_cnt_cfg_dem;
uint32 mdp_vsync_clk_speed_hz;
mdp_vsync_clk_speed_hz = clk_get_rate(mdp_vsync_clk);
if (mdp_vsync_clk_speed_hz == 0) {
mfd->use_mdp_vsync = 0;
} else {
/*
* Do this calculation in 2 steps for
* rounding uint32 properly.
*/
vsync_cnt_cfg_dem =
(mfd->panel_info.lcd.refx100 *
mfd->total_lcd_lines) / 100;
vsync_cnt_cfg =
(mdp_vsync_clk_speed_hz) /
vsync_cnt_cfg_dem;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON,
FALSE);
mdp_hw_vsync_clk_enable(mfd);
mdp_set_sync_cfg_0(mfd, vsync_cnt_cfg);
/*
* load the last line + 1 to be in the
* safety zone
*/
vsync_load_cnt = mfd->panel_info.yres;
/* line counter init value at the next pulse */
MDP_OUTP(MDP_BASE + MDP_PRIM_VSYNC_INIT_VAL,
vsync_load_cnt);
/*
* external vsync source pulse width and
* polarity flip
*/
MDP_OUTP(MDP_BASE + MDP_PRIM_VSYNC_OUT_CTRL,
BIT(30) | BIT(0));
/* threshold */
MDP_OUTP(MDP_BASE + 0x200,
(vsync_above_th << 16) |
(vsync_start_th));
mdp_hw_vsync_clk_disable(mfd);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK,
MDP_BLOCK_POWER_OFF, FALSE);
}
}
#else
mfd->use_mdp_vsync = 0;
hrtimer_init(&mfd->dma_hrtimer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL);
mfd->dma_hrtimer.function = mdp_dma2_vsync_hrtimer_handler;
mfd->vsync_width_boundary = vmalloc(mfd->panel_info.xres * 4);
#endif
mfd->channel_irq = 0;
if (mfd->panel_info.lcd.hw_vsync_mode) {
u32 vsync_gpio = mfd->vsync_gpio;
u32 ret;
if (vsync_gpio == -1) {
MSM_FB_INFO("vsync_gpio not defined!\n");
goto err_handle;
}
ret = gpio_tlmm_config(GPIO_CFG
(vsync_gpio,
(mfd->use_mdp_vsync) ? 1 : 0,
GPIO_INPUT,
GPIO_PULL_DOWN,
GPIO_2MA),
GPIO_ENABLE);
if (ret)
goto err_handle;
if (!mfd->use_mdp_vsync) {
mfd->channel_irq = MSM_GPIO_TO_INT(vsync_gpio);
if (request_irq
(mfd->channel_irq,
&mdp_hw_vsync_handler_proxy,
IRQF_TRIGGER_FALLING, "VSYNC_GPIO",
(void *)mfd)) {
MSM_FB_INFO
("irq=%d failed! vsync_gpio=%d\n",
mfd->channel_irq,
vsync_gpio);
goto err_handle;
}
}
}
mdp_set_vsync((unsigned long)mfd);
}
return;
err_handle:
if (mfd->vsync_width_boundary)
vfree(mfd->vsync_width_boundary);
mfd->panel_info.lcd.vsync_enable = FALSE;
printk(KERN_ERR "%s: failed!\n", __func__);
}
void mdp_vsync_resync_workqueue_handler(struct work_struct *work)
{
struct msm_fb_data_type *mfd = NULL;
int vsync_fnc_enabled = FALSE;
struct msm_fb_panel_data *pdata = NULL;
mfd = container_of(work, struct msm_fb_data_type, vsync_resync_worker);
if (mfd) {
if (mfd->panel_power_on) {
pdata =
(struct msm_fb_panel_data *)mfd->pdev->dev.
platform_data;
/*
* we need to turn on MDP power if it uses MDP vsync
* HW block in SW mode
*/
if ((!mfd->panel_info.lcd.hw_vsync_mode) &&
(mfd->use_mdp_vsync) &&
(pdata) && (pdata->set_vsync_notifier != NULL)) {
/*
* enable pwr here since we can't enable it in
* vsync callback in isr mode
*/
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON,
FALSE);
}
if (pdata->set_vsync_notifier != NULL) {
vsync_fnc_enabled = TRUE;
pdata->set_vsync_notifier(mdp_vsync_handler,
(void *)mfd);
}
}
}
if ((mfd) && (!vsync_fnc_enabled))
mfd->vsync_handler_pending = FALSE;
}
boolean mdp_hw_vsync_set_handler(msm_fb_vsync_handler_type handler, void *data)
{
/*
* ToDo: tried enabling/disabling GPIO MDP HW VSYNC interrupt
* but getting inaccurate timing in mdp_vsync_handler()
* enable_irq(MDP_HW_VSYNC_IRQ);
*/
return TRUE;
}
uint32 mdp_get_lcd_line_counter(struct msm_fb_data_type *mfd)
{
uint32 elapsed_usec_time;
uint32 lcd_line;
ktime_t last_vsync_timetick_local;
ktime_t curr_time;
unsigned long flag;
if ((!mfd->panel_info.lcd.vsync_enable) || (!vsync_mode))
return 0;
spin_lock_irqsave(&mdp_spin_lock, flag);
last_vsync_timetick_local = mfd->last_vsync_timetick;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
curr_time = ktime_get_real();
elapsed_usec_time =
((curr_time.tv.sec - last_vsync_timetick_local.tv.sec) * 1000000) +
((curr_time.tv.nsec - last_vsync_timetick_local.tv.nsec) / 1000);
elapsed_usec_time = elapsed_usec_time % mfd->lcd_ref_usec_time;
/* lcd line calculation referencing to line counter = 0 */
lcd_line =
(elapsed_usec_time * mfd->total_lcd_lines) / mfd->lcd_ref_usec_time;
/* lcd line adjusment referencing to the actual line counter at vsync */
lcd_line =
(mfd->total_lcd_lines - mfd->panel_info.lcd.v_back_porch +
lcd_line) % (mfd->total_lcd_lines + 1);
if (lcd_line > mfd->total_lcd_lines) {
MSM_FB_INFO
("mdp_get_lcd_line_counter: mdp_lcd_rd_cnt >= mfd->total_lcd_lines error!\n");
}
return lcd_line;
}

View file

@ -0,0 +1,214 @@
/* arch/arm/mach-msm/memory.c
*
* Copyright (C) 2007 Google, Inc.
* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* 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.
*
*/
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/bootmem.h>
#include <linux/module.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/mach/map.h>
#include "memory_ll.h"
#include <asm/cacheflush.h>
#if defined(CONFIG_MSM_NPA_REMOTE)
#include "npa_remote.h"
#include <linux/completion.h>
#include <linux/err.h>
#endif
int arch_io_remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot)
{
unsigned long pfn_addr = pfn << PAGE_SHIFT;
/*
if ((pfn_addr >= 0x88000000) && (pfn_addr < 0xD0000000)) {
prot = pgprot_device(prot);
printk("remapping device %lx\n", prot);
}
*/
panic("Memory remap PFN stuff not done\n");
return remap_pfn_range(vma, addr, pfn, size, prot);
}
void *zero_page_strongly_ordered;
static void map_zero_page_strongly_ordered(void)
{
if (zero_page_strongly_ordered)
return;
/*
zero_page_strongly_ordered =
ioremap_strongly_ordered(page_to_pfn(empty_zero_page)
<< PAGE_SHIFT, PAGE_SIZE);
*/
panic("Strongly ordered memory functions not implemented\n");
}
void write_to_strongly_ordered_memory(void)
{
map_zero_page_strongly_ordered();
*(int *)zero_page_strongly_ordered = 0;
}
EXPORT_SYMBOL(write_to_strongly_ordered_memory);
void flush_axi_bus_buffer(void)
{
__asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
: : "r" (0) : "memory");
write_to_strongly_ordered_memory();
}
#define CACHE_LINE_SIZE 32
/* These cache related routines make the assumption that the associated
* physical memory is contiguous. They will operate on all (L1
* and L2 if present) caches.
*/
void clean_and_invalidate_caches(unsigned long vstart,
unsigned long length, unsigned long pstart)
{
unsigned long vaddr;
for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE)
asm ("mcr p15, 0, %0, c7, c14, 1" : : "r" (vaddr));
#ifdef CONFIG_OUTER_CACHE
outer_flush_range(pstart, pstart + length);
#endif
asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
flush_axi_bus_buffer();
}
void clean_caches(unsigned long vstart,
unsigned long length, unsigned long pstart)
{
unsigned long vaddr;
for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE)
asm ("mcr p15, 0, %0, c7, c10, 1" : : "r" (vaddr));
#ifdef CONFIG_OUTER_CACHE
outer_clean_range(pstart, pstart + length);
#endif
asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
flush_axi_bus_buffer();
}
void invalidate_caches(unsigned long vstart,
unsigned long length, unsigned long pstart)
{
unsigned long vaddr;
for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE)
asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (vaddr));
#ifdef CONFIG_OUTER_CACHE
outer_inv_range(pstart, pstart + length);
#endif
asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
flush_axi_bus_buffer();
}
void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment)
{
void *unused_addr = NULL;
unsigned long addr, tmp_size, unused_size;
/* Allocate maximum size needed, see where it ends up.
* Then free it -- in this path there are no other allocators
* so we can depend on getting the same address back
* when we allocate a smaller piece that is aligned
* at the end (if necessary) and the piece we really want,
* then free the unused first piece.
*/
tmp_size = size + alignment - PAGE_SIZE;
addr = (unsigned long)alloc_bootmem(tmp_size);
free_bootmem(__pa(addr), tmp_size);
unused_size = alignment - (addr % alignment);
if (unused_size)
unused_addr = alloc_bootmem(unused_size);
addr = (unsigned long)alloc_bootmem(size);
if (unused_size)
free_bootmem(__pa(unused_addr), unused_size);
return (void *)addr;
}
#if defined(CONFIG_MSM_NPA_REMOTE)
struct npa_client *npa_memory_client;
#endif
static int change_memory_power_state(unsigned long start_pfn,
unsigned long nr_pages, int state)
{
#if defined(CONFIG_MSM_NPA_REMOTE)
static atomic_t node_created_flag = ATOMIC_INIT(1);
#else
unsigned long start;
unsigned long size;
unsigned long virtual;
#endif
int rc = 0;
#if defined(CONFIG_MSM_NPA_REMOTE)
if (atomic_dec_and_test(&node_created_flag)) {
/* Create NPA 'required' client. */
npa_memory_client = npa_create_sync_client(NPA_MEMORY_NODE_NAME,
"memory node", NPA_CLIENT_REQUIRED);
if (IS_ERR(npa_memory_client)) {
rc = PTR_ERR(npa_memory_client);
return rc;
}
}
rc = npa_issue_required_request(npa_memory_client, state);
#else
if (state == MEMORY_DEEP_POWERDOWN) {
/* simulate turning off memory by writing bit pattern into it */
start = start_pfn << PAGE_SHIFT;
size = nr_pages << PAGE_SHIFT;
virtual = __phys_to_virt(start);
memset((void *)virtual, 0x27, size);
}
#endif
return rc;
}
int platform_physical_remove_pages(unsigned long start_pfn,
unsigned long nr_pages)
{
return change_memory_power_state(start_pfn, nr_pages,
MEMORY_DEEP_POWERDOWN);
}
int platform_physical_add_pages(unsigned long start_pfn,
unsigned long nr_pages)
{
return change_memory_power_state(start_pfn, nr_pages, MEMORY_ACTIVE);
}
int platform_physical_low_power_pages(unsigned long start_pfn,
unsigned long nr_pages)
{
return change_memory_power_state(start_pfn, nr_pages,
MEMORY_SELF_REFRESH);
}

View file

@ -0,0 +1,61 @@
/*
* Copyright (C) 2007 Google, Inc.
* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* 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.
*
*/
#ifndef __ASM_ARCH_MEMORY_LL_H
#define __ASM_ARCH_MEMORY_LL_H
#define MAX_PHYSMEM_BITS 32
#define SECTION_SIZE_BITS 25
#define HAS_ARCH_IO_REMAP_PFN_RANGE
#ifndef __ASSEMBLY__
void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment);
void clean_and_invalidate_caches(unsigned long, unsigned long, unsigned long);
void clean_caches(unsigned long, unsigned long, unsigned long);
void invalidate_caches(unsigned long, unsigned long, unsigned long);
int platform_physical_remove_pages(unsigned long, unsigned long);
int platform_physical_add_pages(unsigned long, unsigned long);
int platform_physical_low_power_pages(unsigned long, unsigned long);
#ifdef CONFIG_ARCH_MSM_ARM11
void write_to_strongly_ordered_memory(void);
#include <asm/mach-types.h>
#define arch_barrier_extra() do \
{ if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) \
write_to_strongly_ordered_memory(); \
} while (0)
#endif
#ifdef CONFIG_CACHE_L2X0
extern void l2x0_cache_sync(void);
#define finish_arch_switch(prev) do { l2x0_cache_sync(); } while (0)
#endif
#endif
#ifdef CONFIG_ARCH_MSM_SCORPION
#define arch_has_speculative_dfetch() 1
#endif
#endif
/* these correspond to values known by the modem */
#define MEMORY_DEEP_POWERDOWN 0
#define MEMORY_SELF_REFRESH 1
#define MEMORY_ACTIVE 2
#define NPA_MEMORY_NODE_NAME "/mem/ebi1/cs1"

2354
drivers/staging/msm/msm_fb.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,174 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MSM_FB_H
#define MSM_FB_H
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include "linux/proc_fs.h"
#include <mach/hardware.h>
#include <linux/io.h>
#include <mach/board.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <mach/memory.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/hrtimer.h>
#include <linux/fb.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include "msm_fb_panel.h"
#include "mdp.h"
#define MSM_FB_DEFAULT_PAGE_SIZE 2
#define MFD_KEY 0x11161126
#define MSM_FB_MAX_DEV_LIST 32
struct disp_info_type_suspend {
boolean op_enable;
boolean sw_refreshing_enable;
boolean panel_power_on;
};
struct msm_fb_data_type {
__u32 key;
__u32 index;
__u32 ref_cnt;
__u32 fb_page;
panel_id_type panel;
struct msm_panel_info panel_info;
DISP_TARGET dest;
struct fb_info *fbi;
boolean op_enable;
uint32 fb_imgType;
boolean sw_currently_refreshing;
boolean sw_refreshing_enable;
boolean hw_refresh;
MDPIBUF ibuf;
boolean ibuf_flushed;
struct timer_list refresh_timer;
struct completion refresher_comp;
boolean pan_waiting;
struct completion pan_comp;
/* vsync */
boolean use_mdp_vsync;
__u32 vsync_gpio;
__u32 total_lcd_lines;
__u32 total_porch_lines;
__u32 lcd_ref_usec_time;
__u32 refresh_timer_duration;
struct hrtimer dma_hrtimer;
boolean panel_power_on;
struct work_struct dma_update_worker;
struct semaphore sem;
struct timer_list vsync_resync_timer;
boolean vsync_handler_pending;
struct work_struct vsync_resync_worker;
ktime_t last_vsync_timetick;
__u32 *vsync_width_boundary;
unsigned int pmem_id;
struct disp_info_type_suspend suspend;
__u32 channel_irq;
struct mdp_dma_data *dma;
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;
void *cmd_port;
void *data_port;
void *data_port_phys;
__u32 bl_level;
struct platform_device *pdev;
__u32 var_xres;
__u32 var_yres;
__u32 var_pixclock;
#ifdef MSM_FB_ENABLE_DBGFS
struct dentry *sub_dir;
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
struct early_suspend mddi_early_suspend;
struct early_suspend mddi_ext_early_suspend;
#endif
u32 mdp_fb_page_protection;
int allow_set_offset;
};
struct dentry *msm_fb_get_debugfs_root(void);
void msm_fb_debugfs_file_create(struct dentry *root, const char *name,
u32 *var);
void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl,
u32 save);
void msm_fb_add_device(struct platform_device *pdev);
int msm_fb_detect_client(const char *name);
#ifdef CONFIG_FB_BACKLIGHT
void msm_fb_config_backlight(struct msm_fb_data_type *mfd);
#endif
#endif /* MSM_FB_H */

View file

@ -0,0 +1,79 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/backlight.h>
#include "msm_fb.h"
static int msm_fb_bl_get_brightness(struct backlight_device *pbd)
{
return pbd->props.brightness;
}
static int msm_fb_bl_update_status(struct backlight_device *pbd)
{
struct msm_fb_data_type *mfd = bl_get_data(pbd);
__u32 bl_lvl;
bl_lvl = pbd->props.brightness;
bl_lvl = mfd->fbi->bl_curve[bl_lvl];
msm_fb_set_backlight(mfd, bl_lvl, 1);
return 0;
}
static struct backlight_ops msm_fb_bl_ops = {
.get_brightness = msm_fb_bl_get_brightness,
.update_status = msm_fb_bl_update_status,
};
void msm_fb_config_backlight(struct msm_fb_data_type *mfd)
{
struct msm_fb_panel_data *pdata;
struct backlight_device *pbd;
struct fb_info *fbi;
char name[16];
fbi = mfd->fbi;
pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
if ((pdata) && (pdata->set_backlight)) {
snprintf(name, sizeof(name), "msmfb_bl%d", mfd->index);
pbd =
backlight_device_register(name, fbi->dev, mfd,
&msm_fb_bl_ops);
if (!IS_ERR(pbd)) {
fbi->bl_dev = pbd;
fb_bl_default_curve(fbi,
0,
mfd->panel_info.bl_min,
mfd->panel_info.bl_max);
pbd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
pbd->props.brightness = FB_BACKLIGHT_LEVELS - 1;
backlight_update_status(pbd);
} else {
fbi->bl_dev = NULL;
printk(KERN_ERR "msm_fb: backlight_device_register failed!\n");
}
}
}

View file

@ -0,0 +1,201 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MSM_FB_DEF_H
#define MSM_FB_DEF_H
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include "msm_mdp.h"
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <linux/debugfs.h>
#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include "linux/proc_fs.h"
#include <mach/hardware.h>
#include <linux/io.h>
#include <linux/fb.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/platform_device.h>
typedef s64 int64;
typedef s32 int32;
typedef s16 int16;
typedef s8 int8;
typedef u64 uint64;
typedef u32 uint32;
typedef u16 uint16;
typedef u8 uint8;
typedef s32 int4;
typedef s16 int2;
typedef s8 int1;
typedef u32 uint4;
typedef u16 uint2;
typedef u8 uint1;
typedef u32 dword;
typedef u16 word;
typedef u8 byte;
typedef unsigned int boolean;
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define MSM_FB_ENABLE_DBGFS
#define FEATURE_MDDI
#define outp32(addr, val) writel(val, addr)
#define outp16(addr, val) writew(val, addr)
#define outp8(addr, val) writeb(val, addr)
#define outp(addr, val) outp32(addr, val)
#ifndef MAX
#define MAX( x, y ) (((x) > (y)) ? (x) : (y))
#endif
#ifndef MIN
#define MIN( x, y ) (((x) < (y)) ? (x) : (y))
#endif
/*--------------------------------------------------------------------------*/
#define inp32(addr) readl(addr)
#define inp16(addr) readw(addr)
#define inp8(addr) readb(addr)
#define inp(addr) inp32(addr)
#define inpw(port) readw(port)
#define outpw(port, val) writew(val, port)
#define inpdw(port) readl(port)
#define outpdw(port, val) writel(val, port)
#define clk_busy_wait(x) msleep_interruptible((x)/1000)
#define memory_barrier()
#define assert(expr) \
if(!(expr)) { \
printk(KERN_ERR "msm_fb: assertion failed! %s,%s,%s,line=%d\n",\
#expr, __FILE__, __func__, __LINE__); \
}
#define ASSERT(x) assert(x)
#define DISP_EBI2_LOCAL_DEFINE
#ifdef DISP_EBI2_LOCAL_DEFINE
#define LCD_PRIM_BASE_PHYS 0x98000000
#define LCD_SECD_BASE_PHYS 0x9c000000
#define EBI2_PRIM_LCD_RS_PIN 0x20000
#define EBI2_SECD_LCD_RS_PIN 0x20000
#define EBI2_PRIM_LCD_CLR 0xC0
#define EBI2_PRIM_LCD_SEL 0x40
#define EBI2_SECD_LCD_CLR 0x300
#define EBI2_SECD_LCD_SEL 0x100
#endif
extern u32 msm_fb_msg_level;
/*
* Message printing priorities:
* LEVEL 0 KERN_EMERG (highest priority)
* LEVEL 1 KERN_ALERT
* LEVEL 2 KERN_CRIT
* LEVEL 3 KERN_ERR
* LEVEL 4 KERN_WARNING
* LEVEL 5 KERN_NOTICE
* LEVEL 6 KERN_INFO
* LEVEL 7 KERN_DEBUG (Lowest priority)
*/
#define MSM_FB_EMERG(msg, ...) \
if (msm_fb_msg_level > 0) \
printk(KERN_EMERG msg, ## __VA_ARGS__);
#define MSM_FB_ALERT(msg, ...) \
if (msm_fb_msg_level > 1) \
printk(KERN_ALERT msg, ## __VA_ARGS__);
#define MSM_FB_CRIT(msg, ...) \
if (msm_fb_msg_level > 2) \
printk(KERN_CRIT msg, ## __VA_ARGS__);
#define MSM_FB_ERR(msg, ...) \
if (msm_fb_msg_level > 3) \
printk(KERN_ERR msg, ## __VA_ARGS__);
#define MSM_FB_WARNING(msg, ...) \
if (msm_fb_msg_level > 4) \
printk(KERN_WARNING msg, ## __VA_ARGS__);
#define MSM_FB_NOTICE(msg, ...) \
if (msm_fb_msg_level > 5) \
printk(KERN_NOTICE msg, ## __VA_ARGS__);
#define MSM_FB_INFO(msg, ...) \
if (msm_fb_msg_level > 6) \
printk(KERN_INFO msg, ## __VA_ARGS__);
#define MSM_FB_DEBUG(msg, ...) \
if (msm_fb_msg_level > 7) \
printk(KERN_DEBUG msg, ## __VA_ARGS__);
#ifdef MSM_FB_C
unsigned char *msm_mdp_base;
unsigned char *msm_pmdh_base;
unsigned char *msm_emdh_base;
#else
extern unsigned char *msm_mdp_base;
extern unsigned char *msm_pmdh_base;
extern unsigned char *msm_emdh_base;
#endif
#endif /* MSM_FB_DEF_H */

View file

@ -0,0 +1,136 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <linux/debugfs.h>
#include "msm_fb_panel.h"
int panel_next_on(struct platform_device *pdev)
{
int ret = 0;
struct msm_fb_panel_data *pdata;
struct msm_fb_panel_data *next_pdata;
struct platform_device *next_pdev;
pdata = (struct msm_fb_panel_data *)pdev->dev.platform_data;
if (pdata) {
next_pdev = pdata->next;
if (next_pdev) {
next_pdata =
(struct msm_fb_panel_data *)next_pdev->dev.
platform_data;
if ((next_pdata) && (next_pdata->on))
ret = next_pdata->on(next_pdev);
}
}
return ret;
}
int panel_next_off(struct platform_device *pdev)
{
int ret = 0;
struct msm_fb_panel_data *pdata;
struct msm_fb_panel_data *next_pdata;
struct platform_device *next_pdev;
pdata = (struct msm_fb_panel_data *)pdev->dev.platform_data;
if (pdata) {
next_pdev = pdata->next;
if (next_pdev) {
next_pdata =
(struct msm_fb_panel_data *)next_pdev->dev.
platform_data;
if ((next_pdata) && (next_pdata->on))
ret = next_pdata->off(next_pdev);
}
}
return ret;
}
struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata,
u32 type, u32 id)
{
struct platform_device *this_dev = NULL;
char dev_name[16];
switch (type) {
case EBI2_PANEL:
snprintf(dev_name, sizeof(dev_name), "ebi2_lcd");
break;
case MDDI_PANEL:
snprintf(dev_name, sizeof(dev_name), "mddi");
break;
case EXT_MDDI_PANEL:
snprintf(dev_name, sizeof(dev_name), "mddi_ext");
break;
case TV_PANEL:
snprintf(dev_name, sizeof(dev_name), "tvenc");
break;
case HDMI_PANEL:
case LCDC_PANEL:
snprintf(dev_name, sizeof(dev_name), "lcdc");
break;
default:
return NULL;
}
if (pdata != NULL)
pdata->next = NULL;
else
return NULL;
this_dev =
platform_device_alloc(dev_name, ((u32) type << 16) | (u32) id);
if (this_dev) {
if (platform_device_add_data
(this_dev, pdata, sizeof(struct msm_fb_panel_data))) {
printk
("msm_fb_device_alloc: platform_device_add_data failed!\n");
platform_device_put(this_dev);
return NULL;
}
}
return this_dev;
}

View file

@ -0,0 +1,145 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MSM_FB_PANEL_H
#define MSM_FB_PANEL_H
#include "msm_fb_def.h"
struct msm_fb_data_type;
typedef void (*msm_fb_vsync_handler_type) (void *arg);
/* panel id type */
typedef struct panel_id_s {
uint16 id;
uint16 type;
} panel_id_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 */
/* panel class */
typedef enum {
DISPLAY_LCD = 0, /* lcd = ebi2/mddi */
DISPLAY_LCDC, /* lcdc */
DISPLAY_TV, /* TV Out */
DISPLAY_EXT_MDDI, /* External MDDI */
} DISP_TARGET;
/* panel device locaiton */
typedef enum {
DISPLAY_1 = 0, /* attached as first device */
DISPLAY_2, /* attached on second device */
MAX_PHYS_TARGET_NUM,
} DISP_TARGET_PHYS;
/* 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;
};
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;
};
struct mddi_panel_info {
__u32 vdopkt;
};
struct msm_panel_info {
__u32 xres;
__u32 yres;
__u32 bpp;
__u32 type;
__u32 wait_cycle;
DISP_TARGET_PHYS pdest;
__u32 bl_max;
__u32 bl_min;
__u32 fb_num;
__u32 clk_rate;
__u32 clk_min;
__u32 clk_max;
__u32 frame_count;
union {
struct mddi_panel_info mddi;
};
union {
struct lcd_panel_info lcd;
struct lcdc_panel_info lcdc;
};
};
struct msm_fb_panel_data {
struct msm_panel_info panel_info;
void (*set_rect) (int x, int y, int xres, int yres);
void (*set_vsync_notifier) (msm_fb_vsync_handler_type, void *arg);
void (*set_backlight) (struct msm_fb_data_type *);
/* function entry chain */
int (*on) (struct platform_device *pdev);
int (*off) (struct platform_device *pdev);
struct platform_device *next;
};
/*===========================================================================
FUNCTIONS PROTOTYPES
============================================================================*/
struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata,
u32 type, u32 id);
int panel_next_on(struct platform_device *pdev);
int panel_next_off(struct platform_device *pdev);
int lcdc_device_register(struct msm_panel_info *pinfo);
int mddi_toshiba_device_register(struct msm_panel_info *pinfo,
u32 channel, u32 panel);
#endif /* MSM_FB_PANEL_H */

View file

@ -0,0 +1,245 @@
/* include/linux/msm_mdp.h
*
* Copyright (C) 2007 Google Incorporated
* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* 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.
*/
#ifndef _MSM_MDP_H_
#define _MSM_MDP_H_
#include <linux/types.h>
#include <linux/fb.h>
#define MSMFB_IOCTL_MAGIC 'm'
#define MSMFB_GRP_DISP _IOW(MSMFB_IOCTL_MAGIC, 1, unsigned int)
#define MSMFB_BLIT _IOW(MSMFB_IOCTL_MAGIC, 2, unsigned int)
#define MSMFB_SUSPEND_SW_REFRESHER _IOW(MSMFB_IOCTL_MAGIC, 128, unsigned int)
#define MSMFB_RESUME_SW_REFRESHER _IOW(MSMFB_IOCTL_MAGIC, 129, unsigned int)
#define MSMFB_CURSOR _IOW(MSMFB_IOCTL_MAGIC, 130, struct fb_cursor)
#define MSMFB_SET_LUT _IOW(MSMFB_IOCTL_MAGIC, 131, struct fb_cmap)
#define MSMFB_HISTOGRAM _IOWR(MSMFB_IOCTL_MAGIC, 132, struct mdp_histogram)
/* new ioctls's for set/get ccs matrix */
#define MSMFB_GET_CCS_MATRIX _IOWR(MSMFB_IOCTL_MAGIC, 133, struct mdp_ccs)
#define MSMFB_SET_CCS_MATRIX _IOW(MSMFB_IOCTL_MAGIC, 134, struct mdp_ccs)
#define MSMFB_OVERLAY_SET _IOWR(MSMFB_IOCTL_MAGIC, 135, \
struct mdp_overlay)
#define MSMFB_OVERLAY_UNSET _IOW(MSMFB_IOCTL_MAGIC, 136, unsigned int)
#define MSMFB_OVERLAY_PLAY _IOW(MSMFB_IOCTL_MAGIC, 137, \
struct msmfb_overlay_data)
#define MSMFB_GET_PAGE_PROTECTION _IOR(MSMFB_IOCTL_MAGIC, 138, \
struct mdp_page_protection)
#define MSMFB_SET_PAGE_PROTECTION _IOW(MSMFB_IOCTL_MAGIC, 139, \
struct mdp_page_protection)
#define MSMFB_OVERLAY_GET _IOR(MSMFB_IOCTL_MAGIC, 140, \
struct mdp_overlay)
/* new ioctls for async MDP ops */
#define MSMFB_ASYNC_BLIT _IOW(MSMFB_IOCTL_MAGIC, 141, unsigned int)
#define MSMFB_BLIT_FLUSH _IOR(MSMFB_IOCTL_MAGIC, 142, unsigned int)
#define MDP_IMGTYPE2_START 0x10000
enum {
MDP_RGB_565, /* RGB 565 planer */
MDP_XRGB_8888, /* RGB 888 padded */
MDP_Y_CBCR_H2V2, /* Y and CbCr, pseudo planer w/ Cb is in MSB */
MDP_ARGB_8888, /* ARGB 888 */
MDP_RGB_888, /* RGB 888 planer */
MDP_Y_CRCB_H2V2, /* Y and CrCb, pseudo planer w/ Cr is in MSB */
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_RGBA_8888, /* ARGB 888 */
MDP_BGRA_8888, /* ABGR 888 */
MDP_Y_CRCB_H2V2_TILE, /* Y and CrCb, pseudo planer tile */
MDP_Y_CBCR_H2V2_TILE, /* Y and CbCr, pseudo planer tile */
MDP_IMGTYPE_LIMIT,
MDP_BGR_565 = MDP_IMGTYPE2_START, /* BGR 565 planer */
MDP_FB_FORMAT, /* framebuffer format */
MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */
};
enum {
PMEM_IMG,
FB_IMG,
};
/* mdp_blit_req flag values */
#define MDP_ROT_NOP 0
#define MDP_FLIP_LR 0x1
#define MDP_FLIP_UD 0x2
#define MDP_ROT_90 0x4
#define MDP_ROT_180 (MDP_FLIP_UD|MDP_FLIP_LR)
#define MDP_ROT_270 (MDP_ROT_90|MDP_FLIP_UD|MDP_FLIP_LR)
#define MDP_DITHER 0x8
#define MDP_BLUR 0x10
#define MDP_BLEND_FG_PREMULT 0x20000
#define MDP_DEINTERLACE 0x80000000
#define MDP_SHARPENING 0x40000000
#define MDP_NO_DMA_BARRIER_START 0x20000000
#define MDP_NO_DMA_BARRIER_END 0x10000000
#define MDP_NO_BLIT 0x08000000
#define MDP_BLIT_WITH_DMA_BARRIERS 0x000
#define MDP_BLIT_WITH_NO_DMA_BARRIERS \
(MDP_NO_DMA_BARRIER_START | MDP_NO_DMA_BARRIER_END)
#define MDP_TRANSP_NOP 0xffffffff
#define MDP_ALPHA_NOP 0xff
#define MDP_BLIT_SRC_GEM 0x02000000 /* set for GEM, clear for PMEM */
#define MDP_BLIT_DST_GEM 0x01000000 /* set for GEM, clear for PMEM */
#define MDP_FB_PAGE_PROTECTION_NONCACHED (0)
#define MDP_FB_PAGE_PROTECTION_WRITECOMBINE (1)
#define MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE (2)
#define MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE (3)
#define MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE (4)
/* Sentinel: Don't use! */
#define MDP_FB_PAGE_PROTECTION_INVALID (5)
/* Count of the number of MDP_FB_PAGE_PROTECTION_... values. */
#define MDP_NUM_FB_PAGE_PROTECTION_VALUES (5)
struct mdp_rect {
uint32_t x;
uint32_t y;
uint32_t w;
uint32_t h;
};
struct mdp_img {
uint32_t width;
uint32_t height;
uint32_t format;
uint32_t offset;
int memory_id; /* the file descriptor */
uint32_t priv;
};
/*
* {3x3} + {3} ccs matrix
*/
#define MDP_CCS_RGB2YUV 0
#define MDP_CCS_YUV2RGB 1
#define MDP_CCS_SIZE 9
#define MDP_BV_SIZE 3
struct mdp_ccs {
int direction; /* MDP_CCS_RGB2YUV or YUV2RGB */
uint16_t ccs[MDP_CCS_SIZE]; /* 3x3 color coefficients */
uint16_t bv[MDP_BV_SIZE]; /* 1x3 bias vector */
};
/* The version of the mdp_blit_req structure so that
* user applications can selectively decide which functionality
* to include
*/
#define MDP_BLIT_REQ_VERSION 2
struct mdp_blit_req {
struct mdp_img src;
struct mdp_img dst;
struct mdp_rect src_rect;
struct mdp_rect dst_rect;
uint32_t alpha;
uint32_t transp_mask;
uint32_t flags;
int sharpening_strength; /* -127 <--> 127, default 64 */
};
struct mdp_blit_req_list {
uint32_t count;
struct mdp_blit_req req[];
};
struct msmfb_data {
uint32_t offset;
int memory_id;
int id;
};
#define MSMFB_NEW_REQUEST -1
struct msmfb_overlay_data {
uint32_t id;
struct msmfb_data data;
};
struct msmfb_img {
uint32_t width;
uint32_t height;
uint32_t format;
};
struct mdp_overlay {
struct msmfb_img src;
struct mdp_rect src_rect;
struct mdp_rect dst_rect;
uint32_t z_order; /* stage number */
uint32_t is_fg; /* control alpha & transp */
uint32_t alpha;
uint32_t transp_mask;
uint32_t flags;
uint32_t id;
uint32_t user_data[8];
};
struct mdp_histogram {
uint32_t frame_cnt;
uint32_t bin_cnt;
uint32_t *r;
uint32_t *g;
uint32_t *b;
};
struct mdp_page_protection {
uint32_t page_protection;
};
struct msm_panel_common_pdata {
int gpio;
int (*backlight_level)(int level, int max, int min);
int (*pmic_backlight)(int level);
int (*panel_num)(void);
void (*panel_config_gpio)(int);
int *gpio_num;
};
struct lcdc_platform_data {
int (*lcdc_gpio_config)(int on);
void (*lcdc_power_save)(int);
};
struct tvenc_platform_data {
int (*pm_vid_en)(int on);
};
struct mddi_platform_data {
void (*mddi_power_save)(int on);
int (*mddi_sel_clk)(u32 *clk_rate);
};
struct msm_fb_platform_data {
int (*detect_client)(const char *name);
int mddi_prescan;
int (*allow_set_offset)(void);
};
struct msm_hdmi_platform_data {
int irq;
int (*cable_detect)(int insert);
};
#endif /*_MSM_MDP_H_*/

View file

@ -0,0 +1,323 @@
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/bootmem.h>
#include <linux/delay.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/io.h>
#include <asm/setup.h>
#include <mach/board.h>
#include <mach/irqs.h>
#include <mach/sirc.h>
#include <mach/gpio.h>
#include "msm_mdp.h"
#include "memory_ll.h"
//#include "android_pmem.h"
#include <mach/board.h>
#ifdef CONFIG_MSM_SOC_REV_A
#define MSM_SMI_BASE 0xE0000000
#else
#define MSM_SMI_BASE 0x00000000
#endif
#define TOUCHPAD_SUSPEND 34
#define TOUCHPAD_IRQ 38
#define MSM_PMEM_MDP_SIZE 0x1591000
#ifdef CONFIG_MSM_SOC_REV_A
#define SMEM_SPINLOCK_I2C "D:I2C02000021"
#else
#define SMEM_SPINLOCK_I2C "S:6"
#endif
#define MSM_PMEM_ADSP_SIZE 0x1C00000
#define MSM_FB_SIZE 0x500000
#define MSM_FB_SIZE_ST15 0x800000
#define MSM_AUDIO_SIZE 0x80000
#define MSM_GPU_PHYS_SIZE SZ_2M
#ifdef CONFIG_MSM_SOC_REV_A
#define MSM_SMI_BASE 0xE0000000
#else
#define MSM_SMI_BASE 0x00000000
#endif
#define MSM_SHARED_RAM_PHYS (MSM_SMI_BASE + 0x00100000)
#define MSM_PMEM_SMI_BASE (MSM_SMI_BASE + 0x02B00000)
#define MSM_PMEM_SMI_SIZE 0x01500000
#define MSM_FB_BASE MSM_PMEM_SMI_BASE
#define MSM_GPU_PHYS_BASE (MSM_FB_BASE + MSM_FB_SIZE)
#define MSM_PMEM_SMIPOOL_BASE (MSM_GPU_PHYS_BASE + MSM_GPU_PHYS_SIZE)
#define MSM_PMEM_SMIPOOL_SIZE (MSM_PMEM_SMI_SIZE - MSM_FB_SIZE \
- MSM_GPU_PHYS_SIZE)
#if defined(CONFIG_FB_MSM_MDP40)
#define MDP_BASE 0xA3F00000
#define PMDH_BASE 0xAD600000
#define EMDH_BASE 0xAD700000
#define TVENC_BASE 0xAD400000
#else
#define MDP_BASE 0xAA200000
#define PMDH_BASE 0xAA600000
#define EMDH_BASE 0xAA700000
#define TVENC_BASE 0xAA400000
#endif
#define PMEM_KERNEL_EBI1_SIZE (CONFIG_PMEM_KERNEL_SIZE * 1024 * 1024)
static struct resource msm_fb_resources[] = {
{
.flags = IORESOURCE_DMA,
}
};
static struct resource msm_mdp_resources[] = {
{
.name = "mdp",
.start = MDP_BASE,
.end = MDP_BASE + 0x000F0000 - 1,
.flags = IORESOURCE_MEM,
}
};
static struct platform_device msm_mdp_device = {
.name = "mdp",
.id = 0,
.num_resources = ARRAY_SIZE(msm_mdp_resources),
.resource = msm_mdp_resources,
};
static struct platform_device msm_lcdc_device = {
.name = "lcdc",
.id = 0,
};
static int msm_fb_detect_panel(const char *name)
{
int ret = -EPERM;
if (machine_is_qsd8x50_ffa() || machine_is_qsd8x50a_ffa()) {
if (!strncmp(name, "mddi_toshiba_wvga_pt", 20))
ret = 0;
else
ret = -ENODEV;
} else if ((machine_is_qsd8x50_surf() || machine_is_qsd8x50a_surf())
&& !strcmp(name, "lcdc_external"))
ret = 0;
else if (0 /*machine_is_qsd8x50_grapefruit() */) {
if (!strcmp(name, "lcdc_grapefruit_vga"))
ret = 0;
else
ret = -ENODEV;
} else if (machine_is_qsd8x50_st1()) {
if (!strcmp(name, "lcdc_st1_wxga"))
ret = 0;
else
ret = -ENODEV;
} else if (machine_is_qsd8x50a_st1_5()) {
if (!strcmp(name, "lcdc_st15") ||
!strcmp(name, "hdmi_sii9022"))
ret = 0;
else
ret = -ENODEV;
}
return ret;
}
/* Only allow a small subset of machines to set the offset via
FB PAN_DISPLAY */
static int msm_fb_allow_set_offset(void)
{
return (machine_is_qsd8x50_st1() ||
machine_is_qsd8x50a_st1_5()) ? 1 : 0;
}
static struct msm_fb_platform_data msm_fb_pdata = {
.detect_client = msm_fb_detect_panel,
.allow_set_offset = msm_fb_allow_set_offset,
};
static struct platform_device msm_fb_device = {
.name = "msm_fb",
.id = 0,
.num_resources = ARRAY_SIZE(msm_fb_resources),
.resource = msm_fb_resources,
.dev = {
.platform_data = &msm_fb_pdata,
}
};
static void __init qsd8x50_allocate_memory_regions(void)
{
void *addr;
unsigned long size;
if (machine_is_qsd8x50a_st1_5())
size = MSM_FB_SIZE_ST15;
else
size = MSM_FB_SIZE;
addr = alloc_bootmem(size); // (void *)MSM_FB_BASE;
if (!addr)
printk("Failed to allocate bootmem for framebuffer\n");
msm_fb_resources[0].start = __pa(addr);
msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
pr_info(KERN_ERR "using %lu bytes of SMI at %lx physical for fb\n",
size, (unsigned long)addr);
}
static int msm_fb_lcdc_gpio_config(int on)
{
// return 0;
if (machine_is_qsd8x50_st1()) {
if (on) {
gpio_set_value(32, 1);
mdelay(100);
gpio_set_value(20, 1);
gpio_set_value(17, 1);
gpio_set_value(19, 1);
} else {
gpio_set_value(17, 0);
gpio_set_value(19, 0);
gpio_set_value(20, 0);
mdelay(100);
gpio_set_value(32, 0);
}
} else if (machine_is_qsd8x50a_st1_5()) {
if (on) {
gpio_set_value(17, 1);
gpio_set_value(19, 1);
gpio_set_value(20, 1);
gpio_set_value(22, 0);
gpio_set_value(32, 1);
gpio_set_value(155, 1);
//st15_hdmi_power(1);
gpio_set_value(22, 1);
} else {
gpio_set_value(17, 0);
gpio_set_value(19, 0);
gpio_set_value(22, 0);
gpio_set_value(32, 0);
gpio_set_value(155, 0);
// st15_hdmi_power(0);
}
}
return 0;
}
static struct lcdc_platform_data lcdc_pdata = {
.lcdc_gpio_config = msm_fb_lcdc_gpio_config,
};
static struct msm_gpio msm_fb_st15_gpio_config_data[] = {
{ GPIO_CFG(17, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "lcdc_en0" },
{ GPIO_CFG(19, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "dat_pwr_sv" },
{ GPIO_CFG(20, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "lvds_pwr_dn" },
{ GPIO_CFG(22, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "lcdc_en1" },
{ GPIO_CFG(32, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "lcdc_en2" },
{ GPIO_CFG(103, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), "hdmi_irq" },
{ GPIO_CFG(155, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "hdmi_3v3" },
};
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = 98,
};
static struct platform_device *devices[] __initdata = {
&msm_fb_device,
};
static void __init msm_register_device(struct platform_device *pdev, void *data)
{
int ret;
pdev->dev.platform_data = data;
ret = platform_device_register(pdev);
if (ret)
dev_err(&pdev->dev,
"%s: platform_device_register() failed = %d\n",
__func__, ret);
}
void __init msm_fb_register_device(char *name, void *data)
{
if (!strncmp(name, "mdp", 3))
msm_register_device(&msm_mdp_device, data);
/*
else if (!strncmp(name, "pmdh", 4))
msm_register_device(&msm_mddi_device, data);
else if (!strncmp(name, "emdh", 4))
msm_register_device(&msm_mddi_ext_device, data);
else if (!strncmp(name, "ebi2", 4))
msm_register_device(&msm_ebi2_lcd_device, data);
else if (!strncmp(name, "tvenc", 5))
msm_register_device(&msm_tvenc_device, data);
else */
if (!strncmp(name, "lcdc", 4))
msm_register_device(&msm_lcdc_device, data);
/*else
printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
*/
}
static void __init msm_fb_add_devices(void)
{
int rc;
msm_fb_register_device("mdp", &mdp_pdata);
// msm_fb_register_device("pmdh", &mddi_pdata);
// msm_fb_register_device("emdh", &mddi_pdata);
// msm_fb_register_device("tvenc", 0);
if (machine_is_qsd8x50a_st1_5()) {
/* rc = st15_hdmi_vreg_init();
if (rc)
return;
*/
rc = msm_gpios_request_enable(
msm_fb_st15_gpio_config_data,
ARRAY_SIZE(msm_fb_st15_gpio_config_data));
if (rc) {
printk(KERN_ERR "%s: unable to init lcdc gpios\n",
__func__);
return;
}
msm_fb_register_device("lcdc", &lcdc_pdata);
} else
msm_fb_register_device("lcdc", 0);
}
int __init staging_init_pmem(void)
{
qsd8x50_allocate_memory_regions();
return 0;
}
int __init staging_init_devices(void)
{
platform_add_devices(devices, ARRAY_SIZE(devices));
msm_fb_add_devices();
return 0;
}
arch_initcall(staging_init_pmem);
arch_initcall(staging_init_devices);

View file

@ -0,0 +1,163 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include "msm_fb.h"
#include "tvenc.h"
#define NTSC_TV_DIMENSION_WIDTH 720
#define NTSC_TV_DIMENSION_HEIGHT 480
static int ntsc_off(struct platform_device *pdev);
static int ntsc_on(struct platform_device *pdev);
static int ntsc_on(struct platform_device *pdev)
{
uint32 reg = 0;
int ret = 0;
struct msm_fb_data_type *mfd;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */
if (mfd->panel.id == NTSC_M) {
/* Cr gain 11, Cb gain C6, y_gain 97 */
TV_OUT(TV_GAIN, 0x0081B697);
} else {
/* Cr gain 11, Cb gain C6, y_gain 97 */
TV_OUT(TV_GAIN, 0x008bc4a3);
reg |= TVENC_CTL_NTSCJ_MODE;
}
TV_OUT(TV_CGMS, 0x0);
/* NTSC Timing */
TV_OUT(TV_SYNC_1, 0x0020009e);
TV_OUT(TV_SYNC_2, 0x011306B4);
TV_OUT(TV_SYNC_3, 0x0006000C);
TV_OUT(TV_SYNC_4, 0x0028020D);
TV_OUT(TV_SYNC_5, 0x005E02FB);
TV_OUT(TV_SYNC_6, 0x0006000C);
TV_OUT(TV_SYNC_7, 0x00000012);
TV_OUT(TV_BURST_V1, 0x0013020D);
TV_OUT(TV_BURST_V2, 0x0014020C);
TV_OUT(TV_BURST_V3, 0x0013020D);
TV_OUT(TV_BURST_V4, 0x0014020C);
TV_OUT(TV_BURST_H, 0x00AE00F2);
TV_OUT(TV_SOL_REQ_ODD, 0x00280208);
TV_OUT(TV_SOL_REQ_EVEN, 0x00290209);
reg |= TVENC_CTL_TV_MODE_NTSC_M_PAL60;
reg |= TVENC_CTL_Y_FILTER_EN |
TVENC_CTL_CR_FILTER_EN |
TVENC_CTL_CB_FILTER_EN | TVENC_CTL_SINX_FILTER_EN;
#ifdef CONFIG_FB_MSM_TVOUT_SVIDEO
reg |= TVENC_CTL_S_VIDEO_EN;
#endif
TV_OUT(TV_LEVEL, 0x00000000); /* DC offset to 0. */
TV_OUT(TV_OFFSET, 0x008080f0);
#ifdef CONFIG_FB_MSM_MDP31
TV_OUT(TV_DAC_INTF, 0x29);
#endif
TV_OUT(TV_ENC_CTL, reg);
reg |= TVENC_CTL_ENC_EN;
TV_OUT(TV_ENC_CTL, reg);
return ret;
}
static int ntsc_off(struct platform_device *pdev)
{
TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */
return 0;
}
static int __init ntsc_probe(struct platform_device *pdev)
{
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = ntsc_probe,
.driver = {
.name = "tv_ntsc",
},
};
static struct msm_fb_panel_data ntsc_panel_data = {
.panel_info.xres = NTSC_TV_DIMENSION_WIDTH,
.panel_info.yres = NTSC_TV_DIMENSION_HEIGHT,
.panel_info.type = TV_PANEL,
.panel_info.pdest = DISPLAY_1,
.panel_info.wait_cycle = 0,
.panel_info.bpp = 16,
.panel_info.fb_num = 2,
.on = ntsc_on,
.off = ntsc_off,
};
static struct platform_device this_device = {
.name = "tv_ntsc",
.id = 0,
.dev = {
.platform_data = &ntsc_panel_data,
}
};
static int __init ntsc_init(void)
{
int ret;
ret = platform_driver_register(&this_driver);
if (!ret) {
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
}
return ret;
}
module_init(ntsc_init);

View file

@ -0,0 +1,213 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include "msm_fb.h"
#include "tvenc.h"
#ifdef CONFIG_FB_MSM_TVOUT_PAL_M
#define PAL_TV_DIMENSION_WIDTH 720
#define PAL_TV_DIMENSION_HEIGHT 480
#else
#define PAL_TV_DIMENSION_WIDTH 720
#define PAL_TV_DIMENSION_HEIGHT 576
#endif
static int pal_on(struct platform_device *pdev)
{
uint32 reg = 0;
int ret = 0;
struct msm_fb_data_type *mfd;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */
switch (mfd->panel.id) {
case PAL_BDGHIN:
/* Cr gain 11, Cb gain C6, y_gain 97 */
TV_OUT(TV_GAIN, 0x0088c1a0);
TV_OUT(TV_CGMS, 0x00012345);
TV_OUT(TV_TEST_MUX, 0x0);
/* PAL Timing */
TV_OUT(TV_SYNC_1, 0x00180097);
TV_OUT(TV_SYNC_2, 0x011f06c0);
TV_OUT(TV_SYNC_3, 0x0005000a);
TV_OUT(TV_SYNC_4, 0x00320271);
TV_OUT(TV_SYNC_5, 0x005602f9);
TV_OUT(TV_SYNC_6, 0x0005000a);
TV_OUT(TV_SYNC_7, 0x0000000f);
TV_OUT(TV_BURST_V1, 0x0012026e);
TV_OUT(TV_BURST_V2, 0x0011026d);
TV_OUT(TV_BURST_V3, 0x00100270);
TV_OUT(TV_BURST_V4, 0x0013026f);
TV_OUT(TV_BURST_H, 0x00af00ea);
TV_OUT(TV_SOL_REQ_ODD, 0x0030026e);
TV_OUT(TV_SOL_REQ_EVEN, 0x0031026f);
reg |= TVENC_CTL_TV_MODE_PAL_BDGHIN;
break;
case PAL_M:
/* Cr gain 11, Cb gain C6, y_gain 97 */
TV_OUT(TV_GAIN, 0x0081b697);
TV_OUT(TV_CGMS, 0x000af317);
TV_OUT(TV_TEST_MUX, 0x000001c3);
TV_OUT(TV_TEST_MODE, 0x00000002);
/* PAL Timing */
TV_OUT(TV_SYNC_1, 0x0020009e);
TV_OUT(TV_SYNC_2, 0x011306b4);
TV_OUT(TV_SYNC_3, 0x0006000c);
TV_OUT(TV_SYNC_4, 0x0028020D);
TV_OUT(TV_SYNC_5, 0x005e02fb);
TV_OUT(TV_SYNC_6, 0x0006000c);
TV_OUT(TV_SYNC_7, 0x00000012);
TV_OUT(TV_BURST_V1, 0x0012020b);
TV_OUT(TV_BURST_V2, 0x0016020c);
TV_OUT(TV_BURST_V3, 0x00150209);
TV_OUT(TV_BURST_V4, 0x0013020c);
TV_OUT(TV_BURST_H, 0x00bf010b);
TV_OUT(TV_SOL_REQ_ODD, 0x00280208);
TV_OUT(TV_SOL_REQ_EVEN, 0x00290209);
reg |= TVENC_CTL_TV_MODE_PAL_M;
break;
case PAL_N:
/* Cr gain 11, Cb gain C6, y_gain 97 */
TV_OUT(TV_GAIN, 0x0081b697);
TV_OUT(TV_CGMS, 0x000af317);
TV_OUT(TV_TEST_MUX, 0x000001c3);
TV_OUT(TV_TEST_MODE, 0x00000002);
/* PAL Timing */
TV_OUT(TV_SYNC_1, 0x00180097);
TV_OUT(TV_SYNC_2, 0x12006c0);
TV_OUT(TV_SYNC_3, 0x0005000a);
TV_OUT(TV_SYNC_4, 0x00320271);
TV_OUT(TV_SYNC_5, 0x005602f9);
TV_OUT(TV_SYNC_6, 0x0005000a);
TV_OUT(TV_SYNC_7, 0x0000000f);
TV_OUT(TV_BURST_V1, 0x0012026e);
TV_OUT(TV_BURST_V2, 0x0011026d);
TV_OUT(TV_BURST_V3, 0x00100270);
TV_OUT(TV_BURST_V4, 0x0013026f);
TV_OUT(TV_BURST_H, 0x00af00fa);
TV_OUT(TV_SOL_REQ_ODD, 0x0030026e);
TV_OUT(TV_SOL_REQ_EVEN, 0x0031026f);
reg |= TVENC_CTL_TV_MODE_PAL_N;
break;
default:
return -ENODEV;
}
reg |= TVENC_CTL_Y_FILTER_EN |
TVENC_CTL_CR_FILTER_EN |
TVENC_CTL_CB_FILTER_EN | TVENC_CTL_SINX_FILTER_EN;
#ifdef CONFIG_FB_MSM_TVOUT_SVIDEO
reg |= TVENC_CTL_S_VIDEO_EN;
#endif
TV_OUT(TV_LEVEL, 0x00000000); /* DC offset to 0. */
TV_OUT(TV_OFFSET, 0x008080f0);
#ifdef CONFIG_FB_MSM_MDP31
TV_OUT(TV_DAC_INTF, 0x29);
#endif
TV_OUT(TV_ENC_CTL, reg);
reg |= TVENC_CTL_ENC_EN;
TV_OUT(TV_ENC_CTL, reg);
return ret;
}
static int pal_off(struct platform_device *pdev)
{
TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */
return 0;
}
static int __init pal_probe(struct platform_device *pdev)
{
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = pal_probe,
.driver = {
.name = "tv_pal",
},
};
static struct msm_fb_panel_data pal_panel_data = {
.panel_info.xres = PAL_TV_DIMENSION_WIDTH,
.panel_info.yres = PAL_TV_DIMENSION_HEIGHT,
.panel_info.type = TV_PANEL,
.panel_info.pdest = DISPLAY_1,
.panel_info.wait_cycle = 0,
.panel_info.bpp = 16,
.panel_info.fb_num = 2,
.on = pal_on,
.off = pal_off,
};
static struct platform_device this_device = {
.name = "tv_pal",
.id = 0,
.dev = {
.platform_data = &pal_panel_data,
}
};
static int __init pal_init(void)
{
int ret;
ret = platform_driver_register(&this_driver);
if (!ret) {
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
}
return ret;
}
module_init(pal_init);

295
drivers/staging/msm/tvenc.c Normal file
View file

@ -0,0 +1,295 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/pm_qos_params.h>
#define TVENC_C
#include "tvenc.h"
#include "msm_fb.h"
static int tvenc_probe(struct platform_device *pdev);
static int tvenc_remove(struct platform_device *pdev);
static int tvenc_off(struct platform_device *pdev);
static int tvenc_on(struct platform_device *pdev);
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
static struct clk *tvenc_clk;
static struct clk *tvdac_clk;
static struct platform_driver tvenc_driver = {
.probe = tvenc_probe,
.remove = tvenc_remove,
.suspend = NULL,
// .suspend_late = NULL,
// .resume_early = NULL,
.resume = NULL,
.shutdown = NULL,
.driver = {
.name = "tvenc",
},
};
static struct tvenc_platform_data *tvenc_pdata;
static int tvenc_off(struct platform_device *pdev)
{
int ret = 0;
ret = panel_next_off(pdev);
clk_disable(tvenc_clk);
clk_disable(tvdac_clk);
if (tvenc_pdata && tvenc_pdata->pm_vid_en)
ret = tvenc_pdata->pm_vid_en(0);
//pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc",
// PM_QOS_DEFAULT_VALUE);
if (ret)
printk(KERN_ERR "%s: pm_vid_en(off) failed! %d\n",
__func__, ret);
return ret;
}
static int tvenc_on(struct platform_device *pdev)
{
int ret = 0;
// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc",
// 128000);
if (tvenc_pdata && tvenc_pdata->pm_vid_en)
ret = tvenc_pdata->pm_vid_en(1);
if (ret) {
printk(KERN_ERR "%s: pm_vid_en(on) failed! %d\n",
__func__, ret);
return ret;
}
clk_enable(tvenc_clk);
clk_enable(tvdac_clk);
ret = panel_next_on(pdev);
return ret;
}
void tvenc_gen_test_pattern(struct msm_fb_data_type *mfd)
{
uint32 reg = 0, i;
reg = readl(MSM_TV_ENC_CTL);
reg |= TVENC_CTL_TEST_PATT_EN;
for (i = 0; i < 3; i++) {
TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */
switch (i) {
/*
* TV Encoder - Color Bar Test Pattern
*/
case 0:
reg |= TVENC_CTL_TPG_CLRBAR;
break;
/*
* TV Encoder - Red Frame Test Pattern
*/
case 1:
reg |= TVENC_CTL_TPG_REDCLR;
break;
/*
* TV Encoder - Modulated Ramp Test Pattern
*/
default:
reg |= TVENC_CTL_TPG_MODRAMP;
break;
}
TV_OUT(TV_ENC_CTL, reg);
mdelay(5000);
switch (i) {
/*
* TV Encoder - Color Bar Test Pattern
*/
case 0:
reg &= ~TVENC_CTL_TPG_CLRBAR;
break;
/*
* TV Encoder - Red Frame Test Pattern
*/
case 1:
reg &= ~TVENC_CTL_TPG_REDCLR;
break;
/*
* TV Encoder - Modulated Ramp Test Pattern
*/
default:
reg &= ~TVENC_CTL_TPG_MODRAMP;
break;
}
}
}
static int tvenc_resource_initialized;
static int tvenc_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
int rc;
if (pdev->id == 0) {
tvenc_base = ioremap(pdev->resource[0].start,
pdev->resource[0].end -
pdev->resource[0].start + 1);
if (!tvenc_base) {
printk(KERN_ERR
"tvenc_base ioremap failed!\n");
return -ENOMEM;
}
tvenc_pdata = pdev->dev.platform_data;
tvenc_resource_initialized = 1;
return 0;
}
if (!tvenc_resource_initialized)
return -EPERM;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
return -ENOMEM;
if (tvenc_base == NULL)
return -ENOMEM;
mdp_dev = platform_device_alloc("mdp", pdev->id);
if (!mdp_dev)
return -ENOMEM;
/*
* link to the latest pdev
*/
mfd->pdev = mdp_dev;
mfd->dest = DISPLAY_TV;
/*
* alloc panel device data
*/
if (platform_device_add_data
(mdp_dev, pdev->dev.platform_data,
sizeof(struct msm_fb_panel_data))) {
printk(KERN_ERR "tvenc_probe: platform_device_add_data failed!\n");
platform_device_put(mdp_dev);
return -ENOMEM;
}
/*
* data chain
*/
pdata = mdp_dev->dev.platform_data;
pdata->on = tvenc_on;
pdata->off = tvenc_off;
pdata->next = pdev;
/*
* get/set panel specific fb info
*/
mfd->panel_info = pdata->panel_info;
mfd->fb_imgType = MDP_YCRYCB_H2V1;
/*
* set driver data
*/
platform_set_drvdata(mdp_dev, mfd);
/*
* register in mdp driver
*/
rc = platform_device_add(mdp_dev);
if (rc)
goto tvenc_probe_err;
pdev_list[pdev_list_cnt++] = pdev;
return 0;
tvenc_probe_err:
platform_device_put(mdp_dev);
return rc;
}
static int tvenc_remove(struct platform_device *pdev)
{
// pm_qos_remove_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc");
return 0;
}
static int tvenc_register_driver(void)
{
return platform_driver_register(&tvenc_driver);
}
static int __init tvenc_driver_init(void)
{
tvenc_clk = clk_get(NULL, "tv_enc_clk");
tvdac_clk = clk_get(NULL, "tv_dac_clk");
if (IS_ERR(tvenc_clk)) {
printk(KERN_ERR "error: can't get tvenc_clk!\n");
return IS_ERR(tvenc_clk);
}
if (IS_ERR(tvdac_clk)) {
printk(KERN_ERR "error: can't get tvdac_clk!\n");
return IS_ERR(tvdac_clk);
}
// pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc",
// PM_QOS_DEFAULT_VALUE);
return tvenc_register_driver();
}
module_init(tvenc_driver_init);

117
drivers/staging/msm/tvenc.h Normal file
View file

@ -0,0 +1,117 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TVENC_H
#define TVENC_H
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include "msm_fb_panel.h"
#define NTSC_M 0 /* North America, Korea */
#define NTSC_J 1 /* Japan */
#define PAL_BDGHIN 2 /* Non-argentina PAL-N */
#define PAL_M 3 /* PAL-M */
#define PAL_N 4 /* Argentina PAL-N */
/* 3.57954545 Mhz */
#define TVENC_CTL_TV_MODE_NTSC_M_PAL60 0
/* 3.57961149 Mhz */
#define TVENC_CTL_TV_MODE_PAL_M BIT(0)
/*non-Argintina = 4.3361875 Mhz */
#define TVENC_CTL_TV_MODE_PAL_BDGHIN BIT(1)
/*Argentina = 3.582055625 Mhz */
#define TVENC_CTL_TV_MODE_PAL_N (BIT(1)|BIT(0))
#define TVENC_CTL_ENC_EN BIT(2)
#define TVENC_CTL_CC_EN BIT(3)
#define TVENC_CTL_CGMS_EN BIT(4)
#define TVENC_CTL_MACRO_EN BIT(5)
#define TVENC_CTL_Y_FILTER_W_NOTCH BIT(6)
#define TVENC_CTL_Y_FILTER_WO_NOTCH 0
#define TVENC_CTL_Y_FILTER_EN BIT(7)
#define TVENC_CTL_CR_FILTER_EN BIT(8)
#define TVENC_CTL_CB_FILTER_EN BIT(9)
#define TVENC_CTL_SINX_FILTER_EN BIT(10)
#define TVENC_CTL_TEST_PATT_EN BIT(11)
#define TVENC_CTL_OUTPUT_INV BIT(12)
#define TVENC_CTL_PAL60_MODE BIT(13)
#define TVENC_CTL_NTSCJ_MODE BIT(14)
#define TVENC_CTL_TPG_CLRBAR 0
#define TVENC_CTL_TPG_MODRAMP BIT(15)
#define TVENC_CTL_TPG_REDCLR BIT(16)
#define TVENC_CTL_S_VIDEO_EN BIT(19)
#ifdef TVENC_C
void *tvenc_base;
#else
extern void *tvenc_base;
#endif
#define TV_OUT(reg, v) writel(v, tvenc_base + MSM_##reg)
#define MSM_TV_ENC_CTL 0x00
#define MSM_TV_LEVEL 0x04
#define MSM_TV_GAIN 0x08
#define MSM_TV_OFFSET 0x0c
#define MSM_TV_CGMS 0x10
#define MSM_TV_SYNC_1 0x14
#define MSM_TV_SYNC_2 0x18
#define MSM_TV_SYNC_3 0x1c
#define MSM_TV_SYNC_4 0x20
#define MSM_TV_SYNC_5 0x24
#define MSM_TV_SYNC_6 0x28
#define MSM_TV_SYNC_7 0x2c
#define MSM_TV_BURST_V1 0x30
#define MSM_TV_BURST_V2 0x34
#define MSM_TV_BURST_V3 0x38
#define MSM_TV_BURST_V4 0x3c
#define MSM_TV_BURST_H 0x40
#define MSM_TV_SOL_REQ_ODD 0x44
#define MSM_TV_SOL_REQ_EVEN 0x48
#define MSM_TV_DAC_CTL 0x4c
#define MSM_TV_TEST_MUX 0x50
#define MSM_TV_TEST_MODE 0x54
#define MSM_TV_TEST_MISR_RESET 0x58
#define MSM_TV_TEST_EXPORT_MISR 0x5c
#define MSM_TV_TEST_MISR_CURR_VAL 0x60
#define MSM_TV_TEST_SOF_CFG 0x64
#define MSM_TV_DAC_INTF 0x100
#endif /* TVENC_H */