diff options
author | Stepan Moskovchenko <stepanm@codeaurora.org> | 2010-05-19 11:03:30 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-06-04 13:38:54 -0700 |
commit | 9d20015391dfc47f6371492925cc0333ac403414 (patch) | |
tree | a3c376e4b042f7280d2c1c12f054c8810dc67fe4 /drivers/staging | |
parent | 34ef545aa8c68d91e2e503ac05c129094772afb4 (diff) |
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>
Diffstat (limited to 'drivers/staging')
70 files changed, 30037 insertions, 0 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 883c88f3de7..984a7544071 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -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 diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 352ca2a973c..9fa25133874 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -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/ diff --git a/drivers/staging/msm/Kconfig b/drivers/staging/msm/Kconfig new file mode 100644 index 00000000000..c57039f2060 --- /dev/null +++ b/drivers/staging/msm/Kconfig @@ -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 diff --git a/drivers/staging/msm/Makefile b/drivers/staging/msm/Makefile new file mode 100644 index 00000000000..98a0ce177cb --- /dev/null +++ b/drivers/staging/msm/Makefile @@ -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 diff --git a/drivers/staging/msm/TODO b/drivers/staging/msm/TODO new file mode 100644 index 00000000000..05107a7d516 --- /dev/null +++ b/drivers/staging/msm/TODO @@ -0,0 +1,3 @@ +- Merge this code with the existing MSM framebuffer +- General style clean ups. + diff --git a/drivers/staging/msm/ebi2_l2f.c b/drivers/staging/msm/ebi2_l2f.c new file mode 100644 index 00000000000..eea891d8f0f --- /dev/null +++ b/drivers/staging/msm/ebi2_l2f.c @@ -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); diff --git a/drivers/staging/msm/ebi2_lcd.c b/drivers/staging/msm/ebi2_lcd.c new file mode 100644 index 00000000000..b41e1230cec --- /dev/null +++ b/drivers/staging/msm/ebi2_lcd.c @@ -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);
\ No newline at end of file diff --git a/drivers/staging/msm/ebi2_tmd20.c b/drivers/staging/msm/ebi2_tmd20.c new file mode 100644 index 00000000000..d66d0397825 --- /dev/null +++ b/drivers/staging/msm/ebi2_tmd20.c @@ -0,0 +1,1122 @@ +/* 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> + +/* #define TMD20QVGA_LCD_18BPP */ +#define QVGA_WIDTH 240 +#define QVGA_HEIGHT 320 + +#ifdef TMD20QVGA_LCD_18BPP +#define DISP_QVGA_18BPP(x) ((((x)<<2) & 0x3FC00)|(( (x)<<1)& 0x1FE)) +#define DISP_REG(name) uint32 register_##name; +#define OUTPORT(x, y) outpdw(x, y) +#define INPORT(x) inpdw(x) +#else +#define DISP_QVGA_18BPP(x) (x) +#define DISP_REG(name) uint16 register_##name; +#define OUTPORT(x, y) outpw(x, y) +#define INPORT(x) intpw(x) +#endif + +static void *DISP_CMD_PORT; +static void *DISP_DATA_PORT; + +#define DISP_RNTI 0x10 + +#define DISP_CMD_OUT(cmd) OUTPORT(DISP_CMD_PORT, DISP_QVGA_18BPP(cmd)) +#define DISP_DATA_OUT(data) OUTPORT(DISP_DATA_PORT, data) +#define DISP_DATA_IN() INPORT(DISP_DATA_PORT) + +#if (defined(TMD20QVGA_LCD_18BPP)) +#define DISP_DATA_OUT_16TO18BPP(x) \ + DISP_DATA_OUT((((x)&0xf800)<<2|((x)&0x80000)>>3) \ + | (((x)&0x7e0)<<1) \ + | (((x)&0x1F)<<1|((x)&0x10)>>4)) +#else +#define DISP_DATA_OUT_16TO18BPP(x) \ + DISP_DATA_OUT(x) +#endif + +#define DISP_WRITE_OUT(addr, data) \ + register_##addr = DISP_QVGA_18BPP(data); \ + DISP_CMD_OUT(addr); \ + DISP_DATA_OUT(register_##addr); + +#define DISP_UPDATE_VALUE(addr, bitmask, data) \ + DISP_WRITE_OUT(##addr, (register_##addr & ~(bitmask)) | (data)); + +#define DISP_VAL_IF(bitvalue, bitmask) \ + ((bitvalue) ? (bitmask) : 0) + +/* QVGA = 256 x 320 */ +/* actual display is 240 x 320...offset by 0x10 */ +#define DISP_ROW_COL_TO_ADDR(row, col) ((row) * 0x100 + col) +#define DISP_SET_RECT(ulhc_row, lrhc_row, ulhc_col, lrhc_col) \ + { \ + DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_1_ADDR, (ulhc_col) + tmd20qvga_panel_offset); \ + DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_2_ADDR, (lrhc_col) + tmd20qvga_panel_offset); \ + DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_1_ADDR, (ulhc_row)); \ + DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_2_ADDR, (lrhc_row)); \ + DISP_WRITE_OUT(DISP_RAM_ADDR_SET_1_ADDR, (ulhc_col) + tmd20qvga_panel_offset); \ + DISP_WRITE_OUT(DISP_RAM_ADDR_SET_2_ADDR, (ulhc_row)); \ + } + +#define WAIT_MSEC(msec) mdelay(msec) + +/* + * TMD QVGA Address + */ +/* Display Control */ +#define DISP_START_OSCILLATION_ADDR 0x000 +DISP_REG(DISP_START_OSCILLATION_ADDR) +#define DISP_DRIVER_OUTPUT_CTL_ADDR 0x001 + DISP_REG(DISP_DRIVER_OUTPUT_CTL_ADDR) +#define DISP_LCD_DRIVING_SIG_ADDR 0x002 + DISP_REG(DISP_LCD_DRIVING_SIG_ADDR) +#define DISP_ENTRY_MODE_ADDR 0x003 + DISP_REG(DISP_ENTRY_MODE_ADDR) +#define DISP_DISPLAY_CTL_1_ADDR 0x007 + DISP_REG(DISP_DISPLAY_CTL_1_ADDR) +#define DISP_DISPLAY_CTL_2_ADDR 0x008 + DISP_REG(DISP_DISPLAY_CTL_2_ADDR) + +/* DISPLAY MODE 0x009 partial display not supported */ +#define DISP_POWER_SUPPLY_INTF_ADDR 0x00A + DISP_REG(DISP_POWER_SUPPLY_INTF_ADDR) + +/* DISPLAY MODE 0x00B xZoom feature is not supported */ +#define DISP_EXT_DISPLAY_CTL_1_ADDR 0x00C + DISP_REG(DISP_EXT_DISPLAY_CTL_1_ADDR) + +#define DISP_FRAME_CYCLE_CTL_ADDR 0x00D + DISP_REG(DISP_FRAME_CYCLE_CTL_ADDR) + +#define DISP_EXT_DISPLAY_CTL_2_ADDR 0x00E + DISP_REG(DISP_EXT_DISPLAY_CTL_2_ADDR) + +#define DISP_EXT_DISPLAY_CTL_3_ADDR 0x00F + DISP_REG(DISP_EXT_DISPLAY_CTL_3_ADDR) + +#define DISP_LTPS_CTL_1_ADDR 0x012 + DISP_REG(DISP_LTPS_CTL_1_ADDR) +#define DISP_LTPS_CTL_2_ADDR 0x013 + DISP_REG(DISP_LTPS_CTL_2_ADDR) +#define DISP_LTPS_CTL_3_ADDR 0x014 + DISP_REG(DISP_LTPS_CTL_3_ADDR) +#define DISP_LTPS_CTL_4_ADDR 0x018 + DISP_REG(DISP_LTPS_CTL_4_ADDR) +#define DISP_LTPS_CTL_5_ADDR 0x019 + DISP_REG(DISP_LTPS_CTL_5_ADDR) +#define DISP_LTPS_CTL_6_ADDR 0x01A + DISP_REG(DISP_LTPS_CTL_6_ADDR) +#define DISP_AMP_SETTING_ADDR 0x01C + DISP_REG(DISP_AMP_SETTING_ADDR) +#define DISP_MODE_SETTING_ADDR 0x01D + DISP_REG(DISP_MODE_SETTING_ADDR) +#define DISP_POFF_LN_SETTING_ADDR 0x01E + DISP_REG(DISP_POFF_LN_SETTING_ADDR) +/* Power Contol */ +#define DISP_POWER_CTL_1_ADDR 0x100 + DISP_REG(DISP_POWER_CTL_1_ADDR) +#define DISP_POWER_CTL_2_ADDR 0x101 + DISP_REG(DISP_POWER_CTL_2_ADDR) +#define DISP_POWER_CTL_3_ADDR 0x102 + DISP_REG(DISP_POWER_CTL_3_ADDR) +#define DISP_POWER_CTL_4_ADDR 0x103 + DISP_REG(DISP_POWER_CTL_4_ADDR) +#define DISP_POWER_CTL_5_ADDR 0x104 + DISP_REG(DISP_POWER_CTL_5_ADDR) +#define DISP_POWER_CTL_6_ADDR 0x105 + DISP_REG(DISP_POWER_CTL_6_ADDR) +#define DISP_POWER_CTL_7_ADDR 0x106 + DISP_REG(DISP_POWER_CTL_7_ADDR) +/* RAM Access */ +#define DISP_RAM_ADDR_SET_1_ADDR 0x200 + DISP_REG(DISP_RAM_ADDR_SET_1_ADDR) +#define DISP_RAM_ADDR_SET_2_ADDR 0x201 + DISP_REG(DISP_RAM_ADDR_SET_2_ADDR) +#define DISP_CMD_RAMRD DISP_CMD_RAMWR +#define DISP_CMD_RAMWR 0x202 + DISP_REG(DISP_CMD_RAMWR) +#define DISP_RAM_DATA_MASK_1_ADDR 0x203 + DISP_REG(DISP_RAM_DATA_MASK_1_ADDR) +#define DISP_RAM_DATA_MASK_2_ADDR 0x204 + DISP_REG(DISP_RAM_DATA_MASK_2_ADDR) +/* Gamma Control, Contrast, Gray Scale Setting */ +#define DISP_GAMMA_CONTROL_1_ADDR 0x300 + DISP_REG(DISP_GAMMA_CONTROL_1_ADDR) +#define DISP_GAMMA_CONTROL_2_ADDR 0x301 + DISP_REG(DISP_GAMMA_CONTROL_2_ADDR) +#define DISP_GAMMA_CONTROL_3_ADDR 0x302 + DISP_REG(DISP_GAMMA_CONTROL_3_ADDR) +#define DISP_GAMMA_CONTROL_4_ADDR 0x303 + DISP_REG(DISP_GAMMA_CONTROL_4_ADDR) +#define DISP_GAMMA_CONTROL_5_ADDR 0x304 + DISP_REG(DISP_GAMMA_CONTROL_5_ADDR) +/* Coordinate Control */ +#define DISP_VERT_SCROLL_CTL_1_ADDR 0x400 + DISP_REG(DISP_VERT_SCROLL_CTL_1_ADDR) +#define DISP_VERT_SCROLL_CTL_2_ADDR 0x401 + DISP_REG(DISP_VERT_SCROLL_CTL_2_ADDR) +#define DISP_SCREEN_1_DRV_POS_1_ADDR 0x402 + DISP_REG(DISP_SCREEN_1_DRV_POS_1_ADDR) +#define DISP_SCREEN_1_DRV_POS_2_ADDR 0x403 + DISP_REG(DISP_SCREEN_1_DRV_POS_2_ADDR) +#define DISP_SCREEN_2_DRV_POS_1_ADDR 0x404 + DISP_REG(DISP_SCREEN_2_DRV_POS_1_ADDR) +#define DISP_SCREEN_2_DRV_POS_2_ADDR 0x405 + DISP_REG(DISP_SCREEN_2_DRV_POS_2_ADDR) +#define DISP_HORZ_RAM_ADDR_POS_1_ADDR 0x406 + DISP_REG(DISP_HORZ_RAM_ADDR_POS_1_ADDR) +#define DISP_HORZ_RAM_ADDR_POS_2_ADDR 0x407 + DISP_REG(DISP_HORZ_RAM_ADDR_POS_2_ADDR) +#define DISP_VERT_RAM_ADDR_POS_1_ADDR 0x408 + DISP_REG(DISP_VERT_RAM_ADDR_POS_1_ADDR) +#define DISP_VERT_RAM_ADDR_POS_2_ADDR 0x409 + DISP_REG(DISP_VERT_RAM_ADDR_POS_2_ADDR) +#define DISP_TMD_700_ADDR 0x700 /* 0x700 */ + DISP_REG(DISP_TMD_700_ADDR) +#define DISP_TMD_015_ADDR 0x015 /* 0x700 */ + DISP_REG(DISP_TMD_015_ADDR) +#define DISP_TMD_305_ADDR 0x305 /* 0x700 */ + DISP_REG(DISP_TMD_305_ADDR) + +/* + * TMD QVGA Bit Definations + */ + +#define DISP_BIT_IB15 0x8000 +#define DISP_BIT_IB14 0x4000 +#define DISP_BIT_IB13 0x2000 +#define DISP_BIT_IB12 0x1000 +#define DISP_BIT_IB11 0x0800 +#define DISP_BIT_IB10 0x0400 +#define DISP_BIT_IB09 0x0200 +#define DISP_BIT_IB08 0x0100 +#define DISP_BIT_IB07 0x0080 +#define DISP_BIT_IB06 0x0040 +#define DISP_BIT_IB05 0x0020 +#define DISP_BIT_IB04 0x0010 +#define DISP_BIT_IB03 0x0008 +#define DISP_BIT_IB02 0x0004 +#define DISP_BIT_IB01 0x0002 +#define DISP_BIT_IB00 0x0001 +/* + * Display Control + * DISP_START_OSCILLATION_ADDR Start Oscillation + * DISP_DRIVER_OUTPUT_CTL_ADDR Driver Output Control + */ +#define DISP_BITMASK_SS DISP_BIT_IB08 +#define DISP_BITMASK_NL5 DISP_BIT_IB05 +#define DISP_BITMASK_NL4 DISP_BIT_IB04 +#define DISP_BITMASK_NL3 DISP_BIT_IB03 +#define DISP_BITMASK_NL2 DISP_BIT_IB02 +#define DISP_BITMASK_NL1 DISP_BIT_IB01 +#define DISP_BITMASK_NL0 DISP_BIT_IB00 +/* DISP_LCD_DRIVING_SIG_ADDR LCD Driving Signal Setting */ +#define DISP_BITMASK_BC DISP_BIT_IB09 +/* DISP_ENTRY_MODE_ADDR Entry Mode */ +#define DISP_BITMASK_TRI DISP_BIT_IB15 +#define DISP_BITMASK_DFM1 DISP_BIT_IB14 +#define DISP_BITMASK_DFM0 DISP_BIT_IB13 +#define DISP_BITMASK_BGR DISP_BIT_IB12 +#define DISP_BITMASK_HWM0 DISP_BIT_IB08 +#define DISP_BITMASK_ID1 DISP_BIT_IB05 +#define DISP_BITMASK_ID0 DISP_BIT_IB04 +#define DISP_BITMASK_AM DISP_BIT_IB03 +/* DISP_DISPLAY_CTL_1_ADDR Display Control (1) */ +#define DISP_BITMASK_COL1 DISP_BIT_IB15 +#define DISP_BITMASK_COL0 DISP_BIT_IB14 +#define DISP_BITMASK_VLE2 DISP_BIT_IB10 +#define DISP_BITMASK_VLE1 DISP_BIT_IB09 +#define DISP_BITMASK_SPT DISP_BIT_IB08 +#define DISP_BITMASK_PT1 DISP_BIT_IB07 +#define DISP_BITMASK_PT0 DISP_BIT_IB06 +#define DISP_BITMASK_REV DISP_BIT_IB02 +/* DISP_DISPLAY_CTL_2_ADDR Display Control (2) */ +#define DISP_BITMASK_FP3 DISP_BIT_IB11 +#define DISP_BITMASK_FP2 DISP_BIT_IB10 +#define DISP_BITMASK_FP1 DISP_BIT_IB09 +#define DISP_BITMASK_FP0 DISP_BIT_IB08 +#define DISP_BITMASK_BP3 DISP_BIT_IB03 +#define DISP_BITMASK_BP2 DISP_BIT_IB02 +#define DISP_BITMASK_BP1 DISP_BIT_IB01 +#define DISP_BITMASK_BP0 DISP_BIT_IB00 +/* DISP_POWER_SUPPLY_INTF_ADDR Power Supply IC Interface Control */ +#define DISP_BITMASK_CSE DISP_BIT_IB12 +#define DISP_BITMASK_TE DISP_BIT_IB08 +#define DISP_BITMASK_IX3 DISP_BIT_IB03 +#define DISP_BITMASK_IX2 DISP_BIT_IB02 +#define DISP_BITMASK_IX1 DISP_BIT_IB01 +#define DISP_BITMASK_IX0 DISP_BIT_IB00 +/* DISP_EXT_DISPLAY_CTL_1_ADDR External Display Interface Control (1) */ +#define DISP_BITMASK_RM DISP_BIT_IB08 +#define DISP_BITMASK_DM1 DISP_BIT_IB05 +#define DISP_BITMASK_DM0 DISP_BIT_IB04 +#define DISP_BITMASK_RIM1 DISP_BIT_IB01 +#define DISP_BITMASK_RIM0 DISP_BIT_IB00 +/* DISP_FRAME_CYCLE_CTL_ADDR Frame Frequency Adjustment Control */ +#define DISP_BITMASK_DIVI1 DISP_BIT_IB09 +#define DISP_BITMASK_DIVI0 DISP_BIT_IB08 +#define DISP_BITMASK_RTNI4 DISP_BIT_IB04 +#define DISP_BITMASK_RTNI3 DISP_BIT_IB03 +#define DISP_BITMASK_RTNI2 DISP_BIT_IB02 +#define DISP_BITMASK_RTNI1 DISP_BIT_IB01 +#define DISP_BITMASK_RTNI0 DISP_BIT_IB00 +/* DISP_EXT_DISPLAY_CTL_2_ADDR External Display Interface Control (2) */ +#define DISP_BITMASK_DIVE1 DISP_BIT_IB09 +#define DISP_BITMASK_DIVE0 DISP_BIT_IB08 +#define DISP_BITMASK_RTNE7 DISP_BIT_IB07 +#define DISP_BITMASK_RTNE6 DISP_BIT_IB06 +#define DISP_BITMASK_RTNE5 DISP_BIT_IB05 +#define DISP_BITMASK_RTNE4 DISP_BIT_IB04 +#define DISP_BITMASK_RTNE3 DISP_BIT_IB03 +#define DISP_BITMASK_RTNE2 DISP_BIT_IB02 +#define DISP_BITMASK_RTNE1 DISP_BIT_IB01 +#define DISP_BITMASK_RTNE0 DISP_BIT_IB00 +/* DISP_EXT_DISPLAY_CTL_3_ADDR External Display Interface Control (3) */ +#define DISP_BITMASK_VSPL DISP_BIT_IB04 +#define DISP_BITMASK_HSPL DISP_BIT_IB03 +#define DISP_BITMASK_VPL DISP_BIT_IB02 +#define DISP_BITMASK_EPL DISP_BIT_IB01 +#define DISP_BITMASK_DPL DISP_BIT_IB00 +/* DISP_LTPS_CTL_1_ADDR LTPS Interface Control (1) */ +#define DISP_BITMASK_CLWI3 DISP_BIT_IB11 +#define DISP_BITMASK_CLWI2 DISP_BIT_IB10 +#define DISP_BITMASK_CLWI1 DISP_BIT_IB09 +#define DISP_BITMASK_CLWI0 DISP_BIT_IB08 +#define DISP_BITMASK_CLTI1 DISP_BIT_IB01 +#define DISP_BITMASK_CLTI0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_2_ADDR LTPS Interface Control (2) */ +#define DISP_BITMASK_OEVBI1 DISP_BIT_IB09 +#define DISP_BITMASK_OEVBI0 DISP_BIT_IB08 +#define DISP_BITMASK_OEVFI1 DISP_BIT_IB01 +#define DISP_BITMASK_OEVFI0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_3_ADDR LTPS Interface Control (3) */ +#define DISP_BITMASK_SHI1 DISP_BIT_IB01 +#define DISP_BITMASK_SHI0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_4_ADDR LTPS Interface Control (4) */ +#define DISP_BITMASK_CLWE5 DISP_BIT_IB13 +#define DISP_BITMASK_CLWE4 DISP_BIT_IB12 +#define DISP_BITMASK_CLWE3 DISP_BIT_IB11 +#define DISP_BITMASK_CLWE2 DISP_BIT_IB10 +#define DISP_BITMASK_CLWE1 DISP_BIT_IB09 +#define DISP_BITMASK_CLWE0 DISP_BIT_IB08 +#define DISP_BITMASK_CLTE3 DISP_BIT_IB03 +#define DISP_BITMASK_CLTE2 DISP_BIT_IB02 +#define DISP_BITMASK_CLTE1 DISP_BIT_IB01 +#define DISP_BITMASK_CLTE0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_5_ADDR LTPS Interface Control (5) */ +#define DISP_BITMASK_OEVBE3 DISP_BIT_IB11 +#define DISP_BITMASK_OEVBE2 DISP_BIT_IB10 +#define DISP_BITMASK_OEVBE1 DISP_BIT_IB09 +#define DISP_BITMASK_OEVBE0 DISP_BIT_IB08 +#define DISP_BITMASK_OEVFE3 DISP_BIT_IB03 +#define DISP_BITMASK_OEVFE2 DISP_BIT_IB02 +#define DISP_BITMASK_OEVFE1 DISP_BIT_IB01 +#define DISP_BITMASK_OEVFE0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_6_ADDR LTPS Interface Control (6) */ +#define DISP_BITMASK_SHE3 DISP_BIT_IB03 +#define DISP_BITMASK_SHE2 DISP_BIT_IB02 +#define DISP_BITMASK_SHE1 DISP_BIT_IB01 +#define DISP_BITMASK_SHE0 DISP_BIT_IB00 +/* DISP_AMP_SETTING_ADDR Amplify Setting */ +#define DISP_BITMASK_ABSW1 DISP_BIT_IB01 +#define DISP_BITMASK_ABSW0 DISP_BIT_IB00 +/* DISP_MODE_SETTING_ADDR Mode Setting */ +#define DISP_BITMASK_DSTB DISP_BIT_IB02 +#define DISP_BITMASK_STB DISP_BIT_IB00 +/* DISP_POFF_LN_SETTING_ADDR Power Off Line Setting */ +#define DISP_BITMASK_POFH3 DISP_BIT_IB03 +#define DISP_BITMASK_POFH2 DISP_BIT_IB02 +#define DISP_BITMASK_POFH1 DISP_BIT_IB01 +#define DISP_BITMASK_POFH0 DISP_BIT_IB00 + +/* Power Contol */ +/* DISP_POWER_CTL_1_ADDR Power Control (1) */ +#define DISP_BITMASK_PO DISP_BIT_IB11 +#define DISP_BITMASK_VCD DISP_BIT_IB09 +#define DISP_BITMASK_VSC DISP_BIT_IB08 +#define DISP_BITMASK_CON DISP_BIT_IB07 +#define DISP_BITMASK_ASW1 DISP_BIT_IB06 +#define DISP_BITMASK_ASW0 DISP_BIT_IB05 +#define DISP_BITMASK_OEV DISP_BIT_IB04 +#define DISP_BITMASK_OEVE DISP_BIT_IB03 +#define DISP_BITMASK_FR DISP_BIT_IB02 +#define DISP_BITMASK_D1 DISP_BIT_IB01 +#define DISP_BITMASK_D0 DISP_BIT_IB00 +/* DISP_POWER_CTL_2_ADDR Power Control (2) */ +#define DISP_BITMASK_DC4 DISP_BIT_IB15 +#define DISP_BITMASK_DC3 DISP_BIT_IB14 +#define DISP_BITMASK_SAP2 DISP_BIT_IB13 +#define DISP_BITMASK_SAP1 DISP_BIT_IB12 +#define DISP_BITMASK_SAP0 DISP_BIT_IB11 +#define DISP_BITMASK_BT2 DISP_BIT_IB10 +#define DISP_BITMASK_BT1 DISP_BIT_IB09 +#define DISP_BITMASK_BT0 DISP_BIT_IB08 +#define DISP_BITMASK_DC2 DISP_BIT_IB07 +#define DISP_BITMASK_DC1 DISP_BIT_IB06 +#define DISP_BITMASK_DC0 DISP_BIT_IB05 +#define DISP_BITMASK_AP2 DISP_BIT_IB04 +#define DISP_BITMASK_AP1 DISP_BIT_IB03 +#define DISP_BITMASK_AP0 DISP_BIT_IB02 +/* DISP_POWER_CTL_3_ADDR Power Control (3) */ +#define DISP_BITMASK_VGL4 DISP_BIT_IB10 +#define DISP_BITMASK_VGL3 DISP_BIT_IB09 +#define DISP_BITMASK_VGL2 DISP_BIT_IB08 +#define DISP_BITMASK_VGL1 DISP_BIT_IB07 +#define DISP_BITMASK_VGL0 DISP_BIT_IB06 +#define DISP_BITMASK_VGH4 DISP_BIT_IB04 +#define DISP_BITMASK_VGH3 DISP_BIT_IB03 +#define DISP_BITMASK_VGH2 DISP_BIT_IB02 +#define DISP_BITMASK_VGH1 DISP_BIT_IB01 +#define DISP_BITMASK_VGH0 DISP_BIT_IB00 +/* DISP_POWER_CTL_4_ADDR Power Control (4) */ +#define DISP_BITMASK_VC2 DISP_BIT_IB02 +#define DISP_BITMASK_VC1 DISP_BIT_IB01 +#define DISP_BITMASK_VC0 DISP_BIT_IB00 +/* DISP_POWER_CTL_5_ADDR Power Control (5) */ +#define DISP_BITMASK_VRL3 DISP_BIT_IB11 +#define DISP_BITMASK_VRL2 DISP_BIT_IB10 +#define DISP_BITMASK_VRL1 DISP_BIT_IB09 +#define DISP_BITMASK_VRL0 DISP_BIT_IB08 +#define DISP_BITMASK_PON DISP_BIT_IB04 +#define DISP_BITMASK_VRH3 DISP_BIT_IB03 +#define DISP_BITMASK_VRH2 DISP_BIT_IB02 +#define DISP_BITMASK_VRH1 DISP_BIT_IB01 +#define DISP_BITMASK_VRH0 DISP_BIT_IB00 +/* DISP_POWER_CTL_6_ADDR Power Control (6) */ +#define DISP_BITMASK_VCOMG DISP_BIT_IB13 +#define DISP_BITMASK_VDV4 DISP_BIT_IB12 +#define DISP_BITMASK_VDV3 DISP_BIT_IB11 +#define DISP_BITMASK_VDV2 DISP_BIT_IB10 +#define DISP_BITMASK_VDV1 DISP_BIT_IB09 +#define DISP_BITMASK_VDV0 DISP_BIT_IB08 +#define DISP_BITMASK_VCM4 DISP_BIT_IB04 +#define DISP_BITMASK_VCM3 DISP_BIT_IB03 +#define DISP_BITMASK_VCM2 DISP_BIT_IB02 +#define DISP_BITMASK_VCM1 DISP_BIT_IB01 +#define DISP_BITMASK_VCM0 DISP_BIT_IB00 +/* RAM Access */ +/* DISP_RAM_ADDR_SET_1_ADDR RAM Address Set (1) */ +#define DISP_BITMASK_AD7 DISP_BIT_IB07 +#define DISP_BITMASK_AD6 DISP_BIT_IB06 +#define DISP_BITMASK_AD5 DISP_BIT_IB05 +#define DISP_BITMASK_AD4 DISP_BIT_IB04 +#define DISP_BITMASK_AD3 DISP_BIT_IB03 +#define DISP_BITMASK_AD2 DISP_BIT_IB02 +#define DISP_BITMASK_AD1 DISP_BIT_IB01 +#define DISP_BITMASK_AD0 DISP_BIT_IB00 +/* DISP_RAM_ADDR_SET_2_ADDR RAM Address Set (2) */ +#define DISP_BITMASK_AD16 DISP_BIT_IB08 +#define DISP_BITMASK_AD15 DISP_BIT_IB07 +#define DISP_BITMASK_AD14 DISP_BIT_IB06 +#define DISP_BITMASK_AD13 DISP_BIT_IB05 +#define DISP_BITMASK_AD12 DISP_BIT_IB04 +#define DISP_BITMASK_AD11 DISP_BIT_IB03 +#define DISP_BITMASK_AD10 DISP_BIT_IB02 +#define DISP_BITMASK_AD9 DISP_BIT_IB01 +#define DISP_BITMASK_AD8 DISP_BIT_IB00 +/* + * DISP_CMD_RAMWR RAM Data Read/Write + * Use Data Bit Configuration + */ +/* DISP_RAM_DATA_MASK_1_ADDR RAM Write Data Mask (1) */ +#define DISP_BITMASK_WM11 DISP_BIT_IB13 +#define DISP_BITMASK_WM10 DISP_BIT_IB12 +#define DISP_BITMASK_WM9 DISP_BIT_IB11 +#define DISP_BITMASK_WM8 DISP_BIT_IB10 +#define DISP_BITMASK_WM7 DISP_BIT_IB09 +#define DISP_BITMASK_WM6 DISP_BIT_IB08 +#define DISP_BITMASK_WM5 DISP_BIT_IB05 +#define DISP_BITMASK_WM4 DISP_BIT_IB04 +#define DISP_BITMASK_WM3 DISP_BIT_IB03 +#define DISP_BITMASK_WM2 DISP_BIT_IB02 +#define DISP_BITMASK_WM1 DISP_BIT_IB01 +#define DISP_BITMASK_WM0 DISP_BIT_IB00 +/* DISP_RAM_DATA_MASK_2_ADDR RAM Write Data Mask (2) */ +#define DISP_BITMASK_WM17 DISP_BIT_IB05 +#define DISP_BITMASK_WM16 DISP_BIT_IB04 +#define DISP_BITMASK_WM15 DISP_BIT_IB03 +#define DISP_BITMASK_WM14 DISP_BIT_IB02 +#define DISP_BITMASK_WM13 DISP_BIT_IB01 +#define DISP_BITMASK_WM12 DISP_BIT_IB00 +/*Gamma Control */ +/* DISP_GAMMA_CONTROL_1_ADDR Gamma Control (1) */ +#define DISP_BITMASK_PKP12 DISP_BIT_IB10 +#define DISP_BITMASK_PKP11 DISP_BIT_IB08 +#define DISP_BITMASK_PKP10 DISP_BIT_IB09 +#define DISP_BITMASK_PKP02 DISP_BIT_IB02 +#define DISP_BITMASK_PKP01 DISP_BIT_IB01 +#define DISP_BITMASK_PKP00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_2_ADDR Gamma Control (2) */ +#define DISP_BITMASK_PKP32 DISP_BIT_IB10 +#define DISP_BITMASK_PKP31 DISP_BIT_IB09 +#define DISP_BITMASK_PKP30 DISP_BIT_IB08 +#define DISP_BITMASK_PKP22 DISP_BIT_IB02 +#define DISP_BITMASK_PKP21 DISP_BIT_IB01 +#define DISP_BITMASK_PKP20 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_3_ADDR Gamma Control (3) */ +#define DISP_BITMASK_PKP52 DISP_BIT_IB10 +#define DISP_BITMASK_PKP51 DISP_BIT_IB09 +#define DISP_BITMASK_PKP50 DISP_BIT_IB08 +#define DISP_BITMASK_PKP42 DISP_BIT_IB02 +#define DISP_BITMASK_PKP41 DISP_BIT_IB01 +#define DISP_BITMASK_PKP40 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_4_ADDR Gamma Control (4) */ +#define DISP_BITMASK_PRP12 DISP_BIT_IB10 +#define DISP_BITMASK_PRP11 DISP_BIT_IB08 +#define DISP_BITMASK_PRP10 DISP_BIT_IB09 +#define DISP_BITMASK_PRP02 DISP_BIT_IB02 +#define DISP_BITMASK_PRP01 DISP_BIT_IB01 +#define DISP_BITMASK_PRP00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_5_ADDR Gamma Control (5) */ +#define DISP_BITMASK_VRP14 DISP_BIT_IB12 +#define DISP_BITMASK_VRP13 DISP_BIT_IB11 +#define DISP_BITMASK_VRP12 DISP_BIT_IB10 +#define DISP_BITMASK_VRP11 DISP_BIT_IB08 +#define DISP_BITMASK_VRP10 DISP_BIT_IB09 +#define DISP_BITMASK_VRP03 DISP_BIT_IB03 +#define DISP_BITMASK_VRP02 DISP_BIT_IB02 +#define DISP_BITMASK_VRP01 DISP_BIT_IB01 +#define DISP_BITMASK_VRP00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_6_ADDR Gamma Control (6) */ +#define DISP_BITMASK_PKN12 DISP_BIT_IB10 +#define DISP_BITMASK_PKN11 DISP_BIT_IB08 +#define DISP_BITMASK_PKN10 DISP_BIT_IB09 +#define DISP_BITMASK_PKN02 DISP_BIT_IB02 +#define DISP_BITMASK_PKN01 DISP_BIT_IB01 +#define DISP_BITMASK_PKN00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_7_ADDR Gamma Control (7) */ +#define DISP_BITMASK_PKN32 DISP_BIT_IB10 +#define DISP_BITMASK_PKN31 DISP_BIT_IB08 +#define DISP_BITMASK_PKN30 DISP_BIT_IB09 +#define DISP_BITMASK_PKN22 DISP_BIT_IB02 +#define DISP_BITMASK_PKN21 DISP_BIT_IB01 +#define DISP_BITMASK_PKN20 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_8_ADDR Gamma Control (8) */ +#define DISP_BITMASK_PKN52 DISP_BIT_IB10 +#define DISP_BITMASK_PKN51 DISP_BIT_IB08 +#define DISP_BITMASK_PKN50 DISP_BIT_IB09 +#define DISP_BITMASK_PKN42 DISP_BIT_IB02 +#define DISP_BITMASK_PKN41 DISP_BIT_IB01 +#define DISP_BITMASK_PKN40 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_9_ADDR Gamma Control (9) */ +#define DISP_BITMASK_PRN12 DISP_BIT_IB10 +#define DISP_BITMASK_PRN11 DISP_BIT_IB08 +#define DISP_BITMASK_PRN10 DISP_BIT_IB09 +#define DISP_BITMASK_PRN02 DISP_BIT_IB02 +#define DISP_BITMASK_PRN01 DISP_BIT_IB01 +#define DISP_BITMASK_PRN00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_10_ADDR Gamma Control (10) */ +#define DISP_BITMASK_VRN14 DISP_BIT_IB12 +#define DISP_BITMASK_VRN13 DISP_BIT_IB11 +#define DISP_BITMASK_VRN12 DISP_BIT_IB10 +#define DISP_BITMASK_VRN11 DISP_BIT_IB08 +#define DISP_BITMASK_VRN10 DISP_BIT_IB09 +#define DISP_BITMASK_VRN03 DISP_BIT_IB03 +#define DISP_BITMASK_VRN02 DISP_BIT_IB02 +#define DISP_BITMASK_VRN01 DISP_BIT_IB01 +#define DISP_BITMASK_VRN00 DISP_BIT_IB00 +/* Coordinate Control */ +/* DISP_VERT_SCROLL_CTL_1_ADDR Vertical Scroll Control (1) */ +#define DISP_BITMASK_VL18 DISP_BIT_IB08 +#define DISP_BITMASK_VL17 DISP_BIT_IB07 +#define DISP_BITMASK_VL16 DISP_BIT_IB06 +#define DISP_BITMASK_VL15 DISP_BIT_IB05 +#define DISP_BITMASK_VL14 DISP_BIT_IB04 +#define DISP_BITMASK_VL13 DISP_BIT_IB03 +#define DISP_BITMASK_VL12 DISP_BIT_IB02 +#define DISP_BITMASK_VL11 DISP_BIT_IB01 +#define DISP_BITMASK_VL10 DISP_BIT_IB00 +/* DISP_VERT_SCROLL_CTL_2_ADDR Vertical Scroll Control (2) */ +#define DISP_BITMASK_VL28 DISP_BIT_IB08 +#define DISP_BITMASK_VL27 DISP_BIT_IB07 +#define DISP_BITMASK_VL26 DISP_BIT_IB06 +#define DISP_BITMASK_VL25 DISP_BIT_IB05 +#define DISP_BITMASK_VL24 DISP_BIT_IB04 +#define DISP_BITMASK_VL23 DISP_BIT_IB03 +#define DISP_BITMASK_VL22 DISP_BIT_IB02 +#define DISP_BITMASK_VL21 DISP_BIT_IB01 +#define DISP_BITMASK_VL20 DISP_BIT_IB00 +/* DISP_SCREEN_1_DRV_POS_1_ADDR First Screen Driving Position (1) */ +#define DISP_BITMASK_SS18 DISP_BIT_IB08 +#define DISP_BITMASK_SS17 DISP_BIT_IB07 +#define DISP_BITMASK_SS16 DISP_BIT_IB06 +#define DISP_BITMASK_SS15 DISP_BIT_IB05 +#define DISP_BITMASK_SS14 DISP_BIT_IB04 +#define DISP_BITMASK_SS13 DISP_BIT_IB03 +#define DISP_BITMASK_SS12 DISP_BIT_IB02 +#define DISP_BITMASK_SS11 DISP_BIT_IB01 +#define DISP_BITMASK_SS10 DISP_BIT_IB00 +/* DISP_SCREEN_1_DRV_POS_2_ADDR First Screen Driving Position (2) */ +#define DISP_BITMASK_SE18 DISP_BIT_IB08 +#define DISP_BITMASK_SE17 DISP_BIT_IB07 +#define DISP_BITMASK_SE16 DISP_BIT_IB06 +#define DISP_BITMASK_SE15 DISP_BIT_IB05 +#define DISP_BITMASK_SE14 DISP_BIT_IB04 +#define DISP_BITMASK_SE13 DISP_BIT_IB03 +#define DISP_BITMASK_SE12 DISP_BIT_IB02 +#define DISP_BITMASK_SE11 DISP_BIT_IB01 +#define DISP_BITMASK_SE10 DISP_BIT_IB00 +/* DISP_SCREEN_2_DRV_POS_1_ADDR Second Screen Driving Position (1) */ +#define DISP_BITMASK_SS28 DISP_BIT_IB08 +#define DISP_BITMASK_SS27 DISP_BIT_IB07 +#define DISP_BITMASK_SS26 DISP_BIT_IB06 +#define DISP_BITMASK_SS25 DISP_BIT_IB05 +#define DISP_BITMASK_SS24 DISP_BIT_IB04 +#define DISP_BITMASK_SS23 DISP_BIT_IB03 +#define DISP_BITMASK_SS22 DISP_BIT_IB02 +#define DISP_BITMASK_SS21 DISP_BIT_IB01 +#define DISP_BITMASK_SS20 DISP_BIT_IB00 +/* DISP_SCREEN_3_DRV_POS_2_ADDR Second Screen Driving Position (2) */ +#define DISP_BITMASK_SE28 DISP_BIT_IB08 +#define DISP_BITMASK_SE27 DISP_BIT_IB07 +#define DISP_BITMASK_SE26 DISP_BIT_IB06 +#define DISP_BITMASK_SE25 DISP_BIT_IB05 +#define DISP_BITMASK_SE24 DISP_BIT_IB04 +#define DISP_BITMASK_SE23 DISP_BIT_IB03 +#define DISP_BITMASK_SE22 DISP_BIT_IB02 +#define DISP_BITMASK_SE21 DISP_BIT_IB01 +#define DISP_BITMASK_SE20 DISP_BIT_IB00 +/* DISP_HORZ_RAM_ADDR_POS_1_ADDR Horizontal RAM Address Position (1) */ +#define DISP_BITMASK_HSA7 DISP_BIT_IB07 +#define DISP_BITMASK_HSA6 DISP_BIT_IB06 +#define DISP_BITMASK_HSA5 DISP_BIT_IB05 +#define DISP_BITMASK_HSA4 DISP_BIT_IB04 +#define DISP_BITMASK_HSA3 DISP_BIT_IB03 +#define DISP_BITMASK_HSA2 DISP_BIT_IB02 +#define DISP_BITMASK_HSA1 DISP_BIT_IB01 +#define DISP_BITMASK_HSA0 DISP_BIT_IB00 +/* DISP_HORZ_RAM_ADDR_POS_2_ADDR Horizontal RAM Address Position (2) */ +#define DISP_BITMASK_HEA7 DISP_BIT_IB07 +#define DISP_BITMASK_HEA6 DISP_BIT_IB06 +#define DISP_BITMASK_HEA5 DISP_BIT_IB05 +#define DISP_BITMASK_HEA4 DISP_BIT_IB04 +#define DISP_BITMASK_HEA3 DISP_BIT_IB03 +#define DISP_BITMASK_HEA2 DISP_BIT_IB02 +#define DISP_BITMASK_HEA1 DISP_BIT_IB01 +#define DISP_BITMASK_HEA0 DISP_BIT_IB00 +/* DISP_VERT_RAM_ADDR_POS_1_ADDR Vertical RAM Address Position (1) */ +#define DISP_BITMASK_VSA8 DISP_BIT_IB08 +#define DISP_BITMASK_VSA7 DISP_BIT_IB07 +#define DISP_BITMASK_VSA6 DISP_BIT_IB06 +#define DISP_BITMASK_VSA5 DISP_BIT_IB05 +#define DISP_BITMASK_VSA4 DISP_BIT_IB04 +#define DISP_BITMASK_VSA3 DISP_BIT_IB03 +#define DISP_BITMASK_VSA2 DISP_BIT_IB02 +#define DISP_BITMASK_VSA1 DISP_BIT_IB01 +#define DISP_BITMASK_VSA0 DISP_BIT_IB00 +/* DISP_VERT_RAM_ADDR_POS_2_ADDR Vertical RAM Address Position (2) */ +#define DISP_BITMASK_VEA8 DISP_BIT_IB08 +#define DISP_BITMASK_VEA7 DISP_BIT_IB07 +#define DISP_BITMASK_VEA6 DISP_BIT_IB06 +#define DISP_BITMASK_VEA5 DISP_BIT_IB05 +#define DISP_BITMASK_VEA4 DISP_BIT_IB04 +#define DISP_BITMASK_VEA3 DISP_BIT_IB03 +#define DISP_BITMASK_VEA2 DISP_BIT_IB02 +#define DISP_BITMASK_VEA1 DISP_BIT_IB01 +#define DISP_BITMASK_VEA0 DISP_BIT_IB00 +static word disp_area_start_row; +static word disp_area_end_row; +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 uint32 tmd20qvga_lcd_rev; +uint16 tmd20qvga_panel_offset; + +#ifdef DISP_DEVICE_8BPP +static word convert_8_to_16_tbl[256] = { + 0x0000, 0x2000, 0x4000, 0x6000, 0x8000, 0xA000, 0xC000, 0xE000, + 0x0100, 0x2100, 0x4100, 0x6100, 0x8100, 0xA100, 0xC100, 0xE100, + 0x0200, 0x2200, 0x4200, 0x6200, 0x8200, 0xA200, 0xC200, 0xE200, + 0x0300, 0x2300, 0x4300, 0x6300, 0x8300, 0xA300, 0xC300, 0xE300, + 0x0400, 0x2400, 0x4400, 0x6400, 0x8400, 0xA400, 0xC400, 0xE400, + 0x0500, 0x2500, 0x4500, 0x6500, 0x8500, 0xA500, 0xC500, 0xE500, + 0x0600, 0x2600, 0x4600, 0x6600, 0x8600, 0xA600, 0xC600, 0xE600, + 0x0700, 0x2700, 0x4700, 0x6700, 0x8700, 0xA700, 0xC700, 0xE700, + 0x0008, 0x2008, 0x4008, 0x6008, 0x8008, 0xA008, 0xC008, 0xE008, + 0x0108, 0x2108, 0x4108, 0x6108, 0x8108, 0xA108, 0xC108, 0xE108, + 0x0208, 0x2208, 0x4208, 0x6208, 0x8208, 0xA208, 0xC208, 0xE208, + 0x0308, 0x2308, 0x4308, 0x6308, 0x8308, 0xA308, 0xC308, 0xE308, + 0x0408, 0x2408, 0x4408, 0x6408, 0x8408, 0xA408, 0xC408, 0xE408, + 0x0508, 0x2508, 0x4508, 0x6508, 0x8508, 0xA508, 0xC508, 0xE508, + 0x0608, 0x2608, 0x4608, 0x6608, 0x8608, 0xA608, 0xC608, 0xE608, + 0x0708, 0x2708, 0x4708, 0x6708, 0x8708, 0xA708, 0xC708, 0xE708, + 0x0010, 0x2010, 0x4010, 0x6010, 0x8010, 0xA010, 0xC010, 0xE010, + 0x0110, 0x2110, 0x4110, 0x6110, 0x8110, 0xA110, 0xC110, 0xE110, + 0x0210, 0x2210, 0x4210, 0x6210, 0x8210, 0xA210, 0xC210, 0xE210, + 0x0310, 0x2310, 0x4310, 0x6310, 0x8310, 0xA310, 0xC310, 0xE310, + 0x0410, 0x2410, 0x4410, 0x6410, 0x8410, 0xA410, 0xC410, 0xE410, + 0x0510, 0x2510, 0x4510, 0x6510, 0x8510, 0xA510, 0xC510, 0xE510, + 0x0610, 0x2610, 0x4610, 0x6610, 0x8610, 0xA610, 0xC610, 0xE610, + 0x0710, 0x2710, 0x4710, 0x6710, 0x8710, 0xA710, 0xC710, 0xE710, + 0x0018, 0x2018, 0x4018, 0x6018, 0x8018, 0xA018, 0xC018, 0xE018, + 0x0118, 0x2118, 0x4118, 0x6118, 0x8118, 0xA118, 0xC118, 0xE118, + 0x0218, 0x2218, 0x4218, 0x6218, 0x8218, 0xA218, 0xC218, 0xE218, + 0x0318, 0x2318, 0x4318, 0x6318, 0x8318, 0xA318, 0xC318, 0xE318, + 0x0418, 0x2418, 0x4418, 0x6418, 0x8418, 0xA418, 0xC418, 0xE418, + 0x0518, 0x2518, 0x4518, 0x6518, 0x8518, 0xA518, 0xC518, 0xE518, + 0x0618, 0x2618, 0x4618, 0x6618, 0x8618, 0xA618, 0xC618, 0xE618, + 0x0718, 0x2718, 0x4718, 0x6718, 0x8718, 0xA718, 0xC718, 0xE718 +}; +#endif /* DISP_DEVICE_8BPP */ + +static void tmd20qvga_disp_set_rect(int x, int y, int xres, int yres); +static void tmd20qvga_disp_init(struct platform_device *pdev); +static void tmd20qvga_disp_set_contrast(void); +static void tmd20qvga_disp_set_display_area(word start_row, word end_row); +static int tmd20qvga_disp_off(struct platform_device *pdev); +static int tmd20qvga_disp_on(struct platform_device *pdev); +static void tmd20qvga_set_revId(int); + +/* future use */ +void tmd20qvga_disp_clear_screen_area(word start_row, word end_row, + word start_column, word end_column); + +static void tmd20qvga_set_revId(int id) +{ + + tmd20qvga_lcd_rev = id; + + if (tmd20qvga_lcd_rev == 1) + tmd20qvga_panel_offset = 0x10; + else + tmd20qvga_panel_offset = 0; +} + +static void tmd20qvga_disp_init(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + if (disp_initialized) + return; + + mfd = platform_get_drvdata(pdev); + + DISP_CMD_PORT = mfd->cmd_port; + DISP_DATA_PORT = mfd->data_port; + +#ifdef TMD20QVGA_LCD_18BPP + tmd20qvga_set_revId(2); +#else + tmd20qvga_set_revId(1); +#endif + + disp_initialized = TRUE; + tmd20qvga_disp_set_contrast(); + tmd20qvga_disp_set_display_area(0, QVGA_HEIGHT - 1); +} + +static void tmd20qvga_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 tmd20qvga_disp_set_display_area(word start_row, word end_row) +{ + word start_driving = start_row; + word end_driving = end_row; + + if (!disp_initialized) + return; + + /* Range checking + */ + if (end_driving >= QVGA_HEIGHT) + end_driving = QVGA_HEIGHT - 1; + if (start_driving > end_driving) { + /* Probably Backwards Switch */ + start_driving = end_driving; + end_driving = start_row; /* Has not changed */ + if (end_driving >= QVGA_HEIGHT) + end_driving = QVGA_HEIGHT - 1; + } + + if ((start_driving == disp_area_start_row) + && (end_driving == disp_area_end_row)) + return; + + disp_area_start_row = start_driving; + disp_area_end_row = end_driving; + + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_1_ADDR, + DISP_VAL_IF(start_driving & 0x100, + DISP_BITMASK_SS18) | + DISP_VAL_IF(start_driving & 0x080, + DISP_BITMASK_SS17) | + DISP_VAL_IF(start_driving & 0x040, + DISP_BITMASK_SS16) | + DISP_VAL_IF(start_driving & 0x020, + DISP_BITMASK_SS15) | + DISP_VAL_IF(start_driving & 0x010, + DISP_BITMASK_SS14) | + DISP_VAL_IF(start_driving & 0x008, + DISP_BITMASK_SS13) | + DISP_VAL_IF(start_driving & 0x004, + DISP_BITMASK_SS12) | + DISP_VAL_IF(start_driving & 0x002, + DISP_BITMASK_SS11) | + DISP_VAL_IF(start_driving & 0x001, DISP_BITMASK_SS10)); + + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_2_ADDR, + DISP_VAL_IF(end_driving & 0x100, DISP_BITMASK_SE18) | + DISP_VAL_IF(end_driving & 0x080, DISP_BITMASK_SE17) | + DISP_VAL_IF(end_driving & 0x040, DISP_BITMASK_SE16) | + DISP_VAL_IF(end_driving & 0x020, DISP_BITMASK_SE15) | + DISP_VAL_IF(end_driving & 0x010, DISP_BITMASK_SE14) | + DISP_VAL_IF(end_driving & 0x008, DISP_BITMASK_SE13) | + DISP_VAL_IF(end_driving & 0x004, DISP_BITMASK_SE12) | + DISP_VAL_IF(end_driving & 0x002, DISP_BITMASK_SE11) | + DISP_VAL_IF(end_driving & 0x001, DISP_BITMASK_SE10)); +} + +static int tmd20qvga_disp_off(struct platform_device *pdev) +{ + if (!disp_initialized) + tmd20qvga_disp_init(pdev); + + if (display_on) { + if (tmd20qvga_lcd_rev == 2) { + DISP_WRITE_OUT(DISP_POFF_LN_SETTING_ADDR, 0x000A); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xFFEE); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xF812); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xE811); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xC011); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x4011); + WAIT_MSEC(20); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0010); + + } else { + DISP_WRITE_OUT(DISP_POFF_LN_SETTING_ADDR, 0x000F); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BFE); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BED); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x00CD); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(20); + DISP_WRITE_OUT(DISP_START_OSCILLATION_ADDR, 0x0); + } + + DISP_WRITE_OUT(DISP_MODE_SETTING_ADDR, 0x0004); + DISP_WRITE_OUT(DISP_MODE_SETTING_ADDR, 0x0000); + + display_on = FALSE; + } + + return 0; +} + +static int tmd20qvga_disp_on(struct platform_device *pdev) +{ + if (!disp_initialized) + tmd20qvga_disp_init(pdev); + + if (!display_on) { + /* Deep Stand-by -> Stand-by */ + DISP_CMD_OUT(DISP_START_OSCILLATION_ADDR); + WAIT_MSEC(1); + DISP_CMD_OUT(DISP_START_OSCILLATION_ADDR); + WAIT_MSEC(1); + DISP_CMD_OUT(DISP_START_OSCILLATION_ADDR); + WAIT_MSEC(1); + + /* OFF -> Deep Stan-By -> Stand-by */ + /* let's change the state from "Stand-by" to "Sleep" */ + DISP_WRITE_OUT(DISP_MODE_SETTING_ADDR, 0x0005); + WAIT_MSEC(1); + + /* Sleep -> Displaying */ + DISP_WRITE_OUT(DISP_START_OSCILLATION_ADDR, 0x0001); + DISP_WRITE_OUT(DISP_DRIVER_OUTPUT_CTL_ADDR, 0x0127); + DISP_WRITE_OUT(DISP_LCD_DRIVING_SIG_ADDR, 0x200); + /* fast write mode */ + DISP_WRITE_OUT(DISP_ENTRY_MODE_ADDR, 0x0130); + if (tmd20qvga_lcd_rev == 2) + DISP_WRITE_OUT(DISP_TMD_700_ADDR, 0x0003); + /* back porch = 14 + front porch = 2 --> 16 lines */ + if (tmd20qvga_lcd_rev == 2) { +#ifdef TMD20QVGA_LCD_18BPP + /* 256k color */ + DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x0000); +#else + /* 65k color */ + DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x4000); +#endif + DISP_WRITE_OUT(DISP_DISPLAY_CTL_2_ADDR, 0x0302); + } else { +#ifdef TMD20QVGA_LCD_18BPP + /* 256k color */ + DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x0004); +#else + /* 65k color */ + DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x4004); +#endif + DISP_WRITE_OUT(DISP_DISPLAY_CTL_2_ADDR, 0x020E); + } + /* 16 bit one transfer */ + if (tmd20qvga_lcd_rev == 2) { + DISP_WRITE_OUT(DISP_EXT_DISPLAY_CTL_1_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_FRAME_CYCLE_CTL_ADDR, 0x0010); + DISP_WRITE_OUT(DISP_LTPS_CTL_1_ADDR, 0x0302); + DISP_WRITE_OUT(DISP_LTPS_CTL_2_ADDR, 0x0102); + DISP_WRITE_OUT(DISP_LTPS_CTL_3_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_TMD_015_ADDR, 0x2000); + + DISP_WRITE_OUT(DISP_AMP_SETTING_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0403); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, 0x0304); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, 0x0403); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0303); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0101); + DISP_WRITE_OUT(DISP_TMD_305_ADDR, 0); + + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_1_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_2_ADDR, 0x013F); + + DISP_WRITE_OUT(DISP_POWER_CTL_3_ADDR, 0x077D); + + DISP_WRITE_OUT(DISP_POWER_CTL_4_ADDR, 0x0005); + DISP_WRITE_OUT(DISP_POWER_CTL_5_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_POWER_CTL_6_ADDR, 0x0015); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xC010); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_2_ADDR, 0x0001); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xFFFE); + WAIT_MSEC(60); + } else { + DISP_WRITE_OUT(DISP_EXT_DISPLAY_CTL_1_ADDR, 0x0001); + DISP_WRITE_OUT(DISP_FRAME_CYCLE_CTL_ADDR, 0x0010); + DISP_WRITE_OUT(DISP_LTPS_CTL_1_ADDR, 0x0301); + DISP_WRITE_OUT(DISP_LTPS_CTL_2_ADDR, 0x0001); + DISP_WRITE_OUT(DISP_LTPS_CTL_3_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_AMP_SETTING_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0507); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, 0x0405); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, 0x0607); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0502); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0301); + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_1_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_2_ADDR, 0x013F); + DISP_WRITE_OUT(DISP_POWER_CTL_3_ADDR, 0x0795); + + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0102); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_4_ADDR, 0x0450); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0103); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_5_ADDR, 0x0008); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0104); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_6_ADDR, 0x0C00); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0105); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_7_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0106); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0801); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_2_ADDR, 0x001F); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0101); + WAIT_MSEC(60); + + DISP_WRITE_OUT(DISP_POWER_CTL_2_ADDR, 0x009F); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0101); + WAIT_MSEC(10); + + DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_1_ADDR, 0x0010); + DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_2_ADDR, 0x00FF); + DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_1_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_2_ADDR, 0x013F); + /* RAM starts at address 0x10 */ + DISP_WRITE_OUT(DISP_RAM_ADDR_SET_1_ADDR, 0x0010); + DISP_WRITE_OUT(DISP_RAM_ADDR_SET_2_ADDR, 0x0000); + + /* lcd controller uses internal clock, not ext. vsync */ + DISP_CMD_OUT(DISP_CMD_RAMWR); + + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0881); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(40); + + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BE1); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(40); + + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BFF); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + } + display_on = TRUE; + } + + return 0; +} + +static void tmd20qvga_disp_set_contrast(void) +{ +#if (defined(TMD20QVGA_LCD_18BPP)) + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0403); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, 0x0302); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, 0x0403); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0303); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0F07); + +#else + int newcontrast = 0x46; + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0403); + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, + DISP_VAL_IF(newcontrast & 0x0001, DISP_BITMASK_PKP20) | + DISP_VAL_IF(newcontrast & 0x0002, DISP_BITMASK_PKP21) | + DISP_VAL_IF(newcontrast & 0x0004, DISP_BITMASK_PKP22) | + DISP_VAL_IF(newcontrast & 0x0010, DISP_BITMASK_PKP30) | + DISP_VAL_IF(newcontrast & 0x0020, DISP_BITMASK_PKP31) | + DISP_VAL_IF(newcontrast & 0x0040, DISP_BITMASK_PKP32)); + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, + DISP_VAL_IF(newcontrast & 0x0010, DISP_BITMASK_PKP40) | + DISP_VAL_IF(newcontrast & 0x0020, DISP_BITMASK_PKP41) | + DISP_VAL_IF(newcontrast & 0x0040, DISP_BITMASK_PKP42) | + DISP_VAL_IF(newcontrast & 0x0001, DISP_BITMASK_PKP50) | + DISP_VAL_IF(newcontrast & 0x0002, DISP_BITMASK_PKP51) | + DISP_VAL_IF(newcontrast & 0x0004, DISP_BITMASK_PKP52)); + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0303); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0F07); + +#endif /* defined(TMD20QVGA_LCD_18BPP) */ + +} /* End disp_set_contrast */ + +void tmd20qvga_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_16TO18BPP(0x0); +} + +static int __init tmd20qvga_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = tmd20qvga_probe, + .driver = { + .name = "ebi2_tmd_qvga", + }, +}; + +static struct msm_fb_panel_data tmd20qvga_panel_data = { + .on = tmd20qvga_disp_on, + .off = tmd20qvga_disp_off, + .set_rect = tmd20qvga_disp_set_rect, +}; + +static struct platform_device this_device = { + .name = "ebi2_tmd_qvga", + .id = 0, + .dev = { + .platform_data = &tmd20qvga_panel_data, + } +}; + +static int __init tmd20qvga_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + ret = platform_driver_register(&this_driver); + if (!ret) { + pinfo = &tmd20qvga_panel_data.panel_info; + pinfo->xres = 240; + pinfo->yres = 320; + pinfo->type = EBI2_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0x808000; +#ifdef TMD20QVGA_LCD_18BPP + pinfo->bpp = 18; +#else + pinfo->bpp = 16; +#endif + pinfo->fb_num = 2; + pinfo->lcd.vsync_enable = TRUE; + pinfo->lcd.refx100 = 6000; + pinfo->lcd.v_back_porch = 16; + pinfo->lcd.v_front_porch = 4; + pinfo->lcd.v_pulse_width = 0; + pinfo->lcd.hw_vsync_mode = FALSE; + pinfo->lcd.vsync_notifier_period = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + + return ret; +} + +module_init(tmd20qvga_init); diff --git a/drivers/staging/msm/hdmi_sii9022.c b/drivers/staging/msm/hdmi_sii9022.c new file mode 100644 index 00000000000..6b82b56a77b --- /dev/null +++ b/drivers/staging/msm/hdmi_sii9022.c @@ -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"); diff --git a/drivers/staging/msm/lcdc.c b/drivers/staging/msm/lcdc.c new file mode 100644 index 00000000000..735280ab72c --- /dev/null +++ b/drivers/staging/msm/lcdc.c @@ -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); diff --git a/drivers/staging/msm/lcdc_external.c b/drivers/staging/msm/lcdc_external.c new file mode 100644 index 00000000000..45ff7852711 --- /dev/null +++ b/drivers/staging/msm/lcdc_external.c @@ -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); diff --git a/drivers/staging/msm/lcdc_gordon.c b/drivers/staging/msm/lcdc_gordon.c new file mode 100644 index 00000000000..399ec8c791e --- /dev/null +++ b/drivers/staging/msm/lcdc_gordon.c @@ -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); diff --git a/drivers/staging/msm/lcdc_grapefruit.c b/drivers/staging/msm/lcdc_grapefruit.c new file mode 100644 index 00000000000..7284649ea0a --- /dev/null +++ b/drivers/staging/msm/lcdc_grapefruit.c @@ -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); diff --git a/drivers/staging/msm/lcdc_panel.c b/drivers/staging/msm/lcdc_panel.c new file mode 100644 index 00000000000..b40974e1f27 --- /dev/null +++ b/drivers/staging/msm/lcdc_panel.c @@ -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); diff --git a/drivers/staging/msm/lcdc_prism.c b/drivers/staging/msm/lcdc_prism.c new file mode 100644 index 00000000000..d102c98447c --- /dev/null +++ b/drivers/staging/msm/lcdc_prism.c @@ -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); diff --git a/drivers/staging/msm/lcdc_sharp_wvga_pt.c b/drivers/staging/msm/lcdc_sharp_wvga_pt.c new file mode 100644 index 00000000000..1f08cf9bc21 --- /dev/null +++ b/drivers/staging/msm/lcdc_sharp_wvga_pt.c @@ -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); diff --git a/drivers/staging/msm/lcdc_st15.c b/drivers/staging/msm/lcdc_st15.c new file mode 100644 index 00000000000..fed8278eb15 --- /dev/null +++ b/drivers/staging/msm/lcdc_st15.c @@ -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); diff --git a/drivers/staging/msm/lcdc_st1_wxga.c b/drivers/staging/msm/lcdc_st1_wxga.c new file mode 100644 index 00000000000..73760019cf2 --- /dev/null +++ b/drivers/staging/msm/lcdc_st1_wxga.c @@ -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); diff --git a/drivers/staging/msm/lcdc_toshiba_wvga_pt.c b/drivers/staging/msm/lcdc_toshiba_wvga_pt.c new file mode 100644 index 00000000000..864d7c18913 --- /dev/null +++ b/drivers/staging/msm/lcdc_toshiba_wvga_pt.c @@ -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); diff --git a/drivers/staging/msm/lcdc_wxga.c b/drivers/staging/msm/lcdc_wxga.c new file mode 100644 index 00000000000..202c92c0ef5 --- /dev/null +++ b/drivers/staging/msm/lcdc_wxga.c @@ -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); diff --git a/drivers/staging/msm/logo.c b/drivers/staging/msm/logo.c new file mode 100644 index 00000000000..7272765f48c --- /dev/null +++ b/drivers/staging/msm/logo.c @@ -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); diff --git a/drivers/staging/msm/mddi.c b/drivers/staging/msm/mddi.c new file mode 100644 index 00000000000..132eb1adff1 --- /dev/null +++ b/drivers/staging/msm/mddi.c @@ -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); diff --git a/drivers/staging/msm/mddi_ext.c b/drivers/staging/msm/mddi_ext.c new file mode 100644 index 00000000000..c0c168c7199 --- /dev/null +++ b/drivers/staging/msm/mddi_ext.c @@ -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); diff --git a/drivers/staging/msm/mddi_ext_lcd.c b/drivers/staging/msm/mddi_ext_lcd.c new file mode 100644 index 00000000000..502e80d17ec --- /dev/null +++ b/drivers/staging/msm/mddi_ext_lcd.c @@ -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); diff --git a/drivers/staging/msm/mddi_prism.c b/drivers/staging/msm/mddi_prism.c new file mode 100644 index 00000000000..489d40405a5 --- /dev/null +++ b/drivers/staging/msm/mddi_prism.c @@ -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); diff --git a/drivers/staging/msm/mddi_sharp.c b/drivers/staging/msm/mddi_sharp.c new file mode 100644 index 00000000000..1da1be4052d --- /dev/null +++ b/drivers/staging/msm/mddi_sharp.c @@ -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, ®data, TRUE, 0); + mddi_queue_register_write(REG_GIOA, regdata & 0xfff8, TRUE, 0); + + /* Set lower 3 GPIOs as level */ + mddi_queue_register_read(REG_GIOD, ®data, 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); diff --git a/drivers/staging/msm/mddi_toshiba.c b/drivers/staging/msm/mddi_toshiba.c new file mode 100644 index 00000000000..e96342d477a --- /dev/null +++ b/drivers/staging/msm/mddi_toshiba.c @@ -0,0 +1,1741 @@ +/* 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" +#include "mddi_toshiba.h" + +#define TM_GET_DID(id) ((id) & 0xff) +#define TM_GET_PID(id) (((id) & 0xff00)>>8) + +#define MDDI_CLIENT_CORE_BASE 0x108000 +#define LCD_CONTROL_BLOCK_BASE 0x110000 +#define SPI_BLOCK_BASE 0x120000 +#define PWM_BLOCK_BASE 0x140000 +#define SYSTEM_BLOCK1_BASE 0x160000 + +#define TTBUSSEL (MDDI_CLIENT_CORE_BASE|0x18) +#define DPSET0 (MDDI_CLIENT_CORE_BASE|0x1C) +#define DPSET1 (MDDI_CLIENT_CORE_BASE|0x20) +#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24) +#define DPRUN (MDDI_CLIENT_CORE_BASE|0x28) +#define SYSCKENA (MDDI_CLIENT_CORE_BASE|0x2C) + +#define BITMAP0 (MDDI_CLIENT_CORE_BASE|0x44) +#define BITMAP1 (MDDI_CLIENT_CORE_BASE|0x48) +#define BITMAP2 (MDDI_CLIENT_CORE_BASE|0x4C) +#define BITMAP3 (MDDI_CLIENT_CORE_BASE|0x50) +#define BITMAP4 (MDDI_CLIENT_CORE_BASE|0x54) + +#define SRST (LCD_CONTROL_BLOCK_BASE|0x00) +#define PORT_ENB (LCD_CONTROL_BLOCK_BASE|0x04) +#define START (LCD_CONTROL_BLOCK_BASE|0x08) +#define PORT (LCD_CONTROL_BLOCK_BASE|0x0C) + +#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18) +#define INTMSK (LCD_CONTROL_BLOCK_BASE|0x1C) +#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20) + +#define PXL (LCD_CONTROL_BLOCK_BASE|0x30) +#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34) +#define HSW (LCD_CONTROL_BLOCK_BASE|0x38) +#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C) +#define HDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x40) +#define VCYCLE (LCD_CONTROL_BLOCK_BASE|0x44) +#define VSW (LCD_CONTROL_BLOCK_BASE|0x48) +#define VDE_START (LCD_CONTROL_BLOCK_BASE|0x4C) +#define VDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x50) +#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54) +#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C) +#define VSYNIF (LCD_CONTROL_BLOCK_BASE|0x60) +#define WRSTB (LCD_CONTROL_BLOCK_BASE|0x64) +#define RDSTB (LCD_CONTROL_BLOCK_BASE|0x68) +#define ASY_DATA (LCD_CONTROL_BLOCK_BASE|0x6C) +#define ASY_DATB (LCD_CONTROL_BLOCK_BASE|0x70) +#define ASY_DATC (LCD_CONTROL_BLOCK_BASE|0x74) +#define ASY_DATD (LCD_CONTROL_BLOCK_BASE|0x78) +#define ASY_DATE (LCD_CONTROL_BLOCK_BASE|0x7C) +#define ASY_DATF (LCD_CONTROL_BLOCK_BASE|0x80) +#define ASY_DATG (LCD_CONTROL_BLOCK_BASE|0x84) +#define ASY_DATH (LCD_CONTROL_BLOCK_BASE|0x88) +#define ASY_CMDSET (LCD_CONTROL_BLOCK_BASE|0x8C) +#define MONI (LCD_CONTROL_BLOCK_BASE|0xB0) +#define VPOS (LCD_CONTROL_BLOCK_BASE|0xC0) + +#define SSICTL (SPI_BLOCK_BASE|0x00) +#define SSITIME (SPI_BLOCK_BASE|0x04) +#define SSITX (SPI_BLOCK_BASE|0x08) +#define SSIINTS (SPI_BLOCK_BASE|0x14) + +#define TIMER0LOAD (PWM_BLOCK_BASE|0x00) +#define TIMER0CTRL (PWM_BLOCK_BASE|0x08) +#define PWM0OFF (PWM_BLOCK_BASE|0x1C) +#define TIMER1LOAD (PWM_BLOCK_BASE|0x20) +#define TIMER1CTRL (PWM_BLOCK_BASE|0x28) +#define PWM1OFF (PWM_BLOCK_BASE|0x3C) +#define TIMER2LOAD (PWM_BLOCK_BASE|0x40) +#define TIMER2CTRL (PWM_BLOCK_BASE|0x48) +#define PWM2OFF (PWM_BLOCK_BASE|0x5C) +#define PWMCR (PWM_BLOCK_BASE|0x68) + +#define GPIOIS (GPIO_BLOCK_BASE|0x08) +#define GPIOIEV (GPIO_BLOCK_BASE|0x10) +#define GPIOIC (GPIO_BLOCK_BASE|0x20) + +#define WKREQ (SYSTEM_BLOCK1_BASE|0x00) +#define CLKENB (SYSTEM_BLOCK1_BASE|0x04) +#define DRAMPWR (SYSTEM_BLOCK1_BASE|0x08) +#define INTMASK (SYSTEM_BLOCK1_BASE|0x0C) +#define CNT_DIS (SYSTEM_BLOCK1_BASE|0x10) + +typedef enum { + TOSHIBA_STATE_OFF, + TOSHIBA_STATE_PRIM_SEC_STANDBY, + TOSHIBA_STATE_PRIM_SEC_READY, + TOSHIBA_STATE_PRIM_NORMAL_MODE, + TOSHIBA_STATE_SEC_NORMAL_MODE +} mddi_toshiba_state_t; + +static uint32 mddi_toshiba_curr_vpos; +static boolean mddi_toshiba_monitor_refresh_value = FALSE; +static boolean mddi_toshiba_report_refresh_measurements = FALSE; + +boolean mddi_toshiba_61Hz_refresh = TRUE; + +/* Modifications to timing to increase refresh rate to > 60Hz. + * 20MHz dot clock. + * 646 total rows. + * 506 total columns. + * refresh rate = 61.19Hz + */ +static uint32 mddi_toshiba_rows_per_second = 39526; +static uint32 mddi_toshiba_usecs_per_refresh = 16344; +static uint32 mddi_toshiba_rows_per_refresh = 646; +extern boolean mddi_vsync_detect_enabled; + +static msm_fb_vsync_handler_type mddi_toshiba_vsync_handler; +static void *mddi_toshiba_vsync_handler_arg; +static uint16 mddi_toshiba_vsync_attempts; + +static mddi_toshiba_state_t toshiba_state = TOSHIBA_STATE_OFF; + +static struct msm_panel_common_pdata *mddi_toshiba_pdata; + +static int mddi_toshiba_lcd_on(struct platform_device *pdev); +static int mddi_toshiba_lcd_off(struct platform_device *pdev); + +static void mddi_toshiba_state_transition(mddi_toshiba_state_t a, + mddi_toshiba_state_t b) +{ + if (toshiba_state != a) { + MDDI_MSG_ERR("toshiba state trans. (%d->%d) found %d\n", a, b, + toshiba_state); + } + toshiba_state = b; +} + +#define GORDON_REG_IMGCTL1 0x10 /* Image interface control 1 */ +#define GORDON_REG_IMGCTL2 0x11 /* Image interface control 2 */ +#define GORDON_REG_IMGSET1 0x12 /* Image interface settings 1 */ +#define GORDON_REG_IMGSET2 0x13 /* Image interface settings 2 */ +#define GORDON_REG_IVBP1 0x14 /* DM0: Vert back porch */ +#define GORDON_REG_IHBP1 0x15 /* DM0: Horiz back porch */ +#define GORDON_REG_IVNUM1 0x16 /* DM0: Num of vert lines */ +#define GORDON_REG_IHNUM1 0x17 /* DM0: Num of pixels per line */ +#define GORDON_REG_IVBP2 0x18 /* DM1: Vert back porch */ +#define GORDON_REG_IHBP2 0x19 /* DM1: Horiz back porch */ +#define GORDON_REG_IVNUM2 0x1A /* DM1: Num of vert lines */ +#define GORDON_REG_IHNUM2 0x1B /* DM1: Num of pixels per line */ +#define GORDON_REG_LCDIFCTL1 0x30 /* LCD interface control 1 */ +#define GORDON_REG_VALTRAN 0x31 /* LCD IF ctl: VALTRAN sync flag */ +#define GORDON_REG_AVCTL 0x33 +#define GORDON_REG_LCDIFCTL2 0x34 /* LCD interface control 2 */ +#define GORDON_REG_LCDIFCTL3 0x35 /* LCD interface control 3 */ +#define GORDON_REG_LCDIFSET1 0x36 /* LCD interface settings 1 */ +#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_EVPH2 0x67 +#define GORDON_REG_EVPL2 0x68 +#define GORDON_REG_EVNH2 0x69 +#define GORDON_REG_EVNL2 0x6A +#define GORDON_REG_TBIAS2 0x6B +#define GORDON_REG_POWCTL 0x80 +#define GORDON_REG_POWOSC1 0x81 +#define GORDON_REG_POWOSC2 0x82 +#define GORDON_REG_POWSET 0x83 +#define GORDON_REG_POWTRM1 0x85 +#define GORDON_REG_POWTRM2 0x86 +#define GORDON_REG_POWTRM3 0x87 +#define GORDON_REG_POWTRMSEL 0x88 +#define GORDON_REG_POWHIZ 0x89 + +void serigo(uint16 reg, uint8 data) +{ + uint32 mddi_val = 0; + mddi_queue_register_read(SSIINTS, &mddi_val, TRUE, 0); + if (mddi_val & (1 << 8)) + mddi_wait(1); + /* No De-assert of CS and send 2 bytes */ + mddi_val = 0x90000 | ((0x00FF & reg) << 8) | data; + mddi_queue_register_write(SSITX, mddi_val, TRUE, 0); +} + +void gordon_init(void) +{ + /* Image interface settings ***/ + serigo(GORDON_REG_IMGCTL2, 0x00); + serigo(GORDON_REG_IMGSET1, 0x01); + + /* Exchange the RGB signal for J510(Softbank mobile) */ + serigo(GORDON_REG_IMGSET2, 0x12); + serigo(GORDON_REG_LCDIFSET1, 0x00); + mddi_wait(2); + + /* Pre-charge settings */ + serigo(GORDON_REG_PCCTL, 0x09); + serigo(GORDON_REG_LCDIFCTL2, 0x1B); + mddi_wait(1); +} + +void gordon_disp_on(void) +{ + /*gordon_dispmode setting */ + /*VGA settings */ + serigo(GORDON_REG_TPARAM1, 0x30); + serigo(GORDON_REG_TLCDIF1, 0x00); + serigo(GORDON_REG_TSSPB_ST1, 0x8B); + serigo(GORDON_REG_TSSPB_ED1, 0x93); + mddi_wait(2); + serigo(GORDON_REG_TSCK_ST1, 0x88); + serigo(GORDON_REG_TSCK_WD1, 0x00); + serigo(GORDON_REG_TGSPB_VST1, 0x01); + serigo(GORDON_REG_TGSPB_VED1, 0x02); + mddi_wait(2); + serigo(GORDON_REG_TGSPB_CH1, 0x5E); + serigo(GORDON_REG_TGCK_ST1, 0x80); + serigo(GORDON_REG_TGCK_ED1, 0x3C); + serigo(GORDON_REG_TPCTL_ST1, 0x50); + mddi_wait(2); + serigo(GORDON_REG_TPCTL_ED1, 0x74); + serigo(GORDON_REG_TPCHG_ED1, 0x78); + serigo(GORDON_REG_TCOM_CH1, 0x50); + serigo(GORDON_REG_THBP1, 0x84); + mddi_wait(2); + serigo(GORDON_REG_TPHCTL1, 0x00); + serigo(GORDON_REG_EVPH1, 0x70); + serigo(GORDON_REG_EVPL1, 0x64); + serigo(GORDON_REG_EVNH1, 0x56); + mddi_wait(2); + serigo(GORDON_REG_EVNL1, 0x48); + serigo(GORDON_REG_TBIAS1, 0x88); + mddi_wait(2); + serigo(GORDON_REG_TPARAM2, 0x28); + serigo(GORDON_REG_TLCDIF2, 0x14); + serigo(GORDON_REG_TSSPB_ST2, 0x49); + serigo(GORDON_REG_TSSPB_ED2, 0x4B); + mddi_wait(2); + serigo(GORDON_REG_TSCK_ST2, 0x4A); + serigo(GORDON_REG_TSCK_WD2, 0x02); + serigo(GORDON_REG_TGSPB_VST2, 0x02); + serigo(GORDON_REG_TGSPB_VED2, 0x03); + mddi_wait(2); + serigo(GORDON_REG_TGSPB_CH2, 0x2F); + serigo(GORDON_REG_TGCK_ST2, 0x40); + serigo(GORDON_REG_TGCK_ED2, 0x1E); + serigo(GORDON_REG_TPCTL_ST2, 0x2C); + mddi_wait(2); + serigo(GORDON_REG_TPCTL_ED2, 0x3A); + serigo(GORDON_REG_TPCHG_ED2, 0x3C); + serigo(GORDON_REG_TCOM_CH2, 0x28); + serigo(GORDON_REG_THBP2, 0x4D); + mddi_wait(2); + serigo(GORDON_REG_TPHCTL2, 0x1A); + mddi_wait(2); + serigo(GORDON_REG_IVBP1, 0x02); + serigo(GORDON_REG_IHBP1, 0x90); + serigo(GORDON_REG_IVNUM1, 0xA0); + serigo(GORDON_REG_IHNUM1, 0x78); + mddi_wait(2); + serigo(GORDON_REG_IVBP2, 0x02); + serigo(GORDON_REG_IHBP2, 0x48); + serigo(GORDON_REG_IVNUM2, 0x50); + serigo(GORDON_REG_IHNUM2, 0x3C); + mddi_wait(2); + serigo(GORDON_REG_POWCTL, 0x03); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x07); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x0F); + mddi_wait(15); + serigo(GORDON_REG_AVCTL, 0x03); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x1F); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x5F); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x7F); + mddi_wait(15); + serigo(GORDON_REG_LCDIFCTL1, 0x02); + mddi_wait(15); + serigo(GORDON_REG_IMGCTL1, 0x00); + mddi_wait(15); + serigo(GORDON_REG_LCDIFCTL3, 0x00); + mddi_wait(15); + serigo(GORDON_REG_VALTRAN, 0x01); + mddi_wait(15); + serigo(GORDON_REG_LCDIFCTL1, 0x03); + serigo(GORDON_REG_LCDIFCTL1, 0x03); + mddi_wait(1); +} + +void gordon_disp_off(void) +{ + serigo(GORDON_REG_LCDIFCTL2, 0x7B); + serigo(GORDON_REG_VALTRAN, 0x01); + serigo(GORDON_REG_LCDIFCTL1, 0x02); + serigo(GORDON_REG_LCDIFCTL3, 0x01); + mddi_wait(20); + serigo(GORDON_REG_VALTRAN, 0x01); + serigo(GORDON_REG_IMGCTL1, 0x01); + serigo(GORDON_REG_LCDIFCTL1, 0x00); + mddi_wait(20); + serigo(GORDON_REG_POWCTL, 0x1F); + mddi_wait(40); + serigo(GORDON_REG_POWCTL, 0x07); + mddi_wait(40); + serigo(GORDON_REG_POWCTL, 0x03); + mddi_wait(40); + serigo(GORDON_REG_POWCTL, 0x00); + mddi_wait(40); +} + +void gordon_disp_init(void) +{ + gordon_init(); + mddi_wait(20); + gordon_disp_on(); +} + +static void toshiba_common_initial_setup(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) { + write_client_reg(DPSET0 , 0x4bec0066, TRUE); + write_client_reg(DPSET1 , 0x00000113, TRUE); + write_client_reg(DPSUS , 0x00000000, TRUE); + write_client_reg(DPRUN , 0x00000001, TRUE); + mddi_wait(5); + write_client_reg(SYSCKENA , 0x00000001, TRUE); + write_client_reg(CLKENB , 0x0000a0e9, TRUE); + + write_client_reg(GPIODATA , 0x03FF0000, TRUE); + write_client_reg(GPIODIR , 0x0000024D, TRUE); + write_client_reg(GPIOSEL , 0x00000173, TRUE); + write_client_reg(GPIOPC , 0x03C300C0, TRUE); + write_client_reg(WKREQ , 0x00000000, TRUE); + write_client_reg(GPIOIS , 0x00000000, TRUE); + write_client_reg(GPIOIEV , 0x00000001, TRUE); + write_client_reg(GPIOIC , 0x000003FF, TRUE); + write_client_reg(GPIODATA , 0x00040004, TRUE); + + write_client_reg(GPIODATA , 0x00080008, TRUE); + write_client_reg(DRAMPWR , 0x00000001, TRUE); + write_client_reg(CLKENB , 0x0000a0eb, TRUE); + write_client_reg(PWMCR , 0x00000000, TRUE); + mddi_wait(1); + + write_client_reg(SSICTL , 0x00060399, TRUE); + write_client_reg(SSITIME , 0x00000100, TRUE); + write_client_reg(CNT_DIS , 0x00000002, TRUE); + write_client_reg(SSICTL , 0x0006039b, TRUE); + + write_client_reg(SSITX , 0x00000000, TRUE); + mddi_wait(7); + write_client_reg(SSITX , 0x00000000, TRUE); + mddi_wait(7); + write_client_reg(SSITX , 0x00000000, TRUE); + mddi_wait(7); + + write_client_reg(SSITX , 0x000800BA, TRUE); + write_client_reg(SSITX , 0x00000111, TRUE); + write_client_reg(SSITX , 0x00080036, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x0008003A, TRUE); + write_client_reg(SSITX , 0x00000160, TRUE); + write_client_reg(SSITX , 0x000800B1, TRUE); + write_client_reg(SSITX , 0x0000015D, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B2, TRUE); + write_client_reg(SSITX , 0x00000133, TRUE); + write_client_reg(SSITX , 0x000800B3, TRUE); + write_client_reg(SSITX , 0x00000122, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B4, TRUE); + write_client_reg(SSITX , 0x00000102, TRUE); + write_client_reg(SSITX , 0x000800B5, TRUE); + write_client_reg(SSITX , 0x0000011E, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B6, TRUE); + write_client_reg(SSITX , 0x00000127, TRUE); + write_client_reg(SSITX , 0x000800B7, TRUE); + write_client_reg(SSITX , 0x00000103, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B9, TRUE); + write_client_reg(SSITX , 0x00000124, TRUE); + write_client_reg(SSITX , 0x000800BD, TRUE); + write_client_reg(SSITX , 0x000001A1, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800BB, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + write_client_reg(SSITX , 0x000800BF, TRUE); + write_client_reg(SSITX , 0x00000101, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800BE, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + write_client_reg(SSITX , 0x000800C0, TRUE); + write_client_reg(SSITX , 0x00000111, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C1, TRUE); + write_client_reg(SSITX , 0x00000111, TRUE); + write_client_reg(SSITX , 0x000800C2, TRUE); + write_client_reg(SSITX , 0x00000111, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C3, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000132, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C4, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000132, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C5, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000132, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C6, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000132, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C7, TRUE); + write_client_reg(SSITX , 0x00080164, TRUE); + write_client_reg(SSITX , 0x00000145, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C8, TRUE); + write_client_reg(SSITX , 0x00000144, TRUE); + write_client_reg(SSITX , 0x000800C9, TRUE); + write_client_reg(SSITX , 0x00000152, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800CA, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800EC, TRUE); + write_client_reg(SSITX , 0x00080101, TRUE); + write_client_reg(SSITX , 0x000001FC, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800CF, TRUE); + write_client_reg(SSITX , 0x00000101, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D0, TRUE); + write_client_reg(SSITX , 0x00080110, TRUE); + write_client_reg(SSITX , 0x00000104, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D1, TRUE); + write_client_reg(SSITX , 0x00000101, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D2, TRUE); + write_client_reg(SSITX , 0x00080100, TRUE); + write_client_reg(SSITX , 0x00000128, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D3, TRUE); + write_client_reg(SSITX , 0x00080100, TRUE); + write_client_reg(SSITX , 0x00000128, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D4, TRUE); + write_client_reg(SSITX , 0x00080126, TRUE); + write_client_reg(SSITX , 0x000001A4, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D5, TRUE); + write_client_reg(SSITX , 0x00000120, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800EF, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + mddi_wait(1); + + write_client_reg(BITMAP0 , 0x032001E0, TRUE); + write_client_reg(BITMAP1 , 0x032001E0, TRUE); + write_client_reg(BITMAP2 , 0x014000F0, TRUE); + write_client_reg(BITMAP3 , 0x014000F0, TRUE); + write_client_reg(BITMAP4 , 0x014000F0, TRUE); + write_client_reg(CLKENB , 0x0000A1EB, TRUE); + write_client_reg(PORT_ENB , 0x00000001, TRUE); + write_client_reg(PORT , 0x00000004, TRUE); + write_client_reg(PXL , 0x00000002, TRUE); + write_client_reg(MPLFBUF , 0x00000000, TRUE); + write_client_reg(HCYCLE , 0x000000FD, TRUE); + write_client_reg(HSW , 0x00000003, TRUE); + write_client_reg(HDE_START , 0x00000007, TRUE); + write_client_reg(HDE_SIZE , 0x000000EF, TRUE); + write_client_reg(VCYCLE , 0x00000325, TRUE); + write_client_reg(VSW , 0x00000001, TRUE); + write_client_reg(VDE_START , 0x00000003, TRUE); + write_client_reg(VDE_SIZE , 0x0000031F, TRUE); + write_client_reg(START , 0x00000001, TRUE); + mddi_wait(32); + write_client_reg(SSITX , 0x000800BC, TRUE); + write_client_reg(SSITX , 0x00000180, TRUE); + write_client_reg(SSITX , 0x0008003B, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B0, TRUE); + write_client_reg(SSITX , 0x00000116, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B8, TRUE); + write_client_reg(SSITX , 0x000801FF, TRUE); + write_client_reg(SSITX , 0x000001F5, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x00000011, TRUE); + mddi_wait(5); + write_client_reg(SSITX , 0x00000029, TRUE); + return; + } + + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) { + write_client_reg(DPSET0, 0x4BEC0066, TRUE); + write_client_reg(DPSET1, 0x00000113, TRUE); + write_client_reg(DPSUS, 0x00000000, TRUE); + write_client_reg(DPRUN, 0x00000001, TRUE); + mddi_wait(14); + write_client_reg(SYSCKENA, 0x00000001, TRUE); + write_client_reg(CLKENB, 0x000000EF, TRUE); + write_client_reg(GPIO_BLOCK_BASE, 0x03FF0000, TRUE); + write_client_reg(GPIODIR, 0x0000024D, TRUE); + write_client_reg(SYSTEM_BLOCK2_BASE, 0x00000173, TRUE); + write_client_reg(GPIOPC, 0x03C300C0, TRUE); + write_client_reg(SYSTEM_BLOCK1_BASE, 0x00000000, TRUE); + write_client_reg(GPIOIS, 0x00000000, TRUE); + write_client_reg(GPIOIEV, 0x00000001, TRUE); + write_client_reg(GPIOIC, 0x000003FF, TRUE); + write_client_reg(GPIO_BLOCK_BASE, 0x00060006, TRUE); + write_client_reg(GPIO_BLOCK_BASE, 0x00080008, TRUE); + write_client_reg(GPIO_BLOCK_BASE, 0x02000200, TRUE); + write_client_reg(DRAMPWR, 0x00000001, TRUE); + write_client_reg(TIMER0CTRL, 0x00000060, TRUE); + write_client_reg(PWM_BLOCK_BASE, 0x00001388, TRUE); + write_client_reg(PWM0OFF, 0x00001387, TRUE); + write_client_reg(TIMER1CTRL, 0x00000060, TRUE); + write_client_reg(TIMER1LOAD, 0x00001388, TRUE); + write_client_reg(PWM1OFF, 0x00001387, TRUE); + write_client_reg(TIMER0CTRL, 0x000000E0, TRUE); + write_client_reg(TIMER1CTRL, 0x000000E0, TRUE); + write_client_reg(PWMCR, 0x00000003, TRUE); + mddi_wait(1); + write_client_reg(SPI_BLOCK_BASE, 0x00063111, TRUE); + write_client_reg(SSITIME, 0x00000100, TRUE); + write_client_reg(SPI_BLOCK_BASE, 0x00063113, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(CLKENB, 0x0000A1EF, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(WRSTB, 0x0000003F, TRUE); + write_client_reg(RDSTB, 0x00000432, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000000, TRUE); + write_client_reg(ASY_DATB, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(10); + write_client_reg(ASY_DATA, 0x80000000, TRUE); + write_client_reg(ASY_DATB, 0x80000000, TRUE); + write_client_reg(ASY_DATC, 0x80000000, TRUE); + write_client_reg(ASY_DATD, 0x80000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + } else { + write_client_reg(DPSET0, 0x4BEC0066, TRUE); + write_client_reg(DPSET1, 0x00000113, TRUE); + write_client_reg(DPSUS, 0x00000000, TRUE); + write_client_reg(DPRUN, 0x00000001, TRUE); + mddi_wait(14); + write_client_reg(SYSCKENA, 0x00000001, TRUE); + write_client_reg(CLKENB, 0x000000EF, TRUE); + write_client_reg(GPIODATA, 0x03FF0000, TRUE); + write_client_reg(GPIODIR, 0x0000024D, TRUE); + write_client_reg(GPIOSEL, 0x00000173, TRUE); + write_client_reg(GPIOPC, 0x03C300C0, TRUE); + write_client_reg(WKREQ, 0x00000000, TRUE); + write_client_reg(GPIOIS, 0x00000000, TRUE); + write_client_reg(GPIOIEV, 0x00000001, TRUE); + write_client_reg(GPIOIC, 0x000003FF, TRUE); + write_client_reg(GPIODATA, 0x00060006, TRUE); + write_client_reg(GPIODATA, 0x00080008, TRUE); + write_client_reg(GPIODATA, 0x02000200, TRUE); + + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA) { + mddi_wait(400); + write_client_reg(DRAMPWR, 0x00000001, TRUE); + + write_client_reg(CNT_DIS, 0x00000002, TRUE); + write_client_reg(BITMAP0, 0x01E00320, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(PORT, 0x00000004, TRUE); + write_client_reg(PXL, 0x0000003A, TRUE); + write_client_reg(MPLFBUF, 0x00000000, TRUE); + write_client_reg(HCYCLE, 0x00000253, TRUE); + write_client_reg(HSW, 0x00000003, TRUE); + write_client_reg(HDE_START, 0x00000017, TRUE); + write_client_reg(HDE_SIZE, 0x0000018F, TRUE); + write_client_reg(VCYCLE, 0x000001FF, TRUE); + write_client_reg(VSW, 0x00000001, TRUE); + write_client_reg(VDE_START, 0x00000003, TRUE); + write_client_reg(VDE_SIZE, 0x000001DF, TRUE); + write_client_reg(START, 0x00000001, TRUE); + mddi_wait(1); + write_client_reg(TIMER0CTRL, 0x00000060, TRUE); + write_client_reg(TIMER0LOAD, 0x00001388, TRUE); + write_client_reg(TIMER1CTRL, 0x00000060, TRUE); + write_client_reg(TIMER1LOAD, 0x00001388, TRUE); + write_client_reg(PWM1OFF, 0x00000087, TRUE); + } else { + write_client_reg(DRAMPWR, 0x00000001, TRUE); + write_client_reg(TIMER0CTRL, 0x00000060, TRUE); + write_client_reg(TIMER0LOAD, 0x00001388, TRUE); + write_client_reg(TIMER1CTRL, 0x00000060, TRUE); + write_client_reg(TIMER1LOAD, 0x00001388, TRUE); + write_client_reg(PWM1OFF, 0x00001387, TRUE); + } + + write_client_reg(TIMER0CTRL, 0x000000E0, TRUE); + write_client_reg(TIMER1CTRL, 0x000000E0, TRUE); + write_client_reg(PWMCR, 0x00000003, TRUE); + mddi_wait(1); + write_client_reg(SSICTL, 0x00000799, TRUE); + write_client_reg(SSITIME, 0x00000100, TRUE); + write_client_reg(SSICTL, 0x0000079b, TRUE); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800BA, TRUE); + write_client_reg(SSITX, 0x00000111, TRUE); + write_client_reg(SSITX, 0x00080036, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800BB, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + write_client_reg(SSITX, 0x0008003A, TRUE); + write_client_reg(SSITX, 0x00000160, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800BF, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + write_client_reg(SSITX, 0x000800B1, TRUE); + write_client_reg(SSITX, 0x0000015D, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800B2, TRUE); + write_client_reg(SSITX, 0x00000133, TRUE); + write_client_reg(SSITX, 0x000800B3, TRUE); + write_client_reg(SSITX, 0x00000122, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800B4, TRUE); + write_client_reg(SSITX, 0x00000102, TRUE); + write_client_reg(SSITX, 0x000800B5, TRUE); + write_client_reg(SSITX, 0x0000011F, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800B6, TRUE); + write_client_reg(SSITX, 0x00000128, TRUE); + write_client_reg(SSITX, 0x000800B7, TRUE); + write_client_reg(SSITX, 0x00000103, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800B9, TRUE); + write_client_reg(SSITX, 0x00000120, TRUE); + write_client_reg(SSITX, 0x000800BD, TRUE); + write_client_reg(SSITX, 0x00000102, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800BE, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + write_client_reg(SSITX, 0x000800C0, TRUE); + write_client_reg(SSITX, 0x00000111, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C1, TRUE); + write_client_reg(SSITX, 0x00000111, TRUE); + write_client_reg(SSITX, 0x000800C2, TRUE); + write_client_reg(SSITX, 0x00000111, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C3, TRUE); + write_client_reg(SSITX, 0x0008010A, TRUE); + write_client_reg(SSITX, 0x0000010A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C4, TRUE); + write_client_reg(SSITX, 0x00080160, TRUE); + write_client_reg(SSITX, 0x00000160, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C5, TRUE); + write_client_reg(SSITX, 0x00080160, TRUE); + write_client_reg(SSITX, 0x00000160, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C6, TRUE); + write_client_reg(SSITX, 0x00080160, TRUE); + write_client_reg(SSITX, 0x00000160, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C7, TRUE); + write_client_reg(SSITX, 0x00080133, TRUE); + write_client_reg(SSITX, 0x00000143, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C8, TRUE); + write_client_reg(SSITX, 0x00000144, TRUE); + write_client_reg(SSITX, 0x000800C9, TRUE); + write_client_reg(SSITX, 0x00000133, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800CA, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800EC, TRUE); + write_client_reg(SSITX, 0x00080102, TRUE); + write_client_reg(SSITX, 0x00000118, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800CF, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D0, TRUE); + write_client_reg(SSITX, 0x00080110, TRUE); + write_client_reg(SSITX, 0x00000104, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D1, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D2, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x0000013A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D3, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x0000013A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D4, TRUE); + write_client_reg(SSITX, 0x00080124, TRUE); + write_client_reg(SSITX, 0x0000016E, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800D5, TRUE); + write_client_reg(SSITX, 0x00000124, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800ED, TRUE); + write_client_reg(SSITX, 0x00080101, TRUE); + write_client_reg(SSITX, 0x0000010A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D6, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D7, TRUE); + write_client_reg(SSITX, 0x00080110, TRUE); + write_client_reg(SSITX, 0x0000010A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D8, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D9, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x00000114, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800DE, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x00000114, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800DF, TRUE); + write_client_reg(SSITX, 0x00080112, TRUE); + write_client_reg(SSITX, 0x0000013F, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E0, TRUE); + write_client_reg(SSITX, 0x0000010B, TRUE); + write_client_reg(SSITX, 0x000800E2, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E3, TRUE); + write_client_reg(SSITX, 0x00000136, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E4, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x00000103, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E5, TRUE); + write_client_reg(SSITX, 0x00080102, TRUE); + write_client_reg(SSITX, 0x00000104, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E6, TRUE); + write_client_reg(SSITX, 0x00000103, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E7, TRUE); + write_client_reg(SSITX, 0x00080104, TRUE); + write_client_reg(SSITX, 0x0000010A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E8, TRUE); + write_client_reg(SSITX, 0x00000104, TRUE); + write_client_reg(CLKENB, 0x000001EF, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(WRSTB, 0x0000003F, TRUE); + write_client_reg(RDSTB, 0x00000432, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000000, TRUE); + write_client_reg(ASY_DATB, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(10); + write_client_reg(ASY_DATA, 0x80000000, TRUE); + write_client_reg(ASY_DATB, 0x80000000, TRUE); + write_client_reg(ASY_DATC, 0x80000000, TRUE); + write_client_reg(ASY_DATD, 0x80000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + } + + mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_SEC_STANDBY, + TOSHIBA_STATE_PRIM_SEC_READY); +} + +static void toshiba_prim_start(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) { + write_client_reg(BITMAP1, 0x01E000F0, TRUE); + write_client_reg(BITMAP2, 0x01E000F0, TRUE); + write_client_reg(BITMAP3, 0x01E000F0, TRUE); + write_client_reg(BITMAP4, 0x00DC00B0, TRUE); + write_client_reg(CLKENB, 0x000001EF, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(PORT, 0x00000016, TRUE); + write_client_reg(PXL, 0x00000002, TRUE); + write_client_reg(MPLFBUF, 0x00000000, TRUE); + write_client_reg(HCYCLE, 0x00000185, TRUE); + write_client_reg(HSW, 0x00000018, TRUE); + write_client_reg(HDE_START, 0x0000004A, TRUE); + write_client_reg(HDE_SIZE, 0x000000EF, TRUE); + write_client_reg(VCYCLE, 0x0000028E, TRUE); + write_client_reg(VSW, 0x00000004, TRUE); + write_client_reg(VDE_START, 0x00000009, TRUE); + write_client_reg(VDE_SIZE, 0x0000027F, TRUE); + write_client_reg(START, 0x00000001, TRUE); + write_client_reg(SYSTEM_BLOCK1_BASE, 0x00000002, TRUE); + } else{ + + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(BITMAP1, 0x01E000F0, TRUE); + write_client_reg(BITMAP2, 0x01E000F0, TRUE); + write_client_reg(BITMAP3, 0x01E000F0, TRUE); + write_client_reg(BITMAP4, 0x00DC00B0, TRUE); + write_client_reg(CLKENB, 0x000001EF, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(PORT, 0x00000004, TRUE); + write_client_reg(PXL, 0x00000002, TRUE); + write_client_reg(MPLFBUF, 0x00000000, TRUE); + + if (mddi_toshiba_61Hz_refresh) { + write_client_reg(HCYCLE, 0x000000FC, TRUE); + mddi_toshiba_rows_per_second = 39526; + mddi_toshiba_rows_per_refresh = 646; + mddi_toshiba_usecs_per_refresh = 16344; + } else { + write_client_reg(HCYCLE, 0x0000010b, TRUE); + mddi_toshiba_rows_per_second = 37313; + mddi_toshiba_rows_per_refresh = 646; + mddi_toshiba_usecs_per_refresh = 17313; + } + + write_client_reg(HSW, 0x00000003, TRUE); + write_client_reg(HDE_START, 0x00000007, TRUE); + write_client_reg(HDE_SIZE, 0x000000EF, TRUE); + write_client_reg(VCYCLE, 0x00000285, TRUE); + write_client_reg(VSW, 0x00000001, TRUE); + write_client_reg(VDE_START, 0x00000003, TRUE); + write_client_reg(VDE_SIZE, 0x0000027F, TRUE); + write_client_reg(START, 0x00000001, TRUE); + mddi_wait(10); + write_client_reg(SSITX, 0x000800BC, TRUE); + write_client_reg(SSITX, 0x00000180, TRUE); + write_client_reg(SSITX, 0x0008003B, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800B0, TRUE); + write_client_reg(SSITX, 0x00000116, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800B8, TRUE); + write_client_reg(SSITX, 0x000801FF, TRUE); + write_client_reg(SSITX, 0x000001F5, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000011, TRUE); + write_client_reg(SSITX, 0x00000029, TRUE); + write_client_reg(WKREQ, 0x00000000, TRUE); + write_client_reg(WAKEUP, 0x00000000, TRUE); + write_client_reg(INTMSK, 0x00000001, TRUE); + } + + mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_SEC_READY, + TOSHIBA_STATE_PRIM_NORMAL_MODE); +} + +static void toshiba_sec_start(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(CLKENB, 0x000011EF, TRUE); + write_client_reg(BITMAP0, 0x028001E0, TRUE); + write_client_reg(BITMAP1, 0x00000000, TRUE); + write_client_reg(BITMAP2, 0x00000000, TRUE); + write_client_reg(BITMAP3, 0x00000000, TRUE); + write_client_reg(BITMAP4, 0x00DC00B0, TRUE); + write_client_reg(PORT, 0x00000000, TRUE); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(MPLFBUF, 0x00000004, TRUE); + write_client_reg(HCYCLE, 0x0000006B, TRUE); + write_client_reg(HSW, 0x00000003, TRUE); + write_client_reg(HDE_START, 0x00000007, TRUE); + write_client_reg(HDE_SIZE, 0x00000057, TRUE); + write_client_reg(VCYCLE, 0x000000E6, TRUE); + write_client_reg(VSW, 0x00000001, TRUE); + write_client_reg(VDE_START, 0x00000003, TRUE); + write_client_reg(VDE_SIZE, 0x000000DB, TRUE); + write_client_reg(ASY_DATA, 0x80000001, TRUE); + write_client_reg(ASY_DATB, 0x0000011B, TRUE); + write_client_reg(ASY_DATC, 0x80000002, TRUE); + write_client_reg(ASY_DATD, 0x00000700, TRUE); + write_client_reg(ASY_DATE, 0x80000003, TRUE); + write_client_reg(ASY_DATF, 0x00000230, TRUE); + write_client_reg(ASY_DATG, 0x80000008, TRUE); + write_client_reg(ASY_DATH, 0x00000402, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000009, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_DATC, 0x8000000B, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x8000000C, TRUE); + write_client_reg(ASY_DATF, 0x00000000, TRUE); + write_client_reg(ASY_DATG, 0x8000000D, TRUE); + write_client_reg(ASY_DATH, 0x00000409, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x8000000E, TRUE); + write_client_reg(ASY_DATB, 0x00000409, TRUE); + write_client_reg(ASY_DATC, 0x80000030, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x80000031, TRUE); + write_client_reg(ASY_DATF, 0x00000100, TRUE); + write_client_reg(ASY_DATG, 0x80000032, TRUE); + write_client_reg(ASY_DATH, 0x00000104, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000033, TRUE); + write_client_reg(ASY_DATB, 0x00000400, TRUE); + write_client_reg(ASY_DATC, 0x80000034, TRUE); + write_client_reg(ASY_DATD, 0x00000306, TRUE); + write_client_reg(ASY_DATE, 0x80000035, TRUE); + write_client_reg(ASY_DATF, 0x00000706, TRUE); + write_client_reg(ASY_DATG, 0x80000036, TRUE); + write_client_reg(ASY_DATH, 0x00000707, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000037, TRUE); + write_client_reg(ASY_DATB, 0x00000004, TRUE); + write_client_reg(ASY_DATC, 0x80000038, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x80000039, TRUE); + write_client_reg(ASY_DATF, 0x00000000, TRUE); + write_client_reg(ASY_DATG, 0x8000003A, TRUE); + write_client_reg(ASY_DATH, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000044, TRUE); + write_client_reg(ASY_DATB, 0x0000AF00, TRUE); + write_client_reg(ASY_DATC, 0x80000045, TRUE); + write_client_reg(ASY_DATD, 0x0000DB00, TRUE); + write_client_reg(ASY_DATE, 0x08000042, TRUE); + write_client_reg(ASY_DATF, 0x0000DB00, TRUE); + write_client_reg(ASY_DATG, 0x80000021, TRUE); + write_client_reg(ASY_DATH, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(PXL, 0x0000000C, TRUE); + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(ASY_DATA, 0x80000022, TRUE); + write_client_reg(ASY_CMDSET, 0x00000003, TRUE); + write_client_reg(START, 0x00000001, TRUE); + mddi_wait(60); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000050, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_DATC, 0x80000051, TRUE); + write_client_reg(ASY_DATD, 0x00000E00, TRUE); + write_client_reg(ASY_DATE, 0x80000052, TRUE); + write_client_reg(ASY_DATF, 0x00000D01, TRUE); + write_client_reg(ASY_DATG, 0x80000053, TRUE); + write_client_reg(ASY_DATH, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000058, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_DATC, 0x8000005A, TRUE); + write_client_reg(ASY_DATD, 0x00000E01, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + write_client_reg(ASY_DATA, 0x80000011, TRUE); + write_client_reg(ASY_DATB, 0x00000812, TRUE); + write_client_reg(ASY_DATC, 0x80000012, TRUE); + write_client_reg(ASY_DATD, 0x00000003, TRUE); + write_client_reg(ASY_DATE, 0x80000013, TRUE); + write_client_reg(ASY_DATF, 0x00000909, TRUE); + write_client_reg(ASY_DATG, 0x80000010, TRUE); + write_client_reg(ASY_DATH, 0x00000040, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + mddi_wait(40); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000340, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(60); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00003340, TRUE); + write_client_reg(ASY_DATC, 0x80000007, TRUE); + write_client_reg(ASY_DATD, 0x00004007, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + mddi_wait(1); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004017, TRUE); + write_client_reg(ASY_DATC, 0x8000005B, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x80000059, TRUE); + write_client_reg(ASY_DATF, 0x00000011, TRUE); + write_client_reg(ASY_CMDSET, 0x0000000D, TRUE); + write_client_reg(ASY_CMDSET, 0x0000000C, TRUE); + mddi_wait(20); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + /* LTPS I/F control */ + write_client_reg(ASY_DATB, 0x00000019, TRUE); + /* Direct cmd transfer enable */ + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + /* Direct cmd transfer disable */ + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + /* Index setting of SUB LCDD */ + write_client_reg(ASY_DATA, 0x80000059, TRUE); + /* LTPS I/F control */ + write_client_reg(ASY_DATB, 0x00000079, TRUE); + /* Direct cmd transfer enable */ + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + /* Direct cmd transfer disable */ + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + /* Index setting of SUB LCDD */ + write_client_reg(ASY_DATA, 0x80000059, TRUE); + /* LTPS I/F control */ + write_client_reg(ASY_DATB, 0x000003FD, TRUE); + /* Direct cmd transfer enable */ + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + /* Direct cmd transfer disable */ + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_SEC_READY, + TOSHIBA_STATE_SEC_NORMAL_MODE); +} + +static void toshiba_prim_lcd_off(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) { + gordon_disp_off(); + } else{ + + /* Main panel power off (Deep standby in) */ + write_client_reg(SSITX, 0x000800BC, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + write_client_reg(SSITX, 0x00000028, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800B8, TRUE); + write_client_reg(SSITX, 0x00000180, TRUE); + write_client_reg(SSITX, 0x00000102, TRUE); + write_client_reg(SSITX, 0x00000010, TRUE); + } + write_client_reg(PORT, 0x00000003, TRUE); + write_client_reg(REGENB, 0x00000001, TRUE); + mddi_wait(1); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(REGENB, 0x00000001, TRUE); + mddi_wait(3); + if (TM_GET_PID(mfd->panel.id) != LCD_SHARP_2P4_VGA) { + write_client_reg(SSITX, 0x000800B0, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + } + mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_NORMAL_MODE, + TOSHIBA_STATE_PRIM_SEC_STANDBY); +} + +static void toshiba_sec_lcd_off(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004016, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000019, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x0000000B, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000002, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000300, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004004, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(PORT, 0x00000000, TRUE); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(REGENB, 0x00000001, TRUE); + mddi_toshiba_state_transition(TOSHIBA_STATE_SEC_NORMAL_MODE, + TOSHIBA_STATE_PRIM_SEC_STANDBY); +} + +static void toshiba_sec_cont_update_start(struct msm_fb_data_type *mfd) +{ + + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(INTMASK, 0x00000001, TRUE); + write_client_reg(TTBUSSEL, 0x0000000B, TRUE); + write_client_reg(MONI, 0x00000008, TRUE); + write_client_reg(CLKENB, 0x000000EF, TRUE); + write_client_reg(CLKENB, 0x000010EF, TRUE); + write_client_reg(CLKENB, 0x000011EF, TRUE); + write_client_reg(BITMAP4, 0x00DC00B0, TRUE); + write_client_reg(HCYCLE, 0x0000006B, TRUE); + write_client_reg(HSW, 0x00000003, TRUE); + write_client_reg(HDE_START, 0x00000002, TRUE); + write_client_reg(HDE_SIZE, 0x00000057, TRUE); + write_client_reg(VCYCLE, 0x000000E6, TRUE); + write_client_reg(VSW, 0x00000001, TRUE); + write_client_reg(VDE_START, 0x00000003, TRUE); + write_client_reg(VDE_SIZE, 0x000000DB, TRUE); + write_client_reg(WRSTB, 0x00000015, TRUE); + write_client_reg(MPLFBUF, 0x00000004, TRUE); + write_client_reg(ASY_DATA, 0x80000021, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_DATC, 0x80000022, TRUE); + write_client_reg(ASY_CMDSET, 0x00000007, TRUE); + write_client_reg(PXL, 0x00000089, TRUE); + write_client_reg(VSYNIF, 0x00000001, TRUE); + mddi_wait(2); +} + +static void toshiba_sec_cont_update_stop(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + mddi_wait(3); + write_client_reg(SRST, 0x00000002, TRUE); + mddi_wait(3); + write_client_reg(SRST, 0x00000003, TRUE); +} + +static void toshiba_sec_backlight_on(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(TIMER0CTRL, 0x00000060, TRUE); + write_client_reg(TIMER0LOAD, 0x00001388, TRUE); + write_client_reg(PWM0OFF, 0x00000001, TRUE); + write_client_reg(TIMER1CTRL, 0x00000060, TRUE); + write_client_reg(TIMER1LOAD, 0x00001388, TRUE); + write_client_reg(PWM1OFF, 0x00001387, TRUE); + write_client_reg(TIMER0CTRL, 0x000000E0, TRUE); + write_client_reg(TIMER1CTRL, 0x000000E0, TRUE); + write_client_reg(PWMCR, 0x00000003, TRUE); +} + +static void toshiba_sec_sleep_in(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004016, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000019, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x0000000B, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000002, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000300, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004004, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(PORT, 0x00000000, TRUE); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(REGENB, 0x00000001, TRUE); + /* Sleep in sequence */ + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000302, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); +} + +static void toshiba_sec_sleep_out(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000300, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + /* Display ON sequence */ + write_client_reg(ASY_DATA, 0x80000011, TRUE); + write_client_reg(ASY_DATB, 0x00000812, TRUE); + write_client_reg(ASY_DATC, 0x80000012, TRUE); + write_client_reg(ASY_DATD, 0x00000003, TRUE); + write_client_reg(ASY_DATE, 0x80000013, TRUE); + write_client_reg(ASY_DATF, 0x00000909, TRUE); + write_client_reg(ASY_DATG, 0x80000010, TRUE); + write_client_reg(ASY_DATH, 0x00000040, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000340, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(6); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00003340, TRUE); + write_client_reg(ASY_DATC, 0x80000007, TRUE); + write_client_reg(ASY_DATD, 0x00004007, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + mddi_wait(1); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004017, TRUE); + write_client_reg(ASY_DATC, 0x8000005B, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x80000059, TRUE); + write_client_reg(ASY_DATF, 0x00000011, TRUE); + write_client_reg(ASY_CMDSET, 0x0000000D, TRUE); + write_client_reg(ASY_CMDSET, 0x0000000C, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000019, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000079, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x000003FD, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); +} + +static void mddi_toshiba_lcd_set_backlight(struct msm_fb_data_type *mfd) +{ + int32 level; + int ret = -EPERM; + int max = mfd->panel_info.bl_max; + int min = mfd->panel_info.bl_min; + + if (mddi_toshiba_pdata && mddi_toshiba_pdata->pmic_backlight) { + ret = mddi_toshiba_pdata->pmic_backlight(mfd->bl_level); + if (!ret) + return; + } + + if (ret && mddi_toshiba_pdata && mddi_toshiba_pdata->backlight_level) { + level = mddi_toshiba_pdata->backlight_level(mfd->bl_level, + max, min); + + if (level < 0) + return; + + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) + write_client_reg(TIMER0LOAD, 0x00001388, TRUE); + } else { + if (!max) + level = 0; + else + level = (mfd->bl_level * 4999) / max; + } + + write_client_reg(PWM0OFF, level, TRUE); +} + +static void mddi_toshiba_vsync_set_handler(msm_fb_vsync_handler_type handler, /* ISR to be executed */ + void *arg) +{ + boolean error = FALSE; + unsigned long flags; + + /* Disable interrupts */ + spin_lock_irqsave(&mddi_host_spin_lock, flags); + /* INTLOCK(); */ + + if (mddi_toshiba_vsync_handler != NULL) { + error = TRUE; + } else { + /* Register the handler for this particular GROUP interrupt source */ + mddi_toshiba_vsync_handler = handler; + mddi_toshiba_vsync_handler_arg = arg; + } + + /* Restore interrupts */ + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + /* MDDI_INTFREE(); */ + if (error) { + MDDI_MSG_ERR("MDDI: Previous Vsync handler never called\n"); + } else { + /* Enable the vsync wakeup */ + mddi_queue_register_write(INTMSK, 0x0000, FALSE, 0); + + mddi_toshiba_vsync_attempts = 1; + mddi_vsync_detect_enabled = TRUE; + } +} /* mddi_toshiba_vsync_set_handler */ + +static void mddi_toshiba_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_toshiba_vsync_attempts > 5)) { + if ((detected) && (mddi_toshiba_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_toshiba_usecs_per_refresh >> + 1)) / + mddi_toshiba_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_toshiba_rows_per_second = + (mddi_toshiba_rows_per_refresh * 1000 * + num_vsyncs) / (elapsed_us / 1000); + } + /* start_time = timetick_get(); */ + first_time = FALSE; + jiffies_to_timeval(jiffies, &start_time); + if (mddi_toshiba_report_refresh_measurements) { + (void)mddi_queue_register_read_int(VPOS, + &mddi_toshiba_curr_vpos); + /* mdp_cnt_val = MDP_LINE_COUNT; */ + } + } + /* if detected = TRUE, client initiated wakeup was detected */ + if (mddi_toshiba_vsync_handler != NULL) { + (*mddi_toshiba_vsync_handler) + (mddi_toshiba_vsync_handler_arg); + mddi_toshiba_vsync_handler = NULL; + } + mddi_vsync_detect_enabled = FALSE; + mddi_toshiba_vsync_attempts = 0; + /* need to disable the interrupt wakeup */ + if (!mddi_queue_register_write_int(INTMSK, 0x0001)) + MDDI_MSG_ERR("Vsync interrupt disable failed!\n"); + if (!detected) { + /* give up after 5 failed attempts but show error */ + MDDI_MSG_NOTICE("Vsync detection failed!\n"); + } else if ((mddi_toshiba_monitor_refresh_value) && + (mddi_toshiba_report_refresh_measurements)) { + MDDI_MSG_NOTICE(" Last Line Counter=%d!\n", + mddi_toshiba_curr_vpos); + /* MDDI_MSG_NOTICE(" MDP Line Counter=%d!\n",mdp_cnt_val); */ + MDDI_MSG_NOTICE(" Lines Per Second=%d!\n", + mddi_toshiba_rows_per_second); + } + /* clear the interrupt */ + if (!mddi_queue_register_write_int(INTFLG, 0x0001)) + MDDI_MSG_ERR("Vsync interrupt clear failed!\n"); + } else { + /* if detected = FALSE, we woke up from hibernation, but did not + * detect client initiated wakeup. + */ + mddi_toshiba_vsync_attempts++; + } +} + +static void mddi_toshiba_prim_init(struct msm_fb_data_type *mfd) +{ + + switch (toshiba_state) { + case TOSHIBA_STATE_PRIM_SEC_READY: + break; + case TOSHIBA_STATE_OFF: + toshiba_state = TOSHIBA_STATE_PRIM_SEC_STANDBY; + toshiba_common_initial_setup(mfd); + break; + case TOSHIBA_STATE_PRIM_SEC_STANDBY: + toshiba_common_initial_setup(mfd); + break; + case TOSHIBA_STATE_SEC_NORMAL_MODE: + toshiba_sec_cont_update_stop(mfd); + toshiba_sec_sleep_in(mfd); + toshiba_sec_sleep_out(mfd); + toshiba_sec_lcd_off(mfd); + toshiba_common_initial_setup(mfd); + break; + default: + MDDI_MSG_ERR("mddi_toshiba_prim_init from state %d\n", + toshiba_state); + } + + toshiba_prim_start(mfd); + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) + gordon_disp_init(); + mddi_host_write_pix_attr_reg(0x00C3); +} + +static void mddi_toshiba_sec_init(struct msm_fb_data_type *mfd) +{ + + switch (toshiba_state) { + case TOSHIBA_STATE_PRIM_SEC_READY: + break; + case TOSHIBA_STATE_PRIM_SEC_STANDBY: + toshiba_common_initial_setup(mfd); + break; + case TOSHIBA_STATE_PRIM_NORMAL_MODE: + toshiba_prim_lcd_off(mfd); + toshiba_common_initial_setup(mfd); + break; + default: + MDDI_MSG_ERR("mddi_toshiba_sec_init from state %d\n", + toshiba_state); + } + + toshiba_sec_start(mfd); + toshiba_sec_backlight_on(mfd); + toshiba_sec_cont_update_start(mfd); + mddi_host_write_pix_attr_reg(0x0400); +} + +static void mddi_toshiba_lcd_powerdown(struct msm_fb_data_type *mfd) +{ + switch (toshiba_state) { + case TOSHIBA_STATE_PRIM_SEC_READY: + mddi_toshiba_prim_init(mfd); + mddi_toshiba_lcd_powerdown(mfd); + return; + case TOSHIBA_STATE_PRIM_SEC_STANDBY: + break; + case TOSHIBA_STATE_PRIM_NORMAL_MODE: + toshiba_prim_lcd_off(mfd); + break; + case TOSHIBA_STATE_SEC_NORMAL_MODE: + toshiba_sec_cont_update_stop(mfd); + toshiba_sec_sleep_in(mfd); + toshiba_sec_sleep_out(mfd); + toshiba_sec_lcd_off(mfd); + break; + default: + MDDI_MSG_ERR("mddi_toshiba_lcd_powerdown from state %d\n", + toshiba_state); + } +} + +static int mddi_sharpgordon_firsttime = 1; + +static int mddi_toshiba_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 (TM_GET_DID(mfd->panel.id) == TOSHIBA_VGA_PRIM) + mddi_toshiba_prim_init(mfd); + else + mddi_toshiba_sec_init(mfd); + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) { + if (mddi_sharpgordon_firsttime) { + mddi_sharpgordon_firsttime = 0; + write_client_reg(REGENB, 0x00000001, TRUE); + } + } + return 0; +} + +static int mddi_toshiba_lcd_off(struct platform_device *pdev) +{ + mddi_toshiba_lcd_powerdown(platform_get_drvdata(pdev)); + return 0; +} + +static int __init mddi_toshiba_lcd_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + mddi_toshiba_pdata = pdev->dev.platform_data; + return 0; + } + + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = mddi_toshiba_lcd_probe, + .driver = { + .name = "mddi_toshiba", + }, +}; + +static struct msm_fb_panel_data toshiba_panel_data = { + .on = mddi_toshiba_lcd_on, + .off = mddi_toshiba_lcd_off, +}; + +static int ch_used[3]; + +int mddi_toshiba_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel) +{ + struct platform_device *pdev = NULL; + int ret; + + if ((channel >= 3) || ch_used[channel]) + return -ENODEV; + + if ((channel != TOSHIBA_VGA_PRIM) && + mddi_toshiba_pdata && mddi_toshiba_pdata->panel_num) + if (mddi_toshiba_pdata->panel_num() < 2) + return -ENODEV; + + ch_used[channel] = TRUE; + + pdev = platform_device_alloc("mddi_toshiba", (panel << 8)|channel); + if (!pdev) + return -ENOMEM; + + if (channel == TOSHIBA_VGA_PRIM) { + toshiba_panel_data.set_backlight = + mddi_toshiba_lcd_set_backlight; + + if (pinfo->lcd.vsync_enable) { + toshiba_panel_data.set_vsync_notifier = + mddi_toshiba_vsync_set_handler; + mddi_lcd.vsync_detected = + mddi_toshiba_lcd_vsync_detected; + } + } else { + toshiba_panel_data.set_backlight = NULL; + toshiba_panel_data.set_vsync_notifier = NULL; + } + + toshiba_panel_data.panel_info = *pinfo; + + ret = platform_device_add_data(pdev, &toshiba_panel_data, + sizeof(toshiba_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 mddi_toshiba_lcd_init(void) +{ + return platform_driver_register(&this_driver); +} + +module_init(mddi_toshiba_lcd_init); diff --git a/drivers/staging/msm/mddi_toshiba.h b/drivers/staging/msm/mddi_toshiba.h new file mode 100644 index 00000000000..2d22b9a2c41 --- /dev/null +++ b/drivers/staging/msm/mddi_toshiba.h @@ -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 */ diff --git a/drivers/staging/msm/mddi_toshiba_vga.c b/drivers/staging/msm/mddi_toshiba_vga.c new file mode 100644 index 00000000000..7e61d3a5b8f --- /dev/null +++ b/drivers/staging/msm/mddi_toshiba_vga.c @@ -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); diff --git a/drivers/staging/msm/mddi_toshiba_wvga.c b/drivers/staging/msm/mddi_toshiba_wvga.c new file mode 100644 index 00000000000..557b0f08faf --- /dev/null +++ b/drivers/staging/msm/mddi_toshiba_wvga.c @@ -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); diff --git a/drivers/staging/msm/mddi_toshiba_wvga_pt.c b/drivers/staging/msm/mddi_toshiba_wvga_pt.c new file mode 100644 index 00000000000..fc7d4e0d294 --- /dev/null +++ b/drivers/staging/msm/mddi_toshiba_wvga_pt.c @@ -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); diff --git a/drivers/staging/msm/mddihost.c b/drivers/staging/msm/mddihost.c new file mode 100644 index 00000000000..c6c1ee4eda0 --- /dev/null +++ b/drivers/staging/msm/mddihost.c @@ -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 *)(®acc_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); +} diff --git a/drivers/staging/msm/mddihost.h b/drivers/staging/msm/mddihost.h new file mode 100644 index 00000000000..20b817841c4 --- /dev/null +++ b/drivers/staging/msm/mddihost.h @@ -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 */ diff --git a/drivers/staging/msm/mddihost_e.c b/drivers/staging/msm/mddihost_e.c new file mode 100644 index 00000000000..7de5eda71ce --- /dev/null +++ b/drivers/staging/msm/mddihost_e.c @@ -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); +} diff --git a/drivers/staging/msm/mddihosti.c b/drivers/staging/msm/mddihosti.c new file mode 100644 index 00000000000..f9d6e91e8d5 --- /dev/null +++ b/drivers/staging/msm/mddihosti.c @@ -0,0 +1,2239 @@ +/* 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_panel.h" +#include "mddihost.h" +#include "mddihosti.h" + +#define FEATURE_MDDI_UNDERRUN_RECOVERY +#ifndef FEATURE_MDDI_DISABLE_REVERSE +static void mddi_read_rev_packet(byte *data_ptr); +#endif + +struct timer_list mddi_host_timer; + +#define MDDI_DEFAULT_TIMER_LENGTH 5000 /* 5 seconds */ +uint32 mddi_rtd_frequency = 60000; /* send RTD every 60 seconds */ +uint32 mddi_client_status_frequency = 60000; /* get status pkt every 60 secs */ + +boolean mddi_vsync_detect_enabled = FALSE; +mddi_gpio_info_type mddi_gpio; + +uint32 mddi_host_core_version; +boolean mddi_debug_log_statistics = FALSE; +/* #define FEATURE_MDDI_HOST_ENABLE_EARLY_HIBERNATION */ +/* default to TRUE in case MDP does not vote */ +static boolean mddi_host_mdp_active_flag = TRUE; +static uint32 mddi_log_stats_counter; +uint32 mddi_log_stats_frequency = 4000; + +#define MDDI_DEFAULT_REV_PKT_SIZE 0x20 + +#ifndef FEATURE_MDDI_DISABLE_REVERSE +static boolean mddi_rev_ptr_workaround = TRUE; +static uint32 mddi_reg_read_retry; +static uint32 mddi_reg_read_retry_max = 20; +static boolean mddi_enable_reg_read_retry = TRUE; +static boolean mddi_enable_reg_read_retry_once = FALSE; + +#define MDDI_MAX_REV_PKT_SIZE 0x60 + +#define MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE 0x60 + +#define MDDI_VIDEO_REV_PKT_SIZE 0x40 +#define MDDI_REV_BUFFER_SIZE MDDI_MAX_REV_PKT_SIZE +static byte rev_packet_data[MDDI_MAX_REV_PKT_SIZE]; +#endif /* FEATURE_MDDI_DISABLE_REVERSE */ +/* leave these variables so graphics will compile */ + +#define MDDI_MAX_REV_DATA_SIZE 128 +/*lint -d__align(x) */ +boolean mddi_debug_clear_rev_data = TRUE; + +uint32 *mddi_reg_read_value_ptr; + +mddi_client_capability_type mddi_client_capability_pkt; +static boolean mddi_client_capability_request = FALSE; + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + +#define MAX_MDDI_REV_HANDLERS 2 +#define INVALID_PKT_TYPE 0xFFFF + +typedef struct { + mddi_rev_handler_type handler; /* ISR to be executed */ + uint16 pkt_type; +} mddi_rev_pkt_handler_type; +static mddi_rev_pkt_handler_type mddi_rev_pkt_handler[MAX_MDDI_REV_HANDLERS] = + { {NULL, INVALID_PKT_TYPE}, {NULL, INVALID_PKT_TYPE} }; + +static boolean mddi_rev_encap_user_request = FALSE; +static mddi_linked_list_notify_type mddi_rev_user; + +spinlock_t mddi_host_spin_lock; +extern uint32 mdp_in_processing; +#endif + +typedef enum { + MDDI_REV_IDLE +#ifndef FEATURE_MDDI_DISABLE_REVERSE + , MDDI_REV_REG_READ_ISSUED, + MDDI_REV_REG_READ_SENT, + MDDI_REV_ENCAP_ISSUED, + MDDI_REV_STATUS_REQ_ISSUED, + MDDI_REV_CLIENT_CAP_ISSUED +#endif +} mddi_rev_link_state_type; + +typedef enum { + MDDI_LINK_DISABLED, + MDDI_LINK_HIBERNATING, + MDDI_LINK_ACTIVATING, + MDDI_LINK_ACTIVE +} mddi_host_link_state_type; + +typedef struct { + uint32 count; + uint32 in_count; + uint32 disp_req_count; + uint32 state_change_count; + uint32 ll_done_count; + uint32 rev_avail_count; + uint32 error_count; + uint32 rev_encap_count; + uint32 llist_ptr_write_1; + uint32 llist_ptr_write_2; +} mddi_host_int_type; + +typedef struct { + uint32 fwd_crc_count; + uint32 rev_crc_count; + uint32 pri_underflow; + uint32 sec_underflow; + uint32 rev_overflow; + uint32 pri_overwrite; + uint32 sec_overwrite; + uint32 rev_overwrite; + uint32 dma_failure; + uint32 rtd_failure; + uint32 reg_read_failure; +#ifdef FEATURE_MDDI_UNDERRUN_RECOVERY + uint32 pri_underrun_detected; +#endif +} mddi_host_stat_type; + +typedef struct { + uint32 rtd_cnt; + uint32 rev_enc_cnt; + uint32 vid_cnt; + uint32 reg_acc_cnt; + uint32 cli_stat_cnt; + uint32 cli_cap_cnt; + uint32 reg_read_cnt; + uint32 link_active_cnt; + uint32 link_hibernate_cnt; + uint32 vsync_response_cnt; + uint32 fwd_crc_cnt; + uint32 rev_crc_cnt; +} mddi_log_params_struct_type; + +typedef struct { + uint32 rtd_value; + uint32 rtd_counter; + uint32 client_status_cnt; + boolean rev_ptr_written; + uint8 *rev_ptr_start; + uint8 *rev_ptr_curr; + uint32 mddi_rev_ptr_write_val; + dma_addr_t rev_data_dma_addr; + uint16 rev_pkt_size; + mddi_rev_link_state_type rev_state; + mddi_host_link_state_type link_state; + mddi_host_driver_state_type driver_state; + boolean disable_hibernation; + uint32 saved_int_reg; + uint32 saved_int_en; + mddi_linked_list_type *llist_ptr; + dma_addr_t llist_dma_addr; + mddi_linked_list_type *llist_dma_ptr; + uint32 *rev_data_buf; + struct completion mddi_llist_avail_comp; + boolean mddi_waiting_for_llist_avail; + mddi_host_int_type int_type; + mddi_host_stat_type stats; + mddi_log_params_struct_type log_parms; + mddi_llist_info_type llist_info; + mddi_linked_list_notify_type llist_notify[MDDI_MAX_NUM_LLIST_ITEMS]; +} mddi_host_cntl_type; + +static mddi_host_type mddi_curr_host = MDDI_HOST_PRIM; +static mddi_host_cntl_type mhctl[MDDI_NUM_HOST_CORES]; +mddi_linked_list_type *llist_extern[MDDI_NUM_HOST_CORES]; +mddi_linked_list_type *llist_dma_extern[MDDI_NUM_HOST_CORES]; +mddi_linked_list_notify_type *llist_extern_notify[MDDI_NUM_HOST_CORES]; +static mddi_log_params_struct_type prev_parms[MDDI_NUM_HOST_CORES]; + +extern uint32 mdp_total_vdopkts; + +static boolean mddi_host_io_clock_on = FALSE; +static boolean mddi_host_hclk_on = FALSE; + +int int_mddi_pri_flag = FALSE; +int int_mddi_ext_flag = FALSE; + +static void mddi_report_errors(uint32 int_reg) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (int_reg & MDDI_INT_PRI_UNDERFLOW) { + pmhctl->stats.pri_underflow++; + MDDI_MSG_ERR("!!! MDDI Primary Underflow !!!\n"); + } + if (int_reg & MDDI_INT_SEC_UNDERFLOW) { + pmhctl->stats.sec_underflow++; + MDDI_MSG_ERR("!!! MDDI Secondary Underflow !!!\n"); + } +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (int_reg & MDDI_INT_REV_OVERFLOW) { + pmhctl->stats.rev_overflow++; + MDDI_MSG_ERR("!!! MDDI Reverse Overflow !!!\n"); + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + mddi_host_reg_out(REV_PTR, pmhctl->mddi_rev_ptr_write_val); + + } + if (int_reg & MDDI_INT_CRC_ERROR) + MDDI_MSG_ERR("!!! MDDI Reverse CRC Error !!!\n"); +#endif + if (int_reg & MDDI_INT_PRI_OVERWRITE) { + pmhctl->stats.pri_overwrite++; + MDDI_MSG_ERR("!!! MDDI Primary Overwrite !!!\n"); + } + if (int_reg & MDDI_INT_SEC_OVERWRITE) { + pmhctl->stats.sec_overwrite++; + MDDI_MSG_ERR("!!! MDDI Secondary Overwrite !!!\n"); + } +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (int_reg & MDDI_INT_REV_OVERWRITE) { + pmhctl->stats.rev_overwrite++; + /* This will show up normally and is not a problem */ + MDDI_MSG_DEBUG("MDDI Reverse Overwrite!\n"); + } + if (int_reg & MDDI_INT_RTD_FAILURE) { + mddi_host_reg_outm(INTEN, MDDI_INT_RTD_FAILURE, 0); + pmhctl->stats.rtd_failure++; + MDDI_MSG_ERR("!!! MDDI RTD Failure !!!\n"); + } +#endif + if (int_reg & MDDI_INT_DMA_FAILURE) { + pmhctl->stats.dma_failure++; + MDDI_MSG_ERR("!!! MDDI DMA Abort !!!\n"); + } +} + +static void mddi_host_enable_io_clock(void) +{ + if (!MDDI_HOST_IS_IO_CLOCK_ON) + MDDI_HOST_ENABLE_IO_CLOCK; +} + +static void mddi_host_enable_hclk(void) +{ + + if (!MDDI_HOST_IS_HCLK_ON) + MDDI_HOST_ENABLE_HCLK; +} + +static void mddi_host_disable_io_clock(void) +{ +#ifndef FEATURE_MDDI_HOST_IO_CLOCK_CONTROL_DISABLE + if (MDDI_HOST_IS_IO_CLOCK_ON) + MDDI_HOST_DISABLE_IO_CLOCK; +#endif +} + +static void mddi_host_disable_hclk(void) +{ +#ifndef FEATURE_MDDI_HOST_HCLK_CONTROL_DISABLE + if (MDDI_HOST_IS_HCLK_ON) + MDDI_HOST_DISABLE_HCLK; +#endif +} + +static void mddi_vote_to_sleep(mddi_host_type host_idx, boolean sleep) +{ + uint16 vote_mask; + + if (host_idx == MDDI_HOST_PRIM) + vote_mask = 0x01; + else + vote_mask = 0x02; +} + +static void mddi_report_state_change(uint32 int_reg) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if ((pmhctl->saved_int_reg & MDDI_INT_IN_HIBERNATION) && + (pmhctl->saved_int_reg & MDDI_INT_LINK_ACTIVE)) { + /* recover from condition where the io_clock was turned off by the + clock driver during a transition to hibernation. The io_clock + disable is to prevent MDP/MDDI underruns when changing ARM + clock speeds. In the process of halting the ARM, the hclk + divider needs to be set to 1. When it is set to 1, there is + a small time (usecs) when hclk is off or slow, and this can + cause an underrun. To prevent the underrun, clock driver turns + off the MDDI io_clock before making the change. */ + mddi_host_reg_out(CMD, MDDI_CMD_POWERUP); + } + + if (int_reg & MDDI_INT_LINK_ACTIVE) { + pmhctl->link_state = MDDI_LINK_ACTIVE; + pmhctl->log_parms.link_active_cnt++; + pmhctl->rtd_value = mddi_host_reg_in(RTD_VAL); + MDDI_MSG_DEBUG("!!! MDDI Active RTD:0x%x!!!\n", + pmhctl->rtd_value); + /* now interrupt on hibernation */ + mddi_host_reg_outm(INTEN, + (MDDI_INT_IN_HIBERNATION | + MDDI_INT_LINK_ACTIVE), + MDDI_INT_IN_HIBERNATION); + +#ifdef DEBUG_MDDIHOSTI + /* if gpio interrupt is enabled, start polling at fastest + * registered rate + */ + if (mddi_gpio.polling_enabled) { + timer_reg(&mddi_gpio_poll_timer, + mddi_gpio_poll_timer_cb, 0, mddi_gpio.polling_interval, 0); + } +#endif +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (mddi_rev_ptr_workaround) { + /* HW CR: need to reset reverse register stuff */ + pmhctl->rev_ptr_written = FALSE; + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + } +#endif + /* vote on sleep */ + mddi_vote_to_sleep(host_idx, FALSE); + + if (host_idx == MDDI_HOST_PRIM) { + if (mddi_vsync_detect_enabled) { + /* + * Indicate to client specific code that vsync + * was enabled, but we did not detect a client + * intiated wakeup. The client specific + * handler can either reassert vsync detection, + * or treat this as a valid vsync. + */ + mddi_client_lcd_vsync_detected(FALSE); + pmhctl->log_parms.vsync_response_cnt++; + } + } + } + if (int_reg & MDDI_INT_IN_HIBERNATION) { + pmhctl->link_state = MDDI_LINK_HIBERNATING; + pmhctl->log_parms.link_hibernate_cnt++; + MDDI_MSG_DEBUG("!!! MDDI Hibernating !!!\n"); + /* now interrupt on link_active */ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + mddi_host_reg_outm(INTEN, + (MDDI_INT_MDDI_IN | + MDDI_INT_IN_HIBERNATION | + MDDI_INT_LINK_ACTIVE), + MDDI_INT_LINK_ACTIVE); +#else + mddi_host_reg_outm(INTEN, + (MDDI_INT_MDDI_IN | + MDDI_INT_IN_HIBERNATION | + MDDI_INT_LINK_ACTIVE), + (MDDI_INT_MDDI_IN | MDDI_INT_LINK_ACTIVE)); + + pmhctl->rtd_counter = mddi_rtd_frequency; + + if (pmhctl->rev_state != MDDI_REV_IDLE) { + /* a rev_encap will not wake up the link, so we do that here */ + pmhctl->link_state = MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + } +#endif + + if (pmhctl->disable_hibernation) { + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE); + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + pmhctl->link_state = MDDI_LINK_ACTIVATING; + } +#ifdef FEATURE_MDDI_UNDERRUN_RECOVERY + if ((pmhctl->llist_info.transmitting_start_idx != + UNASSIGNED_INDEX) + && + ((pmhctl-> + saved_int_reg & (MDDI_INT_PRI_LINK_LIST_DONE | + MDDI_INT_PRI_PTR_READ)) == + MDDI_INT_PRI_PTR_READ)) { + mddi_linked_list_type *llist_dma; + llist_dma = pmhctl->llist_dma_ptr; + /* + * All indications are that we have not received a + * linked list done interrupt, due to an underrun + * condition. Recovery attempt is to send again. + */ + dma_coherent_pre_ops(); + /* Write to primary pointer register again */ + mddi_host_reg_out(PRI_PTR, + &llist_dma[pmhctl->llist_info. + transmitting_start_idx]); + pmhctl->stats.pri_underrun_detected++; + } +#endif + + /* vote on sleep */ + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + mddi_vote_to_sleep(host_idx, TRUE); + } + +#ifdef DEBUG_MDDIHOSTI + /* need to stop polling timer */ + if (mddi_gpio.polling_enabled) { + (void) timer_clr(&mddi_gpio_poll_timer, T_NONE); + } +#endif + } +} + +void mddi_host_timer_service(unsigned long data) +{ +#ifndef FEATURE_MDDI_DISABLE_REVERSE + unsigned long flags; +#endif + mddi_host_type host_idx; + mddi_host_cntl_type *pmhctl; + + unsigned long time_ms = MDDI_DEFAULT_TIMER_LENGTH; + init_timer(&mddi_host_timer); + mddi_host_timer.function = mddi_host_timer_service; + mddi_host_timer.data = 0; + + mddi_host_timer.expires = jiffies + ((time_ms * HZ) / 1000); + add_timer(&mddi_host_timer); + + for (host_idx = MDDI_HOST_PRIM; host_idx < MDDI_NUM_HOST_CORES; + host_idx++) { + pmhctl = &(mhctl[host_idx]); + mddi_log_stats_counter += (uint32) time_ms; +#ifndef FEATURE_MDDI_DISABLE_REVERSE + pmhctl->rtd_counter += (uint32) time_ms; + pmhctl->client_status_cnt += (uint32) time_ms; + + if (host_idx == MDDI_HOST_PRIM) { + if (pmhctl->client_status_cnt >= + mddi_client_status_frequency) { + if ((pmhctl->link_state == + MDDI_LINK_HIBERNATING) + && (pmhctl->client_status_cnt > + mddi_client_status_frequency)) { + /* + * special case where we are hibernating + * and mddi_host_isr is not firing, so + * kick the link so that the status can + * be retrieved + */ + + /* need to wake up link before issuing + * rev encap command + */ + MDDI_MSG_INFO("wake up link!\n"); + spin_lock_irqsave(&mddi_host_spin_lock, + flags); + mddi_host_enable_hclk(); + mddi_host_enable_io_clock(); + pmhctl->link_state = + MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, + MDDI_CMD_LINK_ACTIVE); + spin_unlock_irqrestore + (&mddi_host_spin_lock, flags); + } else + if ((pmhctl->link_state == MDDI_LINK_ACTIVE) + && pmhctl->disable_hibernation) { + /* + * special case where we have disabled + * hibernation and mddi_host_isr + * is not firing, so enable interrupt + * for no pkts pending, which will + * generate an interrupt + */ + MDDI_MSG_INFO("kick isr!\n"); + spin_lock_irqsave(&mddi_host_spin_lock, + flags); + mddi_host_enable_hclk(); + mddi_host_reg_outm(INTEN, + MDDI_INT_NO_CMD_PKTS_PEND, + MDDI_INT_NO_CMD_PKTS_PEND); + spin_unlock_irqrestore + (&mddi_host_spin_lock, flags); + } + } + } +#endif /* #ifndef FEATURE_MDDI_DISABLE_REVERSE */ + } + + /* Check if logging is turned on */ + for (host_idx = MDDI_HOST_PRIM; host_idx < MDDI_NUM_HOST_CORES; + host_idx++) { + mddi_log_params_struct_type *prev_ptr = &(prev_parms[host_idx]); + pmhctl = &(mhctl[host_idx]); + + if (mddi_debug_log_statistics) { + + /* get video pkt count from MDP, since MDDI sw cannot know this */ + pmhctl->log_parms.vid_cnt = mdp_total_vdopkts; + + if (mddi_log_stats_counter >= mddi_log_stats_frequency) { + /* mddi_log_stats_counter = 0; */ + if (mddi_debug_log_statistics) { + MDDI_MSG_NOTICE + ("MDDI Statistics since last report:\n"); + MDDI_MSG_NOTICE(" Packets sent:\n"); + MDDI_MSG_NOTICE + (" %d RTD packet(s)\n", + pmhctl->log_parms.rtd_cnt - + prev_ptr->rtd_cnt); + if (prev_ptr->rtd_cnt != + pmhctl->log_parms.rtd_cnt) { + unsigned long flags; + spin_lock_irqsave + (&mddi_host_spin_lock, + flags); + mddi_host_enable_hclk(); + pmhctl->rtd_value = + mddi_host_reg_in(RTD_VAL); + spin_unlock_irqrestore + (&mddi_host_spin_lock, + flags); + MDDI_MSG_NOTICE + (" RTD value=%d\n", + pmhctl->rtd_value); + } + MDDI_MSG_NOTICE + (" %d VIDEO packets\n", + pmhctl->log_parms.vid_cnt - + prev_ptr->vid_cnt); + MDDI_MSG_NOTICE + (" %d Register Access packets\n", + pmhctl->log_parms.reg_acc_cnt - + prev_ptr->reg_acc_cnt); + MDDI_MSG_NOTICE + (" %d Reverse Encapsulation packet(s)\n", + pmhctl->log_parms.rev_enc_cnt - + prev_ptr->rev_enc_cnt); + if (prev_ptr->rev_enc_cnt != + pmhctl->log_parms.rev_enc_cnt) { + /* report # of reverse CRC errors */ + MDDI_MSG_NOTICE + (" %d reverse CRC errors detected\n", + pmhctl->log_parms. + rev_crc_cnt - + prev_ptr->rev_crc_cnt); + } + MDDI_MSG_NOTICE + (" Packets received:\n"); + MDDI_MSG_NOTICE + (" %d Client Status packets", + pmhctl->log_parms.cli_stat_cnt - + prev_ptr->cli_stat_cnt); + if (prev_ptr->cli_stat_cnt != + pmhctl->log_parms.cli_stat_cnt) { + MDDI_MSG_NOTICE + (" %d forward CRC errors reported\n", + pmhctl->log_parms. + fwd_crc_cnt - + prev_ptr->fwd_crc_cnt); + } + MDDI_MSG_NOTICE + (" %d Register Access Read packets\n", + pmhctl->log_parms.reg_read_cnt - + prev_ptr->reg_read_cnt); + + if (pmhctl->link_state == + MDDI_LINK_ACTIVE) { + MDDI_MSG_NOTICE + (" Current Link Status: Active\n"); + } else + if ((pmhctl->link_state == + MDDI_LINK_HIBERNATING) + || (pmhctl->link_state == + MDDI_LINK_ACTIVATING)) { + MDDI_MSG_NOTICE + (" Current Link Status: Hibernation\n"); + } else { + MDDI_MSG_NOTICE + (" Current Link Status: Inactive\n"); + } + MDDI_MSG_NOTICE + (" Active state entered %d times\n", + pmhctl->log_parms.link_active_cnt - + prev_ptr->link_active_cnt); + MDDI_MSG_NOTICE + (" Hibernation state entered %d times\n", + pmhctl->log_parms. + link_hibernate_cnt - + prev_ptr->link_hibernate_cnt); + } + } + prev_parms[host_idx] = pmhctl->log_parms; + } + } + if (mddi_log_stats_counter >= mddi_log_stats_frequency) + mddi_log_stats_counter = 0; + + return; +} /* mddi_host_timer_cb */ + +static void mddi_process_link_list_done(void) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + /* normal forward linked list packet(s) were sent */ + if (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) { + MDDI_MSG_ERR("**** getting LL done, but no list ****\n"); + } else { + uint16 idx; + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (pmhctl->rev_state == MDDI_REV_REG_READ_ISSUED) { + /* special case where a register read packet was sent */ + pmhctl->rev_state = MDDI_REV_REG_READ_SENT; + if (pmhctl->llist_info.reg_read_idx == UNASSIGNED_INDEX) { + MDDI_MSG_ERR + ("**** getting LL done, but no list ****\n"); + } + } +#endif + for (idx = pmhctl->llist_info.transmitting_start_idx;;) { + uint16 next_idx = pmhctl->llist_notify[idx].next_idx; + /* with reg read we don't release the waiting tcb until after + * the reverse encapsulation has completed. + */ + if (idx != pmhctl->llist_info.reg_read_idx) { + /* notify task that may be waiting on this completion */ + if (pmhctl->llist_notify[idx].waiting) { + complete(& + (pmhctl->llist_notify[idx]. + done_comp)); + } + if (pmhctl->llist_notify[idx].done_cb != NULL) { + (*(pmhctl->llist_notify[idx].done_cb)) + (); + } + + pmhctl->llist_notify[idx].in_use = FALSE; + pmhctl->llist_notify[idx].waiting = FALSE; + pmhctl->llist_notify[idx].done_cb = NULL; + if (idx < MDDI_NUM_DYNAMIC_LLIST_ITEMS) { + /* static LLIST items are configured only once */ + pmhctl->llist_notify[idx].next_idx = + UNASSIGNED_INDEX; + } + /* + * currently, all linked list packets are + * register access, so we can increment the + * counter for that packet type here. + */ + pmhctl->log_parms.reg_acc_cnt++; + } + if (idx == pmhctl->llist_info.transmitting_end_idx) + break; + idx = next_idx; + if (idx == UNASSIGNED_INDEX) + MDDI_MSG_CRIT("MDDI linked list corruption!\n"); + } + + pmhctl->llist_info.transmitting_start_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.transmitting_end_idx = UNASSIGNED_INDEX; + + if (pmhctl->mddi_waiting_for_llist_avail) { + if (! + (pmhctl-> + llist_notify[pmhctl->llist_info.next_free_idx]. + in_use)) { + pmhctl->mddi_waiting_for_llist_avail = FALSE; + complete(&(pmhctl->mddi_llist_avail_comp)); + } + } + } + + /* Turn off MDDI_INT_PRI_LINK_LIST_DONE interrupt */ + mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE, 0); + +} + +static void mddi_queue_forward_linked_list(void) +{ + uint16 first_pkt_index; + mddi_linked_list_type *llist_dma; + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + llist_dma = pmhctl->llist_dma_ptr; + + first_pkt_index = UNASSIGNED_INDEX; + + if (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) { +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (pmhctl->llist_info.reg_read_waiting) { + if (pmhctl->rev_state == MDDI_REV_IDLE) { + /* + * we have a register read to send and + * can send it now + */ + pmhctl->rev_state = MDDI_REV_REG_READ_ISSUED; + mddi_reg_read_retry = 0; + first_pkt_index = + pmhctl->llist_info.waiting_start_idx; + pmhctl->llist_info.reg_read_waiting = FALSE; + } + } else +#endif + { + /* + * not register read to worry about, go ahead and write + * anything that may be on the waiting list. + */ + first_pkt_index = pmhctl->llist_info.waiting_start_idx; + } + } + + if (first_pkt_index != UNASSIGNED_INDEX) { + pmhctl->llist_info.transmitting_start_idx = + pmhctl->llist_info.waiting_start_idx; + pmhctl->llist_info.transmitting_end_idx = + pmhctl->llist_info.waiting_end_idx; + pmhctl->llist_info.waiting_start_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.waiting_end_idx = UNASSIGNED_INDEX; + + /* write to the primary pointer register */ + MDDI_MSG_DEBUG("MDDI writing primary ptr with idx=%d\n", + first_pkt_index); + + pmhctl->int_type.llist_ptr_write_2++; + + dma_coherent_pre_ops(); + mddi_host_reg_out(PRI_PTR, &llist_dma[first_pkt_index]); + + /* enable interrupt when complete */ + mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE, + MDDI_INT_PRI_LINK_LIST_DONE); + + } + +} + +#ifndef FEATURE_MDDI_DISABLE_REVERSE +static void mddi_read_rev_packet(byte *data_ptr) +{ + uint16 i, length; + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + uint8 *rev_ptr_overflow = + (pmhctl->rev_ptr_start + MDDI_REV_BUFFER_SIZE); + + /* first determine the length and handle invalid lengths */ + length = *pmhctl->rev_ptr_curr++; + if (pmhctl->rev_ptr_curr >= rev_ptr_overflow) + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + length |= ((*pmhctl->rev_ptr_curr++) << 8); + if (pmhctl->rev_ptr_curr >= rev_ptr_overflow) + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + if (length > (pmhctl->rev_pkt_size - 2)) { + MDDI_MSG_ERR("Invalid rev pkt length %d\n", length); + /* rev_pkt_size should always be <= rev_ptr_size so limit to packet size */ + length = pmhctl->rev_pkt_size - 2; + } + + /* If the data pointer is NULL, just increment the pmhctl->rev_ptr_curr. + * Loop around if necessary. Don't bother reading the data. + */ + if (data_ptr == NULL) { + pmhctl->rev_ptr_curr += length; + if (pmhctl->rev_ptr_curr >= rev_ptr_overflow) + pmhctl->rev_ptr_curr -= MDDI_REV_BUFFER_SIZE; + return; + } + + data_ptr[0] = length & 0x0ff; + data_ptr[1] = length >> 8; + data_ptr += 2; + /* copy the data to data_ptr byte-at-a-time */ + for (i = 0; (i < length) && (pmhctl->rev_ptr_curr < rev_ptr_overflow); + i++) + *data_ptr++ = *pmhctl->rev_ptr_curr++; + if (pmhctl->rev_ptr_curr >= rev_ptr_overflow) + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + for (; (i < length) && (pmhctl->rev_ptr_curr < rev_ptr_overflow); i++) + *data_ptr++ = *pmhctl->rev_ptr_curr++; +} + +static void mddi_process_rev_packets(void) +{ + uint32 rev_packet_count; + word i; + uint32 crc_errors; + boolean mddi_reg_read_successful = FALSE; + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + pmhctl->log_parms.rev_enc_cnt++; + if ((pmhctl->rev_state != MDDI_REV_ENCAP_ISSUED) && + (pmhctl->rev_state != MDDI_REV_STATUS_REQ_ISSUED) && + (pmhctl->rev_state != MDDI_REV_CLIENT_CAP_ISSUED)) { + MDDI_MSG_ERR("Wrong state %d for reverse int\n", + pmhctl->rev_state); + } + /* Turn off MDDI_INT_REV_AVAIL interrupt */ + mddi_host_reg_outm(INTEN, MDDI_INT_REV_DATA_AVAIL, 0); + + /* Clear rev data avail int */ + mddi_host_reg_out(INT, MDDI_INT_REV_DATA_AVAIL); + + /* Get Number of packets */ + rev_packet_count = mddi_host_reg_in(REV_PKT_CNT); + +#ifndef T_MSM7500 + /* Clear out rev packet counter */ + mddi_host_reg_out(REV_PKT_CNT, 0x0000); +#endif + +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) + if ((pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED) && + (rev_packet_count > 0) && + (mddi_host_core_version == 0x28 || + mddi_host_core_version == 0x30)) { + + uint32 int_reg; + uint32 max_count = 0; + + mddi_host_reg_out(REV_PTR, pmhctl->mddi_rev_ptr_write_val); + int_reg = mddi_host_reg_in(INT); + while ((int_reg & 0x100000) == 0) { + udelay(3); + int_reg = mddi_host_reg_in(INT); + if (++max_count > 100) + break; + } + } +#endif + + /* Get CRC error count */ + crc_errors = mddi_host_reg_in(REV_CRC_ERR); + if (crc_errors != 0) { + pmhctl->log_parms.rev_crc_cnt += crc_errors; + pmhctl->stats.rev_crc_count += crc_errors; + MDDI_MSG_ERR("!!! MDDI %d Reverse CRC Error(s) !!!\n", + crc_errors); +#ifndef T_MSM7500 + /* Clear CRC error count */ + mddi_host_reg_out(REV_CRC_ERR, 0x0000); +#endif + /* also issue an RTD to attempt recovery */ + pmhctl->rtd_counter = mddi_rtd_frequency; + } + + pmhctl->rtd_value = mddi_host_reg_in(RTD_VAL); + + MDDI_MSG_DEBUG("MDDI rev pkt cnt=%d, ptr=0x%x, RTD:0x%x\n", + rev_packet_count, + pmhctl->rev_ptr_curr - pmhctl->rev_ptr_start, + pmhctl->rtd_value); + + if (rev_packet_count >= 1) { + mddi_invalidate_cache_lines((uint32 *) pmhctl->rev_ptr_start, + MDDI_REV_BUFFER_SIZE); + } + /* order the reads */ + dma_coherent_post_ops(); + for (i = 0; i < rev_packet_count; i++) { + mddi_rev_packet_type *rev_pkt_ptr; + + mddi_read_rev_packet(rev_packet_data); + + rev_pkt_ptr = (mddi_rev_packet_type *) rev_packet_data; + + if (rev_pkt_ptr->packet_length > pmhctl->rev_pkt_size) { + MDDI_MSG_ERR("!!!invalid packet size: %d\n", + rev_pkt_ptr->packet_length); + } + + MDDI_MSG_DEBUG("MDDI rev pkt 0x%x size 0x%x\n", + rev_pkt_ptr->packet_type, + rev_pkt_ptr->packet_length); + + /* Do whatever you want to do with the data based on the packet type */ + switch (rev_pkt_ptr->packet_type) { + case 66: /* Client Capability */ + { + mddi_client_capability_type + *client_capability_pkt_ptr; + + client_capability_pkt_ptr = + (mddi_client_capability_type *) + rev_packet_data; + MDDI_MSG_NOTICE + ("Client Capability: Week=%d, Year=%d\n", + client_capability_pkt_ptr-> + Week_of_Manufacture, + client_capability_pkt_ptr-> + Year_of_Manufacture); + memcpy((void *)&mddi_client_capability_pkt, + (void *)rev_packet_data, + sizeof(mddi_client_capability_type)); + pmhctl->log_parms.cli_cap_cnt++; + } + break; + + case 70: /* Display Status */ + { + mddi_client_status_type *client_status_pkt_ptr; + + client_status_pkt_ptr = + (mddi_client_status_type *) rev_packet_data; + if ((client_status_pkt_ptr->crc_error_count != + 0) + || (client_status_pkt_ptr-> + reverse_link_request != 0)) { + MDDI_MSG_ERR + ("Client Status: RevReq=%d, CrcErr=%d\n", + client_status_pkt_ptr-> + reverse_link_request, + client_status_pkt_ptr-> + crc_error_count); + } else { + MDDI_MSG_DEBUG + ("Client Status: RevReq=%d, CrcErr=%d\n", + client_status_pkt_ptr-> + reverse_link_request, + client_status_pkt_ptr-> + crc_error_count); + } + pmhctl->log_parms.fwd_crc_cnt += + client_status_pkt_ptr->crc_error_count; + pmhctl->stats.fwd_crc_count += + client_status_pkt_ptr->crc_error_count; + pmhctl->log_parms.cli_stat_cnt++; + } + break; + + case 146: /* register access packet */ + { + mddi_register_access_packet_type + * regacc_pkt_ptr; + + regacc_pkt_ptr = + (mddi_register_access_packet_type *) + rev_packet_data; + + MDDI_MSG_DEBUG + ("Reg Acc parse reg=0x%x, value=0x%x\n", + regacc_pkt_ptr->register_address, + regacc_pkt_ptr->register_data_list); + + /* Copy register value to location passed in */ + if (mddi_reg_read_value_ptr) { +#if defined(T_MSM6280) && !defined(T_MSM7200) + /* only least significant 16 bits are valid with 6280 */ + *mddi_reg_read_value_ptr = + regacc_pkt_ptr-> + register_data_list & 0x0000ffff; +#else + *mddi_reg_read_value_ptr = + regacc_pkt_ptr->register_data_list; +#endif + mddi_reg_read_successful = TRUE; + mddi_reg_read_value_ptr = NULL; + } + +#ifdef DEBUG_MDDIHOSTI + if ((mddi_gpio.polling_enabled) && + (regacc_pkt_ptr->register_address == + mddi_gpio.polling_reg)) { + /* + * ToDo: need to call Linux GPIO call + * here... + */ + mddi_client_lcd_gpio_poll( + regacc_pkt_ptr->register_data_list); + } +#endif + pmhctl->log_parms.reg_read_cnt++; + } + break; + + default: /* any other packet */ + { + uint16 hdlr; + + for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; + hdlr++) { + if (mddi_rev_pkt_handler[hdlr]. + pkt_type == + rev_pkt_ptr->packet_type) { + (* + (mddi_rev_pkt_handler[hdlr]. + handler)) (rev_pkt_ptr); + /* pmhctl->rev_state = MDDI_REV_IDLE; */ + break; + } + } + if (hdlr >= MAX_MDDI_REV_HANDLERS) + MDDI_MSG_ERR("MDDI unknown rev pkt\n"); + } + break; + } + } + if ((pmhctl->rev_ptr_curr + pmhctl->rev_pkt_size) >= + (pmhctl->rev_ptr_start + MDDI_REV_BUFFER_SIZE)) { + pmhctl->rev_ptr_written = FALSE; + } + + if (pmhctl->rev_state == MDDI_REV_ENCAP_ISSUED) { + pmhctl->rev_state = MDDI_REV_IDLE; + if (mddi_rev_user.waiting) { + mddi_rev_user.waiting = FALSE; + complete(&(mddi_rev_user.done_comp)); + } else if (pmhctl->llist_info.reg_read_idx == UNASSIGNED_INDEX) { + MDDI_MSG_ERR + ("Reverse Encap state, but no reg read in progress\n"); + } else { + if ((!mddi_reg_read_successful) && + (mddi_reg_read_retry < mddi_reg_read_retry_max) && + (mddi_enable_reg_read_retry)) { + /* + * There is a race condition that can happen + * where the reverse encapsulation message is + * sent out by the MDDI host before the register + * read packet is sent. As a work-around for + * that problem we issue the reverse + * encapsulation one more time before giving up. + */ + if (mddi_enable_reg_read_retry_once) + mddi_reg_read_retry = + mddi_reg_read_retry_max; + pmhctl->rev_state = MDDI_REV_REG_READ_SENT; + pmhctl->stats.reg_read_failure++; + } else { + uint16 reg_read_idx = + pmhctl->llist_info.reg_read_idx; + + mddi_reg_read_retry = 0; + if (pmhctl->llist_notify[reg_read_idx].waiting) { + complete(& + (pmhctl-> + llist_notify[reg_read_idx]. + done_comp)); + } + pmhctl->llist_info.reg_read_idx = + UNASSIGNED_INDEX; + if (pmhctl->llist_notify[reg_read_idx]. + done_cb != NULL) { + (* + (pmhctl->llist_notify[reg_read_idx]. + done_cb)) (); + } + pmhctl->llist_notify[reg_read_idx].next_idx = + UNASSIGNED_INDEX; + pmhctl->llist_notify[reg_read_idx].in_use = + FALSE; + pmhctl->llist_notify[reg_read_idx].waiting = + FALSE; + pmhctl->llist_notify[reg_read_idx].done_cb = + NULL; + if (!mddi_reg_read_successful) + pmhctl->stats.reg_read_failure++; + } + } + } else if (pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED) { +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) + if (mddi_host_core_version == 0x28 || + mddi_host_core_version == 0x30) { + mddi_host_reg_out(FIFO_ALLOC, 0x00); + pmhctl->rev_ptr_written = TRUE; + mddi_host_reg_out(REV_PTR, + pmhctl->mddi_rev_ptr_write_val); + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + mddi_host_reg_out(CMD, 0xC00); + } +#endif + + if (mddi_rev_user.waiting) { + mddi_rev_user.waiting = FALSE; + complete(&(mddi_rev_user.done_comp)); + } + pmhctl->rev_state = MDDI_REV_IDLE; + } else { + pmhctl->rev_state = MDDI_REV_IDLE; + } + + /* pmhctl->rev_state = MDDI_REV_IDLE; */ + + /* Re-enable interrupt */ + mddi_host_reg_outm(INTEN, MDDI_INT_REV_DATA_AVAIL, + MDDI_INT_REV_DATA_AVAIL); + +} + +static void mddi_issue_reverse_encapsulation(void) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + /* Only issue a reverse encapsulation packet if: + * 1) another reverse is not in progress (MDDI_REV_IDLE). + * 2) a register read has been sent (MDDI_REV_REG_READ_SENT). + * 3) forward is not in progress, because of a hw bug in client that + * causes forward crc errors on packet immediately after rev encap. + */ + if (((pmhctl->rev_state == MDDI_REV_IDLE) || + (pmhctl->rev_state == MDDI_REV_REG_READ_SENT)) && + (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) && + (!mdp_in_processing)) { + uint32 mddi_command = MDDI_CMD_SEND_REV_ENCAP; + + if ((pmhctl->rev_state == MDDI_REV_REG_READ_SENT) || + (mddi_rev_encap_user_request == TRUE)) { + mddi_host_enable_io_clock(); + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + /* need to wake up link before issuing rev encap command */ + MDDI_MSG_DEBUG("wake up link!\n"); + pmhctl->link_state = MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + } else { + if (pmhctl->rtd_counter >= mddi_rtd_frequency) { + MDDI_MSG_DEBUG + ("mddi sending RTD command!\n"); + mddi_host_reg_out(CMD, + MDDI_CMD_SEND_RTD); + pmhctl->rtd_counter = 0; + pmhctl->log_parms.rtd_cnt++; + } + if (pmhctl->rev_state != MDDI_REV_REG_READ_SENT) { + /* this is generic reverse request by user, so + * reset the waiting flag. */ + mddi_rev_encap_user_request = FALSE; + } + /* link is active so send reverse encap to get register read results */ + pmhctl->rev_state = MDDI_REV_ENCAP_ISSUED; + mddi_command = MDDI_CMD_SEND_REV_ENCAP; + MDDI_MSG_DEBUG("sending rev encap!\n"); + } + } else + if ((pmhctl->client_status_cnt >= + mddi_client_status_frequency) + || mddi_client_capability_request) { + mddi_host_enable_io_clock(); + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + /* only wake up the link if it client status is overdue */ + if ((pmhctl->client_status_cnt >= + (mddi_client_status_frequency * 2)) + || mddi_client_capability_request) { + /* need to wake up link before issuing rev encap command */ + MDDI_MSG_DEBUG("wake up link!\n"); + pmhctl->link_state = + MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, + MDDI_CMD_LINK_ACTIVE); + } + } else { + if (pmhctl->rtd_counter >= mddi_rtd_frequency) { + MDDI_MSG_DEBUG + ("mddi sending RTD command!\n"); + mddi_host_reg_out(CMD, + MDDI_CMD_SEND_RTD); + pmhctl->rtd_counter = 0; + pmhctl->log_parms.rtd_cnt++; + } + /* periodically get client status */ + MDDI_MSG_DEBUG + ("mddi sending rev enc! (get status)\n"); + if (mddi_client_capability_request) { + pmhctl->rev_state = + MDDI_REV_CLIENT_CAP_ISSUED; + mddi_command = MDDI_CMD_GET_CLIENT_CAP; + mddi_client_capability_request = FALSE; + } else { + pmhctl->rev_state = + MDDI_REV_STATUS_REQ_ISSUED; + pmhctl->client_status_cnt = 0; + mddi_command = + MDDI_CMD_GET_CLIENT_STATUS; + } + } + } + if ((pmhctl->rev_state == MDDI_REV_ENCAP_ISSUED) || + (pmhctl->rev_state == MDDI_REV_STATUS_REQ_ISSUED) || + (pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED)) { + pmhctl->int_type.rev_encap_count++; +#if defined(T_MSM6280) && !defined(T_MSM7200) + mddi_rev_pointer_written = TRUE; + mddi_host_reg_out(REV_PTR, mddi_rev_ptr_write_val); + mddi_rev_ptr_curr = mddi_rev_ptr_start; + /* force new rev ptr command */ + mddi_host_reg_out(CMD, 0xC00); +#else + if (!pmhctl->rev_ptr_written) { + MDDI_MSG_DEBUG("writing reverse pointer!\n"); + pmhctl->rev_ptr_written = TRUE; +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) + if ((pmhctl->rev_state == + MDDI_REV_CLIENT_CAP_ISSUED) && + (mddi_host_core_version == 0x28 || + mddi_host_core_version == 0x30)) { + pmhctl->rev_ptr_written = FALSE; + mddi_host_reg_out(FIFO_ALLOC, 0x02); + } else + mddi_host_reg_out(REV_PTR, + pmhctl-> + mddi_rev_ptr_write_val); +#else + mddi_host_reg_out(REV_PTR, + pmhctl-> + mddi_rev_ptr_write_val); +#endif + } +#endif + if (mddi_debug_clear_rev_data) { + uint16 i; + for (i = 0; i < MDDI_MAX_REV_DATA_SIZE / 4; i++) + pmhctl->rev_data_buf[i] = 0xdddddddd; + /* clean cache */ + mddi_flush_cache_lines(pmhctl->rev_data_buf, + MDDI_MAX_REV_DATA_SIZE); + } + + /* send reverse encapsulation to get needed data */ + mddi_host_reg_out(CMD, mddi_command); + } + } + +} + +static void mddi_process_client_initiated_wakeup(void) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + /* Disable MDDI_INT Interrupt, we detect client initiated wakeup one + * time for each entry into hibernation */ + mddi_host_reg_outm(INTEN, MDDI_INT_MDDI_IN, 0); + + if (host_idx == MDDI_HOST_PRIM) { + if (mddi_vsync_detect_enabled) { + mddi_host_enable_io_clock(); +#ifndef MDDI_HOST_DISP_LISTEN + /* issue command to bring up link */ + /* need to do this to clear the vsync condition */ + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + pmhctl->link_state = MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + } +#endif + /* + * Indicate to client specific code that vsync was + * enabled, and we did not detect a client initiated + * wakeup. The client specific handler can clear the + * condition if necessary to prevent subsequent + * client initiated wakeups. + */ + mddi_client_lcd_vsync_detected(TRUE); + pmhctl->log_parms.vsync_response_cnt++; + MDDI_MSG_NOTICE("MDDI_INT_IN condition\n"); + + } + } + + if (mddi_gpio.polling_enabled) { + mddi_host_enable_io_clock(); + /* check interrupt status now */ + (void)mddi_queue_register_read_int(mddi_gpio.polling_reg, + &mddi_gpio.polling_val); + } +} +#endif /* FEATURE_MDDI_DISABLE_REVERSE */ + +static void mddi_host_isr(void) +{ + uint32 int_reg, int_en; +#ifndef FEATURE_MDDI_DISABLE_REVERSE + uint32 status_reg; +#endif + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (!MDDI_HOST_IS_HCLK_ON) { + MDDI_HOST_ENABLE_HCLK; + MDDI_MSG_DEBUG("HCLK disabled, but isr is firing\n"); + } + int_reg = mddi_host_reg_in(INT); + int_en = mddi_host_reg_in(INTEN); + pmhctl->saved_int_reg = int_reg; + pmhctl->saved_int_en = int_en; + int_reg = int_reg & int_en; + pmhctl->int_type.count++; + + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + status_reg = mddi_host_reg_in(STAT); + + if ((int_reg & MDDI_INT_MDDI_IN) || + ((int_en & MDDI_INT_MDDI_IN) && + ((int_reg == 0) || (status_reg & MDDI_STAT_CLIENT_WAKEUP_REQ)))) { + /* + * The MDDI_IN condition will clear itself, and so it is + * possible that MDDI_IN was the reason for the isr firing, + * even though the interrupt register does not have the + * MDDI_IN bit set. To check if this was the case we need to + * look at the status register bit that signifies a client + * initiated wakeup. If the status register bit is set, as well + * as the MDDI_IN interrupt enabled, then we treat this as a + * client initiated wakeup. + */ + if (int_reg & MDDI_INT_MDDI_IN) + pmhctl->int_type.in_count++; + mddi_process_client_initiated_wakeup(); + } +#endif + + if (int_reg & MDDI_INT_LINK_STATE_CHANGES) { + pmhctl->int_type.state_change_count++; + mddi_report_state_change(int_reg); + } + + if (int_reg & MDDI_INT_PRI_LINK_LIST_DONE) { + pmhctl->int_type.ll_done_count++; + mddi_process_link_list_done(); + } +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (int_reg & MDDI_INT_REV_DATA_AVAIL) { + pmhctl->int_type.rev_avail_count++; + mddi_process_rev_packets(); + } +#endif + + if (int_reg & MDDI_INT_ERROR_CONDITIONS) { + pmhctl->int_type.error_count++; + mddi_report_errors(int_reg); + + mddi_host_reg_out(INT, int_reg & MDDI_INT_ERROR_CONDITIONS); + } +#ifndef FEATURE_MDDI_DISABLE_REVERSE + mddi_issue_reverse_encapsulation(); + + if ((pmhctl->rev_state != MDDI_REV_ENCAP_ISSUED) && + (pmhctl->rev_state != MDDI_REV_STATUS_REQ_ISSUED)) +#endif + /* don't want simultaneous reverse and forward with Eagle */ + mddi_queue_forward_linked_list(); + + if (int_reg & MDDI_INT_NO_CMD_PKTS_PEND) { + /* this interrupt is used to kick the isr when hibernation is disabled */ + mddi_host_reg_outm(INTEN, MDDI_INT_NO_CMD_PKTS_PEND, 0); + } + + if ((!mddi_host_mdp_active_flag) && + (!mddi_vsync_detect_enabled) && + (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) && + (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) && + (pmhctl->rev_state == MDDI_REV_IDLE)) { + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + mddi_host_disable_io_clock(); + mddi_host_disable_hclk(); + } +#ifdef FEATURE_MDDI_HOST_ENABLE_EARLY_HIBERNATION + else if ((pmhctl->link_state == MDDI_LINK_ACTIVE) && + (!pmhctl->disable_hibernation)) { + mddi_host_reg_out(CMD, MDDI_CMD_POWERDOWN); + } +#endif + } +} + +static void mddi_host_isr_primary(void) +{ + mddi_curr_host = MDDI_HOST_PRIM; + mddi_host_isr(); +} + +irqreturn_t mddi_pmdh_isr_proxy(int irq, void *ptr) +{ + mddi_host_isr_primary(); + return IRQ_HANDLED; +} + +static void mddi_host_isr_external(void) +{ + mddi_curr_host = MDDI_HOST_EXT; + mddi_host_isr(); + mddi_curr_host = MDDI_HOST_PRIM; +} + +irqreturn_t mddi_emdh_isr_proxy(int irq, void *ptr) +{ + mddi_host_isr_external(); + return IRQ_HANDLED; +} + +static void mddi_host_initialize_registers(mddi_host_type host_idx) +{ + uint32 pad_reg_val; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (pmhctl->driver_state == MDDI_DRIVER_ENABLED) + return; + + /* turn on HCLK to MDDI host core */ + mddi_host_enable_hclk(); + + /* MDDI Reset command */ + mddi_host_reg_out(CMD, MDDI_CMD_RESET); + + /* Version register (= 0x01) */ + mddi_host_reg_out(VERSION, 0x0001); + + /* Bytes per subframe register */ + mddi_host_reg_out(BPS, MDDI_HOST_BYTES_PER_SUBFRAME); + + /* Subframes per media frames register (= 0x03) */ + mddi_host_reg_out(SPM, 0x0003); + + /* Turn Around 1 register (= 0x05) */ + mddi_host_reg_out(TA1_LEN, 0x0005); + + /* Turn Around 2 register (= 0x0C) */ + mddi_host_reg_out(TA2_LEN, MDDI_HOST_TA2_LEN); + + /* Drive hi register (= 0x96) */ + mddi_host_reg_out(DRIVE_HI, 0x0096); + + /* Drive lo register (= 0x32) */ + mddi_host_reg_out(DRIVE_LO, 0x0032); + + /* Display wakeup count register (= 0x3c) */ + mddi_host_reg_out(DISP_WAKE, 0x003c); + + /* Reverse Rate Divisor register (= 0x2) */ + mddi_host_reg_out(REV_RATE_DIV, MDDI_HOST_REV_RATE_DIV); + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + /* Reverse Pointer Size */ + mddi_host_reg_out(REV_SIZE, MDDI_REV_BUFFER_SIZE); + + /* Rev Encap Size */ + mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size); +#endif + + /* Periodic Rev Encap */ + /* don't send periodically */ + mddi_host_reg_out(CMD, MDDI_CMD_PERIODIC_REV_ENCAP); + + pad_reg_val = mddi_host_reg_in(PAD_CTL); + if (pad_reg_val == 0) { + /* If we are turning on band gap, need to wait 5us before turning + * on the rest of the PAD */ + mddi_host_reg_out(PAD_CTL, 0x08000); + udelay(5); + } +#ifdef T_MSM7200 + /* Recommendation from PAD hw team */ + mddi_host_reg_out(PAD_CTL, 0xa850a); +#else + /* Recommendation from PAD hw team */ + mddi_host_reg_out(PAD_CTL, 0xa850f); +#endif + +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) + mddi_host_reg_out(PAD_IO_CTL, 0x00320000); + mddi_host_reg_out(PAD_CAL, 0x00220020); +#endif + + mddi_host_core_version = mddi_host_reg_inm(CORE_VER, 0xffff); + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (mddi_host_core_version >= 8) + mddi_rev_ptr_workaround = FALSE; + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; +#endif + + if ((mddi_host_core_version > 8) && (mddi_host_core_version < 0x19)) + mddi_host_reg_out(TEST, 0x2); + + /* Need an even number for counts */ + mddi_host_reg_out(DRIVER_START_CNT, 0x60006); + +#ifndef T_MSM7500 + /* Setup defaults for MDP related register */ + mddi_host_reg_out(MDP_VID_FMT_DES, 0x5666); + mddi_host_reg_out(MDP_VID_PIX_ATTR, 0x00C3); + mddi_host_reg_out(MDP_VID_CLIENTID, 0); +#endif + + /* automatically hibernate after 1 empty subframe */ + if (pmhctl->disable_hibernation) + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE); + else + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1); + + /* Bring up link if display (client) requests it */ +#ifdef MDDI_HOST_DISP_LISTEN + mddi_host_reg_out(CMD, MDDI_CMD_DISP_LISTEN); +#else + mddi_host_reg_out(CMD, MDDI_CMD_DISP_IGNORE); +#endif + +} + +void mddi_host_configure_interrupts(mddi_host_type host_idx, boolean enable) +{ + unsigned long flags; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + /* turn on HCLK to MDDI host core if it has been disabled */ + mddi_host_enable_hclk(); + /* Clear MDDI Interrupt enable reg */ + mddi_host_reg_out(INTEN, 0); + + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (enable) { + pmhctl->driver_state = MDDI_DRIVER_ENABLED; + + if (host_idx == MDDI_HOST_PRIM) { + if (request_irq + (INT_MDDI_PRI, mddi_pmdh_isr_proxy, IRQF_DISABLED, + "PMDH", 0) != 0) + printk(KERN_ERR + "a mddi: unable to request_irq\n"); + else + int_mddi_pri_flag = TRUE; + } else { + if (request_irq + (INT_MDDI_EXT, mddi_emdh_isr_proxy, IRQF_DISABLED, + "EMDH", 0) != 0) + printk(KERN_ERR + "b mddi: unable to request_irq\n"); + else + int_mddi_ext_flag = TRUE; + } + + /* Set MDDI Interrupt enable reg -- Enable Reverse data avail */ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + mddi_host_reg_out(INTEN, + MDDI_INT_ERROR_CONDITIONS | + MDDI_INT_LINK_STATE_CHANGES); +#else + /* Reverse Pointer register */ + pmhctl->rev_ptr_written = FALSE; + + mddi_host_reg_out(INTEN, + MDDI_INT_REV_DATA_AVAIL | + MDDI_INT_ERROR_CONDITIONS | + MDDI_INT_LINK_STATE_CHANGES); + pmhctl->rtd_counter = mddi_rtd_frequency; + pmhctl->client_status_cnt = 0; +#endif + } else { + if (pmhctl->driver_state == MDDI_DRIVER_ENABLED) + pmhctl->driver_state = MDDI_DRIVER_DISABLED; + } + +} + +static void mddi_host_powerup(mddi_host_type host_idx) +{ + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (pmhctl->link_state != MDDI_LINK_DISABLED) + return; + + /* enable IO_CLK and hclk to MDDI host core */ + mddi_host_enable_io_clock(); + + mddi_host_initialize_registers(host_idx); + mddi_host_configure_interrupts(host_idx, TRUE); + + pmhctl->link_state = MDDI_LINK_ACTIVATING; + + /* Link activate command */ + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + +#ifdef CLKRGM_MDDI_IO_CLOCK_IN_MHZ + MDDI_MSG_NOTICE("MDDI Host: Activating Link %d Mbps\n", + CLKRGM_MDDI_IO_CLOCK_IN_MHZ * 2); +#else + MDDI_MSG_NOTICE("MDDI Host: Activating Link\n"); +#endif + + /* Initialize the timer */ + if (host_idx == MDDI_HOST_PRIM) + mddi_host_timer_service(0); +} + +void mddi_host_init(mddi_host_type host_idx) +/* Write out the MDDI configuration registers */ +{ + static boolean initialized = FALSE; + mddi_host_cntl_type *pmhctl; + + if (host_idx >= MDDI_NUM_HOST_CORES) { + MDDI_MSG_ERR("Invalid host core index\n"); + return; + } + + if (!initialized) { + uint16 idx; + mddi_host_type host; + for (host = MDDI_HOST_PRIM; host < MDDI_NUM_HOST_CORES; host++) { + pmhctl = &(mhctl[host]); + initialized = TRUE; + + pmhctl->llist_ptr = + dma_alloc_coherent(NULL, MDDI_LLIST_POOL_SIZE, + &(pmhctl->llist_dma_addr), + GFP_KERNEL); + pmhctl->llist_dma_ptr = + (mddi_linked_list_type *) (void *)pmhctl-> + llist_dma_addr; +#ifdef FEATURE_MDDI_DISABLE_REVERSE + pmhctl->rev_data_buf = NULL; + if (pmhctl->llist_ptr == NULL) +#else + mddi_rev_user.waiting = FALSE; + init_completion(&(mddi_rev_user.done_comp)); + pmhctl->rev_data_buf = + dma_alloc_coherent(NULL, MDDI_MAX_REV_DATA_SIZE, + &(pmhctl->rev_data_dma_addr), + GFP_KERNEL); + if ((pmhctl->llist_ptr == NULL) + || (pmhctl->rev_data_buf == NULL)) +#endif + { + MDDI_MSG_CRIT + ("unable to alloc non-cached memory\n"); + } + llist_extern[host] = pmhctl->llist_ptr; + llist_dma_extern[host] = pmhctl->llist_dma_ptr; + llist_extern_notify[host] = pmhctl->llist_notify; + + for (idx = 0; idx < UNASSIGNED_INDEX; idx++) { + init_completion(& + (pmhctl->llist_notify[idx]. + done_comp)); + } + init_completion(&(pmhctl->mddi_llist_avail_comp)); + spin_lock_init(&mddi_host_spin_lock); + pmhctl->mddi_waiting_for_llist_avail = FALSE; + pmhctl->mddi_rev_ptr_write_val = + (uint32) (void *)(pmhctl->rev_data_dma_addr); + pmhctl->rev_ptr_start = (void *)pmhctl->rev_data_buf; + + pmhctl->rev_pkt_size = MDDI_DEFAULT_REV_PKT_SIZE; + pmhctl->rev_state = MDDI_REV_IDLE; +#ifdef IMAGE_MODEM_PROC + /* assume hibernation state is last state from APPS proc, so that + * we don't reinitialize the host core */ + pmhctl->link_state = MDDI_LINK_HIBERNATING; +#else + pmhctl->link_state = MDDI_LINK_DISABLED; +#endif + pmhctl->driver_state = MDDI_DRIVER_DISABLED; + pmhctl->disable_hibernation = FALSE; + + /* initialize llist variables */ + pmhctl->llist_info.transmitting_start_idx = + UNASSIGNED_INDEX; + pmhctl->llist_info.transmitting_end_idx = + UNASSIGNED_INDEX; + pmhctl->llist_info.waiting_start_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.waiting_end_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.reg_read_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.next_free_idx = + MDDI_FIRST_DYNAMIC_LLIST_IDX; + pmhctl->llist_info.reg_read_waiting = FALSE; + + mddi_vsync_detect_enabled = FALSE; + mddi_gpio.polling_enabled = FALSE; + + pmhctl->int_type.count = 0; + pmhctl->int_type.in_count = 0; + pmhctl->int_type.disp_req_count = 0; + pmhctl->int_type.state_change_count = 0; + pmhctl->int_type.ll_done_count = 0; + pmhctl->int_type.rev_avail_count = 0; + pmhctl->int_type.error_count = 0; + pmhctl->int_type.rev_encap_count = 0; + pmhctl->int_type.llist_ptr_write_1 = 0; + pmhctl->int_type.llist_ptr_write_2 = 0; + + pmhctl->stats.fwd_crc_count = 0; + pmhctl->stats.rev_crc_count = 0; + pmhctl->stats.pri_underflow = 0; + pmhctl->stats.sec_underflow = 0; + pmhctl->stats.rev_overflow = 0; + pmhctl->stats.pri_overwrite = 0; + pmhctl->stats.sec_overwrite = 0; + pmhctl->stats.rev_overwrite = 0; + pmhctl->stats.dma_failure = 0; + pmhctl->stats.rtd_failure = 0; + pmhctl->stats.reg_read_failure = 0; +#ifdef FEATURE_MDDI_UNDERRUN_RECOVERY + pmhctl->stats.pri_underrun_detected = 0; +#endif + + pmhctl->log_parms.rtd_cnt = 0; + pmhctl->log_parms.rev_enc_cnt = 0; + pmhctl->log_parms.vid_cnt = 0; + pmhctl->log_parms.reg_acc_cnt = 0; + pmhctl->log_parms.cli_stat_cnt = 0; + pmhctl->log_parms.cli_cap_cnt = 0; + pmhctl->log_parms.reg_read_cnt = 0; + pmhctl->log_parms.link_active_cnt = 0; + pmhctl->log_parms.link_hibernate_cnt = 0; + pmhctl->log_parms.fwd_crc_cnt = 0; + pmhctl->log_parms.rev_crc_cnt = 0; + pmhctl->log_parms.vsync_response_cnt = 0; + + prev_parms[host_idx] = pmhctl->log_parms; + mddi_client_capability_pkt.packet_length = 0; + } + +#ifndef T_MSM7500 + /* tell clock driver we are user of this PLL */ + MDDI_HOST_ENABLE_IO_CLOCK; +#endif + } + + mddi_host_powerup(host_idx); + pmhctl = &(mhctl[host_idx]); +} + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT +static uint32 mddi_client_id; + +uint32 mddi_get_client_id(void) +{ + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + mddi_host_type host_idx = MDDI_HOST_PRIM; + static boolean client_detection_try = FALSE; + mddi_host_cntl_type *pmhctl; + unsigned long flags; + uint16 saved_rev_pkt_size; + + if (!client_detection_try) { + /* Toshiba display requires larger drive_lo value */ + mddi_host_reg_out(DRIVE_LO, 0x0050); + + pmhctl = &(mhctl[MDDI_HOST_PRIM]); + + saved_rev_pkt_size = pmhctl->rev_pkt_size; + + /* Increase Rev Encap Size */ + pmhctl->rev_pkt_size = MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE; + mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size); + + /* disable hibernation temporarily */ + if (!pmhctl->disable_hibernation) + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE); + + mddi_rev_user.waiting = TRUE; + INIT_COMPLETION(mddi_rev_user.done_comp); + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + /* turn on clock(s), if they have been disabled */ + mddi_host_enable_hclk(); + mddi_host_enable_io_clock(); + + mddi_client_capability_request = TRUE; + + if (pmhctl->rev_state == MDDI_REV_IDLE) { + /* attempt to send the reverse encapsulation now */ + mddi_issue_reverse_encapsulation(); + } + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + wait_for_completion_killable(&(mddi_rev_user.done_comp)); + + /* Set Rev Encap Size back to its original value */ + pmhctl->rev_pkt_size = saved_rev_pkt_size; + mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size); + + /* reenable auto-hibernate */ + if (!pmhctl->disable_hibernation) + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1); + + mddi_host_reg_out(DRIVE_LO, 0x0032); + client_detection_try = TRUE; + + mddi_client_id = (mddi_client_capability_pkt.Mfr_Name<<16) | + mddi_client_capability_pkt.Product_Code; + + if (!mddi_client_id) + mddi_disable(1); + } + +#if 0 + switch (mddi_client_capability_pkt.Mfr_Name) { + case 0x4474: + if ((mddi_client_capability_pkt.Product_Code != 0x8960) && + (target == DISPLAY_1)) { + ret = PRISM_WVGA; + } + break; + + case 0xD263: + if (target == DISPLAY_1) + ret = TOSHIBA_VGA_PRIM; + else if (target == DISPLAY_2) + ret = TOSHIBA_QCIF_SECD; + break; + + case 0: + if (mddi_client_capability_pkt.Product_Code == 0x8835) { + if (target == DISPLAY_1) + ret = SHARP_QVGA_PRIM; + else if (target == DISPLAY_2) + ret = SHARP_128x128_SECD; + } + break; + + default: + break; + } + + if ((!client_detection_try) && (ret != TOSHIBA_VGA_PRIM) + && (ret != TOSHIBA_QCIF_SECD)) { + /* Not a Toshiba display, so change drive_lo back to default value */ + mddi_host_reg_out(DRIVE_LO, 0x0032); + } +#endif + +#endif + + return mddi_client_id; +} +#endif + +void mddi_host_powerdown(mddi_host_type host_idx) +{ + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (host_idx >= MDDI_NUM_HOST_CORES) { + MDDI_MSG_ERR("Invalid host core index\n"); + return; + } + + if (pmhctl->driver_state == MDDI_DRIVER_RESET) { + return; + } + + if (host_idx == MDDI_HOST_PRIM) { + /* disable timer */ + del_timer(&mddi_host_timer); + } + + mddi_host_configure_interrupts(host_idx, FALSE); + + /* turn on HCLK to MDDI host core if it has been disabled */ + mddi_host_enable_hclk(); + + /* MDDI Reset command */ + mddi_host_reg_out(CMD, MDDI_CMD_RESET); + + /* Pad Control Register */ + mddi_host_reg_out(PAD_CTL, 0x0); + + /* disable IO_CLK and hclk to MDDI host core */ + mddi_host_disable_io_clock(); + mddi_host_disable_hclk(); + + pmhctl->link_state = MDDI_LINK_DISABLED; + pmhctl->driver_state = MDDI_DRIVER_RESET; + + MDDI_MSG_NOTICE("MDDI Host: Disabling Link\n"); + +} + +uint16 mddi_get_next_free_llist_item(mddi_host_type host_idx, boolean wait) +{ + unsigned long flags; + uint16 ret_idx; + boolean forced_wait = FALSE; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + ret_idx = pmhctl->llist_info.next_free_idx; + + pmhctl->llist_info.next_free_idx++; + if (pmhctl->llist_info.next_free_idx >= MDDI_NUM_DYNAMIC_LLIST_ITEMS) + pmhctl->llist_info.next_free_idx = MDDI_FIRST_DYNAMIC_LLIST_IDX; + spin_lock_irqsave(&mddi_host_spin_lock, flags); + if (pmhctl->llist_notify[ret_idx].in_use) { + if (!wait) { + pmhctl->llist_info.next_free_idx = ret_idx; + ret_idx = UNASSIGNED_INDEX; + } else { + forced_wait = TRUE; + INIT_COMPLETION(pmhctl->mddi_llist_avail_comp); + } + } + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (forced_wait) { + wait_for_completion_killable(& + (pmhctl-> + mddi_llist_avail_comp)); + MDDI_MSG_ERR("task waiting on mddi llist item\n"); + } + + if (ret_idx != UNASSIGNED_INDEX) { + pmhctl->llist_notify[ret_idx].waiting = FALSE; + pmhctl->llist_notify[ret_idx].done_cb = NULL; + pmhctl->llist_notify[ret_idx].in_use = TRUE; + pmhctl->llist_notify[ret_idx].next_idx = UNASSIGNED_INDEX; + } + + return ret_idx; +} + +uint16 mddi_get_reg_read_llist_item(mddi_host_type host_idx, boolean wait) +{ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + MDDI_MSG_CRIT("No reverse link available\n"); + (void)wait; + return FALSE; +#else + unsigned long flags; + uint16 ret_idx; + boolean error = FALSE; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + if (pmhctl->llist_info.reg_read_idx != UNASSIGNED_INDEX) { + /* need to block here or is this an error condition? */ + error = TRUE; + ret_idx = UNASSIGNED_INDEX; + } + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (!error) { + ret_idx = pmhctl->llist_info.reg_read_idx = + mddi_get_next_free_llist_item(host_idx, wait); + /* clear the reg_read_waiting flag */ + pmhctl->llist_info.reg_read_waiting = FALSE; + } + + if (error) + MDDI_MSG_ERR("***** Reg read still in progress! ****\n"); + return ret_idx; +#endif + +} + +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_idx) +{ + unsigned long flags; + mddi_linked_list_type *llist; + mddi_linked_list_type *llist_dma; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if ((first_llist_idx >= UNASSIGNED_INDEX) || + (last_llist_idx >= UNASSIGNED_INDEX)) { + MDDI_MSG_ERR("MDDI queueing invalid linked list\n"); + return; + } + + if (pmhctl->link_state == MDDI_LINK_DISABLED) + MDDI_MSG_CRIT("MDDI host powered down!\n"); + + llist = pmhctl->llist_ptr; + llist_dma = pmhctl->llist_dma_ptr; + + /* clean cache so MDDI host can read data */ + memory_barrier(); + + pmhctl->llist_notify[last_llist_idx].waiting = wait; + if (wait) + INIT_COMPLETION(pmhctl->llist_notify[last_llist_idx].done_comp); + pmhctl->llist_notify[last_llist_idx].done_cb = llist_done_cb; + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + if ((pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) && + (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) && + (pmhctl->rev_state == MDDI_REV_IDLE)) { + /* no packets are currently transmitting */ +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (first_llist_idx == pmhctl->llist_info.reg_read_idx) { + /* This is the special case where the packet is a register read. */ + pmhctl->rev_state = MDDI_REV_REG_READ_ISSUED; + mddi_reg_read_retry = 0; + /* mddi_rev_reg_read_attempt = 1; */ + } +#endif + /* assign transmitting index values */ + pmhctl->llist_info.transmitting_start_idx = first_llist_idx; + pmhctl->llist_info.transmitting_end_idx = last_llist_idx; + + /* turn on clock(s), if they have been disabled */ + mddi_host_enable_hclk(); + mddi_host_enable_io_clock(); + pmhctl->int_type.llist_ptr_write_1++; + /* Write to primary pointer register */ + dma_coherent_pre_ops(); + mddi_host_reg_out(PRI_PTR, &llist_dma[first_llist_idx]); + + /* enable interrupt when complete */ + mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE, + MDDI_INT_PRI_LINK_LIST_DONE); + + } else if (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) { +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (first_llist_idx == pmhctl->llist_info.reg_read_idx) { + /* + * we have a register read to send but need to wait + * for current reverse activity to end or there are + * packets currently transmitting + */ + /* mddi_rev_reg_read_attempt = 0; */ + pmhctl->llist_info.reg_read_waiting = TRUE; + } +#endif + + /* assign waiting index values */ + pmhctl->llist_info.waiting_start_idx = first_llist_idx; + pmhctl->llist_info.waiting_end_idx = last_llist_idx; + } else { + uint16 prev_end_idx = pmhctl->llist_info.waiting_end_idx; +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (first_llist_idx == pmhctl->llist_info.reg_read_idx) { + /* + * we have a register read to send but need to wait + * for current reverse activity to end or there are + * packets currently transmitting + */ + /* mddi_rev_reg_read_attempt = 0; */ + pmhctl->llist_info.reg_read_waiting = TRUE; + } +#endif + + llist = pmhctl->llist_ptr; + + /* clear end flag in previous last packet */ + llist[prev_end_idx].link_controller_flags = 0; + pmhctl->llist_notify[prev_end_idx].next_idx = first_llist_idx; + + /* set the next_packet_pointer of the previous last packet */ + llist[prev_end_idx].next_packet_pointer = + (void *)(&llist_dma[first_llist_idx]); + + /* clean cache so MDDI host can read data */ + memory_barrier(); + + /* assign new waiting last index value */ + pmhctl->llist_info.waiting_end_idx = last_llist_idx; + } + + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + +} + +void mddi_host_write_pix_attr_reg(uint32 value) +{ + (void)value; +} + +void mddi_queue_reverse_encapsulation(boolean wait) +{ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + MDDI_MSG_CRIT("No reverse link available\n"); + (void)wait; +#else + unsigned long flags; + boolean error = FALSE; + mddi_host_type host_idx = MDDI_HOST_PRIM; + mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]); + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + /* turn on clock(s), if they have been disabled */ + mddi_host_enable_hclk(); + mddi_host_enable_io_clock(); + + if (wait) { + if (!mddi_rev_user.waiting) { + mddi_rev_user.waiting = TRUE; + INIT_COMPLETION(mddi_rev_user.done_comp); + } else + error = TRUE; + } + mddi_rev_encap_user_request = TRUE; + + if (pmhctl->rev_state == MDDI_REV_IDLE) { + /* attempt to send the reverse encapsulation now */ + mddi_host_type orig_host_idx = mddi_curr_host; + mddi_curr_host = host_idx; + mddi_issue_reverse_encapsulation(); + mddi_curr_host = orig_host_idx; + } + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (error) { + MDDI_MSG_ERR("Reverse Encap request already in progress\n"); + } else if (wait) + wait_for_completion_killable(&(mddi_rev_user.done_comp)); +#endif +} + +/* ISR to be executed */ +boolean mddi_set_rev_handler(mddi_rev_handler_type handler, uint16 pkt_type) +{ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + MDDI_MSG_CRIT("No reverse link available\n"); + (void)handler; + (void)pkt_type; + return (FALSE); +#else + unsigned long flags; + uint16 hdlr; + boolean handler_set = FALSE; + boolean overwrite = FALSE; + mddi_host_type host_idx = MDDI_HOST_PRIM; + mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]); + + /* Disable interrupts */ + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; hdlr++) { + if (mddi_rev_pkt_handler[hdlr].pkt_type == pkt_type) { + mddi_rev_pkt_handler[hdlr].handler = handler; + if (handler == NULL) { + /* clearing handler from table */ + mddi_rev_pkt_handler[hdlr].pkt_type = + INVALID_PKT_TYPE; + handler_set = TRUE; + if (pkt_type == 0x10) { /* video stream packet */ + /* ensure HCLK on to MDDI host core before register write */ + mddi_host_enable_hclk(); + /* No longer getting video, so reset rev encap size to default */ + pmhctl->rev_pkt_size = + MDDI_DEFAULT_REV_PKT_SIZE; + mddi_host_reg_out(REV_ENCAP_SZ, + pmhctl->rev_pkt_size); + } + } else { + /* already a handler for this packet */ + overwrite = TRUE; + } + break; + } + } + if ((hdlr >= MAX_MDDI_REV_HANDLERS) && (handler != NULL)) { + /* assigning new handler */ + for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; hdlr++) { + if (mddi_rev_pkt_handler[hdlr].pkt_type == + INVALID_PKT_TYPE) { + if ((pkt_type == 0x10) && /* video stream packet */ + (pmhctl->rev_pkt_size < + MDDI_VIDEO_REV_PKT_SIZE)) { + /* ensure HCLK on to MDDI host core before register write */ + mddi_host_enable_hclk(); + /* Increase Rev Encap Size */ + pmhctl->rev_pkt_size = + MDDI_VIDEO_REV_PKT_SIZE; + mddi_host_reg_out(REV_ENCAP_SZ, + pmhctl->rev_pkt_size); + } + mddi_rev_pkt_handler[hdlr].handler = handler; + mddi_rev_pkt_handler[hdlr].pkt_type = pkt_type; + handler_set = TRUE; + break; + } + } + } + + /* Restore interrupts */ + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (overwrite) + MDDI_MSG_ERR("Overwriting previous rev packet handler\n"); + + return handler_set; + +#endif +} /* mddi_set_rev_handler */ + +void mddi_host_disable_hibernation(boolean disable) +{ + mddi_host_type host_idx = MDDI_HOST_PRIM; + mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]); + + if (disable) { + pmhctl->disable_hibernation = TRUE; + /* hibernation will be turned off by isr next time it is entered */ + } else { + if (pmhctl->disable_hibernation) { + unsigned long flags; + spin_lock_irqsave(&mddi_host_spin_lock, flags); + if (!MDDI_HOST_IS_HCLK_ON) + MDDI_HOST_ENABLE_HCLK; + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1); + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + pmhctl->disable_hibernation = FALSE; + } + } +} + +void mddi_mhctl_remove(mddi_host_type host_idx) +{ + mddi_host_cntl_type *pmhctl; + + pmhctl = &(mhctl[host_idx]); + + dma_free_coherent(NULL, MDDI_LLIST_POOL_SIZE, (void *)pmhctl->llist_ptr, + pmhctl->llist_dma_addr); + + dma_free_coherent(NULL, MDDI_MAX_REV_DATA_SIZE, + (void *)pmhctl->rev_data_buf, + pmhctl->rev_data_dma_addr); +} diff --git a/drivers/staging/msm/mddihosti.h b/drivers/staging/msm/mddihosti.h new file mode 100644 index 00000000000..7b26a425389 --- /dev/null +++ b/drivers/staging/msm/mddihosti.h @@ -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 */ diff --git a/drivers/staging/msm/mdp.c b/drivers/staging/msm/mdp.c new file mode 100644 index 00000000000..36053afdebe --- /dev/null +++ b/drivers/staging/msm/mdp.c @@ -0,0 +1,1113 @@ +/* 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/spinlock.h> +#include <linux/hrtimer.h> +#include <linux/clk.h> +#include <mach/hardware.h> +#include <linux/io.h> +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/mutex.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" +#ifdef CONFIG_FB_MSM_MDP40 +#include "mdp4.h" +#endif + +static struct clk *mdp_clk; +static struct clk *mdp_pclk; + +struct completion mdp_ppp_comp; +struct semaphore mdp_ppp_mutex; +struct semaphore mdp_pipe_ctrl_mutex; + +unsigned long mdp_timer_duration = (HZ); /* 1 sec */ +/* unsigned long mdp_mdp_timer_duration=0; */ + +boolean mdp_ppp_waiting = FALSE; +uint32 mdp_tv_underflow_cnt; +uint32 mdp_lcdc_underflow_cnt; + +boolean mdp_current_clk_on = FALSE; +boolean mdp_is_in_isr = FALSE; + +/* + * legacy mdp_in_processing is only for DMA2-MDDI + * this applies to DMA2 block only + */ +uint32 mdp_in_processing = FALSE; + +#ifdef CONFIG_FB_MSM_MDP40 +uint32 mdp_intr_mask = MDP4_ANY_INTR_MASK; +#else +uint32 mdp_intr_mask = MDP_ANY_INTR_MASK; +#endif + +MDP_BLOCK_TYPE mdp_debug[MDP_MAX_BLOCK]; + +int32 mdp_block_power_cnt[MDP_MAX_BLOCK]; + +spinlock_t mdp_spin_lock; +struct workqueue_struct *mdp_dma_wq; /*mdp dma wq */ +struct workqueue_struct *mdp_vsync_wq; /*mdp vsync wq */ + +static struct workqueue_struct *mdp_pipe_ctrl_wq; /* mdp mdp pipe ctrl wq */ +static struct delayed_work mdp_pipe_ctrl_worker; + +#ifdef CONFIG_FB_MSM_MDP40 +struct mdp_dma_data dma2_data; +struct mdp_dma_data dma_s_data; +struct mdp_dma_data dma_e_data; +#else +static struct mdp_dma_data dma2_data; +static struct mdp_dma_data dma_s_data; +static struct mdp_dma_data dma_e_data; +#endif +static struct mdp_dma_data dma3_data; + +extern ktime_t mdp_dma2_last_update_time; + +extern uint32 mdp_dma2_update_time_in_usec; +extern int mdp_lcd_rd_cnt_offset_slow; +extern int mdp_lcd_rd_cnt_offset_fast; +extern int mdp_usec_diff_threshold; + +#ifdef CONFIG_FB_MSM_LCDC +extern int mdp_lcdc_pclk_clk_rate; +extern int mdp_lcdc_pad_pclk_clk_rate; +extern int first_pixel_start_x; +extern int first_pixel_start_y; +#endif + +#ifdef MSM_FB_ENABLE_DBGFS +struct dentry *mdp_dir; +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int mdp_suspend(struct platform_device *pdev, pm_message_t state); +#else +#define mdp_suspend NULL +#endif + +struct timeval mdp_dma2_timeval; +struct timeval mdp_ppp_timeval; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static struct early_suspend early_suspend; +#endif + +#ifndef CONFIG_FB_MSM_MDP22 +DEFINE_MUTEX(mdp_lut_push_sem); +static int mdp_lut_i; +static int mdp_lut_hw_update(struct fb_cmap *cmap) +{ + int i; + u16 *c[3]; + u16 r, g, b; + + c[0] = cmap->green; + c[1] = cmap->blue; + c[2] = cmap->red; + + for (i = 0; i < cmap->len; i++) { + if (copy_from_user(&r, cmap->red++, sizeof(r)) || + copy_from_user(&g, cmap->green++, sizeof(g)) || + copy_from_user(&b, cmap->blue++, sizeof(b))) + return -EFAULT; + +#ifdef CONFIG_FB_MSM_MDP40 + MDP_OUTP(MDP_BASE + 0x94800 + +#else + MDP_OUTP(MDP_BASE + 0x93800 + +#endif + (0x400*mdp_lut_i) + cmap->start*4 + i*4, + ((g & 0xff) | + ((b & 0xff) << 8) | + ((r & 0xff) << 16))); + } + + return 0; +} + +static int mdp_lut_push; +static int mdp_lut_push_i; +static int mdp_lut_update_nonlcdc(struct fb_info *info, struct fb_cmap *cmap) +{ + int ret; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + ret = mdp_lut_hw_update(cmap); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + if (ret) + return ret; + + mutex_lock(&mdp_lut_push_sem); + mdp_lut_push = 1; + mdp_lut_push_i = mdp_lut_i; + mutex_unlock(&mdp_lut_push_sem); + + mdp_lut_i = (mdp_lut_i + 1)%2; + + return 0; +} + +static int mdp_lut_update_lcdc(struct fb_info *info, struct fb_cmap *cmap) +{ + int ret; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + ret = mdp_lut_hw_update(cmap); + + if (ret) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return ret; + } + + MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x17); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_lut_i = (mdp_lut_i + 1)%2; + + return 0; +} + +#define MDP_HIST_MAX_BIN 32 +static __u32 mdp_hist_r[MDP_HIST_MAX_BIN]; +static __u32 mdp_hist_g[MDP_HIST_MAX_BIN]; +static __u32 mdp_hist_b[MDP_HIST_MAX_BIN]; + +#ifdef CONFIG_FB_MSM_MDP40 +struct mdp_histogram mdp_hist; +struct completion mdp_hist_comp; +#else +static struct mdp_histogram mdp_hist; +static struct completion mdp_hist_comp; +#endif + +static int mdp_do_histogram(struct fb_info *info, struct mdp_histogram *hist) +{ + int ret = 0; + + if (!hist->frame_cnt || (hist->bin_cnt == 0) || + (hist->bin_cnt > MDP_HIST_MAX_BIN)) + return -EINVAL; + + INIT_COMPLETION(mdp_hist_comp); + + mdp_hist.bin_cnt = hist->bin_cnt; + mdp_hist.r = (hist->r) ? mdp_hist_r : 0; + mdp_hist.g = (hist->g) ? mdp_hist_g : 0; + mdp_hist.b = (hist->b) ? mdp_hist_b : 0; + +#ifdef CONFIG_FB_MSM_MDP40 + MDP_OUTP(MDP_BASE + 0x95004, hist->frame_cnt); + MDP_OUTP(MDP_BASE + 0x95000, 1); +#else + MDP_OUTP(MDP_BASE + 0x94004, hist->frame_cnt); + MDP_OUTP(MDP_BASE + 0x94000, 1); +#endif + wait_for_completion_killable(&mdp_hist_comp); + + if (hist->r) { + ret = copy_to_user(hist->r, mdp_hist.r, hist->bin_cnt*4); + if (ret) + goto hist_err; + } + if (hist->g) { + ret = copy_to_user(hist->g, mdp_hist.g, hist->bin_cnt*4); + if (ret) + goto hist_err; + } + if (hist->b) { + ret = copy_to_user(hist->b, mdp_hist.b, hist->bin_cnt*4); + if (ret) + goto hist_err; + } + return 0; + +hist_err: + printk(KERN_ERR "%s: invalid hist buffer\n", __func__); + return ret; +} +#endif + +/* Returns < 0 on error, 0 on timeout, or > 0 on successful wait */ + +int mdp_ppp_pipe_wait(void) +{ + int ret = 1; + + /* wait 5 seconds for the operation to complete before declaring + the MDP hung */ + + if (mdp_ppp_waiting == TRUE) { + ret = wait_for_completion_interruptible_timeout(&mdp_ppp_comp, + 5 * HZ); + + if (!ret) + printk(KERN_ERR "%s: Timed out waiting for the MDP.\n", + __func__); + } + + return ret; +} + +static DEFINE_SPINLOCK(mdp_lock); +static int mdp_irq_mask; +static int mdp_irq_enabled; + +void mdp_enable_irq(uint32 term) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&mdp_lock, irq_flags); + if (mdp_irq_mask & term) { + printk(KERN_ERR "MDP IRQ term-0x%x is already set\n", term); + } else { + mdp_irq_mask |= term; + if (mdp_irq_mask && !mdp_irq_enabled) { + mdp_irq_enabled = 1; + enable_irq(INT_MDP); + } + } + spin_unlock_irqrestore(&mdp_lock, irq_flags); +} + +void mdp_disable_irq(uint32 term) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&mdp_lock, irq_flags); + if (!(mdp_irq_mask & term)) { + printk(KERN_ERR "MDP IRQ term-0x%x is not set\n", term); + } else { + mdp_irq_mask &= ~term; + if (!mdp_irq_mask && mdp_irq_enabled) { + mdp_irq_enabled = 0; + disable_irq(INT_MDP); + } + } + spin_unlock_irqrestore(&mdp_lock, irq_flags); +} + +void mdp_disable_irq_nolock(uint32 term) +{ + + if (!(mdp_irq_mask & term)) { + printk(KERN_ERR "MDP IRQ term-0x%x is not set\n", term); + } else { + mdp_irq_mask &= ~term; + if (!mdp_irq_mask && mdp_irq_enabled) { + mdp_irq_enabled = 0; + disable_irq(INT_MDP); + } + } +} + +void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd) +{ + + dmb(); /* memory barrier */ + + /* kick off PPP engine */ + if (term == MDP_PPP_TERM) { + if (mdp_debug[MDP_PPP_BLOCK]) + jiffies_to_timeval(jiffies, &mdp_ppp_timeval); + + /* let's turn on PPP block */ + mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + mdp_enable_irq(term); + INIT_COMPLETION(mdp_ppp_comp); + mdp_ppp_waiting = TRUE; + outpdw(MDP_BASE + 0x30, 0x1000); + wait_for_completion_killable(&mdp_ppp_comp); + mdp_disable_irq(term); + + if (mdp_debug[MDP_PPP_BLOCK]) { + struct timeval now; + + jiffies_to_timeval(jiffies, &now); + mdp_ppp_timeval.tv_usec = + now.tv_usec - mdp_ppp_timeval.tv_usec; + MSM_FB_INFO("MDP-PPP: %d\n", + (int)mdp_ppp_timeval.tv_usec); + } + } else if (term == MDP_DMA2_TERM) { + if (mdp_debug[MDP_DMA2_BLOCK]) { + MSM_FB_INFO("MDP-DMA2: %d\n", + (int)mdp_dma2_timeval.tv_usec); + jiffies_to_timeval(jiffies, &mdp_dma2_timeval); + } + /* DMA update timestamp */ + mdp_dma2_last_update_time = ktime_get_real(); + /* let's turn on DMA2 block */ +#if 0 + mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE); +#endif +#ifdef CONFIG_FB_MSM_MDP22 + outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x0044, 0x0);/* start DMA */ +#else + if (mdp_lut_push) { + mutex_lock(&mdp_lut_push_sem); + mdp_lut_push = 0; + MDP_OUTP(MDP_BASE + 0x90070, + (mdp_lut_push_i << 10) | 0x17); + mutex_unlock(&mdp_lut_push_sem); + } +#ifdef CONFIG_FB_MSM_MDP40 + outpdw(MDP_BASE + 0x000c, 0x0); /* start DMA */ +#else + outpdw(MDP_BASE + 0x0044, 0x0); /* start DMA */ +#endif +#endif +#ifdef CONFIG_FB_MSM_MDP40 + } else if (term == MDP_DMA_S_TERM) { + mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0010, 0x0); /* start DMA */ + } else if (term == MDP_DMA_E_TERM) { + mdp_pipe_ctrl(MDP_DMA_E_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0014, 0x0); /* start DMA */ + } else if (term == MDP_OVERLAY0_TERM) { + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0004, 0); + } else if (term == MDP_OVERLAY1_TERM) { + mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0008, 0); + } +#else + } else if (term == MDP_DMA_S_TERM) { + mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0048, 0x0); /* start DMA */ + } +#endif +} + +static void mdp_pipe_ctrl_workqueue_handler(struct work_struct *work) +{ + mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state, + boolean isr) +{ + boolean mdp_all_blocks_off = TRUE; + int i; + unsigned long flag; + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (MDP_BLOCK_POWER_ON == state) { + mdp_block_power_cnt[block]++; + + if (MDP_DMA2_BLOCK == block) + mdp_in_processing = TRUE; + } else { + mdp_block_power_cnt[block]--; + + if (mdp_block_power_cnt[block] < 0) { + /* + * Master has to serve a request to power off MDP always + * It also has a timer to power off. So, in case of + * timer expires first and DMA2 finishes later, + * master has to power off two times + * There shouldn't be multiple power-off request for + * other blocks + */ + if (block != MDP_MASTER_BLOCK) { + MSM_FB_INFO("mdp_block_power_cnt[block=%d] \ + multiple power-off request\n", block); + } + mdp_block_power_cnt[block] = 0; + } + + if (MDP_DMA2_BLOCK == block) + mdp_in_processing = FALSE; + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + /* + * If it's in isr, we send our request to workqueue. + * Otherwise, processing happens in the current context + */ + if (isr) { + /* checking all blocks power state */ + for (i = 0; i < MDP_MAX_BLOCK; i++) { + if (mdp_block_power_cnt[i] > 0) + mdp_all_blocks_off = FALSE; + } + + if ((mdp_all_blocks_off) && (mdp_current_clk_on)) { + /* send workqueue to turn off mdp power */ + queue_delayed_work(mdp_pipe_ctrl_wq, + &mdp_pipe_ctrl_worker, + mdp_timer_duration); + } + } else { + down(&mdp_pipe_ctrl_mutex); + /* checking all blocks power state */ + for (i = 0; i < MDP_MAX_BLOCK; i++) { + if (mdp_block_power_cnt[i] > 0) + mdp_all_blocks_off = FALSE; + } + + /* + * find out whether a delayable work item is currently + * pending + */ + + if (delayed_work_pending(&mdp_pipe_ctrl_worker)) { + /* + * try to cancel the current work if it fails to + * stop (which means del_timer can't delete it + * from the list, it's about to expire and run), + * we have to let it run. queue_delayed_work won't + * accept the next job which is same as + * queue_delayed_work(mdp_timer_duration = 0) + */ + cancel_delayed_work(&mdp_pipe_ctrl_worker); + } + + if ((mdp_all_blocks_off) && (mdp_current_clk_on)) { + if (block == MDP_MASTER_BLOCK) { + mdp_current_clk_on = FALSE; + /* turn off MDP clks */ + if (mdp_clk != NULL) { + clk_disable(mdp_clk); + MSM_FB_DEBUG("MDP CLK OFF\n"); + } + if (mdp_pclk != NULL) { + clk_disable(mdp_pclk); + MSM_FB_DEBUG("MDP PCLK OFF\n"); + } + } else { + /* send workqueue to turn off mdp power */ + queue_delayed_work(mdp_pipe_ctrl_wq, + &mdp_pipe_ctrl_worker, + mdp_timer_duration); + } + } else if ((!mdp_all_blocks_off) && (!mdp_current_clk_on)) { + mdp_current_clk_on = TRUE; + /* turn on MDP clks */ + if (mdp_clk != NULL) { + clk_enable(mdp_clk); + MSM_FB_DEBUG("MDP CLK ON\n"); + } + if (mdp_pclk != NULL) { + clk_enable(mdp_pclk); + MSM_FB_DEBUG("MDP PCLK ON\n"); + } + } + up(&mdp_pipe_ctrl_mutex); + } +} + +#ifndef CONFIG_FB_MSM_MDP40 +irqreturn_t mdp_isr(int irq, void *ptr) +{ + uint32 mdp_interrupt = 0; + struct mdp_dma_data *dma; + + mdp_is_in_isr = TRUE; + do { + mdp_interrupt = inp32(MDP_INTR_STATUS); + outp32(MDP_INTR_CLEAR, mdp_interrupt); + + mdp_interrupt &= mdp_intr_mask; + + if (mdp_interrupt & TV_ENC_UNDERRUN) { + mdp_interrupt &= ~(TV_ENC_UNDERRUN); + mdp_tv_underflow_cnt++; + } + + if (!mdp_interrupt) + break; + + /* DMA3 TV-Out Start */ + if (mdp_interrupt & TV_OUT_DMA3_START) { + /* let's disable TV out interrupt */ + mdp_intr_mask &= ~TV_OUT_DMA3_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + + dma = &dma3_data; + if (dma->waiting) { + dma->waiting = FALSE; + complete(&dma->comp); + } + } +#ifndef CONFIG_FB_MSM_MDP22 + if (mdp_interrupt & MDP_HIST_DONE) { + outp32(MDP_BASE + 0x94018, 0x3); + outp32(MDP_INTR_CLEAR, MDP_HIST_DONE); + if (mdp_hist.r) + memcpy(mdp_hist.r, MDP_BASE + 0x94100, + mdp_hist.bin_cnt*4); + if (mdp_hist.g) + memcpy(mdp_hist.g, MDP_BASE + 0x94200, + mdp_hist.bin_cnt*4); + if (mdp_hist.b) + memcpy(mdp_hist.b, MDP_BASE + 0x94300, + mdp_hist.bin_cnt*4); + complete(&mdp_hist_comp); + } + + /* LCDC UnderFlow */ + if (mdp_interrupt & LCDC_UNDERFLOW) { + mdp_lcdc_underflow_cnt++; + } + /* LCDC Frame Start */ + if (mdp_interrupt & LCDC_FRAME_START) { + /* let's disable LCDC interrupt */ + mdp_intr_mask &= ~LCDC_FRAME_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + + dma = &dma2_data; + if (dma->waiting) { + dma->waiting = FALSE; + complete(&dma->comp); + } + } + + /* DMA2 LCD-Out Complete */ + if (mdp_interrupt & MDP_DMA_S_DONE) { + dma = &dma_s_data; + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_OFF, + TRUE); + complete(&dma->comp); + } +#endif + + /* DMA2 LCD-Out Complete */ + if (mdp_interrupt & MDP_DMA_P_DONE) { + struct timeval now; + ktime_t now_k; + + now_k = ktime_get_real(); + mdp_dma2_last_update_time.tv.sec = + now_k.tv.sec - mdp_dma2_last_update_time.tv.sec; + mdp_dma2_last_update_time.tv.nsec = + now_k.tv.nsec - mdp_dma2_last_update_time.tv.nsec; + + if (mdp_debug[MDP_DMA2_BLOCK]) { + jiffies_to_timeval(jiffies, &now); + mdp_dma2_timeval.tv_usec = + now.tv_usec - mdp_dma2_timeval.tv_usec; + } + + dma = &dma2_data; + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, + TRUE); + complete(&dma->comp); + } + /* PPP Complete */ + if (mdp_interrupt & MDP_PPP_DONE) { +#ifdef CONFIG_MDP_PPP_ASYNC_OP + mdp_ppp_djob_done(); +#else + mdp_pipe_ctrl(MDP_PPP_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + if (mdp_ppp_waiting) { + mdp_ppp_waiting = FALSE; + complete(&mdp_ppp_comp); + } +#endif + } + } while (1); + + mdp_is_in_isr = FALSE; + + return IRQ_HANDLED; +} +#endif + +static void mdp_drv_init(void) +{ + int i; + + for (i = 0; i < MDP_MAX_BLOCK; i++) { + mdp_debug[i] = 0; + } + + /* initialize spin lock and workqueue */ + spin_lock_init(&mdp_spin_lock); + mdp_dma_wq = create_singlethread_workqueue("mdp_dma_wq"); + mdp_vsync_wq = create_singlethread_workqueue("mdp_vsync_wq"); + mdp_pipe_ctrl_wq = create_singlethread_workqueue("mdp_pipe_ctrl_wq"); + INIT_DELAYED_WORK(&mdp_pipe_ctrl_worker, + mdp_pipe_ctrl_workqueue_handler); +#ifdef CONFIG_MDP_PPP_ASYNC_OP + mdp_ppp_dq_init(); +#endif + + /* initialize semaphore */ + init_completion(&mdp_ppp_comp); + init_MUTEX(&mdp_ppp_mutex); + init_MUTEX(&mdp_pipe_ctrl_mutex); + + dma2_data.busy = FALSE; + dma2_data.waiting = FALSE; + init_completion(&dma2_data.comp); + init_MUTEX(&dma2_data.mutex); + mutex_init(&dma2_data.ov_mutex); + + dma3_data.busy = FALSE; + dma3_data.waiting = FALSE; + init_completion(&dma3_data.comp); + init_MUTEX(&dma3_data.mutex); + + dma_s_data.busy = FALSE; + dma_s_data.waiting = FALSE; + init_completion(&dma_s_data.comp); + init_MUTEX(&dma_s_data.mutex); + + dma_e_data.busy = FALSE; + dma_e_data.waiting = FALSE; + init_completion(&dma_e_data.comp); + +#ifndef CONFIG_FB_MSM_MDP22 + init_completion(&mdp_hist_comp); +#endif + + /* initializing mdp power block counter to 0 */ + for (i = 0; i < MDP_MAX_BLOCK; i++) { + mdp_block_power_cnt[i] = 0; + } + +#ifdef MSM_FB_ENABLE_DBGFS + { + struct dentry *root; + char sub_name[] = "mdp"; + + root = msm_fb_get_debugfs_root(); + if (root != NULL) { + mdp_dir = debugfs_create_dir(sub_name, root); + + if (mdp_dir) { + msm_fb_debugfs_file_create(mdp_dir, + "dma2_update_time_in_usec", + (u32 *) &mdp_dma2_update_time_in_usec); + msm_fb_debugfs_file_create(mdp_dir, + "vs_rdcnt_slow", + (u32 *) &mdp_lcd_rd_cnt_offset_slow); + msm_fb_debugfs_file_create(mdp_dir, + "vs_rdcnt_fast", + (u32 *) &mdp_lcd_rd_cnt_offset_fast); + msm_fb_debugfs_file_create(mdp_dir, + "mdp_usec_diff_threshold", + (u32 *) &mdp_usec_diff_threshold); + msm_fb_debugfs_file_create(mdp_dir, + "mdp_current_clk_on", + (u32 *) &mdp_current_clk_on); +#ifdef CONFIG_FB_MSM_LCDC + msm_fb_debugfs_file_create(mdp_dir, + "lcdc_start_x", + (u32 *) &first_pixel_start_x); + msm_fb_debugfs_file_create(mdp_dir, + "lcdc_start_y", + (u32 *) &first_pixel_start_y); + msm_fb_debugfs_file_create(mdp_dir, + "mdp_lcdc_pclk_clk_rate", + (u32 *) &mdp_lcdc_pclk_clk_rate); + msm_fb_debugfs_file_create(mdp_dir, + "mdp_lcdc_pad_pclk_clk_rate", + (u32 *) &mdp_lcdc_pad_pclk_clk_rate); +#endif + } + } + } +#endif +} + +static int mdp_probe(struct platform_device *pdev); +static int mdp_remove(struct platform_device *pdev); + +static struct platform_driver mdp_driver = { + .probe = mdp_probe, + .remove = mdp_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = mdp_suspend, + .resume = NULL, +#endif + .shutdown = NULL, + .driver = { + /* + * Driver name must match the device name added in + * platform.c. + */ + .name = "mdp", + }, +}; + +static int mdp_off(struct platform_device *pdev) +{ + int ret = 0; + +#ifdef MDP_HW_VSYNC + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); +#endif + + ret = panel_next_off(pdev); + +#ifdef MDP_HW_VSYNC + mdp_hw_vsync_clk_disable(mfd); +#endif + + return ret; +} + +static int mdp_on(struct platform_device *pdev) +{ +#ifdef MDP_HW_VSYNC + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); +#endif + + int ret = 0; + +#ifdef MDP_HW_VSYNC + mdp_hw_vsync_clk_enable(mfd); +#endif + + ret = panel_next_on(pdev); + + return ret; +} + +static int mdp_irq_clk_setup(void) +{ + int ret; + +#ifdef CONFIG_FB_MSM_MDP40 + ret = request_irq(INT_MDP, mdp4_isr, IRQF_DISABLED, "MDP", 0); +#else + ret = request_irq(INT_MDP, mdp_isr, IRQF_DISABLED, "MDP", 0); +#endif + if (ret) { + printk(KERN_ERR "mdp request_irq() failed!\n"); + return ret; + } + disable_irq(INT_MDP); + + mdp_clk = clk_get(NULL, "mdp_clk"); + + if (IS_ERR(mdp_clk)) { + ret = PTR_ERR(mdp_clk); + printk(KERN_ERR "can't get mdp_clk error:%d!\n", ret); + free_irq(INT_MDP, 0); + return ret; + } + + mdp_pclk = clk_get(NULL, "mdp_pclk"); + if (IS_ERR(mdp_pclk)) + mdp_pclk = NULL; + + +#ifdef CONFIG_FB_MSM_MDP40 + /* + * mdp_clk should greater than mdp_pclk always + */ + clk_set_rate(mdp_clk, 122880000); /* 122.88 Mhz */ + printk(KERN_INFO "mdp_clk: mdp_clk=%d mdp_pclk=%d\n", + (int)clk_get_rate(mdp_clk), (int)clk_get_rate(mdp_pclk)); +#endif + + return 0; +} + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; +static int mdp_resource_initialized; +static struct msm_panel_common_pdata *mdp_pdata; + +static int mdp_probe(struct platform_device *pdev) +{ + struct platform_device *msm_fb_dev = NULL; + struct msm_fb_data_type *mfd; + struct msm_fb_panel_data *pdata = NULL; + int rc; + resource_size_t size ; +#ifdef CONFIG_FB_MSM_MDP40 + int intf, if_no; +#else + unsigned long flag; +#endif + + if ((pdev->id == 0) && (pdev->num_resources > 0)) { + mdp_pdata = pdev->dev.platform_data; + + size = resource_size(&pdev->resource[0]); + msm_mdp_base = ioremap(pdev->resource[0].start, size); + + MSM_FB_INFO("MDP HW Base phy_Address = 0x%x virt = 0x%x\n", + (int)pdev->resource[0].start, (int)msm_mdp_base); + + if (unlikely(!msm_mdp_base)) + return -ENOMEM; + + printk("irq clk setup\n"); + rc = mdp_irq_clk_setup(); + printk("irq clk setup done\n"); + if (rc) + return rc; + + /* initializing mdp hw */ +#ifdef CONFIG_FB_MSM_MDP40 + mdp4_hw_init(); +#else + mdp_hw_init(); +#endif + + mdp_resource_initialized = 1; + return 0; + } + + if (!mdp_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; + + msm_fb_dev = platform_device_alloc("msm_fb", pdev->id); + if (!msm_fb_dev) + return -ENOMEM; + + /* link to the latest pdev */ + mfd->pdev = msm_fb_dev; + + /* add panel data */ + if (platform_device_add_data + (msm_fb_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + printk(KERN_ERR "mdp_probe: platform_device_add_data failed!\n"); + rc = -ENOMEM; + goto mdp_probe_err; + } + /* data chain */ + pdata = msm_fb_dev->dev.platform_data; + pdata->on = mdp_on; + pdata->off = mdp_off; + pdata->next = pdev; + + switch (mfd->panel.type) { + case EXT_MDDI_PANEL: + case MDDI_PANEL: + case EBI2_PANEL: + INIT_WORK(&mfd->dma_update_worker, + mdp_lcd_update_workqueue_handler); + INIT_WORK(&mfd->vsync_resync_worker, + mdp_vsync_resync_workqueue_handler); + mfd->hw_refresh = FALSE; + + if (mfd->panel.type == EXT_MDDI_PANEL) { + /* 15 fps -> 66 msec */ + mfd->refresh_timer_duration = (66 * HZ / 1000); + } else { + /* 24 fps -> 42 msec */ + mfd->refresh_timer_duration = (42 * HZ / 1000); + } + +#ifdef CONFIG_FB_MSM_MDP22 + mfd->dma_fnc = mdp_dma2_update; + mfd->dma = &dma2_data; +#else + if (mfd->panel_info.pdest == DISPLAY_1) { +#ifdef CONFIG_FB_MSM_OVERLAY + mfd->dma_fnc = mdp4_mddi_overlay; +#else + mfd->dma_fnc = mdp_dma2_update; +#endif + mfd->dma = &dma2_data; + mfd->lut_update = mdp_lut_update_nonlcdc; + mfd->do_histogram = mdp_do_histogram; + } else { + mfd->dma_fnc = mdp_dma_s_update; + mfd->dma = &dma_s_data; + } +#endif + if (mdp_pdata) + mfd->vsync_gpio = mdp_pdata->gpio; + else + mfd->vsync_gpio = -1; + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == EBI2_PANEL) + intf = EBI2_INTF; + else + intf = MDDI_INTF; + + if (mfd->panel_info.pdest == DISPLAY_1) + if_no = PRIMARY_INTF_SEL; + else + if_no = SECONDARY_INTF_SEL; + + mdp4_display_intf_sel(if_no, intf); +#endif + mdp_config_vsync(mfd); + break; + + case HDMI_PANEL: + case LCDC_PANEL: + pdata->on = mdp_lcdc_on; + pdata->off = mdp_lcdc_off; + mfd->hw_refresh = TRUE; + mfd->cursor_update = mdp_hw_cursor_update; +#ifndef CONFIG_FB_MSM_MDP22 + mfd->lut_update = mdp_lut_update_lcdc; + mfd->do_histogram = mdp_do_histogram; +#endif +#ifdef CONFIG_FB_MSM_OVERLAY + mfd->dma_fnc = mdp4_lcdc_overlay; +#else + mfd->dma_fnc = mdp_lcdc_update; +#endif + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == HDMI_PANEL) { + mfd->dma = &dma_e_data; + mdp4_display_intf_sel(EXTERNAL_INTF_SEL, LCDC_RGB_INTF); + } else { + mfd->dma = &dma2_data; + mdp4_display_intf_sel(PRIMARY_INTF_SEL, LCDC_RGB_INTF); + } +#else + mfd->dma = &dma2_data; + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_intr_mask &= ~MDP_DMA_P_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + spin_unlock_irqrestore(&mdp_spin_lock, flag); +#endif + break; + + case TV_PANEL: + pdata->on = mdp_dma3_on; + pdata->off = mdp_dma3_off; + mfd->hw_refresh = TRUE; + mfd->dma_fnc = mdp_dma3_update; + mfd->dma = &dma3_data; + break; + + default: + printk(KERN_ERR "mdp_probe: unknown device type!\n"); + rc = -ENODEV; + goto mdp_probe_err; + } + + /* set driver data */ + platform_set_drvdata(msm_fb_dev, mfd); + + rc = platform_device_add(msm_fb_dev); + if (rc) { + goto mdp_probe_err; + } + + pdev_list[pdev_list_cnt++] = pdev; + return 0; + + mdp_probe_err: + platform_device_put(msm_fb_dev); + return rc; +} + +static void mdp_suspend_sub(void) +{ + /* cancel pipe ctrl worker */ + cancel_delayed_work(&mdp_pipe_ctrl_worker); + + /* for workder can't be cancelled... */ + flush_workqueue(mdp_pipe_ctrl_wq); + + /* let's wait for PPP completion */ + while (mdp_block_power_cnt[MDP_PPP_BLOCK] > 0) ; + + /* try to power down */ + mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int mdp_suspend(struct platform_device *pdev, pm_message_t state) +{ + mdp_suspend_sub(); + return 0; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mdp_early_suspend(struct early_suspend *h) +{ + mdp_suspend_sub(); +} +#endif + +static int mdp_remove(struct platform_device *pdev) +{ + iounmap(msm_mdp_base); + return 0; +} + +static int mdp_register_driver(void) +{ +#ifdef CONFIG_HAS_EARLYSUSPEND + early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1; + early_suspend.suspend = mdp_early_suspend; + register_early_suspend(&early_suspend); +#endif + + return platform_driver_register(&mdp_driver); +} + +static int __init mdp_driver_init(void) +{ + int ret; + + mdp_drv_init(); + + ret = mdp_register_driver(); + if (ret) { + printk(KERN_ERR "mdp_register_driver() failed!\n"); + return ret; + } + +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_FB_MSM_MDP40) + mdp4_debugfs_init(); +#endif + + return 0; + +} + +module_init(mdp_driver_init); diff --git a/drivers/staging/msm/mdp.h b/drivers/staging/msm/mdp.h new file mode 100644 index 00000000000..0a5d6ac386a --- /dev/null +++ b/drivers/staging/msm/mdp.h @@ -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 */ diff --git a/drivers/staging/msm/mdp4.h b/drivers/staging/msm/mdp4.h new file mode 100644 index 00000000000..26ec8f12cf6 --- /dev/null +++ b/drivers/staging/msm/mdp4.h @@ -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 */ diff --git a/drivers/staging/msm/mdp4_debugfs.c b/drivers/staging/msm/mdp4_debugfs.c new file mode 100644 index 00000000000..844d46775ec --- /dev/null +++ b/drivers/staging/msm/mdp4_debugfs.c @@ -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; +} diff --git a/drivers/staging/msm/mdp4_overlay.c b/drivers/staging/msm/mdp4_overlay.c new file mode 100644 index 00000000000..304bb829763 --- /dev/null +++ b/drivers/staging/msm/mdp4_overlay.c @@ -0,0 +1,1259 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/hrtimer.h> +#include <linux/clk.h> +#include <mach/hardware.h> +#include <linux/io.h> +#include <linux/debugfs.h> +#include <linux/fb.h> +#include <msm_mdp.h> +#include <linux/file.h> +#include "android_pmem.h" +#include <linux/major.h> +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> +#include <linux/mutex.h> + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + + +struct mdp4_overlay_ctrl { + struct mdp4_overlay_pipe plist[MDP4_MAX_OVERLAY_PIPE]; + struct mdp4_overlay_pipe *stage[MDP4_MAX_MIXER][MDP4_MAX_STAGE]; +} mdp4_overlay_db; + +static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db; + + +void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc) +{ + uint32 dma2_cfg_reg; + + dma2_cfg_reg = DMA_DITHER_EN; + + if (mfd->fb_imgType == MDP_BGR_565) + dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dma2_cfg_reg |= DMA_PACK_PATTERN_RGB; + + + if (mfd->panel_info.bpp == 18) { + dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + } else if (mfd->panel_info.bpp == 16) { + dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + } else { + dma2_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 16BPP */ + DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; + } + + if (lcdc) + dma2_cfg_reg |= DMA_PACK_ALIGN_MSB; + + /* dma2 config register */ + MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg); + +} + +void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe) +{ + + /* dma_p source */ + MDP_OUTP(MDP_BASE + 0x90004, + (pipe->src_height << 16 | pipe->src_width)); + MDP_OUTP(MDP_BASE + 0x90008, pipe->srcp0_addr); + MDP_OUTP(MDP_BASE + 0x9000c, pipe->srcp0_ystride); + + /* dma_p dest */ + MDP_OUTP(MDP_BASE + 0x90010, (pipe->dst_y << 16 | pipe->dst_x)); +} + +#define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000 +#define MDP4_VG_PHASE_STEP_SHIFT 29 + +static int mdp4_leading_0(uint32 num) +{ + uint32 bit = 0x80000000; + int i; + + for (i = 0; i < 32; i++) { + if (bit & num) + return i; + bit >>= 1; + } + + return i; +} + +static uint32 mdp4_scale_phase_step(int f_num, uint32 src, uint32 dst) +{ + uint32 val; + int n; + + n = mdp4_leading_0(src); + if (n > f_num) + n = f_num; + val = src << n; /* maximum to reduce lose of resolution */ + val /= dst; + if (n < f_num) { + n = f_num - n; + val <<= n; + } + + return val; +} + +static void mdp4_scale_setup(struct mdp4_overlay_pipe *pipe) +{ + + pipe->phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; + pipe->phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; + + if (pipe->dst_h && pipe->src_h != pipe->dst_h) { + if (pipe->dst_h >= pipe->src_h * 8) /* too much */ + return; + pipe->op_mode |= MDP4_OP_SCALEY_EN; + + if (pipe->pipe_type == OVERLAY_TYPE_VG) { + if (pipe->dst_h <= (pipe->src_h / 4)) + pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE; + else + pipe->op_mode |= MDP4_OP_SCALEY_FIR; + } + + pipe->phasey_step = mdp4_scale_phase_step(29, + pipe->src_h, pipe->dst_h); + } + + if (pipe->dst_w && pipe->src_w != pipe->dst_w) { + if (pipe->dst_w >= pipe->src_w * 8) /* too much */ + return; + pipe->op_mode |= MDP4_OP_SCALEX_EN; + + if (pipe->pipe_type == OVERLAY_TYPE_VG) { + if (pipe->dst_w <= (pipe->src_w / 4)) + pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE; + else + pipe->op_mode |= MDP4_OP_SCALEY_FIR; + } + + pipe->phasex_step = mdp4_scale_phase_step(29, + pipe->src_w, pipe->dst_w); + } +} + +void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe) +{ + char *rgb_base; + uint32 src_size, src_xy, dst_size, dst_xy; + uint32 format, pattern; + + rgb_base = MDP_BASE + MDP4_RGB_BASE; + rgb_base += (MDP4_RGB_OFF * pipe->pipe_num); + + src_size = ((pipe->src_h << 16) | pipe->src_w); + src_xy = ((pipe->src_y << 16) | pipe->src_x); + dst_size = ((pipe->dst_h << 16) | pipe->dst_w); + dst_xy = ((pipe->dst_y << 16) | pipe->dst_x); + + format = mdp4_overlay_format(pipe); + pattern = mdp4_overlay_unpack_pattern(pipe); + + pipe->op_mode |= MDP4_OP_IGC_LUT_EN; + + mdp4_scale_setup(pipe); + + outpdw(rgb_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */ + outpdw(rgb_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ + outpdw(rgb_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */ + outpdw(rgb_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */ + + outpdw(rgb_base + 0x0010, pipe->srcp0_addr); + outpdw(rgb_base + 0x0040, pipe->srcp0_ystride); + + outpdw(rgb_base + 0x0050, format);/* MDP_RGB_SRC_FORMAT */ + outpdw(rgb_base + 0x0054, pattern);/* MDP_RGB_SRC_UNPACK_PATTERN */ + outpdw(rgb_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ + outpdw(rgb_base + 0x005c, pipe->phasex_step); + outpdw(rgb_base + 0x0060, pipe->phasey_step); + + /* 16 bytes-burst x 3 req <= 48 bytes */ + outpdw(rgb_base + 0x1004, 0xc2); /* MDP_RGB_FETCH_CFG */ +} + +void mdp4_overlay_vg_setup(struct mdp4_overlay_pipe *pipe) +{ + char *vg_base; + uint32 frame_size, src_size, src_xy, dst_size, dst_xy; + uint32 format, pattern; + + vg_base = MDP_BASE + MDP4_VIDEO_BASE; + vg_base += (MDP4_VIDEO_OFF * pipe->pipe_num); + + frame_size = ((pipe->src_height << 16) | pipe->src_width); + src_size = ((pipe->src_h << 16) | pipe->src_w); + src_xy = ((pipe->src_y << 16) | pipe->src_x); + dst_size = ((pipe->dst_h << 16) | pipe->dst_w); + dst_xy = ((pipe->dst_y << 16) | pipe->dst_x); + + format = mdp4_overlay_format(pipe); + pattern = mdp4_overlay_unpack_pattern(pipe); + + pipe->op_mode |= (MDP4_OP_CSC_EN | MDP4_OP_SRC_DATA_YCBCR | + MDP4_OP_IGC_LUT_EN); + + mdp4_scale_setup(pipe); + + outpdw(vg_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */ + outpdw(vg_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ + outpdw(vg_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */ + outpdw(vg_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */ + outpdw(vg_base + 0x0048, frame_size); /* TILE frame size */ + + /* luma component plane */ + outpdw(vg_base + 0x0010, pipe->srcp0_addr); + + /* chroma component plane */ + outpdw(vg_base + 0x0014, pipe->srcp1_addr); + + outpdw(vg_base + 0x0040, + pipe->srcp1_ystride << 16 | pipe->srcp0_ystride); + + outpdw(vg_base + 0x0050, format); /* MDP_RGB_SRC_FORMAT */ + outpdw(vg_base + 0x0054, pattern); /* MDP_RGB_SRC_UNPACK_PATTERN */ + outpdw(vg_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ + outpdw(vg_base + 0x005c, pipe->phasex_step); + outpdw(vg_base + 0x0060, pipe->phasey_step); + + if (pipe->op_mode & MDP4_OP_DITHER_EN) { + outpdw(vg_base + 0x0068, + pipe->r_bit << 4 | pipe->b_bit << 2 | pipe->g_bit); + } + + /* 16 bytes-burst x 3 req <= 48 bytes */ + outpdw(vg_base + 0x1004, 0xc2); /* MDP_VG_FETCH_CFG */ +} + +int mdp4_overlay_format2type(uint32 format) +{ + switch (format) { + case MDP_RGB_565: + case MDP_RGB_888: + case MDP_BGR_565: + case MDP_ARGB_8888: + case MDP_RGBA_8888: + case MDP_BGRA_8888: + return OVERLAY_TYPE_RGB; + case MDP_YCRYCB_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V2_TILE: + case MDP_Y_CRCB_H2V2_TILE: + return OVERLAY_TYPE_VG; + default: + return -ERANGE; + } + +} + +#define C3_ALPHA 3 /* alpha */ +#define C2_R_Cr 2 /* R/Cr */ +#define C1_B_Cb 1 /* B/Cb */ +#define C0_G_Y 0 /* G/luma */ + +int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe) +{ + switch (pipe->src_format) { + case MDP_RGB_565: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 1; /* R, 5 bits */ + pipe->b_bit = 1; /* B, 5 bits */ + pipe->g_bit = 2; /* G, 6 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_RGB_888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 3; /* 3 bpp */ + break; + case MDP_BGR_565: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 1; /* R, 5 bits */ + pipe->b_bit = 1; /* B, 5 bits */ + pipe->g_bit = 2; /* G, 6 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element2 = C1_B_Cb; /* B */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_ARGB_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 1; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C3_ALPHA; /* alpha */ + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_RGBA_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 1; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C2_R_Cr; /* R */ + pipe->element2 = C0_G_Y; /* G */ + pipe->element1 = C1_B_Cb; /* B */ + pipe->element0 = C3_ALPHA; /* alpha */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_BGRA_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 1; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C1_B_Cb; /* B */ + pipe->element2 = C0_G_Y; /* G */ + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C3_ALPHA; /* alpha */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_YCRYCB_H2V1: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C0_G_Y; /* G */ + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 2; /* 2 bpp */ + pipe->chroma_sample = MDP4_CHROMA_H2V1; + break; + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 1; /* 2 */ + pipe->element3 = C0_G_Y; /* not used */ + pipe->element2 = C0_G_Y; /* not used */ + if (pipe->src_format == MDP_Y_CRCB_H2V1) { + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->chroma_sample = MDP4_CHROMA_H2V1; + } else if (pipe->src_format == MDP_Y_CBCR_H2V1) { + pipe->element1 = C1_B_Cb; /* B */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->chroma_sample = MDP4_CHROMA_H2V1; + } else if (pipe->src_format == MDP_Y_CRCB_H2V2) { + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->chroma_sample = MDP4_CHROMA_420; + } else if (pipe->src_format == MDP_Y_CBCR_H2V2) { + pipe->element1 = C1_B_Cb; /* B */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->chroma_sample = MDP4_CHROMA_420; + } + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_Y_CBCR_H2V2_TILE: + case MDP_Y_CRCB_H2V2_TILE: + pipe->frame_format = MDP4_FRAME_FORMAT_VIDEO_SUPERTILE; + pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 1; /* 2 */ + pipe->element3 = C0_G_Y; /* not used */ + pipe->element2 = C0_G_Y; /* not used */ + if (pipe->src_format == MDP_Y_CRCB_H2V2_TILE) { + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->chroma_sample = MDP4_CHROMA_420; + } else if (pipe->src_format == MDP_Y_CBCR_H2V2_TILE) { + pipe->element1 = C1_B_Cb; /* B */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->chroma_sample = MDP4_CHROMA_420; + } + pipe->bpp = 2; /* 2 bpp */ + break; + default: + /* not likely */ + return -ERANGE; + } + + return 0; +} + +/* + * color_key_convert: output with 12 bits color key + */ +static uint32 color_key_convert(int start, int num, uint32 color) +{ + + uint32 data; + + data = (color >> start) & ((1 << num) - 1); + + if (num == 5) + data = (data << 7) + (data << 2) + (data >> 3); + else if (num == 6) + data = (data << 6) + data; + else /* 8 bits */ + data = (data << 4) + (data >> 4); + + return data; + +} + +void transp_color_key(int format, uint32 transp, + uint32 *c0, uint32 *c1, uint32 *c2) +{ + int b_start, g_start, r_start; + int b_num, g_num, r_num; + + switch (format) { + case MDP_RGB_565: + b_start = 0; + g_start = 5; + r_start = 11; + r_num = 5; + g_num = 6; + b_num = 5; + break; + case MDP_RGB_888: + case MDP_XRGB_8888: + case MDP_ARGB_8888: + b_start = 0; + g_start = 8; + r_start = 16; + r_num = 8; + g_num = 8; + b_num = 8; + break; + case MDP_BGR_565: + b_start = 11; + g_start = 5; + r_start = 0; + r_num = 5; + g_num = 6; + b_num = 5; + break; + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V1: + b_start = 8; + g_start = 16; + r_start = 0; + r_num = 8; + g_num = 8; + b_num = 8; + break; + case MDP_Y_CRCB_H2V2: + case MDP_Y_CRCB_H2V1: + b_start = 0; + g_start = 16; + r_start = 8; + r_num = 8; + g_num = 8; + b_num = 8; + break; + default: + b_start = 0; + g_start = 8; + r_start = 16; + r_num = 8; + g_num = 8; + b_num = 8; + break; + } + + *c0 = color_key_convert(g_start, g_num, transp); + *c1 = color_key_convert(b_start, b_num, transp); + *c2 = color_key_convert(r_start, r_num, transp); +} + +uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe) +{ + uint32 format; + + format = 0; + + if (pipe->solid_fill) + format |= MDP4_FORMAT_SOLID_FILL; + + if (pipe->unpack_align_msb) + format |= MDP4_FORMAT_UNPACK_ALIGN_MSB; + + if (pipe->unpack_tight) + format |= MDP4_FORMAT_UNPACK_TIGHT; + + if (pipe->alpha_enable) + format |= MDP4_FORMAT_ALPHA_ENABLE; + + format |= (pipe->unpack_count << 13); + format |= ((pipe->bpp - 1) << 9); + format |= (pipe->a_bit << 6); + format |= (pipe->r_bit << 4); + format |= (pipe->b_bit << 2); + format |= pipe->g_bit; + + format |= (pipe->frame_format << 29); + + if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) { + /* video/graphic */ + format |= (pipe->fetch_plane << 19); + format |= (pipe->chroma_site << 28); + format |= (pipe->chroma_sample << 26); + } + + return format; +} + +uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe) +{ + return (pipe->element3 << 24) | (pipe->element2 << 16) | + (pipe->element1 << 8) | pipe->element0; +} + +void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe) +{ + uint32 data; + char *overlay_base; + + if (pipe->mixer_num == MDP4_MIXER1) + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + else + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + /* MDP_OVERLAYPROC_CFG */ + outpdw(overlay_base + 0x0004, 0x01); /* directout */ + data = pipe->src_height; + data <<= 16; + data |= pipe->src_width; + outpdw(overlay_base + 0x0008, data); /* ROI, height + width */ + outpdw(overlay_base + 0x000c, pipe->srcp0_addr); + outpdw(overlay_base + 0x0010, pipe->srcp0_ystride); + outpdw(overlay_base + 0x0014, 0x4); /* GC_LUT_EN, 888 */ +} + +int mdp4_overlay_active(int mixer) +{ + uint32 data, mask, i; + int p1, p2; + + data = inpdw(MDP_BASE + 0x10100); + p1 = 0; + p2 = 0; + for (i = 0; i < 8; i++) { + mask = data & 0x0f; + if (mask) { + if (mask <= 4) + p1++; + else + p2++; + } + data >>= 4; + } + + if (mixer) + return p2; + else + return p1; +} + +void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe) +{ + uint32 data, mask, snum, stage, mixer; + + stage = pipe->mixer_stage; + mixer = pipe->mixer_num; + + /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */ + data = inpdw(MDP_BASE + 0x10100); + + if (mixer == MDP4_MIXER1) + stage += 8; + + if (pipe->pipe_type == OVERLAY_TYPE_VG) {/* VG1 and VG2 */ + snum = 0; + snum += (4 * pipe->pipe_num); + } else { + snum = 8; + snum += (4 * pipe->pipe_num); /* RGB1 and RGB2 */ + } + + mask = 0x0f; + mask <<= snum; + stage <<= snum; + data &= ~mask; /* clear old bits */ + + data |= stage; + + outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */ + + data = inpdw(MDP_BASE + 0x10100); + + ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = pipe; /* keep it */ +} + +void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe) +{ + uint32 data, mask, snum, stage, mixer; + + stage = pipe->mixer_stage; + mixer = pipe->mixer_num; + + if (pipe != ctrl->stage[mixer][stage]) /* not runing */ + return; + + /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */ + data = inpdw(MDP_BASE + 0x10100); + + if (mixer == MDP4_MIXER1) + stage += 8; + + if (pipe->pipe_type == OVERLAY_TYPE_VG) {/* VG1 and VG2 */ + snum = 0; + snum += (4 * pipe->pipe_num); + } else { + snum = 8; + snum += (4 * pipe->pipe_num); /* RGB1 and RGB2 */ + } + + mask = 0x0f; + mask <<= snum; + data &= ~mask; /* clear old bits */ + + outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */ + + data = inpdw(MDP_BASE + 0x10100); + + ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL; /* clear it */ +} + +void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe) +{ + unsigned char *overlay_base; + uint32 c0, c1, c2, blend_op; + int off; + + if (pipe->mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */ + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + else + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + /* stage 0 to stage 2 */ + off = 0x20 * (pipe->mixer_stage - MDP4_MIXER_STAGE0); + + blend_op = 0; + if (pipe->alpha_enable) /* ARGB */ + blend_op = MDP4_BLEND_FG_ALPHA_FG_PIXEL | + MDP4_BLEND_BG_ALPHA_FG_PIXEL; + else + blend_op = (MDP4_BLEND_BG_ALPHA_BG_CONST | + MDP4_BLEND_FG_ALPHA_FG_CONST); + + + if (pipe->alpha_enable == 0) { /* not ARGB */ + if (pipe->is_fg) { + outpdw(overlay_base + off + 0x108, pipe->alpha); + outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha); + } else { + outpdw(overlay_base + off + 0x108, 0xff - pipe->alpha); + outpdw(overlay_base + off + 0x10c, pipe->alpha); + } + } + + if (pipe->transp != MDP_TRANSP_NOP) { + transp_color_key(pipe->src_format, pipe->transp, &c0, &c1, &c2); + if (pipe->is_fg) { + blend_op |= MDP4_BLEND_FG_TRANSP_EN; /* Fg blocked */ + /* lower limit */ + if (c0 > 0x10) + c0 -= 0x10; + if (c1 > 0x10) + c1 -= 0x10; + if (c2 > 0x10) + c2 -= 0x10; + outpdw(overlay_base + off + 0x110, + (c1 << 16 | c0));/* low */ + outpdw(overlay_base + off + 0x114, c2);/* low */ + /* upper limit */ + if ((c0 + 0x20) < 0x0fff) + c0 += 0x20; + else + c0 = 0x0fff; + if ((c1 + 0x20) < 0x0fff) + c1 += 0x20; + else + c1 = 0x0fff; + if ((c2 + 0x20) < 0x0fff) + c2 += 0x20; + else + c2 = 0x0fff; + outpdw(overlay_base + off + 0x118, + (c1 << 16 | c0));/* high */ + outpdw(overlay_base + off + 0x11c, c2);/* high */ + } else { + blend_op |= MDP4_BLEND_BG_TRANSP_EN; /* bg blocked */ + /* lower limit */ + if (c0 > 0x10) + c0 -= 0x10; + if (c1 > 0x10) + c1 -= 0x10; + if (c2 > 0x10) + c2 -= 0x10; + outpdw(overlay_base + 0x180, + (c1 << 16 | c0));/* low */ + outpdw(overlay_base + 0x184, c2);/* low */ + /* upper limit */ + if ((c0 + 0x20) < 0x0fff) + c0 += 0x20; + else + c0 = 0x0fff; + if ((c1 + 0x20) < 0x0fff) + c1 += 0x20; + else + c1 = 0x0fff; + if ((c2 + 0x20) < 0x0fff) + c2 += 0x20; + else + c2 = 0x0fff; + outpdw(overlay_base + 0x188, + (c1 << 16 | c0));/* high */ + outpdw(overlay_base + 0x18c, c2);/* high */ + } + } + outpdw(overlay_base + off + 0x104, blend_op); +} + +void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all) +{ + uint32 bits = 0; + + if (pipe->mixer_num == MDP4_MIXER1) + bits |= 0x02; + else + bits |= 0x01; + + if (all) { + if (pipe->pipe_type == OVERLAY_TYPE_RGB) { + if (pipe->pipe_num == OVERLAY_PIPE_RGB2) + bits |= 0x20; + else + bits |= 0x10; + } else { + if (pipe->pipe_num == OVERLAY_PIPE_VG2) + bits |= 0x08; + else + bits |= 0x04; + } + } + + outpdw(MDP_BASE + 0x18000, bits); /* MDP_OVERLAY_REG_FLUSH */ + + while (inpdw(MDP_BASE + 0x18000) & bits) /* self clear when complete */ + ; +} + +struct mdp4_overlay_pipe *mdp4_overlay_ndx2pipe(int ndx) +{ + struct mdp4_overlay_pipe *pipe; + + if (ndx == 0 || ndx >= MDP4_MAX_OVERLAY_PIPE) + return NULL; + + pipe = &ctrl->plist[ndx - 1]; /* ndx start from 1 */ + + if (pipe->pipe_ndx == 0) + return NULL; + + return pipe; +} + +struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(void) +{ + int i; + struct mdp4_overlay_pipe *pipe; + + pipe = &ctrl->plist[0]; + for (i = 0; i < MDP4_MAX_OVERLAY_PIPE; i++) { + if (pipe->pipe_ndx == 0) { + pipe->pipe_ndx = i + 1; /* start from 1 */ + init_completion(&pipe->comp); + printk(KERN_INFO "mdp4_overlay_pipe_alloc: pipe=%x ndx=%d\n", + (int)pipe, pipe->pipe_ndx); + return pipe; + } + pipe++; + } + + return NULL; +} + + +void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe) +{ + printk(KERN_INFO "mdp4_overlay_pipe_free: pipe=%x ndx=%d\n", + (int)pipe, pipe->pipe_ndx); + memset(pipe, 0, sizeof(*pipe)); +} + +static int get_pipe_num(int ptype, int stage) +{ + if (ptype == OVERLAY_TYPE_RGB) { + if (stage == MDP4_MIXER_STAGE_BASE) + return OVERLAY_PIPE_RGB1; + else + return OVERLAY_PIPE_RGB2; + } else { + if (stage == MDP4_MIXER_STAGE0) + return OVERLAY_PIPE_VG1; + else + return OVERLAY_PIPE_VG2; + } +} + +int mdp4_overlay_req_check(uint32 id, uint32 z_order, uint32 mixer) +{ + struct mdp4_overlay_pipe *pipe; + + pipe = ctrl->stage[mixer][z_order]; + + if (pipe == NULL) + return 0; + + if (pipe->pipe_ndx == id) /* same req, recycle */ + return 0; + + return -EPERM; +} + +static int mdp4_overlay_req2pipe(struct mdp_overlay *req, int mixer, + struct mdp4_overlay_pipe **ppipe) +{ + struct mdp4_overlay_pipe *pipe; + int ret, ptype; + + if (mixer >= MDP4_MAX_MIXER) { + printk(KERN_ERR "mpd_overlay_req2pipe: mixer out of range!\n"); + return -ERANGE; + } + + if (req->z_order < 0 || req->z_order > 2) { + printk(KERN_ERR "mpd_overlay_req2pipe: z_order=%d out of range!\n", + req->z_order); + return -ERANGE; + } + + if (req->src_rect.h == 0 || req->src_rect.w == 0) { + printk(KERN_ERR "mpd_overlay_req2pipe: src img of zero size!\n"); + return -EINVAL; + } + + ret = mdp4_overlay_req_check(req->id, req->z_order, mixer); + if (ret < 0) + return ret; + + ptype = mdp4_overlay_format2type(req->src.format); + if (ptype < 0) + return ptype; + + if (req->id == MSMFB_NEW_REQUEST) /* new request */ + pipe = mdp4_overlay_pipe_alloc(); + else + pipe = mdp4_overlay_ndx2pipe(req->id); + + if (pipe == NULL) + return -ENOMEM; + + pipe->src_format = req->src.format; + ret = mdp4_overlay_format2pipe(pipe); + + if (ret < 0) + return ret; + + /* + * base layer == 1, reserved for frame buffer + * zorder 0 == stage 0 == 2 + * zorder 1 == stage 1 == 3 + * zorder 2 == stage 2 == 4 + */ + if (req->id == MSMFB_NEW_REQUEST) { /* new request */ + pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0; + pipe->pipe_type = ptype; + pipe->pipe_num = get_pipe_num(ptype, pipe->mixer_stage); + printk(KERN_INFO "mpd4_overlay_req2pipe: zorder=%d pipe_num=%d\n", + req->z_order, pipe->pipe_num); + } + + pipe->src_width = req->src.width & 0x07ff; /* source img width */ + pipe->src_height = req->src.height & 0x07ff; /* source img height */ + pipe->src_h = req->src_rect.h & 0x07ff; + pipe->src_w = req->src_rect.w & 0x07ff; + pipe->src_y = req->src_rect.y & 0x07ff; + pipe->src_x = req->src_rect.x & 0x07ff; + pipe->dst_h = req->dst_rect.h & 0x07ff; + pipe->dst_w = req->dst_rect.w & 0x07ff; + pipe->dst_y = req->dst_rect.y & 0x07ff; + pipe->dst_x = req->dst_rect.x & 0x07ff; + + if (req->flags & MDP_FLIP_LR) + pipe->op_mode |= MDP4_OP_FLIP_LR; + + if (req->flags & MDP_FLIP_UD) + pipe->op_mode |= MDP4_OP_FLIP_UD; + + if (req->flags & MDP_DITHER) + pipe->op_mode |= MDP4_OP_DITHER_EN; + + if (req->flags & MDP_DEINTERLACE) + pipe->op_mode |= MDP4_OP_DEINT_ODD_REF; + + pipe->is_fg = req->is_fg;/* control alpha and color key */ + + pipe->alpha = req->alpha & 0x0ff; + + pipe->transp = req->transp_mask; + + *ppipe = pipe; + + return 0; +} + +int get_img(struct msmfb_data *img, struct fb_info *info, + unsigned long *start, unsigned long *len, struct file **pp_file) +{ + int put_needed, ret = 0; + struct file *file; +#ifdef CONFIG_ANDROID_PMEM + unsigned long vstart; +#endif + +#ifdef CONFIG_ANDROID_PMEM + if (!get_pmem_file(img->memory_id, start, &vstart, len, pp_file)) + return 0; +#endif + file = fget_light(img->memory_id, &put_needed); + if (file == NULL) + return -1; + + if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { + *start = info->fix.smem_start; + *len = info->fix.smem_len; + *pp_file = file; + } else { + ret = -1; + fput_light(file, put_needed); + } + return ret; +} +int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req) +{ + struct mdp4_overlay_pipe *pipe; + + pipe = mdp4_overlay_ndx2pipe(req->id); + if (pipe == NULL) + return -ENODEV; + + *req = pipe->req_data; + + return 0; +} + +int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + int ret, mixer; + struct mdp4_overlay_pipe *pipe; + int lcdc; + + if (mfd == NULL) + return -ENODEV; + + if (req->src.format == MDP_FB_FORMAT) + req->src.format = mfd->fb_imgType; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + mixer = info->node; /* minor number of char device */ + + ret = mdp4_overlay_req2pipe(req, mixer, &pipe); + if (ret < 0) { + mutex_unlock(&mfd->dma->ov_mutex); + return ret; + } + + lcdc = inpdw(MDP_BASE + 0xc0000); + + if (lcdc == 0) { /* mddi */ + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + } + + /* return id back to user */ + req->id = pipe->pipe_ndx; /* pipe_ndx start from 1 */ + pipe->req_data = *req; /* keep original req */ + + mutex_unlock(&mfd->dma->ov_mutex); + + return 0; +} + +int mdp4_overlay_unset(struct fb_info *info, int ndx) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct mdp4_overlay_pipe *pipe; + int lcdc; + + if (mfd == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + pipe = mdp4_overlay_ndx2pipe(ndx); + + if (pipe == NULL) { + mutex_unlock(&mfd->dma->ov_mutex); + return -ENODEV; + } + + lcdc = inpdw(MDP_BASE + 0xc0000); + + mdp4_mixer_stage_down(pipe); + + if (lcdc == 0) { /* mddi */ + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } + + if (lcdc) /* LCDC mode */ + mdp4_overlay_reg_flush(pipe, 0); + + mdp4_overlay_pipe_free(pipe); + + if (lcdc == 0) { /* mddi */ + mdp4_mddi_overlay_restore(); + } + + mutex_unlock(&mfd->dma->ov_mutex); + + return 0; +} + +struct tile_desc { + uint32 width; /* tile's width */ + uint32 height; /* tile's height */ + uint32 row_tile_w; /* tiles per row's width */ + uint32 row_tile_h; /* tiles per row's height */ +}; + +void tile_samsung(struct tile_desc *tp) +{ + /* + * each row of samsung tile consists of two tiles in height + * and two tiles in width which means width should align to + * 64 x 2 bytes and height should align to 32 x 2 bytes. + * video decoder generate two tiles in width and one tile + * in height which ends up height align to 32 X 1 bytes. + */ + tp->width = 64; /* 64 bytes */ + tp->row_tile_w = 2; /* 2 tiles per row's width */ + tp->height = 32; /* 32 bytes */ + tp->row_tile_h = 1; /* 1 tiles per row's height */ +} + +uint32 tile_mem_size(struct mdp4_overlay_pipe *pipe, struct tile_desc *tp) +{ + uint32 tile_w, tile_h; + uint32 row_num_w, row_num_h; + + + tile_w = tp->width * tp->row_tile_w; + tile_h = tp->height * tp->row_tile_h; + + row_num_w = (pipe->src_width + tile_w - 1) / tile_w; + row_num_h = (pipe->src_height + tile_h - 1) / tile_h; + + return row_num_w * row_num_h * tile_w * tile_h; +} + +int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req, + struct file **pp_src_file) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msmfb_data *img; + struct mdp4_overlay_pipe *pipe; + ulong start, addr; + ulong len = 0; + struct file *p_src_file = 0; + int lcdc; + + if (mfd == NULL) + return -ENODEV; + + pipe = mdp4_overlay_ndx2pipe(req->id); + if (pipe == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + img = &req->data; + get_img(img, info, &start, &len, &p_src_file); + if (len == 0) { + mutex_unlock(&mfd->dma->ov_mutex); + printk(KERN_ERR "mdp_overlay_play: could not retrieve" + " image from memory\n"); + return -1; + } + *pp_src_file = p_src_file; + + addr = start + img->offset; + pipe->srcp0_addr = addr; + pipe->srcp0_ystride = pipe->src_width * pipe->bpp; + + if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) { + if (pipe->frame_format == MDP4_FRAME_FORMAT_VIDEO_SUPERTILE) { + struct tile_desc tile; + + tile_samsung(&tile); + pipe->srcp1_addr = addr + tile_mem_size(pipe, &tile); + } else + pipe->srcp1_addr = addr + + pipe->src_width * pipe->src_height; + + pipe->srcp0_ystride = pipe->src_width; + pipe->srcp1_ystride = pipe->src_width; + } + + lcdc = inpdw(MDP_BASE + 0xc0000); + lcdc &= 0x01; /* LCDC mode */ + + if (pipe->pipe_type == OVERLAY_TYPE_VG) + mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */ + else + mdp4_overlay_rgb_setup(pipe); /* rgb pipe */ + + mdp4_mixer_blend_setup(pipe); + mdp4_mixer_stage_up(pipe); + + if (lcdc) { /* LCDC mode */ + mdp4_overlay_reg_flush(pipe, 1); + } + + if (lcdc) { /* LCDC mode */ + if (pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) { /* done */ + mutex_unlock(&mfd->dma->ov_mutex); + return 0; + } + } + + if (lcdc == 0) { /* MDDI mode */ +#ifdef MDP4_NONBLOCKING + if (mfd->panel_power_on) +#else + if (!mfd->dma->busy && mfd->panel_power_on) +#endif + mdp4_mddi_overlay_kickoff(mfd, pipe); + } + + mutex_unlock(&mfd->dma->ov_mutex); + + return 0; +} diff --git a/drivers/staging/msm/mdp4_overlay_lcdc.c b/drivers/staging/msm/mdp4_overlay_lcdc.c new file mode 100644 index 00000000000..a6ab8ec83f5 --- /dev/null +++ b/drivers/staging/msm/mdp4_overlay_lcdc.c @@ -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); +} diff --git a/drivers/staging/msm/mdp4_overlay_mddi.c b/drivers/staging/msm/mdp4_overlay_mddi.c new file mode 100644 index 00000000000..be1b2874185 --- /dev/null +++ b/drivers/staging/msm/mdp4_overlay_mddi.c @@ -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); +} diff --git a/drivers/staging/msm/mdp4_util.c b/drivers/staging/msm/mdp4_util.c new file mode 100644 index 00000000000..fd97f520599 --- /dev/null +++ b/drivers/staging/msm/mdp4_util.c @@ -0,0 +1,1686 @@ + +/* 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" + +void mdp4_sw_reset(ulong bits) +{ + bits &= 0x1f; /* 5 bits */ + outpdw(MDP_BASE + 0x001c, bits); /* MDP_SW_RESET */ + + while (inpdw(MDP_BASE + 0x001c) & bits) /* self clear when complete */ + ; + MSM_FB_INFO("mdp4_sw_reset: 0x%x\n", (int)bits); +} + +void mdp4_overlay_cfg(int overlayer, int blt_mode, int refresh, int direct_out) +{ + ulong bits = 0; + + if (blt_mode) + bits |= (1 << 3); + refresh &= 0x03; /* 2 bites */ + bits |= (refresh << 1); + direct_out &= 0x01; + bits |= direct_out; + + if (overlayer == MDP4_MIXER0) + outpdw(MDP_BASE + 0x10004, bits); /* MDP_OVERLAY0_CFG */ + else + outpdw(MDP_BASE + 0x18004, bits); /* MDP_OVERLAY1_CFG */ + + MSM_FB_INFO("mdp4_overlay_cfg: 0x%x\n", (int)inpdw(MDP_BASE + 0x10004)); +} + +void mdp4_display_intf_sel(int output, ulong intf) +{ + ulong bits, mask; + + bits = inpdw(MDP_BASE + 0x0038); /* MDP_DISP_INTF_SEL */ + + mask = 0x03; /* 2 bits */ + intf &= 0x03; /* 2 bits */ + + switch (output) { + case EXTERNAL_INTF_SEL: + intf <<= 4; + mask <<= 4; + break; + case SECONDARY_INTF_SEL: + intf &= 0x02; /* only MDDI and EBI2 support */ + intf <<= 2; + mask <<= 2; + break; + default: + break; + } + + + bits &= ~mask; + bits |= intf; + + outpdw(MDP_BASE + 0x0038, bits); /* MDP_DISP_INTF_SEL */ + + MSM_FB_INFO("mdp4_display_intf_sel: 0x%x\n", (int)inpdw(MDP_BASE + 0x0038)); +} + +unsigned long mdp4_display_status(void) +{ + return inpdw(MDP_BASE + 0x0018) & 0x3ff; /* MDP_DISPLAY_STATUS */ +} + +void mdp4_ebi2_lcd_setup(int lcd, ulong base, int ystride) +{ + /* always use memory map */ + ystride &= 0x01fff; /* 13 bits */ + if (lcd == EBI2_LCD0) { + outpdw(MDP_BASE + 0x0060, base);/* MDP_EBI2_LCD0 */ + outpdw(MDP_BASE + 0x0068, ystride);/* MDP_EBI2_LCD0_YSTRIDE */ + } else { + outpdw(MDP_BASE + 0x0064, base);/* MDP_EBI2_LCD1 */ + outpdw(MDP_BASE + 0x006c, ystride);/* MDP_EBI2_LCD1_YSTRIDE */ + } +} + +void mdp4_mddi_setup(int mddi, unsigned long id) +{ + ulong bits; + + if (mddi == MDDI_EXTERNAL_SET) + bits = 0x02; + else if (mddi == MDDI_SECONDARY_SET) + bits = 0x01; + else + bits = 0; /* PRIMARY_SET */ + + id <<= 16; + + bits |= id; + + outpdw(MDP_BASE + 0x0090, bits); /* MDP_MDDI_PARAM_WR_SEL */ +} + +int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req, + struct file **pp_src_file, struct file **pp_dst_file) +{ + + /* not implemented yet */ + return -1; +} + +void mdp4_hw_init(void) +{ + ulong bits; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + +#ifdef MDP4_ERROR + /* + * Issue software reset on DMA_P will casue DMA_P dma engine stall + * on LCDC mode. However DMA_P does not stall at MDDI mode. + * This need further investigation. + */ + mdp4_sw_reset(0x17); +#endif + + mdp4_clear_lcdc(); + + mdp4_mixer_blend_init(0); + mdp4_mixer_blend_init(1); + mdp4_vg_qseed_init(0); + mdp4_vg_qseed_init(1); + mdp4_vg_csc_mv_setup(0); + mdp4_vg_csc_mv_setup(1); + mdp4_vg_csc_pre_bv_setup(0); + mdp4_vg_csc_pre_bv_setup(1); + mdp4_vg_csc_post_bv_setup(0); + mdp4_vg_csc_post_bv_setup(1); + mdp4_vg_csc_pre_lv_setup(0); + mdp4_vg_csc_pre_lv_setup(1); + mdp4_vg_csc_post_lv_setup(0); + mdp4_vg_csc_post_lv_setup(1); + + mdp4_mixer_gc_lut_setup(0); + mdp4_mixer_gc_lut_setup(1); + + mdp4_vg_igc_lut_setup(0); + mdp4_vg_igc_lut_setup(1); + + mdp4_rgb_igc_lut_setup(0); + mdp4_rgb_igc_lut_setup(1); + + outp32(MDP_EBI2_PORTMAP_MODE, 0x3); + + /* system interrupts */ + + bits = mdp_intr_mask; + outpdw(MDP_BASE + 0x0050, bits);/* enable specififed interrupts */ + + /* histogram */ + MDP_OUTP(MDP_BASE + 0x95010, 1); /* auto clear HIST */ + + /* enable histogram interrupts */ + outpdw(MDP_BASE + 0x9501c, INTR_HIST_DONE); + + /* For the max read pending cmd config below, if the MDP clock */ + /* is less than the AXI clock, then we must use 3 pending */ + /* pending requests. Otherwise, we should use 8 pending requests. */ + /* In the future we should do this detection automatically. */ + + /* max read pending cmd config */ + outpdw(MDP_BASE + 0x004c, 0x02222); /* 3 pending requests */ + + /* dma_p fetch config */ + outpdw(MDP_BASE + 0x91004, 0x27); /* burst size of 8 */ + +#ifndef CONFIG_FB_MSM_OVERLAY + /* both REFRESH_MODE and DIRECT_OUT are ignored at BLT mode */ + mdp4_overlay_cfg(MDP4_MIXER0, OVERLAY_MODE_BLT, 0, 0); + mdp4_overlay_cfg(MDP4_MIXER1, OVERLAY_MODE_BLT, 0, 0); +#endif + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + + +void mdp4_clear_lcdc(void) +{ + uint32 bits; + + bits = inpdw(MDP_BASE + 0xc0000); + if (bits & 0x01) /* enabled already */ + return; + + outpdw(MDP_BASE + 0xc0004, 0); /* vsync ctrl out */ + outpdw(MDP_BASE + 0xc0008, 0); /* vsync period */ + outpdw(MDP_BASE + 0xc000c, 0); /* vsync pusle width */ + outpdw(MDP_BASE + 0xc0010, 0); /* lcdc display HCTL */ + outpdw(MDP_BASE + 0xc0014, 0); /* lcdc display v start */ + outpdw(MDP_BASE + 0xc0018, 0); /* lcdc display v end */ + outpdw(MDP_BASE + 0xc001c, 0); /* lcdc active hctl */ + outpdw(MDP_BASE + 0xc0020, 0); /* lcdc active v start */ + outpdw(MDP_BASE + 0xc0024, 0); /* lcdc active v end */ + outpdw(MDP_BASE + 0xc0028, 0); /* lcdc board color */ + outpdw(MDP_BASE + 0xc002c, 0); /* lcdc underflow ctrl */ + outpdw(MDP_BASE + 0xc0030, 0); /* lcdc hsync skew */ + outpdw(MDP_BASE + 0xc0034, 0); /* lcdc test ctl */ + outpdw(MDP_BASE + 0xc0038, 0); /* lcdc ctl polarity */ +} + +static struct mdp_dma_data overlay1_data; +static int intr_dma_p; +static int intr_dma_s; +static int intr_dma_e; +static int intr_overlay0; +static int intr_overlay1; + +irqreturn_t mdp4_isr(int irq, void *ptr) +{ + uint32 isr, mask, lcdc; + struct mdp_dma_data *dma; + + mdp_is_in_isr = TRUE; + + while (1) { + isr = inpdw(MDP_INTR_STATUS); + if (isr == 0) + break; + + mask = inpdw(MDP_INTR_ENABLE); + outpdw(MDP_INTR_CLEAR, isr); + + isr &= mask; + + if (unlikely(isr == 0)) + break; + + if (isr & INTR_DMA_P_DONE) { + intr_dma_p++; + lcdc = inpdw(MDP_BASE + 0xc0000); + dma = &dma2_data; + if (lcdc & 0x01) { /* LCDC enable */ + /* disable LCDC interrupt */ + mdp_intr_mask &= ~INTR_DMA_P_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->waiting = FALSE; + } else { + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_DMA2_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + } + complete(&dma->comp); + } + if (isr & INTR_DMA_S_DONE) { + intr_dma_s++; + dma = &dma_s_data; + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_DMA_S_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + complete(&dma->comp); + } + if (isr & INTR_DMA_E_DONE) { + intr_dma_e++; + dma = &dma_e_data; + mdp_intr_mask &= ~INTR_DMA_E_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->busy = FALSE; + + if (dma->waiting) { + dma->waiting = FALSE; + complete(&dma->comp); + } + } + if (isr & INTR_OVERLAY0_DONE) { + intr_overlay0++; + lcdc = inpdw(MDP_BASE + 0xc0000); + dma = &dma2_data; + if (lcdc & 0x01) { /* LCDC enable */ + /* disable LCDC interrupt */ + mdp_intr_mask &= ~INTR_OVERLAY0_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->waiting = FALSE; + mdp4_overlay0_done_lcdc(); + } else { /* MDDI */ + dma->busy = FALSE; +#ifdef MDP4_NONBLOCKING + mdp_disable_irq_nolock(MDP_OVERLAY0_TERM); +#endif + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + mdp4_overlay0_done_mddi(); + } + } + if (isr & INTR_OVERLAY1_DONE) { + intr_overlay1++; + dma = &overlay1_data; + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + complete(&dma->comp); + } + if (isr & INTR_DMA_P_HISTOGRAM) { + isr = inpdw(MDP_DMA_P_HIST_INTR_STATUS); + mask = inpdw(MDP_DMA_P_HIST_INTR_ENABLE); + outpdw(MDP_DMA_P_HIST_INTR_CLEAR, isr); + isr &= mask; + if (isr & INTR_HIST_DONE) { + if (mdp_hist.r) + memcpy(mdp_hist.r, MDP_BASE + 0x95100, + mdp_hist.bin_cnt*4); + if (mdp_hist.g) + memcpy(mdp_hist.g, MDP_BASE + 0x95200, + mdp_hist.bin_cnt*4); + if (mdp_hist.b) + memcpy(mdp_hist.b, MDP_BASE + 0x95300, + mdp_hist.bin_cnt*4); + complete(&mdp_hist_comp); + } + } + } + + mdp_is_in_isr = FALSE; + + return IRQ_HANDLED; +} + + +/* + * QSEED tables + */ + +static uint32 vg_qseed_table0[] = { + 0x5556aaff, 0x00000000, 0x00000000, 0x00000000 +}; + +static uint32 vg_qseed_table1[] = { + 0x76543210, 0xfedcba98 +}; + +static uint32 vg_qseed_table2[] = { + 0x02000000, 0x00000000, 0x02060ff2, 0x00000008, + 0x02090fe4, 0x00000013, 0x020a0fd9, 0x0ffc0021, + 0x02080fce, 0x0ffa0030, 0x02030fc5, 0x0ff60042, + 0x01fd0fbe, 0x0ff10054, 0x01f50fb6, 0x0fed0068, + 0x01e90fb1, 0x0fe60080, 0x01dc0fae, 0x0fe10095, + 0x01ca0fae, 0x0fda00ae, 0x01b70fad, 0x0fd600c6, + 0x01a40fad, 0x0fcf00e0, 0x018f0faf, 0x0fc800fa, + 0x01780fb1, 0x0fc30114, 0x015f0fb5, 0x0fbf012d, + 0x01490fb7, 0x0fb70149, 0x012d0fbf, 0x0fb5015f, + 0x01140fc3, 0x0fb10178, 0x00fa0fc8, 0x0faf018f, + 0x00e00fcf, 0x0fad01a4, 0x00c60fd6, 0x0fad01b7, + 0x00ae0fda, 0x0fae01ca, 0x00950fe1, 0x0fae01dc, + 0x00800fe6, 0x0fb101e9, 0x00680fed, 0x0fb601f5, + 0x00540ff1, 0x0fbe01fd, 0x00420ff6, 0x0fc50203, + 0x00300ffa, 0x0fce0208, 0x00210ffc, 0x0fd9020a, + 0x00130000, 0x0fe40209, 0x00080000, 0x0ff20206, + 0x02000000, 0x00000000, 0x02040ff2, 0x0000000a, + 0x02040fe4, 0x00000018, 0x02010fda, 0x0ffc0029, + 0x01fc0fcf, 0x0ffa003b, 0x01f30fc7, 0x0ff60050, + 0x01e90fc0, 0x0ff20065, 0x01dc0fba, 0x0fee007c, + 0x01cc0fb6, 0x0fe80096, 0x01ba0fb4, 0x0fe400ae, + 0x01a70fb4, 0x0fdd00c8, 0x018f0fb5, 0x0fda00e2, + 0x017a0fb5, 0x0fd400fd, 0x01630fb8, 0x0fce0117, + 0x014c0fba, 0x0fca0130, 0x01320fbf, 0x0fc70148, + 0x011b0fc1, 0x0fc10163, 0x01010fc8, 0x0fc00177, + 0x00e90fcd, 0x0fbd018d, 0x00d10fd1, 0x0fbc01a2, + 0x00ba0fd7, 0x0fbb01b4, 0x00a30fdd, 0x0fbc01c4, + 0x008e0fe1, 0x0fbd01d4, 0x00790fe7, 0x0fbe01e2, + 0x00670feb, 0x0fc001ee, 0x00540ff1, 0x0fc501f6, + 0x00430ff4, 0x0fcb01fe, 0x00340ff8, 0x0fd10203, + 0x00260ffb, 0x0fd80207, 0x001a0ffd, 0x0fe10208, + 0x000f0000, 0x0fea0207, 0x00060000, 0x0ff50205, + 0x02000000, 0x00000000, 0x02020ff2, 0x0000000c, + 0x02000fe4, 0x0000001c, 0x01fa0fda, 0x0ffc0030, + 0x01f10fd0, 0x0ffa0045, 0x01e50fc8, 0x0ff6005d, + 0x01d60fc3, 0x0ff30074, 0x01c60fbd, 0x0fef008e, + 0x01b30fba, 0x0fe900aa, 0x019e0fb9, 0x0fe500c4, + 0x01870fba, 0x0fe000df, 0x016f0fbb, 0x0fdd00f9, + 0x01580fbc, 0x0fd80114, 0x01400fbf, 0x0fd3012e, + 0x01280fc2, 0x0fd00146, 0x010f0fc6, 0x0fce015d, + 0x00f90fc9, 0x0fc90175, 0x00e00fcf, 0x0fc90188, + 0x00ca0fd4, 0x0fc6019c, 0x00b40fd8, 0x0fc601ae, + 0x009f0fdd, 0x0fc501bf, 0x008b0fe3, 0x0fc601cc, + 0x00780fe6, 0x0fc701db, 0x00660feb, 0x0fc801e7, + 0x00560fef, 0x0fcb01f0, 0x00460ff3, 0x0fcf01f8, + 0x00380ff6, 0x0fd401fe, 0x002c0ff9, 0x0fd90202, + 0x00200ffc, 0x0fdf0205, 0x00160ffe, 0x0fe60206, + 0x000c0000, 0x0fed0207, 0x00050000, 0x0ff70204, + 0x02000000, 0x00000000, 0x01fe0ff3, 0x0000000f, + 0x01f60fe5, 0x00000025, 0x01ea0fdb, 0x0ffd003e, + 0x01db0fd2, 0x0ffb0058, 0x01c80fcc, 0x0ff70075, + 0x01b50fc7, 0x0ff40090, 0x01a00fc3, 0x0ff000ad, + 0x01880fc1, 0x0feb00cc, 0x01700fc1, 0x0fe800e7, + 0x01550fc3, 0x0fe40104, 0x013b0fc5, 0x0fe2011e, + 0x01240fc6, 0x0fde0138, 0x010c0fca, 0x0fda0150, + 0x00f40fcd, 0x0fd90166, 0x00dd0fd1, 0x0fd7017b, + 0x00c80fd4, 0x0fd40190, 0x00b20fd9, 0x0fd401a1, + 0x009f0fdd, 0x0fd301b1, 0x008c0fe1, 0x0fd301c0, + 0x007b0fe5, 0x0fd301cd, 0x006a0fea, 0x0fd401d8, + 0x005c0fec, 0x0fd501e3, 0x004d0ff0, 0x0fd601ed, + 0x00410ff3, 0x0fd801f4, 0x00340ff7, 0x0fdb01fa, + 0x002a0ff9, 0x0fdf01fe, 0x00200ffb, 0x0fe30202, + 0x00180ffd, 0x0fe70204, 0x00100ffe, 0x0fed0205, + 0x00090000, 0x0ff20205, 0x00040000, 0x0ff90203, + 0x02000000, 0x00000000, 0x02050ff5, 0x00000006, + 0x02070fea, 0x0000000f, 0x02080fe1, 0x0ffd001a, + 0x02070fd8, 0x0ffb0026, 0x02030fd1, 0x0ff80034, + 0x01fe0fcb, 0x0ff40043, 0x01f60fc5, 0x0ff10054, + 0x01ee0fc0, 0x0feb0067, 0x01e20fbe, 0x0fe70079, + 0x01d40fbd, 0x0fe1008e, 0x01c40fbc, 0x0fdd00a3, + 0x01b40fbb, 0x0fd700ba, 0x01a20fbc, 0x0fd100d1, + 0x018d0fbd, 0x0fcd00e9, 0x01770fc0, 0x0fc80101, + 0x01630fc1, 0x0fc1011b, 0x01480fc7, 0x0fbf0132, + 0x01300fca, 0x0fba014c, 0x01170fce, 0x0fb80163, + 0x00fd0fd4, 0x0fb5017a, 0x00e20fda, 0x0fb5018f, + 0x00c80fdd, 0x0fb401a7, 0x00ae0fe4, 0x0fb401ba, + 0x00960fe8, 0x0fb601cc, 0x007c0fee, 0x0fba01dc, + 0x00650ff2, 0x0fc001e9, 0x00500ff6, 0x0fc701f3, + 0x003b0ffa, 0x0fcf01fc, 0x00290ffc, 0x0fda0201, + 0x00180000, 0x0fe40204, 0x000a0000, 0x0ff20204, + 0x02000000, 0x00000000, 0x02030ff5, 0x00000008, + 0x02030fea, 0x00000013, 0x02020fe1, 0x0ffd0020, + 0x01fc0fd9, 0x0ffc002f, 0x01f60fd2, 0x0ff80040, + 0x01ed0fcd, 0x0ff50051, 0x01e30fc7, 0x0ff10065, + 0x01d70fc3, 0x0fec007a, 0x01c60fc2, 0x0fe9008f, + 0x01b60fc1, 0x0fe300a6, 0x01a20fc1, 0x0fe000bd, + 0x018f0fc1, 0x0fdb00d5, 0x017b0fc2, 0x0fd500ee, + 0x01640fc4, 0x0fd20106, 0x014d0fc8, 0x0fce011d, + 0x01370fc9, 0x0fc90137, 0x011d0fce, 0x0fc8014d, + 0x01060fd2, 0x0fc40164, 0x00ee0fd5, 0x0fc2017b, + 0x00d50fdb, 0x0fc1018f, 0x00bd0fe0, 0x0fc101a2, + 0x00a60fe3, 0x0fc101b6, 0x008f0fe9, 0x0fc201c6, + 0x007a0fec, 0x0fc301d7, 0x00650ff1, 0x0fc701e3, + 0x00510ff5, 0x0fcd01ed, 0x00400ff8, 0x0fd201f6, + 0x002f0ffc, 0x0fd901fc, 0x00200ffd, 0x0fe10202, + 0x00130000, 0x0fea0203, 0x00080000, 0x0ff50203, + 0x02000000, 0x00000000, 0x02020ff5, 0x00000009, + 0x01ff0fea, 0x00000017, 0x01fb0fe2, 0x0ffd0026, + 0x01f30fda, 0x0ffc0037, 0x01ea0fd3, 0x0ff8004b, + 0x01df0fce, 0x0ff5005e, 0x01d10fc9, 0x0ff20074, + 0x01c10fc6, 0x0fed008c, 0x01ae0fc5, 0x0fea00a3, + 0x019b0fc5, 0x0fe500bb, 0x01850fc6, 0x0fe200d3, + 0x01700fc6, 0x0fde00ec, 0x015a0fc8, 0x0fd90105, + 0x01430fca, 0x0fd6011d, 0x012b0fcd, 0x0fd30135, + 0x01150fcf, 0x0fcf014d, 0x00fc0fd4, 0x0fce0162, + 0x00e50fd8, 0x0fcc0177, 0x00cf0fdb, 0x0fca018c, + 0x00b80fe0, 0x0fc9019f, 0x00a20fe5, 0x0fca01af, + 0x008e0fe8, 0x0fcb01bf, 0x00790fec, 0x0fcb01d0, + 0x00670fef, 0x0fcd01dd, 0x00550ff4, 0x0fd001e7, + 0x00440ff7, 0x0fd501f0, 0x00350ffa, 0x0fda01f7, + 0x00270ffc, 0x0fdf01fe, 0x001b0ffe, 0x0fe70200, + 0x00100000, 0x0fee0202, 0x00060000, 0x0ff70203, + 0x02000000, 0x00000000, 0x01ff0ff5, 0x0000000c, + 0x01f80fea, 0x0000001e, 0x01ef0fe2, 0x0ffd0032, + 0x01e20fdb, 0x0ffc0047, 0x01d30fd5, 0x0ff9005f, + 0x01c20fd1, 0x0ff60077, 0x01b00fcd, 0x0ff30090, + 0x019b0fcb, 0x0fef00ab, 0x01850fcb, 0x0fec00c4, + 0x016e0fcc, 0x0fe800de, 0x01550fcd, 0x0fe600f8, + 0x013f0fce, 0x0fe20111, 0x01280fd0, 0x0fdf0129, + 0x01110fd2, 0x0fdd0140, 0x00f90fd6, 0x0fdb0156, + 0x00e40fd8, 0x0fd8016c, 0x00cd0fdd, 0x0fd8017e, + 0x00b80fe0, 0x0fd60192, 0x00a40fe3, 0x0fd601a3, + 0x00910fe7, 0x0fd501b3, 0x007f0feb, 0x0fd601c0, + 0x006e0fed, 0x0fd701ce, 0x005d0ff1, 0x0fd701db, + 0x004f0ff3, 0x0fd901e5, 0x00400ff7, 0x0fdc01ed, + 0x00330ff9, 0x0fe001f4, 0x00280ffb, 0x0fe301fa, + 0x001d0ffd, 0x0fe801fe, 0x00140ffe, 0x0fed0201, + 0x000c0000, 0x0ff20202, 0x00050000, 0x0ff90202, + 0x02000000, 0x00000000, 0x02040ff7, 0x00000005, + 0x02070fed, 0x0000000c, 0x02060fe6, 0x0ffe0016, + 0x02050fdf, 0x0ffc0020, 0x02020fd9, 0x0ff9002c, + 0x01fe0fd4, 0x0ff60038, 0x01f80fcf, 0x0ff30046, + 0x01f00fcb, 0x0fef0056, 0x01e70fc8, 0x0feb0066, + 0x01db0fc7, 0x0fe60078, 0x01cc0fc6, 0x0fe3008b, + 0x01bf0fc5, 0x0fdd009f, 0x01ae0fc6, 0x0fd800b4, + 0x019c0fc6, 0x0fd400ca, 0x01880fc9, 0x0fcf00e0, + 0x01750fc9, 0x0fc900f9, 0x015d0fce, 0x0fc6010f, + 0x01460fd0, 0x0fc20128, 0x012e0fd3, 0x0fbf0140, + 0x01140fd8, 0x0fbc0158, 0x00f90fdd, 0x0fbb016f, + 0x00df0fe0, 0x0fba0187, 0x00c40fe5, 0x0fb9019e, + 0x00aa0fe9, 0x0fba01b3, 0x008e0fef, 0x0fbd01c6, + 0x00740ff3, 0x0fc301d6, 0x005d0ff6, 0x0fc801e5, + 0x00450ffa, 0x0fd001f1, 0x00300ffc, 0x0fda01fa, + 0x001c0000, 0x0fe40200, 0x000c0000, 0x0ff20202, + 0x02000000, 0x00000000, 0x02030ff7, 0x00000006, + 0x02020fee, 0x00000010, 0x02000fe7, 0x0ffe001b, + 0x01fe0fdf, 0x0ffc0027, 0x01f70fda, 0x0ffa0035, + 0x01f00fd5, 0x0ff70044, 0x01e70fd0, 0x0ff40055, + 0x01dd0fcd, 0x0fef0067, 0x01d00fcb, 0x0fec0079, + 0x01bf0fcb, 0x0fe8008e, 0x01af0fca, 0x0fe500a2, + 0x019f0fc9, 0x0fe000b8, 0x018c0fca, 0x0fdb00cf, + 0x01770fcc, 0x0fd800e5, 0x01620fce, 0x0fd400fc, + 0x014d0fcf, 0x0fcf0115, 0x01350fd3, 0x0fcd012b, + 0x011d0fd6, 0x0fca0143, 0x01050fd9, 0x0fc8015a, + 0x00ec0fde, 0x0fc60170, 0x00d30fe2, 0x0fc60185, + 0x00bb0fe5, 0x0fc5019b, 0x00a30fea, 0x0fc501ae, + 0x008c0fed, 0x0fc601c1, 0x00740ff2, 0x0fc901d1, + 0x005e0ff5, 0x0fce01df, 0x004b0ff8, 0x0fd301ea, + 0x00370ffc, 0x0fda01f3, 0x00260ffd, 0x0fe201fb, + 0x00170000, 0x0fea01ff, 0x00090000, 0x0ff50202, + 0x02000000, 0x00000000, 0x02010ff7, 0x00000008, + 0x01ff0fee, 0x00000013, 0x01fb0fe7, 0x0ffe0020, + 0x01f60fe0, 0x0ffc002e, 0x01ed0fda, 0x0ffa003f, + 0x01e40fd6, 0x0ff7004f, 0x01d80fd2, 0x0ff40062, + 0x01ca0fcf, 0x0ff00077, 0x01bb0fcd, 0x0fed008b, + 0x01a90fcd, 0x0fe900a1, 0x01960fcd, 0x0fe600b7, + 0x01830fcd, 0x0fe200ce, 0x016d0fcf, 0x0fde00e6, + 0x01580fd0, 0x0fdb00fd, 0x01410fd3, 0x0fd80114, + 0x012c0fd4, 0x0fd4012c, 0x01140fd8, 0x0fd30141, + 0x00fd0fdb, 0x0fd00158, 0x00e60fde, 0x0fcf016d, + 0x00ce0fe2, 0x0fcd0183, 0x00b70fe6, 0x0fcd0196, + 0x00a10fe9, 0x0fcd01a9, 0x008b0fed, 0x0fcd01bb, + 0x00770ff0, 0x0fcf01ca, 0x00620ff4, 0x0fd201d8, + 0x004f0ff7, 0x0fd601e4, 0x003f0ffa, 0x0fda01ed, + 0x002e0ffc, 0x0fe001f6, 0x00200ffe, 0x0fe701fb, + 0x00130000, 0x0fee01ff, 0x00080000, 0x0ff70201, + 0x02000000, 0x00000000, 0x01ff0ff7, 0x0000000a, + 0x01f90fee, 0x00000019, 0x01f10fe7, 0x0ffe002a, + 0x01e60fe1, 0x0ffd003c, 0x01d90fdc, 0x0ffa0051, + 0x01cc0fd8, 0x0ff70065, 0x01bb0fd5, 0x0ff5007b, + 0x01a80fd3, 0x0ff10094, 0x01950fd2, 0x0fef00aa, + 0x01800fd2, 0x0feb00c3, 0x016a0fd3, 0x0fe900da, + 0x01540fd3, 0x0fe600f3, 0x013f0fd5, 0x0fe2010a, + 0x01280fd7, 0x0fe00121, 0x01100fda, 0x0fde0138, + 0x00fb0fdb, 0x0fdb014f, 0x00e40fdf, 0x0fdb0162, + 0x00ce0fe2, 0x0fd90177, 0x00b90fe4, 0x0fd8018b, + 0x00a50fe8, 0x0fd8019b, 0x00910fec, 0x0fd801ab, + 0x007e0fee, 0x0fd801bc, 0x006c0ff2, 0x0fd901c9, + 0x005c0ff4, 0x0fda01d6, 0x004b0ff7, 0x0fdd01e1, + 0x003c0ff9, 0x0fe001eb, 0x002f0ffb, 0x0fe401f2, + 0x00230ffd, 0x0fe801f8, 0x00180ffe, 0x0fed01fd, + 0x000e0000, 0x0ff20200, 0x00060000, 0x0ff90201, + 0x02000000, 0x00000000, 0x02030ff9, 0x00000004, + 0x02050ff2, 0x00000009, 0x02050fed, 0x0ffe0010, + 0x02040fe7, 0x0ffd0018, 0x02020fe3, 0x0ffb0020, + 0x01fe0fdf, 0x0ff9002a, 0x01fa0fdb, 0x0ff70034, + 0x01f40fd8, 0x0ff30041, 0x01ed0fd6, 0x0ff0004d, + 0x01e30fd5, 0x0fec005c, 0x01d80fd4, 0x0fea006a, + 0x01cd0fd3, 0x0fe5007b, 0x01c00fd3, 0x0fe1008c, + 0x01b10fd3, 0x0fdd009f, 0x01a10fd4, 0x0fd900b2, + 0x01900fd4, 0x0fd400c8, 0x017b0fd7, 0x0fd100dd, + 0x01660fd9, 0x0fcd00f4, 0x01500fda, 0x0fca010c, + 0x01380fde, 0x0fc60124, 0x011e0fe2, 0x0fc5013b, + 0x01040fe4, 0x0fc30155, 0x00e70fe8, 0x0fc10170, + 0x00cc0feb, 0x0fc10188, 0x00ad0ff0, 0x0fc301a0, + 0x00900ff4, 0x0fc701b5, 0x00750ff7, 0x0fcc01c8, + 0x00580ffb, 0x0fd201db, 0x003e0ffd, 0x0fdb01ea, + 0x00250000, 0x0fe501f6, 0x000f0000, 0x0ff301fe, + 0x02000000, 0x00000000, 0x02020ff9, 0x00000005, + 0x02020ff2, 0x0000000c, 0x02010fed, 0x0ffe0014, + 0x01fe0fe8, 0x0ffd001d, 0x01fa0fe3, 0x0ffb0028, + 0x01f40fe0, 0x0ff90033, 0x01ed0fdc, 0x0ff70040, + 0x01e50fd9, 0x0ff3004f, 0x01db0fd7, 0x0ff1005d, + 0x01ce0fd7, 0x0fed006e, 0x01c00fd6, 0x0feb007f, + 0x01b30fd5, 0x0fe70091, 0x01a30fd6, 0x0fe300a4, + 0x01920fd6, 0x0fe000b8, 0x017e0fd8, 0x0fdd00cd, + 0x016c0fd8, 0x0fd800e4, 0x01560fdb, 0x0fd600f9, + 0x01400fdd, 0x0fd20111, 0x01290fdf, 0x0fd00128, + 0x01110fe2, 0x0fce013f, 0x00f80fe6, 0x0fcd0155, + 0x00de0fe8, 0x0fcc016e, 0x00c40fec, 0x0fcb0185, + 0x00ab0fef, 0x0fcb019b, 0x00900ff3, 0x0fcd01b0, + 0x00770ff6, 0x0fd101c2, 0x005f0ff9, 0x0fd501d3, + 0x00470ffc, 0x0fdb01e2, 0x00320ffd, 0x0fe201ef, + 0x001e0000, 0x0fea01f8, 0x000c0000, 0x0ff501ff, + 0x02000000, 0x00000000, 0x02010ff9, 0x00000006, + 0x02000ff2, 0x0000000e, 0x01fd0fed, 0x0ffe0018, + 0x01f80fe8, 0x0ffd0023, 0x01f20fe4, 0x0ffb002f, + 0x01eb0fe0, 0x0ff9003c, 0x01e10fdd, 0x0ff7004b, + 0x01d60fda, 0x0ff4005c, 0x01c90fd9, 0x0ff2006c, + 0x01bc0fd8, 0x0fee007e, 0x01ab0fd8, 0x0fec0091, + 0x019b0fd8, 0x0fe800a5, 0x018b0fd8, 0x0fe400b9, + 0x01770fd9, 0x0fe200ce, 0x01620fdb, 0x0fdf00e4, + 0x014f0fdb, 0x0fdb00fb, 0x01380fde, 0x0fda0110, + 0x01210fe0, 0x0fd70128, 0x010a0fe2, 0x0fd5013f, + 0x00f30fe6, 0x0fd30154, 0x00da0fe9, 0x0fd3016a, + 0x00c30feb, 0x0fd20180, 0x00aa0fef, 0x0fd20195, + 0x00940ff1, 0x0fd301a8, 0x007b0ff5, 0x0fd501bb, + 0x00650ff7, 0x0fd801cc, 0x00510ffa, 0x0fdc01d9, + 0x003c0ffd, 0x0fe101e6, 0x002a0ffe, 0x0fe701f1, + 0x00190000, 0x0fee01f9, 0x000a0000, 0x0ff701ff, + 0x02000000, 0x00000000, 0x01ff0ff9, 0x00000008, + 0x01fb0ff2, 0x00000013, 0x01f50fed, 0x0ffe0020, + 0x01ed0fe8, 0x0ffd002e, 0x01e30fe4, 0x0ffb003e, + 0x01d80fe1, 0x0ff9004e, 0x01cb0fde, 0x0ff70060, + 0x01bc0fdc, 0x0ff40074, 0x01ac0fdb, 0x0ff20087, + 0x019a0fdb, 0x0fef009c, 0x01870fdb, 0x0fed00b1, + 0x01740fdb, 0x0fea00c7, 0x01600fdc, 0x0fe700dd, + 0x014b0fdd, 0x0fe500f3, 0x01350fdf, 0x0fe30109, + 0x01200fe0, 0x0fe00120, 0x01090fe3, 0x0fdf0135, + 0x00f30fe5, 0x0fdd014b, 0x00dd0fe7, 0x0fdc0160, + 0x00c70fea, 0x0fdb0174, 0x00b10fed, 0x0fdb0187, + 0x009c0fef, 0x0fdb019a, 0x00870ff2, 0x0fdb01ac, + 0x00740ff4, 0x0fdc01bc, 0x00600ff7, 0x0fde01cb, + 0x004e0ff9, 0x0fe101d8, 0x003e0ffb, 0x0fe401e3, + 0x002e0ffd, 0x0fe801ed, 0x00200ffe, 0x0fed01f5, + 0x00130000, 0x0ff201fb, 0x00080000, 0x0ff901ff, + 0x02000000, 0x00000000, 0x02060ff2, 0x00000008, + 0x02090fe4, 0x00000013, 0x020a0fd9, 0x0ffc0021, + 0x02080fce, 0x0ffa0030, 0x02030fc5, 0x0ff60042, + 0x01fd0fbe, 0x0ff10054, 0x01f50fb6, 0x0fed0068, + 0x01e90fb1, 0x0fe60080, 0x01dc0fae, 0x0fe10095, + 0x01ca0fae, 0x0fda00ae, 0x01b70fad, 0x0fd600c6, + 0x01a40fad, 0x0fcf00e0, 0x018f0faf, 0x0fc800fa, + 0x01780fb1, 0x0fc30114, 0x015f0fb5, 0x0fbf012d, + 0x01490fb7, 0x0fb70149, 0x012d0fbf, 0x0fb5015f, + 0x01140fc3, 0x0fb10178, 0x00fa0fc8, 0x0faf018f, + 0x00e00fcf, 0x0fad01a4, 0x00c60fd6, 0x0fad01b7, + 0x00ae0fda, 0x0fae01ca, 0x00950fe1, 0x0fae01dc, + 0x00800fe6, 0x0fb101e9, 0x00680fed, 0x0fb601f5, + 0x00540ff1, 0x0fbe01fd, 0x00420ff6, 0x0fc50203, + 0x00300ffa, 0x0fce0208, 0x00210ffc, 0x0fd9020a, + 0x00130000, 0x0fe40209, 0x00080000, 0x0ff20206, + 0x02000000, 0x00000000, 0x02040ff2, 0x0000000a, + 0x02040fe4, 0x00000018, 0x02010fda, 0x0ffc0029, + 0x01fc0fcf, 0x0ffa003b, 0x01f30fc7, 0x0ff60050, + 0x01e90fc0, 0x0ff20065, 0x01dc0fba, 0x0fee007c, + 0x01cc0fb6, 0x0fe80096, 0x01ba0fb4, 0x0fe400ae, + 0x01a70fb4, 0x0fdd00c8, 0x018f0fb5, 0x0fda00e2, + 0x017a0fb5, 0x0fd400fd, 0x01630fb8, 0x0fce0117, + 0x014c0fba, 0x0fca0130, 0x01320fbf, 0x0fc70148, + 0x011b0fc1, 0x0fc10163, 0x01010fc8, 0x0fc00177, + 0x00e90fcd, 0x0fbd018d, 0x00d10fd1, 0x0fbc01a2, + 0x00ba0fd7, 0x0fbb01b4, 0x00a30fdd, 0x0fbc01c4, + 0x008e0fe1, 0x0fbd01d4, 0x00790fe7, 0x0fbe01e2, + 0x00670feb, 0x0fc001ee, 0x00540ff1, 0x0fc501f6, + 0x00430ff4, 0x0fcb01fe, 0x00340ff8, 0x0fd10203, + 0x00260ffb, 0x0fd80207, 0x001a0ffd, 0x0fe10208, + 0x000f0000, 0x0fea0207, 0x00060000, 0x0ff50205, + 0x02000000, 0x00000000, 0x02020ff2, 0x0000000c, + 0x02000fe4, 0x0000001c, 0x01fa0fda, 0x0ffc0030, + 0x01f10fd0, 0x0ffa0045, 0x01e50fc8, 0x0ff6005d, + 0x01d60fc3, 0x0ff30074, 0x01c60fbd, 0x0fef008e, + 0x01b30fba, 0x0fe900aa, 0x019e0fb9, 0x0fe500c4, + 0x01870fba, 0x0fe000df, 0x016f0fbb, 0x0fdd00f9, + 0x01580fbc, 0x0fd80114, 0x01400fbf, 0x0fd3012e, + 0x01280fc2, 0x0fd00146, 0x010f0fc6, 0x0fce015d, + 0x00f90fc9, 0x0fc90175, 0x00e00fcf, 0x0fc90188, + 0x00ca0fd4, 0x0fc6019c, 0x00b40fd8, 0x0fc601ae, + 0x009f0fdd, 0x0fc501bf, 0x008b0fe3, 0x0fc601cc, + 0x00780fe6, 0x0fc701db, 0x00660feb, 0x0fc801e7, + 0x00560fef, 0x0fcb01f0, 0x00460ff3, 0x0fcf01f8, + 0x00380ff6, 0x0fd401fe, 0x002c0ff9, 0x0fd90202, + 0x00200ffc, 0x0fdf0205, 0x00160ffe, 0x0fe60206, + 0x000c0000, 0x0fed0207, 0x00050000, 0x0ff70204, + 0x02000000, 0x00000000, 0x01fe0ff3, 0x0000000f, + 0x01f60fe5, 0x00000025, 0x01ea0fdb, 0x0ffd003e, + 0x01db0fd2, 0x0ffb0058, 0x01c80fcc, 0x0ff70075, + 0x01b50fc7, 0x0ff40090, 0x01a00fc3, 0x0ff000ad, + 0x01880fc1, 0x0feb00cc, 0x01700fc1, 0x0fe800e7, + 0x01550fc3, 0x0fe40104, 0x013b0fc5, 0x0fe2011e, + 0x01240fc6, 0x0fde0138, 0x010c0fca, 0x0fda0150, + 0x00f40fcd, 0x0fd90166, 0x00dd0fd1, 0x0fd7017b, + 0x00c80fd4, 0x0fd40190, 0x00b20fd9, 0x0fd401a1, + 0x009f0fdd, 0x0fd301b1, 0x008c0fe1, 0x0fd301c0, + 0x007b0fe5, 0x0fd301cd, 0x006a0fea, 0x0fd401d8, + 0x005c0fec, 0x0fd501e3, 0x004d0ff0, 0x0fd601ed, + 0x00410ff3, 0x0fd801f4, 0x00340ff7, 0x0fdb01fa, + 0x002a0ff9, 0x0fdf01fe, 0x00200ffb, 0x0fe30202, + 0x00180ffd, 0x0fe70204, 0x00100ffe, 0x0fed0205, + 0x00090000, 0x0ff20205, 0x00040000, 0x0ff90203, + 0x02000000, 0x00000000, 0x02050ff5, 0x00000006, + 0x02070fea, 0x0000000f, 0x02080fe1, 0x0ffd001a, + 0x02070fd8, 0x0ffb0026, 0x02030fd1, 0x0ff80034, + 0x01fe0fcb, 0x0ff40043, 0x01f60fc5, 0x0ff10054, + 0x01ee0fc0, 0x0feb0067, 0x01e20fbe, 0x0fe70079, + 0x01d40fbd, 0x0fe1008e, 0x01c40fbc, 0x0fdd00a3, + 0x01b40fbb, 0x0fd700ba, 0x01a20fbc, 0x0fd100d1, + 0x018d0fbd, 0x0fcd00e9, 0x01770fc0, 0x0fc80101, + 0x01630fc1, 0x0fc1011b, 0x01480fc7, 0x0fbf0132, + 0x01300fca, 0x0fba014c, 0x01170fce, 0x0fb80163, + 0x00fd0fd4, 0x0fb5017a, 0x00e20fda, 0x0fb5018f, + 0x00c80fdd, 0x0fb401a7, 0x00ae0fe4, 0x0fb401ba, + 0x00960fe8, 0x0fb601cc, 0x007c0fee, 0x0fba01dc, + 0x00650ff2, 0x0fc001e9, 0x00500ff6, 0x0fc701f3, + 0x003b0ffa, 0x0fcf01fc, 0x00290ffc, 0x0fda0201, + 0x00180000, 0x0fe40204, 0x000a0000, 0x0ff20204, + 0x02000000, 0x00000000, 0x02030ff5, 0x00000008, + 0x02030fea, 0x00000013, 0x02020fe1, 0x0ffd0020, + 0x01fc0fd9, 0x0ffc002f, 0x01f60fd2, 0x0ff80040, + 0x01ed0fcd, 0x0ff50051, 0x01e30fc7, 0x0ff10065, + 0x01d70fc3, 0x0fec007a, 0x01c60fc2, 0x0fe9008f, + 0x01b60fc1, 0x0fe300a6, 0x01a20fc1, 0x0fe000bd, + 0x018f0fc1, 0x0fdb00d5, 0x017b0fc2, 0x0fd500ee, + 0x01640fc4, 0x0fd20106, 0x014d0fc8, 0x0fce011d, + 0x01370fc9, 0x0fc90137, 0x011d0fce, 0x0fc8014d, + 0x01060fd2, 0x0fc40164, 0x00ee0fd5, 0x0fc2017b, + 0x00d50fdb, 0x0fc1018f, 0x00bd0fe0, 0x0fc101a2, + 0x00a60fe3, 0x0fc101b6, 0x008f0fe9, 0x0fc201c6, + 0x007a0fec, 0x0fc301d7, 0x00650ff1, 0x0fc701e3, + 0x00510ff5, 0x0fcd01ed, 0x00400ff8, 0x0fd201f6, + 0x002f0ffc, 0x0fd901fc, 0x00200ffd, 0x0fe10202, + 0x00130000, 0x0fea0203, 0x00080000, 0x0ff50203, + 0x02000000, 0x00000000, 0x02020ff5, 0x00000009, + 0x01ff0fea, 0x00000017, 0x01fb0fe2, 0x0ffd0026, + 0x01f30fda, 0x0ffc0037, 0x01ea0fd3, 0x0ff8004b, + 0x01df0fce, 0x0ff5005e, 0x01d10fc9, 0x0ff20074, + 0x01c10fc6, 0x0fed008c, 0x01ae0fc5, 0x0fea00a3, + 0x019b0fc5, 0x0fe500bb, 0x01850fc6, 0x0fe200d3, + 0x01700fc6, 0x0fde00ec, 0x015a0fc8, 0x0fd90105, + 0x01430fca, 0x0fd6011d, 0x012b0fcd, 0x0fd30135, + 0x01150fcf, 0x0fcf014d, 0x00fc0fd4, 0x0fce0162, + 0x00e50fd8, 0x0fcc0177, 0x00cf0fdb, 0x0fca018c, + 0x00b80fe0, 0x0fc9019f, 0x00a20fe5, 0x0fca01af, + 0x008e0fe8, 0x0fcb01bf, 0x00790fec, 0x0fcb01d0, + 0x00670fef, 0x0fcd01dd, 0x00550ff4, 0x0fd001e7, + 0x00440ff7, 0x0fd501f0, 0x00350ffa, 0x0fda01f7, + 0x00270ffc, 0x0fdf01fe, 0x001b0ffe, 0x0fe70200, + 0x00100000, 0x0fee0202, 0x00060000, 0x0ff70203, + 0x02000000, 0x00000000, 0x01ff0ff5, 0x0000000c, + 0x01f80fea, 0x0000001e, 0x01ef0fe2, 0x0ffd0032, + 0x01e20fdb, 0x0ffc0047, 0x01d30fd5, 0x0ff9005f, + 0x01c20fd1, 0x0ff60077, 0x01b00fcd, 0x0ff30090, + 0x019b0fcb, 0x0fef00ab, 0x01850fcb, 0x0fec00c4, + 0x016e0fcc, 0x0fe800de, 0x01550fcd, 0x0fe600f8, + 0x013f0fce, 0x0fe20111, 0x01280fd0, 0x0fdf0129, + 0x01110fd2, 0x0fdd0140, 0x00f90fd6, 0x0fdb0156, + 0x00e40fd8, 0x0fd8016c, 0x00cd0fdd, 0x0fd8017e, + 0x00b80fe0, 0x0fd60192, 0x00a40fe3, 0x0fd601a3, + 0x00910fe7, 0x0fd501b3, 0x007f0feb, 0x0fd601c0, + 0x006e0fed, 0x0fd701ce, 0x005d0ff1, 0x0fd701db, + 0x004f0ff3, 0x0fd901e5, 0x00400ff7, 0x0fdc01ed, + 0x00330ff9, 0x0fe001f4, 0x00280ffb, 0x0fe301fa, + 0x001d0ffd, 0x0fe801fe, 0x00140ffe, 0x0fed0201, + 0x000c0000, 0x0ff20202, 0x00050000, 0x0ff90202, + 0x02000000, 0x00000000, 0x02040ff7, 0x00000005, + 0x02070fed, 0x0000000c, 0x02060fe6, 0x0ffe0016, + 0x02050fdf, 0x0ffc0020, 0x02020fd9, 0x0ff9002c, + 0x01fe0fd4, 0x0ff60038, 0x01f80fcf, 0x0ff30046, + 0x01f00fcb, 0x0fef0056, 0x01e70fc8, 0x0feb0066, + 0x01db0fc7, 0x0fe60078, 0x01cc0fc6, 0x0fe3008b, + 0x01bf0fc5, 0x0fdd009f, 0x01ae0fc6, 0x0fd800b4, + 0x019c0fc6, 0x0fd400ca, 0x01880fc9, 0x0fcf00e0, + 0x01750fc9, 0x0fc900f9, 0x015d0fce, 0x0fc6010f, + 0x01460fd0, 0x0fc20128, 0x012e0fd3, 0x0fbf0140, + 0x01140fd8, 0x0fbc0158, 0x00f90fdd, 0x0fbb016f, + 0x00df0fe0, 0x0fba0187, 0x00c40fe5, 0x0fb9019e, + 0x00aa0fe9, 0x0fba01b3, 0x008e0fef, 0x0fbd01c6, + 0x00740ff3, 0x0fc301d6, 0x005d0ff6, 0x0fc801e5, + 0x00450ffa, 0x0fd001f1, 0x00300ffc, 0x0fda01fa, + 0x001c0000, 0x0fe40200, 0x000c0000, 0x0ff20202, + 0x02000000, 0x00000000, 0x02030ff7, 0x00000006, + 0x02020fee, 0x00000010, 0x02000fe7, 0x0ffe001b, + 0x01fe0fdf, 0x0ffc0027, 0x01f70fda, 0x0ffa0035, + 0x01f00fd5, 0x0ff70044, 0x01e70fd0, 0x0ff40055, + 0x01dd0fcd, 0x0fef0067, 0x01d00fcb, 0x0fec0079, + 0x01bf0fcb, 0x0fe8008e, 0x01af0fca, 0x0fe500a2, + 0x019f0fc9, 0x0fe000b8, 0x018c0fca, 0x0fdb00cf, + 0x01770fcc, 0x0fd800e5, 0x01620fce, 0x0fd400fc, + 0x014d0fcf, 0x0fcf0115, 0x01350fd3, 0x0fcd012b, + 0x011d0fd6, 0x0fca0143, 0x01050fd9, 0x0fc8015a, + 0x00ec0fde, 0x0fc60170, 0x00d30fe2, 0x0fc60185, + 0x00bb0fe5, 0x0fc5019b, 0x00a30fea, 0x0fc501ae, + 0x008c0fed, 0x0fc601c1, 0x00740ff2, 0x0fc901d1, + 0x005e0ff5, 0x0fce01df, 0x004b0ff8, 0x0fd301ea, + 0x00370ffc, 0x0fda01f3, 0x00260ffd, 0x0fe201fb, + 0x00170000, 0x0fea01ff, 0x00090000, 0x0ff50202, + 0x02000000, 0x00000000, 0x02010ff7, 0x00000008, + 0x01ff0fee, 0x00000013, 0x01fb0fe7, 0x0ffe0020, + 0x01f60fe0, 0x0ffc002e, 0x01ed0fda, 0x0ffa003f, + 0x01e40fd6, 0x0ff7004f, 0x01d80fd2, 0x0ff40062, + 0x01ca0fcf, 0x0ff00077, 0x01bb0fcd, 0x0fed008b, + 0x01a90fcd, 0x0fe900a1, 0x01960fcd, 0x0fe600b7, + 0x01830fcd, 0x0fe200ce, 0x016d0fcf, 0x0fde00e6, + 0x01580fd0, 0x0fdb00fd, 0x01410fd3, 0x0fd80114, + 0x012c0fd4, 0x0fd4012c, 0x01140fd8, 0x0fd30141, + 0x00fd0fdb, 0x0fd00158, 0x00e60fde, 0x0fcf016d, + 0x00ce0fe2, 0x0fcd0183, 0x00b70fe6, 0x0fcd0196, + 0x00a10fe9, 0x0fcd01a9, 0x008b0fed, 0x0fcd01bb, + 0x00770ff0, 0x0fcf01ca, 0x00620ff4, 0x0fd201d8, + 0x004f0ff7, 0x0fd601e4, 0x003f0ffa, 0x0fda01ed, + 0x002e0ffc, 0x0fe001f6, 0x00200ffe, 0x0fe701fb, + 0x00130000, 0x0fee01ff, 0x00080000, 0x0ff70201, + 0x02000000, 0x00000000, 0x01ff0ff7, 0x0000000a, + 0x01f90fee, 0x00000019, 0x01f10fe7, 0x0ffe002a, + 0x01e60fe1, 0x0ffd003c, 0x01d90fdc, 0x0ffa0051, + 0x01cc0fd8, 0x0ff70065, 0x01bb0fd5, 0x0ff5007b, + 0x01a80fd3, 0x0ff10094, 0x01950fd2, 0x0fef00aa, + 0x01800fd2, 0x0feb00c3, 0x016a0fd3, 0x0fe900da, + 0x01540fd3, 0x0fe600f3, 0x013f0fd5, 0x0fe2010a, + 0x01280fd7, 0x0fe00121, 0x01100fda, 0x0fde0138, + 0x00fb0fdb, 0x0fdb014f, 0x00e40fdf, 0x0fdb0162, + 0x00ce0fe2, 0x0fd90177, 0x00b90fe4, 0x0fd8018b, + 0x00a50fe8, 0x0fd8019b, 0x00910fec, 0x0fd801ab, + 0x007e0fee, 0x0fd801bc, 0x006c0ff2, 0x0fd901c9, + 0x005c0ff4, 0x0fda01d6, 0x004b0ff7, 0x0fdd01e1, + 0x003c0ff9, 0x0fe001eb, 0x002f0ffb, 0x0fe401f2, + 0x00230ffd, 0x0fe801f8, 0x00180ffe, 0x0fed01fd, + 0x000e0000, 0x0ff20200, 0x00060000, 0x0ff90201, + 0x02000000, 0x00000000, 0x02030ff9, 0x00000004, + 0x02050ff2, 0x00000009, 0x02050fed, 0x0ffe0010, + 0x02040fe7, 0x0ffd0018, 0x02020fe3, 0x0ffb0020, + 0x01fe0fdf, 0x0ff9002a, 0x01fa0fdb, 0x0ff70034, + 0x01f40fd8, 0x0ff30041, 0x01ed0fd6, 0x0ff0004d, + 0x01e30fd5, 0x0fec005c, 0x01d80fd4, 0x0fea006a, + 0x01cd0fd3, 0x0fe5007b, 0x01c00fd3, 0x0fe1008c, + 0x01b10fd3, 0x0fdd009f, 0x01a10fd4, 0x0fd900b2, + 0x01900fd4, 0x0fd400c8, 0x017b0fd7, 0x0fd100dd, + 0x01660fd9, 0x0fcd00f4, 0x01500fda, 0x0fca010c, + 0x01380fde, 0x0fc60124, 0x011e0fe2, 0x0fc5013b, + 0x01040fe4, 0x0fc30155, 0x00e70fe8, 0x0fc10170, + 0x00cc0feb, 0x0fc10188, 0x00ad0ff0, 0x0fc301a0, + 0x00900ff4, 0x0fc701b5, 0x00750ff7, 0x0fcc01c8, + 0x00580ffb, 0x0fd201db, 0x003e0ffd, 0x0fdb01ea, + 0x00250000, 0x0fe501f6, 0x000f0000, 0x0ff301fe, + 0x02000000, 0x00000000, 0x02020ff9, 0x00000005, + 0x02020ff2, 0x0000000c, 0x02010fed, 0x0ffe0014, + 0x01fe0fe8, 0x0ffd001d, 0x01fa0fe3, 0x0ffb0028, + 0x01f40fe0, 0x0ff90033, 0x01ed0fdc, 0x0ff70040, + 0x01e50fd9, 0x0ff3004f, 0x01db0fd7, 0x0ff1005d, + 0x01ce0fd7, 0x0fed006e, 0x01c00fd6, 0x0feb007f, + 0x01b30fd5, 0x0fe70091, 0x01a30fd6, 0x0fe300a4, + 0x01920fd6, 0x0fe000b8, 0x017e0fd8, 0x0fdd00cd, + 0x016c0fd8, 0x0fd800e4, 0x01560fdb, 0x0fd600f9, + 0x01400fdd, 0x0fd20111, 0x01290fdf, 0x0fd00128, + 0x01110fe2, 0x0fce013f, 0x00f80fe6, 0x0fcd0155, + 0x00de0fe8, 0x0fcc016e, 0x00c40fec, 0x0fcb0185, + 0x00ab0fef, 0x0fcb019b, 0x00900ff3, 0x0fcd01b0, + 0x00770ff6, 0x0fd101c2, 0x005f0ff9, 0x0fd501d3, + 0x00470ffc, 0x0fdb01e2, 0x00320ffd, 0x0fe201ef, + 0x001e0000, 0x0fea01f8, 0x000c0000, 0x0ff501ff, + 0x02000000, 0x00000000, 0x02010ff9, 0x00000006, + 0x02000ff2, 0x0000000e, 0x01fd0fed, 0x0ffe0018, + 0x01f80fe8, 0x0ffd0023, 0x01f20fe4, 0x0ffb002f, + 0x01eb0fe0, 0x0ff9003c, 0x01e10fdd, 0x0ff7004b, + 0x01d60fda, 0x0ff4005c, 0x01c90fd9, 0x0ff2006c, + 0x01bc0fd8, 0x0fee007e, 0x01ab0fd8, 0x0fec0091, + 0x019b0fd8, 0x0fe800a5, 0x018b0fd8, 0x0fe400b9, + 0x01770fd9, 0x0fe200ce, 0x01620fdb, 0x0fdf00e4, + 0x014f0fdb, 0x0fdb00fb, 0x01380fde, 0x0fda0110, + 0x01210fe0, 0x0fd70128, 0x010a0fe2, 0x0fd5013f, + 0x00f30fe6, 0x0fd30154, 0x00da0fe9, 0x0fd3016a, + 0x00c30feb, 0x0fd20180, 0x00aa0fef, 0x0fd20195, + 0x00940ff1, 0x0fd301a8, 0x007b0ff5, 0x0fd501bb, + 0x00650ff7, 0x0fd801cc, 0x00510ffa, 0x0fdc01d9, + 0x003c0ffd, 0x0fe101e6, 0x002a0ffe, 0x0fe701f1, + 0x00190000, 0x0fee01f9, 0x000a0000, 0x0ff701ff, + 0x02000000, 0x00000000, 0x01ff0ff9, 0x00000008, + 0x01fb0ff2, 0x00000013, 0x01f50fed, 0x0ffe0020, + 0x01ed0fe8, 0x0ffd002e, 0x01e30fe4, 0x0ffb003e, + 0x01d80fe1, 0x0ff9004e, 0x01cb0fde, 0x0ff70060, + 0x01bc0fdc, 0x0ff40074, 0x01ac0fdb, 0x0ff20087, + 0x019a0fdb, 0x0fef009c, 0x01870fdb, 0x0fed00b1, + 0x01740fdb, 0x0fea00c7, 0x01600fdc, 0x0fe700dd, + 0x014b0fdd, 0x0fe500f3, 0x01350fdf, 0x0fe30109, + 0x01200fe0, 0x0fe00120, 0x01090fe3, 0x0fdf0135, + 0x00f30fe5, 0x0fdd014b, 0x00dd0fe7, 0x0fdc0160, + 0x00c70fea, 0x0fdb0174, 0x00b10fed, 0x0fdb0187, + 0x009c0fef, 0x0fdb019a, 0x00870ff2, 0x0fdb01ac, + 0x00740ff4, 0x0fdc01bc, 0x00600ff7, 0x0fde01cb, + 0x004e0ff9, 0x0fe101d8, 0x003e0ffb, 0x0fe401e3, + 0x002e0ffd, 0x0fe801ed, 0x00200ffe, 0x0fed01f5, + 0x00130000, 0x0ff201fb, 0x00080000, 0x0ff901ff +}; + + +#define MDP4_QSEED_TABLE0_OFF 0x8100 +#define MDP4_QSEED_TABLE1_OFF 0x8200 +#define MDP4_QSEED_TABLE2_OFF 0x9000 + +void mdp4_vg_qseed_init(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE0_OFF); + for (i = 0; i < (sizeof(vg_qseed_table0) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table0[i]); + off++; + } + + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE1_OFF); + for (i = 0; i < (sizeof(vg_qseed_table1) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table1[i]); + off++; + } + + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE2_OFF); + for (i = 0; i < (sizeof(vg_qseed_table2) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table2[i]); + off++; + } + +} + +void mdp4_mixer_blend_init(mixer_num) +{ + unsigned char *overlay_base; + int off; + + if (mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */ + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + else + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + /* stage 0 to stage 2 */ + off = 0; + outpdw(overlay_base + off + 0x104, 0x010); + outpdw(overlay_base + off + 0x108, 0xff);/* FG */ + outpdw(overlay_base + off + 0x10c, 0x00);/* BG */ + + off += 0x20; + outpdw(overlay_base + off + 0x104, 0x010); + outpdw(overlay_base + off + 0x108, 0xff);/* FG */ + outpdw(overlay_base + off + 0x10c, 0x00);/* BG */ + + off += 0x20; + outpdw(overlay_base + off + 0x104, 0x010); + outpdw(overlay_base + off + 0x108, 0xff);/* FG */ + outpdw(overlay_base + off + 0x10c, 0x00);/* BG */ +} + + +static uint32 csc_matrix_tab[9] = { + 0x0254, 0x0000, 0x0331, + 0x0254, 0xff37, 0xfe60, + 0x0254, 0x0409, 0x0000 +}; + +static uint32 csc_pre_bv_tab[3] = {0xfff0, 0xff80, 0xff80 }; +static uint32 csc_post_bv_tab[3] = {0, 0, 0 }; + +static uint32 csc_pre_lv_tab[6] = {0, 0xff, 0, 0xff, 0, 0xff }; +static uint32 csc_post_lv_tab[6] = {0, 0xff, 0, 0xff, 0, 0xff }; + +#define MDP4_CSC_MV_OFF 0x4400 +#define MDP4_CSC_PRE_BV_OFF 0x4500 +#define MDP4_CSC_POST_BV_OFF 0x4580 +#define MDP4_CSC_PRE_LV_OFF 0x4600 +#define MDP4_CSC_POST_LV_OFF 0x4680 + +void mdp4_vg_csc_mv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_MV_OFF); + for (i = 0; i < 9; i++) { + outpdw(off, csc_matrix_tab[i]); + off++; + } +} + +void mdp4_vg_csc_pre_bv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_PRE_BV_OFF); + for (i = 0; i < 3; i++) { + outpdw(off, csc_pre_bv_tab[i]); + off++; + } +} + +void mdp4_vg_csc_post_bv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_POST_BV_OFF); + for (i = 0; i < 3; i++) { + outpdw(off, csc_post_bv_tab[i]); + off++; + } +} + +void mdp4_vg_csc_pre_lv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_PRE_LV_OFF); + + for (i = 0; i < 6; i++) { + outpdw(off, csc_pre_lv_tab[i]); + off++; + } +} + +void mdp4_vg_csc_post_lv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_POST_LV_OFF); + + for (i = 0; i < 6; i++) { + outpdw(off, csc_post_lv_tab[i]); + off++; + } +} + +char gc_lut[] = { + 0x0, 0x1, 0x2, 0x2, 0x3, 0x4, 0x5, 0x6, + 0x6, 0x7, 0x8, 0x9, 0xA, 0xA, 0xB, 0xC, + 0xD, 0xD, 0xE, 0xF, 0xF, 0x10, 0x10, 0x11, + 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, + 0x16, 0x16, 0x17, 0x17, 0x17, 0x18, 0x18, 0x19, + 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1C, 0x1D, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, + 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, + 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24, + 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, + 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, + 0x28, 0x29, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, + 0x2C, 0x2C, 0x2D, 0x2D, 0x2D, 0x2D, 0x2E, 0x2E, + 0x2E, 0x2E, 0x2E, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, + 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, + 0x3D, 0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, + 0x3E, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, + 0x49, 0x49, 0x49, 0x49, 0x49, 0x4A, 0x4A, 0x4A, + 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4B, 0x4B, 0x4B, + 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4C, 0x4C, 0x4C, + 0x4C, 0x4C, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4D, + 0x4D, 0x4D, 0x4D, 0x4D, 0x4E, 0x4E, 0x4E, 0x4E, + 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, + 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, + 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, + 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, + 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, + 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, + 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5A, 0x5A, + 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, + 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, + 0x5B, 0x5B, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5E, 0x5E, + 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, + 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, + 0x5F, 0x5F, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x62, + 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, + 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, + 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, + 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, + 0x68, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, + 0x69, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, + 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6B, 0x6B, 0x6B, + 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, + 0x6B, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, + 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6D, 0x6D, 0x6D, + 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, + 0x6D, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, + 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6F, 0x6F, 0x6F, + 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, + 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, 0x72, + 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, + 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, + 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, + 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, + 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, + 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, + 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, + 0x76, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, + 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x7A, 0x7A, + 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, + 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, + 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, + 0x7B, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, + 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, + 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, + 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, + 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, + 0x8A, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, + 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, + 0x8B, 0x8B, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, + 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, + 0x8C, 0x8C, 0x8C, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, + 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, + 0x8D, 0x8D, 0x8D, 0x8D, 0x8E, 0x8E, 0x8E, 0x8E, + 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, + 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8F, 0x8F, 0x8F, + 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, + 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9B, 0x9B, 0x9B, + 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, + 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, + 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, + 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, + 0x9C, 0x9C, 0x9C, 0x9C, 0x9D, 0x9D, 0x9D, 0x9D, + 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, + 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9E, + 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, + 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, + 0x9E, 0x9E, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, + 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, + 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, + 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, + 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA2, 0xA2, + 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, + 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, + 0xA2, 0xA2, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, + 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, + 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA4, 0xA4, + 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, + 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, + 0xA4, 0xA4, 0xA4, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, + 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, + 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, + 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, + 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, + 0xA6, 0xA6, 0xA6, 0xA6, 0xA7, 0xA7, 0xA7, 0xA7, + 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, + 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, + 0xA7, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, + 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, + 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA9, + 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, + 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, + 0xA9, 0xA9, 0xA9, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, + 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, + 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAC, + 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, + 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, + 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAD, 0xAD, 0xAD, + 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, + 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, + 0xAD, 0xAD, 0xAD, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, + 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, + 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, + 0xAE, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, + 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, + 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xB0, + 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, + 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, + 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB1, + 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, + 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, + 0xB1, 0xB1, 0xB1, 0xB1, 0xB2, 0xB2, 0xB2, 0xB2, + 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, + 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, + 0xB2, 0xB2, 0xB2, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, + 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, + 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, + 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, + 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, + 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, + 0xB4, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, + 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, + 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, + 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, + 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, + 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, + 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, + 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, + 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB8, + 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, + 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, + 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB9, + 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, + 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, + 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xBA, + 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, + 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, + 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBB, + 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, + 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, + 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, + 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, + 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, + 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, + 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, + 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, + 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, + 0xBD, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, + 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, + 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, + 0xBE, 0xBE, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, + 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, + 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, + 0xBF, 0xBF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC1, 0xC1, 0xC1, 0xC1, + 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, + 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, + 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC2, 0xC2, 0xC2, + 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, + 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, + 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, + 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, + 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, + 0xC4, 0xC4, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, + 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, + 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, + 0xC5, 0xC5, 0xC5, 0xC5, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7, 0xC7, + 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, + 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, + 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, + 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, + 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, + 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xCA, 0xCA, + 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, + 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, + 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, + 0xCA, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, + 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, + 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, + 0xCB, 0xCB, 0xCB, 0xCB, 0xCC, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCD, + 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, + 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, + 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, + 0xCD, 0xCD, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, + 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, + 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, + 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCF, 0xCF, + 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, + 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, + 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, + 0xCF, 0xCF, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD1, 0xD1, 0xD1, + 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, + 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, + 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, + 0xD1, 0xD1, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, + 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, + 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, + 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD3, 0xD3, + 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, + 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, + 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, + 0xD3, 0xD3, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, + 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, + 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, + 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD6, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, + 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, + 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, + 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, + 0xD9, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, + 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, + 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, + 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDC, 0xDC, 0xDC, 0xDC, + 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, + 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, + 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, + 0xDC, 0xDC, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, + 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, + 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, + 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE1, 0xE1, 0xE1, 0xE1, + 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, + 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, + 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, + 0xE1, 0xE1, 0xE1, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, + 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, + 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, + 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, + 0xE2, 0xE2, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, + 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, + 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, + 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, + 0xE3, 0xE3, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, + 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, + 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, + 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, + 0xE4, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, + 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, + 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, + 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, + 0xE5, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, + 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, + 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, + 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, + 0xE6, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xE7, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, + 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, + 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, + 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, + 0xE8, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, + 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, + 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, + 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, + 0xEB, 0xEB, 0xEB, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, 0xEC, 0xED, 0xED, 0xED, 0xED, + 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, + 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, + 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, + 0xED, 0xED, 0xED, 0xED, 0xED, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF3, 0xF3, + 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, + 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, + 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, + 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, + 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, + 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, + 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, + 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, + 0xF4, 0xF4, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6, 0xF6, + 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, + 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, + 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, + 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, + 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, + 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +void mdp4_mixer_gc_lut_setup(int mixer_num) +{ + unsigned char *base; + uint32 data; + char val; + int i, off; + + if (mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */ + base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + else + base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + base += 0x4000; /* GC_LUT offset */ + + off = 0; + for (i = 0; i < 4096; i++) { + val = gc_lut[i]; + data = (val << 16 | val << 8 | val); /* R, B, and G are same */ + outpdw(base + off, data); + off += 4; + } +} + +uint32 igc_video_lut[] = { /* non linear */ + 0x0, 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x9, + 0xA, 0xB, 0xC, 0xE, 0xF, 0x10, 0x12, 0x14, + 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F, 0x21, 0x23, + 0x25, 0x28, 0x2A, 0x2D, 0x30, 0x32, 0x35, 0x38, + 0x3B, 0x3E, 0x42, 0x45, 0x48, 0x4C, 0x4F, 0x53, + 0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x70, 0x74, + 0x79, 0x7E, 0x83, 0x88, 0x8D, 0x92, 0x97, 0x9C, + 0xA2, 0xA8, 0xAD, 0xB3, 0xB9, 0xBF, 0xC5, 0xCC, + 0xD2, 0xD8, 0xDF, 0xE6, 0xED, 0xF4, 0xFB, 0x102, + 0x109, 0x111, 0x118, 0x120, 0x128, 0x130, 0x138, 0x140, + 0x149, 0x151, 0x15A, 0x162, 0x16B, 0x174, 0x17D, 0x186, + 0x190, 0x199, 0x1A3, 0x1AC, 0x1B6, 0x1C0, 0x1CA, 0x1D5, + 0x1DF, 0x1EA, 0x1F4, 0x1FF, 0x20A, 0x215, 0x220, 0x22B, + 0x237, 0x242, 0x24E, 0x25A, 0x266, 0x272, 0x27F, 0x28B, + 0x298, 0x2A4, 0x2B1, 0x2BE, 0x2CB, 0x2D8, 0x2E6, 0x2F3, + 0x301, 0x30F, 0x31D, 0x32B, 0x339, 0x348, 0x356, 0x365, + 0x374, 0x383, 0x392, 0x3A1, 0x3B1, 0x3C0, 0x3D0, 0x3E0, + 0x3F0, 0x400, 0x411, 0x421, 0x432, 0x443, 0x454, 0x465, + 0x476, 0x487, 0x499, 0x4AB, 0x4BD, 0x4CF, 0x4E1, 0x4F3, + 0x506, 0x518, 0x52B, 0x53E, 0x551, 0x565, 0x578, 0x58C, + 0x5A0, 0x5B3, 0x5C8, 0x5DC, 0x5F0, 0x605, 0x61A, 0x62E, + 0x643, 0x659, 0x66E, 0x684, 0x699, 0x6AF, 0x6C5, 0x6DB, + 0x6F2, 0x708, 0x71F, 0x736, 0x74D, 0x764, 0x77C, 0x793, + 0x7AB, 0x7C3, 0x7DB, 0x7F3, 0x80B, 0x824, 0x83D, 0x855, + 0x86F, 0x888, 0x8A1, 0x8BB, 0x8D4, 0x8EE, 0x908, 0x923, + 0x93D, 0x958, 0x973, 0x98E, 0x9A9, 0x9C4, 0x9DF, 0x9FB, + 0xA17, 0xA33, 0xA4F, 0xA6C, 0xA88, 0xAA5, 0xAC2, 0xADF, + 0xAFC, 0xB19, 0xB37, 0xB55, 0xB73, 0xB91, 0xBAF, 0xBCE, + 0xBEC, 0xC0B, 0xC2A, 0xC4A, 0xC69, 0xC89, 0xCA8, 0xCC8, + 0xCE8, 0xD09, 0xD29, 0xD4A, 0xD6B, 0xD8C, 0xDAD, 0xDCF, + 0xDF0, 0xE12, 0xE34, 0xE56, 0xE79, 0xE9B, 0xEBE, 0xEE1, + 0xF04, 0xF27, 0xF4B, 0xF6E, 0xF92, 0xFB6, 0xFDB, 0xFFF, +}; + +void mdp4_vg_igc_lut_setup(int vp_num) +{ + unsigned char *base; + int i, voff, off; + uint32 data, val; + + voff = MDP4_VIDEO_OFF * vp_num; + base = MDP_BASE + MDP4_VIDEO_BASE + voff + 0x5000; + + off = 0; + for (i = 0; i < 256; i++) { + val = igc_video_lut[i]; + data = (val << 16 | val); /* color 0 and 1 */ + outpdw(base + off, data); + outpdw(base + off + 0x800, val); /* color 2 */ + off += 4; + } +} + +uint32 igc_rgb_lut[] = { /* linear */ + 0x0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + 0x80, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, + 0x101, 0x111, 0x121, 0x131, 0x141, 0x151, 0x161, 0x171, + 0x181, 0x191, 0x1A2, 0x1B2, 0x1C2, 0x1D2, 0x1E2, 0x1F2, + 0x202, 0x212, 0x222, 0x232, 0x242, 0x252, 0x262, 0x272, + 0x282, 0x292, 0x2A2, 0x2B3, 0x2C3, 0x2D3, 0x2E3, 0x2F3, + 0x303, 0x313, 0x323, 0x333, 0x343, 0x353, 0x363, 0x373, + 0x383, 0x393, 0x3A3, 0x3B3, 0x3C4, 0x3D4, 0x3E4, 0x3F4, + 0x404, 0x414, 0x424, 0x434, 0x444, 0x454, 0x464, 0x474, + 0x484, 0x494, 0x4A4, 0x4B4, 0x4C4, 0x4D5, 0x4E5, 0x4F5, + 0x505, 0x515, 0x525, 0x535, 0x545, 0x555, 0x565, 0x575, + 0x585, 0x595, 0x5A5, 0x5B5, 0x5C5, 0x5D5, 0x5E6, 0x5F6, + 0x606, 0x616, 0x626, 0x636, 0x646, 0x656, 0x666, 0x676, + 0x686, 0x696, 0x6A6, 0x6B6, 0x6C6, 0x6D6, 0x6E6, 0x6F7, + 0x707, 0x717, 0x727, 0x737, 0x747, 0x757, 0x767, 0x777, + 0x787, 0x797, 0x7A7, 0x7B7, 0x7C7, 0x7D7, 0x7E7, 0x7F7, + 0x808, 0x818, 0x828, 0x838, 0x848, 0x858, 0x868, 0x878, + 0x888, 0x898, 0x8A8, 0x8B8, 0x8C8, 0x8D8, 0x8E8, 0x8F8, + 0x908, 0x919, 0x929, 0x939, 0x949, 0x959, 0x969, 0x979, + 0x989, 0x999, 0x9A9, 0x9B9, 0x9C9, 0x9D9, 0x9E9, 0x9F9, + 0xA09, 0xA19, 0xA2A, 0xA3A, 0xA4A, 0xA5A, 0xA6A, 0xA7A, + 0xA8A, 0xA9A, 0xAAA, 0xABA, 0xACA, 0xADA, 0xAEA, 0xAFA, + 0xB0A, 0xB1A, 0xB2A, 0xB3B, 0xB4B, 0xB5B, 0xB6B, 0xB7B, + 0xB8B, 0xB9B, 0xBAB, 0xBBB, 0xBCB, 0xBDB, 0xBEB, 0xBFB, + 0xC0B, 0xC1B, 0xC2B, 0xC3B, 0xC4C, 0xC5C, 0xC6C, 0xC7C, + 0xC8C, 0xC9C, 0xCAC, 0xCBC, 0xCCC, 0xCDC, 0xCEC, 0xCFC, + 0xD0C, 0xD1C, 0xD2C, 0xD3C, 0xD4C, 0xD5D, 0xD6D, 0xD7D, + 0xD8D, 0xD9D, 0xDAD, 0xDBD, 0xDCD, 0xDDD, 0xDED, 0xDFD, + 0xE0D, 0xE1D, 0xE2D, 0xE3D, 0xE4D, 0xE5D, 0xE6E, 0xE7E, + 0xE8E, 0xE9E, 0xEAE, 0xEBE, 0xECE, 0xEDE, 0xEEE, 0xEFE, + 0xF0E, 0xF1E, 0xF2E, 0xF3E, 0xF4E, 0xF5E, 0xF6E, 0xF7F, + 0xF8F, 0xF9F, 0xFAF, 0xFBF, 0xFCF, 0xFDF, 0xFEF, 0xFFF, +}; + +void mdp4_rgb_igc_lut_setup(int num) +{ + unsigned char *base; + int i, voff, off; + uint32 data, val; + + voff = MDP4_RGB_OFF * num; + base = MDP_BASE + MDP4_RGB_BASE + voff + 0x5000; + + off = 0; + for (i = 0; i < 256; i++) { + val = igc_rgb_lut[i]; + data = (val << 16 | val); /* color 0 and 1 */ + outpdw(base + off, data); + outpdw(base + off + 0x800, val); /* color 2 */ + off += 4; + } +} diff --git a/drivers/staging/msm/mdp_cursor.c b/drivers/staging/msm/mdp_cursor.c new file mode 100644 index 00000000000..7d28f30d931 --- /dev/null +++ b/drivers/staging/msm/mdp_cursor.c @@ -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; +} diff --git a/drivers/staging/msm/mdp_dma.c b/drivers/staging/msm/mdp_dma.c new file mode 100644 index 00000000000..639918b143b --- /dev/null +++ b/drivers/staging/msm/mdp_dma.c @@ -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); + } +} diff --git a/drivers/staging/msm/mdp_dma_lcdc.c b/drivers/staging/msm/mdp_dma_lcdc.c new file mode 100644 index 00000000000..b57fa1a0ceb --- /dev/null +++ b/drivers/staging/msm/mdp_dma_lcdc.c @@ -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); +} diff --git a/drivers/staging/msm/mdp_dma_s.c b/drivers/staging/msm/mdp_dma_s.c new file mode 100644 index 00000000000..0c34a1010f1 --- /dev/null +++ b/drivers/staging/msm/mdp_dma_s.c @@ -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); +} diff --git a/drivers/staging/msm/mdp_dma_tv.c b/drivers/staging/msm/mdp_dma_tv.c new file mode 100644 index 00000000000..70989fb32c1 --- /dev/null +++ b/drivers/staging/msm/mdp_dma_tv.c @@ -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); +} diff --git a/drivers/staging/msm/mdp_hw_init.c b/drivers/staging/msm/mdp_hw_init.c new file mode 100644 index 00000000000..807362ac592 --- /dev/null +++ b/drivers/staging/msm/mdp_hw_init.c @@ -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); +}
\ No newline at end of file diff --git a/drivers/staging/msm/mdp_ppp.c b/drivers/staging/msm/mdp_ppp.c new file mode 100644 index 00000000000..c35a6aebca1 --- /dev/null +++ b/drivers/staging/msm/mdp_ppp.c @@ -0,0 +1,1502 @@ +/* drivers/video/msm/src/drv/mdp/mdp_ppp.c + * + * Copyright (C) 2007 Google Incorporated + * Copyright (c) 2008-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/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 <msm_mdp.h> +#include <linux/file.h> +#include <linux/major.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 "mdp.h" +#include "msm_fb.h" + +#define MDP_IS_IMGTYPE_BAD(x) (((x) >= MDP_IMGTYPE_LIMIT) && \ + (((x) < MDP_IMGTYPE2_START) || \ + ((x) >= MDP_IMGTYPE_LIMIT2))) + +static uint32_t bytes_per_pixel[] = { + [MDP_RGB_565] = 2, + [MDP_RGB_888] = 3, + [MDP_XRGB_8888] = 4, + [MDP_ARGB_8888] = 4, + [MDP_RGBA_8888] = 4, + [MDP_BGRA_8888] = 4, + [MDP_Y_CBCR_H2V1] = 1, + [MDP_Y_CBCR_H2V2] = 1, + [MDP_Y_CRCB_H2V1] = 1, + [MDP_Y_CRCB_H2V2] = 1, + [MDP_YCRYCB_H2V1] = 2, + [MDP_BGR_565] = 2 +}; + +extern uint32 mdp_plv[]; +extern struct semaphore mdp_ppp_mutex; + +uint32_t mdp_get_bytes_per_pixel(uint32_t format) +{ + uint32_t bpp = 0; + if (format < ARRAY_SIZE(bytes_per_pixel)) + bpp = bytes_per_pixel[format]; + + BUG_ON(!bpp); + return bpp; +} + +static uint32 mdp_conv_matx_rgb2yuv(uint32 input_pixel, + uint16 *matrix_and_bias_vector, + uint32 *clamp_vector, + uint32 *look_up_table) +{ + uint8 input_C2, input_C0, input_C1; + uint32 output; + int32 comp_C2, comp_C1, comp_C0, temp; + int32 temp1, temp2, temp3; + int32 matrix[9]; + int32 bias_vector[3]; + int32 Y_low_limit, Y_high_limit, C_low_limit, C_high_limit; + int32 i; + uint32 _is_lookup_table_enabled; + + input_C2 = (input_pixel >> 16) & 0xFF; + input_C1 = (input_pixel >> 8) & 0xFF; + input_C0 = (input_pixel >> 0) & 0xFF; + + comp_C0 = input_C0; + comp_C1 = input_C1; + comp_C2 = input_C2; + + for (i = 0; i < 9; i++) + matrix[i] = + ((int32) (((int32) matrix_and_bias_vector[i]) << 20)) >> 20; + + bias_vector[0] = (int32) (matrix_and_bias_vector[9] & 0xFF); + bias_vector[1] = (int32) (matrix_and_bias_vector[10] & 0xFF); + bias_vector[2] = (int32) (matrix_and_bias_vector[11] & 0xFF); + + Y_low_limit = (int32) clamp_vector[0]; + Y_high_limit = (int32) clamp_vector[1]; + C_low_limit = (int32) clamp_vector[2]; + C_high_limit = (int32) clamp_vector[3]; + + if (look_up_table == 0) /* check for NULL point */ + _is_lookup_table_enabled = 0; + else + _is_lookup_table_enabled = 1; + + if (_is_lookup_table_enabled == 1) { + comp_C2 = (look_up_table[comp_C2] >> 16) & 0xFF; + comp_C1 = (look_up_table[comp_C1] >> 8) & 0xFF; + comp_C0 = (look_up_table[comp_C0] >> 0) & 0xFF; + } + /* + * Color Conversion + * reorder input colors + */ + temp = comp_C2; + comp_C2 = comp_C1; + comp_C1 = comp_C0; + comp_C0 = temp; + + /* matrix multiplication */ + temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] + comp_C2 * matrix[2]; + temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] + comp_C2 * matrix[5]; + temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] + comp_C2 * matrix[8]; + + comp_C0 = temp1 + 0x100; + comp_C1 = temp2 + 0x100; + comp_C2 = temp3 + 0x100; + + /* take interger part */ + comp_C0 >>= 9; + comp_C1 >>= 9; + comp_C2 >>= 9; + + /* post bias (+) */ + comp_C0 += bias_vector[0]; + comp_C1 += bias_vector[1]; + comp_C2 += bias_vector[2]; + + /* limit pixel to 8-bit */ + if (comp_C0 < 0) + comp_C0 = 0; + + if (comp_C0 > 255) + comp_C0 = 255; + + if (comp_C1 < 0) + comp_C1 = 0; + + if (comp_C1 > 255) + comp_C1 = 255; + + if (comp_C2 < 0) + comp_C2 = 0; + + if (comp_C2 > 255) + comp_C2 = 255; + + /* clamp */ + if (comp_C0 < Y_low_limit) + comp_C0 = Y_low_limit; + + if (comp_C0 > Y_high_limit) + comp_C0 = Y_high_limit; + + if (comp_C1 < C_low_limit) + comp_C1 = C_low_limit; + + if (comp_C1 > C_high_limit) + comp_C1 = C_high_limit; + + if (comp_C2 < C_low_limit) + comp_C2 = C_low_limit; + + if (comp_C2 > C_high_limit) + comp_C2 = C_high_limit; + + output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0; + return output; +} + +uint32 mdp_conv_matx_yuv2rgb(uint32 input_pixel, + uint16 *matrix_and_bias_vector, + uint32 *clamp_vector, uint32 *look_up_table) +{ + uint8 input_C2, input_C0, input_C1; + uint32 output; + int32 comp_C2, comp_C1, comp_C0, temp; + int32 temp1, temp2, temp3; + int32 matrix[9]; + int32 bias_vector[3]; + int32 Y_low_limit, Y_high_limit, C_low_limit, C_high_limit; + int32 i; + uint32 _is_lookup_table_enabled; + + input_C2 = (input_pixel >> 16) & 0xFF; + input_C1 = (input_pixel >> 8) & 0xFF; + input_C0 = (input_pixel >> 0) & 0xFF; + + comp_C0 = input_C0; + comp_C1 = input_C1; + comp_C2 = input_C2; + + for (i = 0; i < 9; i++) + matrix[i] = + ((int32) (((int32) matrix_and_bias_vector[i]) << 20)) >> 20; + + bias_vector[0] = (int32) (matrix_and_bias_vector[9] & 0xFF); + bias_vector[1] = (int32) (matrix_and_bias_vector[10] & 0xFF); + bias_vector[2] = (int32) (matrix_and_bias_vector[11] & 0xFF); + + Y_low_limit = (int32) clamp_vector[0]; + Y_high_limit = (int32) clamp_vector[1]; + C_low_limit = (int32) clamp_vector[2]; + C_high_limit = (int32) clamp_vector[3]; + + if (look_up_table == 0) /* check for NULL point */ + _is_lookup_table_enabled = 0; + else + _is_lookup_table_enabled = 1; + + /* clamp */ + if (comp_C0 < Y_low_limit) + comp_C0 = Y_low_limit; + + if (comp_C0 > Y_high_limit) + comp_C0 = Y_high_limit; + + if (comp_C1 < C_low_limit) + comp_C1 = C_low_limit; + + if (comp_C1 > C_high_limit) + comp_C1 = C_high_limit; + + if (comp_C2 < C_low_limit) + comp_C2 = C_low_limit; + + if (comp_C2 > C_high_limit) + comp_C2 = C_high_limit; + + /* + * Color Conversion + * pre bias (-) + */ + comp_C0 -= bias_vector[0]; + comp_C1 -= bias_vector[1]; + comp_C2 -= bias_vector[2]; + + /* matrix multiplication */ + temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] + comp_C2 * matrix[2]; + temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] + comp_C2 * matrix[5]; + temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] + comp_C2 * matrix[8]; + + comp_C0 = temp1 + 0x100; + comp_C1 = temp2 + 0x100; + comp_C2 = temp3 + 0x100; + + /* take interger part */ + comp_C0 >>= 9; + comp_C1 >>= 9; + comp_C2 >>= 9; + + /* reorder output colors */ + temp = comp_C0; + comp_C0 = comp_C1; + comp_C1 = comp_C2; + comp_C2 = temp; + + /* limit pixel to 8-bit */ + if (comp_C0 < 0) + comp_C0 = 0; + + if (comp_C0 > 255) + comp_C0 = 255; + + if (comp_C1 < 0) + comp_C1 = 0; + + if (comp_C1 > 255) + comp_C1 = 255; + + if (comp_C2 < 0) + comp_C2 = 0; + + if (comp_C2 > 255) + comp_C2 = 255; + + /* Look-up table */ + if (_is_lookup_table_enabled == 1) { + comp_C2 = (look_up_table[comp_C2] >> 16) & 0xFF; + comp_C1 = (look_up_table[comp_C1] >> 8) & 0xFF; + comp_C0 = (look_up_table[comp_C0] >> 0) & 0xFF; + } + + output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0; + return output; +} + +static uint32 mdp_calc_tpval(MDPIMG *mdpImg) +{ + uint32 tpVal; + uint8 plane_tp; + + tpVal = 0; + if ((mdpImg->imgType == MDP_RGB_565) + || (mdpImg->imgType == MDP_BGR_565)) { + /* + * transparent color conversion into 24 bpp + * + * C2R_8BIT + * left shift the entire bit and or it with the upper most bits + */ + plane_tp = (uint8) ((mdpImg->tpVal & 0xF800) >> 11); + tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 16; + + /* C1B_8BIT */ + plane_tp = (uint8) (mdpImg->tpVal & 0x1F); + tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 8; + + /* C0G_8BIT */ + plane_tp = (uint8) ((mdpImg->tpVal & 0x7E0) >> 5); + tpVal |= ((plane_tp << 2) | ((plane_tp & 0x30) >> 4)); + } else { + /* 24bit RGB to RBG conversion */ + + tpVal = (mdpImg->tpVal & 0xFF00) >> 8; + tpVal |= (mdpImg->tpVal & 0xFF) << 8; + tpVal |= (mdpImg->tpVal & 0xFF0000); + } + + return tpVal; +} + +static uint8 *mdp_get_chroma_addr(MDPIBUF *iBuf) +{ + uint8 *dest1; + + dest1 = NULL; + switch (iBuf->ibuf_type) { + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + dest1 = (uint8 *) iBuf->buf; + dest1 += iBuf->ibuf_width * iBuf->ibuf_height * iBuf->bpp; + break; + + default: + break; + } + + return dest1; +} + +static void mdp_ppp_setbg(MDPIBUF *iBuf) +{ + uint8 *bg0_addr; + uint8 *bg1_addr; + uint32 bg0_ystride, bg1_ystride; + uint32 ppp_src_cfg_reg, unpack_pattern; + int v_slice, h_slice; + + v_slice = h_slice = 1; + bg0_addr = (uint8 *) iBuf->buf; + bg1_addr = mdp_get_chroma_addr(iBuf); + + bg0_ystride = iBuf->ibuf_width * iBuf->bpp; + bg1_ystride = iBuf->ibuf_width * iBuf->bpp; + + switch (iBuf->ibuf_type) { + case MDP_BGR_565: + case MDP_RGB_565: + /* 888 = 3bytes + * RGB = 3Components + * RGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_5BITS | PPP_SRC_C0G_6BITS | + PPP_SRC_C1B_5BITS | PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + if (iBuf->ibuf_type == MDP_RGB_565) + unpack_pattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + else + unpack_pattern = + MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8); + break; + + case MDP_RGB_888: + /* + * 888 = 3bytes + * RGB = 3Components + * RGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_BPP_INTERLVD_3BYTES | + PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_INTERLVD; + + unpack_pattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + break; + + case MDP_BGRA_8888: + case MDP_RGBA_8888: + case MDP_ARGB_8888: + case MDP_XRGB_8888: + /* + * 8888 = 4bytes + * ARGB = 4Components + * ARGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_C3A_8BITS | PPP_SRC_C3_ALPHA_EN | + PPP_SRC_BPP_INTERLVD_4BYTES | PPP_SRC_INTERLVD_4COMPONENTS | + PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + if (iBuf->ibuf_type == MDP_BGRA_8888) + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + else if (iBuf->ibuf_type == MDP_RGBA_8888) + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, + 8); + else + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_2COMPONENTS | + PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR; + + if (iBuf->ibuf_type == MDP_Y_CBCR_H2V1) + unpack_pattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + unpack_pattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + v_slice = h_slice = 2; + break; + + case MDP_YCRYCB_H2V1: + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_4COMPONENTS | + PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB; + + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8); + h_slice = 2; + break; + + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_2COMPONENTS | + PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR; + + if (iBuf->ibuf_type == MDP_Y_CBCR_H2V1) + unpack_pattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + unpack_pattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + h_slice = 2; + break; + + default: + return; + } + + /* starting input address adjustment */ + mdp_adjust_start_addr(&bg0_addr, &bg1_addr, v_slice, h_slice, + iBuf->roi.lcd_x, iBuf->roi.lcd_y, + iBuf->ibuf_width, iBuf->ibuf_height, iBuf->bpp, + iBuf, 1); + + /* + * 0x01c0: background plane 0 addr + * 0x01c4: background plane 1 addr + * 0x01c8: background plane 2 addr + * 0x01cc: bg y stride for plane 0 and 1 + * 0x01d0: bg y stride for plane 2 + * 0x01d4: bg src PPP config + * 0x01d8: unpack pattern + */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c0, bg0_addr); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c4, bg1_addr); + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01cc, + (bg1_ystride << 16) | bg0_ystride); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d4, ppp_src_cfg_reg); + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d8, unpack_pattern); +} + +#define IS_PSEUDOPLNR(img) ((img == MDP_Y_CRCB_H2V2) | \ + (img == MDP_Y_CBCR_H2V2) | \ + (img == MDP_Y_CRCB_H2V1) | \ + (img == MDP_Y_CBCR_H2V1)) + +#define IMG_LEN(rect_h, w, rect_w, bpp) (((rect_h) * w) * bpp) + +#define Y_TO_CRCB_RATIO(format) \ + ((format == MDP_Y_CBCR_H2V2 || format == MDP_Y_CRCB_H2V2) ? 2 :\ + (format == MDP_Y_CBCR_H2V1 || format == MDP_Y_CRCB_H2V1) ? 1 : 1) + +static void get_len(struct mdp_img *img, struct mdp_rect *rect, uint32_t bpp, + uint32_t *len0, uint32_t *len1) +{ + *len0 = IMG_LEN(rect->h, img->width, rect->w, bpp); + if (IS_PSEUDOPLNR(img->format)) + *len1 = *len0/Y_TO_CRCB_RATIO(img->format); + else + *len1 = 0; +} + +static void flush_imgs(struct mdp_blit_req *req, int src_bpp, int dst_bpp, + struct file *p_src_file, struct file *p_dst_file) +{ +#ifdef CONFIG_ANDROID_PMEM + uint32_t src0_len, src1_len, dst0_len, dst1_len; + + /* flush src images to memory before dma to mdp */ + get_len(&req->src, &req->src_rect, src_bpp, + &src0_len, &src1_len); + + flush_pmem_file(p_src_file, + req->src.offset, src0_len); + + if (IS_PSEUDOPLNR(req->src.format)) + flush_pmem_file(p_src_file, + req->src.offset + src0_len, src1_len); + + get_len(&req->dst, &req->dst_rect, dst_bpp, &dst0_len, &dst1_len); + flush_pmem_file(p_dst_file, req->dst.offset, dst0_len); + + if (IS_PSEUDOPLNR(req->dst.format)) + flush_pmem_file(p_dst_file, + req->dst.offset + dst0_len, dst1_len); +#endif +} + +static void mdp_start_ppp(struct msm_fb_data_type *mfd, MDPIBUF *iBuf, +struct mdp_blit_req *req, struct file *p_src_file, struct file *p_dst_file) +{ + uint8 *src0, *src1; + uint8 *dest0, *dest1; + uint16 inpBpp; + uint32 dest0_ystride; + uint32 src_width; + uint32 src_height; + uint32 src0_ystride; + uint32 dst_roi_width; + uint32 dst_roi_height; + uint32 ppp_src_cfg_reg, ppp_operation_reg, ppp_dst_cfg_reg; + uint32 alpha, tpVal; + uint32 packPattern; + uint32 dst_packPattern; + boolean inputRGB, outputRGB, pseudoplanr_output; + int sv_slice, sh_slice; + int dv_slice, dh_slice; + boolean perPixelAlpha = FALSE; + boolean ppp_lookUp_enable = FALSE; + + sv_slice = sh_slice = dv_slice = dh_slice = 1; + alpha = tpVal = 0; + src_width = iBuf->mdpImg.width; + src_height = iBuf->roi.y + iBuf->roi.height; + src1 = NULL; + dest1 = NULL; + + inputRGB = outputRGB = TRUE; + pseudoplanr_output = FALSE; + ppp_operation_reg = 0; + ppp_dst_cfg_reg = 0; + ppp_src_cfg_reg = 0; + + /* Wait for the pipe to clear */ + do { } while (mdp_ppp_pipe_wait() <= 0); + + /* + * destination config + */ + switch (iBuf->ibuf_type) { + case MDP_RGB_888: + dst_packPattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + ppp_dst_cfg_reg = + PPP_DST_C0G_8BIT | PPP_DST_C1B_8BIT | PPP_DST_C2R_8BIT | + PPP_DST_PACKET_CNT_INTERLVD_3ELEM | PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | PPP_DST_OUT_SEL_AXI | + PPP_DST_BPP_3BYTES | PPP_DST_PLANE_INTERLVD; + break; + + case MDP_XRGB_8888: + case MDP_ARGB_8888: + case MDP_RGBA_8888: + if (iBuf->ibuf_type == MDP_BGRA_8888) + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + else if (iBuf->ibuf_type == MDP_RGBA_8888) + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, + 8); + else + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + + ppp_dst_cfg_reg = PPP_DST_C0G_8BIT | + PPP_DST_C1B_8BIT | + PPP_DST_C2R_8BIT | + PPP_DST_C3A_8BIT | + PPP_DST_C3ALPHA_EN | + PPP_DST_PACKET_CNT_INTERLVD_4ELEM | + PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | + PPP_DST_BPP_4BYTES | PPP_DST_PLANE_INTERLVD; + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + if (iBuf->ibuf_type == MDP_Y_CBCR_H2V2) + dst_packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + dst_packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + + ppp_dst_cfg_reg = PPP_DST_C2R_8BIT | + PPP_DST_C0G_8BIT | + PPP_DST_C1B_8BIT | + PPP_DST_C3A_8BIT | + PPP_DST_PACKET_CNT_INTERLVD_2ELEM | + PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES; + + ppp_operation_reg |= PPP_OP_DST_CHROMA_420; + outputRGB = FALSE; + pseudoplanr_output = TRUE; + /* + * vertically (y direction) and horizontally (x direction) + * sample reduction by 2 + */ + + /* + * H2V2(YUV420) Cosite + * + * Y Y Y Y + * CbCr CbCr + * Y Y Y Y + * Y Y Y Y + * CbCr CbCr + * Y Y Y Y + */ + dv_slice = dh_slice = 2; + + /* (x,y) and (width,height) must be even numbern */ + iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2; + iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2; + iBuf->roi.x = (iBuf->roi.x / 2) * 2; + iBuf->roi.width = (iBuf->roi.width / 2) * 2; + + iBuf->roi.lcd_y = (iBuf->roi.lcd_y / 2) * 2; + iBuf->roi.dst_height = (iBuf->roi.dst_height / 2) * 2; + iBuf->roi.y = (iBuf->roi.y / 2) * 2; + iBuf->roi.height = (iBuf->roi.height / 2) * 2; + break; + + case MDP_YCRYCB_H2V1: + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8); + ppp_dst_cfg_reg = + PPP_DST_C2R_8BIT | PPP_DST_C0G_8BIT | PPP_DST_C1B_8BIT | + PPP_DST_C3A_8BIT | PPP_DST_PACKET_CNT_INTERLVD_4ELEM | + PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES | + PPP_DST_PLANE_INTERLVD; + + ppp_operation_reg |= PPP_OP_DST_CHROMA_H2V1; + outputRGB = FALSE; + /* + * horizontally (x direction) sample reduction by 2 + * + * H2V1(YUV422) Cosite + * + * YCbCr Y YCbCr Y + * YCbCr Y YCbCr Y + * YCbCr Y YCbCr Y + * YCbCr Y YCbCr Y + */ + dh_slice = 2; + + /* + * if it's TV-Out/MDP_YCRYCB_H2V1, let's go through the + * preloaded gamma setting of 2.2 when the content is + * non-linear ppp_lookUp_enable = TRUE; + */ + + /* x and width must be even number */ + iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2; + iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2; + iBuf->roi.x = (iBuf->roi.x / 2) * 2; + iBuf->roi.width = (iBuf->roi.width / 2) * 2; + break; + + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + if (iBuf->ibuf_type == MDP_Y_CBCR_H2V1) + dst_packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + dst_packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + + ppp_dst_cfg_reg = PPP_DST_C2R_8BIT | + PPP_DST_C0G_8BIT | + PPP_DST_C1B_8BIT | + PPP_DST_C3A_8BIT | + PPP_DST_PACKET_CNT_INTERLVD_2ELEM | + PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES; + + ppp_operation_reg |= PPP_OP_DST_CHROMA_H2V1; + outputRGB = FALSE; + pseudoplanr_output = TRUE; + /* horizontally (x direction) sample reduction by 2 */ + dh_slice = 2; + + /* x and width must be even number */ + iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2; + iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2; + iBuf->roi.x = (iBuf->roi.x / 2) * 2; + iBuf->roi.width = (iBuf->roi.width / 2) * 2; + break; + + case MDP_BGR_565: + case MDP_RGB_565: + default: + if (iBuf->ibuf_type == MDP_RGB_565) + dst_packPattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + else + dst_packPattern = + MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8); + + ppp_dst_cfg_reg = PPP_DST_C0G_6BIT | + PPP_DST_C1B_5BIT | + PPP_DST_C2R_5BIT | + PPP_DST_PACKET_CNT_INTERLVD_3ELEM | + PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | + PPP_DST_BPP_2BYTES | PPP_DST_PLANE_INTERLVD; + break; + } + + /* source config */ + switch (iBuf->mdpImg.imgType) { + case MDP_RGB_888: + inpBpp = 3; + /* + * 565 = 2bytes + * RGB = 3Components + * RGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_BPP_INTERLVD_3BYTES | + PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + packPattern = MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + + ppp_operation_reg |= PPP_OP_COLOR_SPACE_RGB | + PPP_OP_SRC_CHROMA_RGB | PPP_OP_DST_CHROMA_RGB; + break; + + case MDP_BGRA_8888: + case MDP_RGBA_8888: + case MDP_ARGB_8888: + perPixelAlpha = TRUE; + case MDP_XRGB_8888: + inpBpp = 4; + /* + * 8888 = 4bytes + * ARGB = 4Components + * ARGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_C3A_8BITS | + PPP_SRC_C3_ALPHA_EN | PPP_SRC_BPP_INTERLVD_4BYTES | + PPP_SRC_INTERLVD_4COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + if (iBuf->mdpImg.imgType == MDP_BGRA_8888) + packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + else if (iBuf->mdpImg.imgType == MDP_RGBA_8888) + packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, + 8); + else + packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + + ppp_operation_reg |= PPP_OP_COLOR_SPACE_RGB | + PPP_OP_SRC_CHROMA_RGB | PPP_OP_DST_CHROMA_RGB; + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + inpBpp = 1; + src1 = (uint8 *) iBuf->mdpImg.cbcr_addr; + + /* + * CbCr = 2bytes + * CbCr = 2Components + * Y+CbCr + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_2COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_PSEUDOPLNR; + + if (iBuf->mdpImg.imgType == MDP_Y_CRCB_H2V2) + packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + else + packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + + ppp_operation_reg |= PPP_OP_COLOR_SPACE_YCBCR | + PPP_OP_SRC_CHROMA_420 | + PPP_OP_SRC_CHROMA_COSITE | + PPP_OP_DST_CHROMA_RGB | PPP_OP_DST_CHROMA_COSITE; + + inputRGB = FALSE; + sh_slice = sv_slice = 2; + break; + + case MDP_YCRYCB_H2V1: + inpBpp = 2; + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_4COMPONENTS | + PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB; + + packPattern = + MDP_GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8); + + ppp_operation_reg |= PPP_OP_SRC_CHROMA_H2V1 | + PPP_OP_SRC_CHROMA_COSITE | PPP_OP_DST_CHROMA_COSITE; + + /* + * if it's TV-Out/MDP_YCRYCB_H2V1, let's go through the + * preloaded inverse gamma setting of 2.2 since they're + * symetric when the content is non-linear + * ppp_lookUp_enable = TRUE; + */ + + /* x and width must be even number */ + iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2; + iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2; + iBuf->roi.x = (iBuf->roi.x / 2) * 2; + iBuf->roi.width = (iBuf->roi.width / 2) * 2; + + inputRGB = FALSE; + sh_slice = 2; + break; + + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + inpBpp = 1; + src1 = (uint8 *) iBuf->mdpImg.cbcr_addr; + + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_2COMPONENTS | + PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR; + + if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V1) + packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + + ppp_operation_reg |= PPP_OP_SRC_CHROMA_H2V1 | + PPP_OP_SRC_CHROMA_COSITE | PPP_OP_DST_CHROMA_COSITE; + inputRGB = FALSE; + sh_slice = 2; + break; + + case MDP_BGR_565: + case MDP_RGB_565: + default: + inpBpp = 2; + /* + * 565 = 2bytes + * RGB = 3Components + * RGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_5BITS | PPP_SRC_C0G_6BITS | + PPP_SRC_C1B_5BITS | PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + if (iBuf->mdpImg.imgType == MDP_RGB_565) + packPattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + else + packPattern = + MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8); + + ppp_operation_reg |= PPP_OP_COLOR_SPACE_RGB | + PPP_OP_SRC_CHROMA_RGB | PPP_OP_DST_CHROMA_RGB; + break; + + } + + if (pseudoplanr_output) + ppp_dst_cfg_reg |= PPP_DST_PLANE_PSEUDOPLN; + + /* YCbCr to RGB color conversion flag */ + if ((!inputRGB) && (outputRGB)) { + ppp_operation_reg |= PPP_OP_CONVERT_YCBCR2RGB | + PPP_OP_CONVERT_ON; + + /* + * primary/secondary is sort of misleading term...but + * in mdp2.2/3.0 we only use primary matrix (forward/rev) + * in mdp3.1 we use set1(prim) and set2(secd) + */ +#ifdef CONFIG_FB_MSM_MDP31 + ppp_operation_reg |= PPP_OP_CONVERT_MATRIX_SECONDARY | + PPP_OP_DST_RGB; + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0240, 0); +#endif + + if (ppp_lookUp_enable) { + ppp_operation_reg |= PPP_OP_LUT_C0_ON | + PPP_OP_LUT_C1_ON | PPP_OP_LUT_C2_ON; + } + } + /* RGB to YCbCr color conversion flag */ + if ((inputRGB) && (!outputRGB)) { + ppp_operation_reg |= PPP_OP_CONVERT_RGB2YCBCR | + PPP_OP_CONVERT_ON; + +#ifdef CONFIG_FB_MSM_MDP31 + ppp_operation_reg |= PPP_OP_CONVERT_MATRIX_PRIMARY | + PPP_OP_DST_YCBCR; + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0240, 0x1e); +#endif + + if (ppp_lookUp_enable) { + ppp_operation_reg |= PPP_OP_LUT_C0_ON | + PPP_OP_LUT_C1_ON | PPP_OP_LUT_C2_ON; + } + } + /* YCbCr to YCbCr color conversion flag */ + if ((!inputRGB) && (!outputRGB)) { + if ((ppp_lookUp_enable) && + (iBuf->mdpImg.imgType != iBuf->ibuf_type)) { + ppp_operation_reg |= PPP_OP_LUT_C0_ON; + } + } + + ppp_src_cfg_reg |= (iBuf->roi.x % 2) ? PPP_SRC_BPP_ROI_ODD_X : 0; + ppp_src_cfg_reg |= (iBuf->roi.y % 2) ? PPP_SRC_BPP_ROI_ODD_Y : 0; + + if (req->flags & MDP_DEINTERLACE) + ppp_operation_reg |= PPP_OP_DEINT_EN; + + /* Dither at DMA side only since iBuf format is RGB888 */ + if (iBuf->mdpImg.mdpOp & MDPOP_DITHER) + ppp_operation_reg |= PPP_OP_DITHER_EN; + + if (iBuf->mdpImg.mdpOp & MDPOP_ROTATION) { + ppp_operation_reg |= PPP_OP_ROT_ON; + + if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) { + ppp_operation_reg |= PPP_OP_ROT_90; + } + if (iBuf->mdpImg.mdpOp & MDPOP_LR) { + ppp_operation_reg |= PPP_OP_FLIP_LR; + } + if (iBuf->mdpImg.mdpOp & MDPOP_UD) { + ppp_operation_reg |= PPP_OP_FLIP_UD; + } + } + + src0_ystride = src_width * inpBpp; + dest0_ystride = iBuf->ibuf_width * iBuf->bpp; + + /* no need to care about rotation since it's the real-XY. */ + dst_roi_width = iBuf->roi.dst_width; + dst_roi_height = iBuf->roi.dst_height; + + src0 = (uint8 *) iBuf->mdpImg.bmy_addr; + dest0 = (uint8 *) iBuf->buf; + + /* Jumping from Y-Plane to Chroma Plane */ + dest1 = mdp_get_chroma_addr(iBuf); + + /* first pixel addr calculation */ + mdp_adjust_start_addr(&src0, &src1, sv_slice, sh_slice, iBuf->roi.x, + iBuf->roi.y, src_width, src_height, inpBpp, iBuf, + 0); + mdp_adjust_start_addr(&dest0, &dest1, dv_slice, dh_slice, + iBuf->roi.lcd_x, iBuf->roi.lcd_y, + iBuf->ibuf_width, iBuf->ibuf_height, iBuf->bpp, + iBuf, 2); + + /* set scale operation */ + mdp_set_scale(iBuf, dst_roi_width, dst_roi_height, + inputRGB, outputRGB, &ppp_operation_reg); + + /* + * setting background source for blending + */ + mdp_set_blend_attr(iBuf, &alpha, &tpVal, perPixelAlpha, + &ppp_operation_reg); + + if (ppp_operation_reg & PPP_OP_BLEND_ON) { + mdp_ppp_setbg(iBuf); + + if (iBuf->ibuf_type == MDP_YCRYCB_H2V1) { + ppp_operation_reg |= PPP_OP_BG_CHROMA_H2V1; + + if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) { + tpVal = mdp_conv_matx_rgb2yuv(tpVal, + (uint16 *) & + mdp_ccs_rgb2yuv, + &mdp_plv[0], NULL); + } + } + } + + /* + * 0x0004: enable dbg bus + * 0x0100: "don't care" Edge Condit until scaling is on + * 0x0104: xrc tile x&y size u7.6 format = 7bit.6bit + * 0x0108: src pixel size + * 0x010c: component plane 0 starting address + * 0x011c: component plane 0 ystride + * 0x0124: PPP source config register + * 0x0128: unpacked pattern from lsb to msb (eg. RGB->BGR) + */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0108, (iBuf->roi.height << 16 | + iBuf->roi.width)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x010c, src0); /* comp.plane 0 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0110, src1); /* comp.plane 1 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x011c, + (src0_ystride << 16 | src0_ystride)); + + /* setup for rgb 565 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0124, ppp_src_cfg_reg); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0128, packPattern); + /* + * 0x0138: PPP destination operation register + * 0x014c: constant_alpha|transparent_color + * 0x0150: PPP destination config register + * 0x0154: PPP packing pattern + */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0138, ppp_operation_reg); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x014c, alpha << 24 | tpVal); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0150, ppp_dst_cfg_reg); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0154, dst_packPattern); + + /* + * 0x0164: ROI height and width + * 0x0168: Component Plane 0 starting addr + * 0x016c: Component Plane 1 starting addr + * 0x0178: Component Plane 1/0 y stride + */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0164, + (dst_roi_height << 16 | dst_roi_width)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0168, dest0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x016c, dest1); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0178, + (dest0_ystride << 16 | dest0_ystride)); + + flush_imgs(req, inpBpp, iBuf->bpp, p_src_file, p_dst_file); +#ifdef CONFIG_MDP_PPP_ASYNC_OP + mdp_ppp_process_curr_djob(); +#else + mdp_pipe_kickoff(MDP_PPP_TERM, mfd); +#endif +} + +static int mdp_ppp_verify_req(struct mdp_blit_req *req) +{ + u32 src_width, src_height, dst_width, dst_height; + + if (req == NULL) + return -1; + + if (MDP_IS_IMGTYPE_BAD(req->src.format) || + MDP_IS_IMGTYPE_BAD(req->dst.format)) + return -1; + + if ((req->src.width == 0) || (req->src.height == 0) || + (req->src_rect.w == 0) || (req->src_rect.h == 0) || + (req->dst.width == 0) || (req->dst.height == 0) || + (req->dst_rect.w == 0) || (req->dst_rect.h == 0)) + + return -1; + + if (((req->src_rect.x + req->src_rect.w) > req->src.width) || + ((req->src_rect.y + req->src_rect.h) > req->src.height)) + return -1; + + if (((req->dst_rect.x + req->dst_rect.w) > req->dst.width) || + ((req->dst_rect.y + req->dst_rect.h) > req->dst.height)) + return -1; + + /* + * scaling range check + */ + src_width = req->src_rect.w; + src_height = req->src_rect.h; + + if (req->flags & MDP_ROT_90) { + dst_width = req->dst_rect.h; + dst_height = req->dst_rect.w; + } else { + dst_width = req->dst_rect.w; + dst_height = req->dst_rect.h; + } + + switch (req->dst.format) { + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + src_width = (src_width / 2) * 2; + src_height = (src_height / 2) * 2; + dst_width = (src_width / 2) * 2; + dst_height = (src_height / 2) * 2; + break; + + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + case MDP_YCRYCB_H2V1: + src_width = (src_width / 2) * 2; + dst_width = (src_width / 2) * 2; + break; + + default: + break; + } + + if (((MDP_SCALE_Q_FACTOR * dst_width) / src_width > + MDP_MAX_X_SCALE_FACTOR) + || ((MDP_SCALE_Q_FACTOR * dst_width) / src_width < + MDP_MIN_X_SCALE_FACTOR)) + return -1; + + if (((MDP_SCALE_Q_FACTOR * dst_height) / src_height > + MDP_MAX_Y_SCALE_FACTOR) + || ((MDP_SCALE_Q_FACTOR * dst_height) / src_height < + MDP_MIN_Y_SCALE_FACTOR)) + return -1; + + return 0; +} + +/** + * get_gem_img() - retrieve drm obj's start address and size + * @img: contains drm file descriptor and gem handle + * @start: repository of starting address of drm obj allocated memory + * @len: repository of size of drm obj alloacted memory + * + **/ +int get_gem_img(struct mdp_img *img, unsigned long *start, unsigned long *len) +{ + panic("waaaaaaaah"); + //return kgsl_gem_obj_addr(img->memory_id, (int)img->priv, start, len); +} + +int get_img(struct mdp_img *img, struct fb_info *info, unsigned long *start, + unsigned long *len, struct file **pp_file) +{ + int put_needed, ret = 0; + struct file *file; + unsigned long vstart; +#ifdef CONFIG_ANDROID_PMEM + if (!get_pmem_file(img->memory_id, start, &vstart, len, pp_file)) + return 0; +#endif + file = fget_light(img->memory_id, &put_needed); + if (file == NULL) + return -1; + + if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { + *start = info->fix.smem_start; + *len = info->fix.smem_len; + *pp_file = file; + } else { + ret = -1; + fput_light(file, put_needed); + } + return ret; +} + +int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req, + struct file **pp_src_file, struct file **pp_dst_file) +{ + unsigned long src_start, dst_start; + unsigned long src_len = 0; + unsigned long dst_len = 0; + MDPIBUF iBuf; + u32 dst_width, dst_height; + struct file *p_src_file = 0 , *p_dst_file = 0; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (req->dst.format == MDP_FB_FORMAT) + req->dst.format = mfd->fb_imgType; + if (req->src.format == MDP_FB_FORMAT) + req->src.format = mfd->fb_imgType; + + if (req->flags & MDP_BLIT_SRC_GEM) { + if (get_gem_img(&req->src, &src_start, &src_len) < 0) + return -1; + } else { + get_img(&req->src, info, &src_start, &src_len, &p_src_file); + } + if (src_len == 0) { + printk(KERN_ERR "mdp_ppp: could not retrieve image from " + "memory\n"); + return -1; + } + + if (req->flags & MDP_BLIT_DST_GEM) { + if (get_gem_img(&req->dst, &dst_start, &dst_len) < 0) + return -1; + } else { + get_img(&req->dst, info, &dst_start, &dst_len, &p_dst_file); + } + if (dst_len == 0) { + printk(KERN_ERR "mdp_ppp: could not retrieve image from " + "memory\n"); + return -1; + } + *pp_src_file = p_src_file; + *pp_dst_file = p_dst_file; + if (mdp_ppp_verify_req(req)) { + printk(KERN_ERR "mdp_ppp: invalid image!\n"); + return -1; + } + + iBuf.ibuf_width = req->dst.width; + iBuf.ibuf_height = req->dst.height; + iBuf.bpp = bytes_per_pixel[req->dst.format]; + + iBuf.ibuf_type = req->dst.format; + iBuf.buf = (uint8 *) dst_start; + iBuf.buf += req->dst.offset; + + iBuf.roi.lcd_x = req->dst_rect.x; + iBuf.roi.lcd_y = req->dst_rect.y; + iBuf.roi.dst_width = req->dst_rect.w; + iBuf.roi.dst_height = req->dst_rect.h; + + iBuf.roi.x = req->src_rect.x; + iBuf.roi.width = req->src_rect.w; + iBuf.roi.y = req->src_rect.y; + iBuf.roi.height = req->src_rect.h; + + iBuf.mdpImg.width = req->src.width; + iBuf.mdpImg.imgType = req->src.format; + + iBuf.mdpImg.bmy_addr = (uint32 *) (src_start + req->src.offset); + iBuf.mdpImg.cbcr_addr = + (uint32 *) ((uint32) iBuf.mdpImg.bmy_addr + + req->src.width * req->src.height); + + iBuf.mdpImg.mdpOp = MDPOP_NOP; + + /* blending check */ + if (req->transp_mask != MDP_TRANSP_NOP) { + iBuf.mdpImg.mdpOp |= MDPOP_TRANSP; + iBuf.mdpImg.tpVal = req->transp_mask; + iBuf.mdpImg.tpVal = mdp_calc_tpval(&iBuf.mdpImg); + } + + req->alpha &= 0xff; + if (req->alpha < MDP_ALPHA_NOP) { + iBuf.mdpImg.mdpOp |= MDPOP_ALPHAB; + iBuf.mdpImg.alpha = req->alpha; + } + + /* rotation check */ + if (req->flags & MDP_FLIP_LR) + iBuf.mdpImg.mdpOp |= MDPOP_LR; + if (req->flags & MDP_FLIP_UD) + iBuf.mdpImg.mdpOp |= MDPOP_UD; + if (req->flags & MDP_ROT_90) + iBuf.mdpImg.mdpOp |= MDPOP_ROT90; + if (req->flags & MDP_DITHER) + iBuf.mdpImg.mdpOp |= MDPOP_DITHER; + + if (req->flags & MDP_BLEND_FG_PREMULT) { +#ifdef CONFIG_FB_MSM_MDP31 + iBuf.mdpImg.mdpOp |= MDPOP_FG_PM_ALPHA; +#else + return -EINVAL; +#endif + } + + if (req->flags & MDP_DEINTERLACE) { +#ifdef CONFIG_FB_MSM_MDP31 + if ((req->src.format != MDP_Y_CBCR_H2V2) && + (req->src.format != MDP_Y_CRCB_H2V2)) +#endif + return -EINVAL; + } + + /* scale check */ + if (req->flags & MDP_ROT_90) { + dst_width = req->dst_rect.h; + dst_height = req->dst_rect.w; + } else { + dst_width = req->dst_rect.w; + dst_height = req->dst_rect.h; + } + + if ((iBuf.roi.width != dst_width) || (iBuf.roi.height != dst_height)) + iBuf.mdpImg.mdpOp |= MDPOP_ASCALE; + + if (req->flags & MDP_BLUR) { +#ifdef CONFIG_FB_MSM_MDP31 + if (req->flags & MDP_SHARPENING) + printk(KERN_WARNING + "mdp: MDP_SHARPENING is set with MDP_BLUR!\n"); + req->flags |= MDP_SHARPENING; + req->sharpening_strength = -127; +#else + iBuf.mdpImg.mdpOp |= MDPOP_ASCALE | MDPOP_BLUR; + +#endif + } + + if (req->flags & MDP_SHARPENING) { +#ifdef CONFIG_FB_MSM_MDP31 + if ((req->sharpening_strength > 127) || + (req->sharpening_strength < -127)) { + printk(KERN_ERR + "%s: sharpening strength out of range\n", + __func__); + return -EINVAL; + } + + iBuf.mdpImg.mdpOp |= MDPOP_ASCALE | MDPOP_SHARPENING; + iBuf.mdpImg.sp_value = req->sharpening_strength & 0xff; +#else + return -EINVAL; +#endif + } + + down(&mdp_ppp_mutex); + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + +#ifdef CONFIG_FB_MSM_MDP31 + mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file); +#else + /* bg tile fetching HW workaround */ + if (((iBuf.mdpImg.mdpOp & (MDPOP_TRANSP | MDPOP_ALPHAB)) || + (req->src.format == MDP_ARGB_8888) || + (req->src.format == MDP_BGRA_8888) || + (req->src.format == MDP_RGBA_8888)) && + (iBuf.mdpImg.mdpOp & MDPOP_ROT90) && (req->dst_rect.w <= 16)) { + int dst_h, src_w, i; + + src_w = req->src_rect.w; + dst_h = iBuf.roi.dst_height; + + for (i = 0; i < (req->dst_rect.h / 16); i++) { + /* this tile size */ + iBuf.roi.dst_height = 16; + iBuf.roi.width = + (16 * req->src_rect.w) / req->dst_rect.h; + + /* if it's out of scale range... */ + if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + iBuf.roi.width) > MDP_MAX_X_SCALE_FACTOR) + iBuf.roi.width = + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + MDP_MAX_X_SCALE_FACTOR; + else if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + iBuf.roi.width) < MDP_MIN_X_SCALE_FACTOR) + iBuf.roi.width = + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + MDP_MIN_X_SCALE_FACTOR; + + mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file); + + /* next tile location */ + iBuf.roi.lcd_y += 16; + iBuf.roi.x += iBuf.roi.width; + + /* this is for a remainder update */ + dst_h -= 16; + src_w -= iBuf.roi.width; + } + + if ((dst_h < 0) || (src_w < 0)) + printk + ("msm_fb: mdp_blt_ex() unexpected result! line:%d\n", + __LINE__); + + /* remainder update */ + if ((dst_h > 0) && (src_w > 0)) { + u32 tmp_v; + + iBuf.roi.dst_height = dst_h; + iBuf.roi.width = src_w; + + if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + iBuf.roi.width) > MDP_MAX_X_SCALE_FACTOR) { + tmp_v = + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + MDP_MAX_X_SCALE_FACTOR + + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) % + MDP_MAX_X_SCALE_FACTOR ? 1 : 0; + + /* move x location as roi width gets bigger */ + iBuf.roi.x -= tmp_v - iBuf.roi.width; + iBuf.roi.width = tmp_v; + } else + if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + iBuf.roi.width) < MDP_MIN_X_SCALE_FACTOR) { + tmp_v = + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + MDP_MIN_X_SCALE_FACTOR + + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) % + MDP_MIN_X_SCALE_FACTOR ? 1 : 0; + + /* + * we don't move x location for continuity of + * source image + */ + iBuf.roi.width = tmp_v; + } + + mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file); + } + } else { + mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file); + } +#endif + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + up(&mdp_ppp_mutex); + + return 0; +} diff --git a/drivers/staging/msm/mdp_ppp_dq.c b/drivers/staging/msm/mdp_ppp_dq.c new file mode 100644 index 00000000000..3dc1c0cc61f --- /dev/null +++ b/drivers/staging/msm/mdp_ppp_dq.c @@ -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); + } +} diff --git a/drivers/staging/msm/mdp_ppp_dq.h b/drivers/staging/msm/mdp_ppp_dq.h new file mode 100644 index 00000000000..03e4e9a5f23 --- /dev/null +++ b/drivers/staging/msm/mdp_ppp_dq.h @@ -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 */ diff --git a/drivers/staging/msm/mdp_ppp_v20.c b/drivers/staging/msm/mdp_ppp_v20.c new file mode 100644 index 00000000000..b5b7271921e --- /dev/null +++ b/drivers/staging/msm/mdp_ppp_v20.c @@ -0,0 +1,2486 @@ +/* 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/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" + +static MDP_SCALE_MODE mdp_curr_up_scale_xy; +static MDP_SCALE_MODE mdp_curr_down_scale_x; +static MDP_SCALE_MODE mdp_curr_down_scale_y; + +static long long mdp_do_div(long long num, long long den) +{ + do_div(num, den); + return num; +} + +struct mdp_table_entry mdp_gaussian_blur_table[] = { + /* max variance */ + { 0x5fffc, 0x20000080 }, + { 0x50280, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50284, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50288, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5028c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50290, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50294, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50298, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5029c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502ac, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502bc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502cc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502dc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502ec, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502fc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50300, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50304, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50308, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5030c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50310, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50314, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50318, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5031c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50320, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50324, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50328, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5032c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50330, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50334, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50338, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5033c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50340, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50344, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50348, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5034c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50350, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50354, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50358, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5035c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50360, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50364, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50368, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5036c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50370, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50374, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50378, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5037c, 0x20000080 }, +}; + +static void load_scale_table( + struct mdp_table_entry *table, int len) +{ + int i; + for (i = 0; i < len; i++) + MDP_OUTP(MDP_BASE + table[i].reg, table[i].val); +} + +static void mdp_load_pr_upscale_table(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50200, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50204, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50208, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5020c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50210, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50214, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50218, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5021c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50220, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50224, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50228, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5022c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50230, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50234, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50238, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5023c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50240, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50244, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50248, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5024c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50250, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50254, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50258, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5025c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50260, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50264, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50268, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5026c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50270, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50274, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50278, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5027c, 0x0); +} + +static void mdp_load_pr_downscale_table_x_point2TOpoint4(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502cc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502dc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502ec, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502fc, 0x0); +} + +static void mdp_load_pr_downscale_table_y_point2TOpoint4(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50340, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50344, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50348, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5034c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50350, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50354, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50358, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5035c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50360, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50364, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50368, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5036c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50370, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50374, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50378, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5037c, 0x0); +} + +static void mdp_load_pr_downscale_table_x_point4TOpoint6(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502cc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502dc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502ec, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502fc, 0x0); +} + +static void mdp_load_pr_downscale_table_y_point4TOpoint6(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50340, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50344, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50348, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5034c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50350, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50354, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50358, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5035c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50360, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50364, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50368, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5036c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50370, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50374, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50378, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5037c, 0x0); +} + +static void mdp_load_pr_downscale_table_x_point6TOpoint8(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502cc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502dc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502ec, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502fc, 0x0); +} + +static void mdp_load_pr_downscale_table_y_point6TOpoint8(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50340, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50344, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50348, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5034c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50350, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50354, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50358, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5035c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50360, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50364, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50368, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5036c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50370, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50374, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50378, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5037c, 0x0); +} + +static void mdp_load_pr_downscale_table_x_point8TO1(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502cc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502dc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502ec, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502fc, 0x0); +} + +static void mdp_load_pr_downscale_table_y_point8TO1(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50340, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50344, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50348, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5034c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50350, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50354, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50358, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5035c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50360, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50364, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50368, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5036c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50370, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50374, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50378, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5037c, 0x0); +} + +static void mdp_load_bc_upscale_table(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50200, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff80000d); + MDP_OUTP(MDP_BASE + 0x50204, 0x7ec003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec0001c); + MDP_OUTP(MDP_BASE + 0x50208, 0x7d4003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40002b); + MDP_OUTP(MDP_BASE + 0x5020c, 0x7b8003ed); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfd80003c); + MDP_OUTP(MDP_BASE + 0x50210, 0x794003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc0004d); + MDP_OUTP(MDP_BASE + 0x50214, 0x76c003e4); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfc40005f); + MDP_OUTP(MDP_BASE + 0x50218, 0x73c003e0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb800071); + MDP_OUTP(MDP_BASE + 0x5021c, 0x708003de); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfac00085); + MDP_OUTP(MDP_BASE + 0x50220, 0x6d0003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa000098); + MDP_OUTP(MDP_BASE + 0x50224, 0x698003d9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf98000ac); + MDP_OUTP(MDP_BASE + 0x50228, 0x654003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8c000c1); + MDP_OUTP(MDP_BASE + 0x5022c, 0x610003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf84000d5); + MDP_OUTP(MDP_BASE + 0x50230, 0x5c8003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf7c000e9); + MDP_OUTP(MDP_BASE + 0x50234, 0x580003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf74000fd); + MDP_OUTP(MDP_BASE + 0x50238, 0x534003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c00112); + MDP_OUTP(MDP_BASE + 0x5023c, 0x4e8003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6800126); + MDP_OUTP(MDP_BASE + 0x50240, 0x494003da); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600013a); + MDP_OUTP(MDP_BASE + 0x50244, 0x448003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600014d); + MDP_OUTP(MDP_BASE + 0x50248, 0x3f4003dd); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00160); + MDP_OUTP(MDP_BASE + 0x5024c, 0x3a4003df); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00172); + MDP_OUTP(MDP_BASE + 0x50250, 0x354003e1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00184); + MDP_OUTP(MDP_BASE + 0x50254, 0x304003e3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6000195); + MDP_OUTP(MDP_BASE + 0x50258, 0x2b0003e6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf64001a6); + MDP_OUTP(MDP_BASE + 0x5025c, 0x260003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c001b4); + MDP_OUTP(MDP_BASE + 0x50260, 0x214003eb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf78001c2); + MDP_OUTP(MDP_BASE + 0x50264, 0x1c4003ee); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf80001cf); + MDP_OUTP(MDP_BASE + 0x50268, 0x17c003f1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf90001db); + MDP_OUTP(MDP_BASE + 0x5026c, 0x134003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa0001e5); + MDP_OUTP(MDP_BASE + 0x50270, 0xf0003f6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb4001ee); + MDP_OUTP(MDP_BASE + 0x50274, 0xac003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc001f5); + MDP_OUTP(MDP_BASE + 0x50278, 0x70003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe4001fb); + MDP_OUTP(MDP_BASE + 0x5027c, 0x34003fe); +} + +static void mdp_load_bc_downscale_table_x_point2TOpoint4(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac00084); + MDP_OUTP(MDP_BASE + 0x50280, 0x23400083); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b000084); + MDP_OUTP(MDP_BASE + 0x50284, 0x23000083); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400084); + MDP_OUTP(MDP_BASE + 0x50288, 0x23000082); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400085); + MDP_OUTP(MDP_BASE + 0x5028c, 0x23000081); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b800085); + MDP_OUTP(MDP_BASE + 0x50290, 0x23000080); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc00086); + MDP_OUTP(MDP_BASE + 0x50294, 0x22c0007f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c000086); + MDP_OUTP(MDP_BASE + 0x50298, 0x2280007f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c400086); + MDP_OUTP(MDP_BASE + 0x5029c, 0x2280007e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c800086); + MDP_OUTP(MDP_BASE + 0x502a0, 0x2280007d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00086); + MDP_OUTP(MDP_BASE + 0x502a4, 0x2240007d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00087); + MDP_OUTP(MDP_BASE + 0x502a8, 0x2240007c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d000087); + MDP_OUTP(MDP_BASE + 0x502ac, 0x2240007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400087); + MDP_OUTP(MDP_BASE + 0x502b0, 0x2200007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400088); + MDP_OUTP(MDP_BASE + 0x502b4, 0x22400079); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d800088); + MDP_OUTP(MDP_BASE + 0x502b8, 0x22400078); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00088); + MDP_OUTP(MDP_BASE + 0x502bc, 0x22400077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00089); + MDP_OUTP(MDP_BASE + 0x502c0, 0x22000077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e000089); + MDP_OUTP(MDP_BASE + 0x502c4, 0x22000076); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e400089); + MDP_OUTP(MDP_BASE + 0x502c8, 0x22000075); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00088); + MDP_OUTP(MDP_BASE + 0x502cc, 0x21c00075); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00089); + MDP_OUTP(MDP_BASE + 0x502d0, 0x21c00074); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f000089); + MDP_OUTP(MDP_BASE + 0x502d4, 0x21c00073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f400089); + MDP_OUTP(MDP_BASE + 0x502d8, 0x21800073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f40008a); + MDP_OUTP(MDP_BASE + 0x502dc, 0x21800072); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f80008a); + MDP_OUTP(MDP_BASE + 0x502e0, 0x21800071); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008a); + MDP_OUTP(MDP_BASE + 0x502e4, 0x21800070); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008b); + MDP_OUTP(MDP_BASE + 0x502e8, 0x2180006f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2000008c); + MDP_OUTP(MDP_BASE + 0x502ec, 0x2140006e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2040008c); + MDP_OUTP(MDP_BASE + 0x502f0, 0x2140006d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2080008c); + MDP_OUTP(MDP_BASE + 0x502f4, 0x2100006d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008c); + MDP_OUTP(MDP_BASE + 0x502f8, 0x2100006c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008d); + MDP_OUTP(MDP_BASE + 0x502fc, 0x2100006b); +} + +static void mdp_load_bc_downscale_table_y_point2TOpoint4(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac00084); + MDP_OUTP(MDP_BASE + 0x50300, 0x23400083); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b000084); + MDP_OUTP(MDP_BASE + 0x50304, 0x23000083); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400084); + MDP_OUTP(MDP_BASE + 0x50308, 0x23000082); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400085); + MDP_OUTP(MDP_BASE + 0x5030c, 0x23000081); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b800085); + MDP_OUTP(MDP_BASE + 0x50310, 0x23000080); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc00086); + MDP_OUTP(MDP_BASE + 0x50314, 0x22c0007f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c000086); + MDP_OUTP(MDP_BASE + 0x50318, 0x2280007f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c400086); + MDP_OUTP(MDP_BASE + 0x5031c, 0x2280007e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c800086); + MDP_OUTP(MDP_BASE + 0x50320, 0x2280007d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00086); + MDP_OUTP(MDP_BASE + 0x50324, 0x2240007d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00087); + MDP_OUTP(MDP_BASE + 0x50328, 0x2240007c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d000087); + MDP_OUTP(MDP_BASE + 0x5032c, 0x2240007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400087); + MDP_OUTP(MDP_BASE + 0x50330, 0x2200007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400088); + MDP_OUTP(MDP_BASE + 0x50334, 0x22400079); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d800088); + MDP_OUTP(MDP_BASE + 0x50338, 0x22400078); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00088); + MDP_OUTP(MDP_BASE + 0x5033c, 0x22400077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00089); + MDP_OUTP(MDP_BASE + 0x50340, 0x22000077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e000089); + MDP_OUTP(MDP_BASE + 0x50344, 0x22000076); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e400089); + MDP_OUTP(MDP_BASE + 0x50348, 0x22000075); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00088); + MDP_OUTP(MDP_BASE + 0x5034c, 0x21c00075); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00089); + MDP_OUTP(MDP_BASE + 0x50350, 0x21c00074); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f000089); + MDP_OUTP(MDP_BASE + 0x50354, 0x21c00073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f400089); + MDP_OUTP(MDP_BASE + 0x50358, 0x21800073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f40008a); + MDP_OUTP(MDP_BASE + 0x5035c, 0x21800072); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f80008a); + MDP_OUTP(MDP_BASE + 0x50360, 0x21800071); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008a); + MDP_OUTP(MDP_BASE + 0x50364, 0x21800070); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008b); + MDP_OUTP(MDP_BASE + 0x50368, 0x2180006f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2000008c); + MDP_OUTP(MDP_BASE + 0x5036c, 0x2140006e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2040008c); + MDP_OUTP(MDP_BASE + 0x50370, 0x2140006d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2080008c); + MDP_OUTP(MDP_BASE + 0x50374, 0x2100006d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008c); + MDP_OUTP(MDP_BASE + 0x50378, 0x2100006c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008d); + MDP_OUTP(MDP_BASE + 0x5037c, 0x2100006b); +} + +static void mdp_load_bc_downscale_table_x_point4TOpoint6(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x740008c); + MDP_OUTP(MDP_BASE + 0x50280, 0x33800088); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x800008e); + MDP_OUTP(MDP_BASE + 0x50284, 0x33400084); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x8400092); + MDP_OUTP(MDP_BASE + 0x50288, 0x33000080); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9000094); + MDP_OUTP(MDP_BASE + 0x5028c, 0x3300007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9c00098); + MDP_OUTP(MDP_BASE + 0x50290, 0x32400077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xa40009b); + MDP_OUTP(MDP_BASE + 0x50294, 0x32000073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xb00009d); + MDP_OUTP(MDP_BASE + 0x50298, 0x31c0006f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xbc000a0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x3140006b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc8000a2); + MDP_OUTP(MDP_BASE + 0x502a0, 0x31000067); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xd8000a5); + MDP_OUTP(MDP_BASE + 0x502a4, 0x30800062); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xe4000a8); + MDP_OUTP(MDP_BASE + 0x502a8, 0x2fc0005f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xec000aa); + MDP_OUTP(MDP_BASE + 0x502ac, 0x2fc0005b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8000ad); + MDP_OUTP(MDP_BASE + 0x502b0, 0x2f400057); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x108000b0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x2e400054); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x114000b2); + MDP_OUTP(MDP_BASE + 0x502b8, 0x2e000050); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x124000b4); + MDP_OUTP(MDP_BASE + 0x502bc, 0x2d80004c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x130000b6); + MDP_OUTP(MDP_BASE + 0x502c0, 0x2d000049); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x140000b8); + MDP_OUTP(MDP_BASE + 0x502c4, 0x2c800045); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x150000b9); + MDP_OUTP(MDP_BASE + 0x502c8, 0x2c000042); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x15c000bd); + MDP_OUTP(MDP_BASE + 0x502cc, 0x2b40003e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x16c000bf); + MDP_OUTP(MDP_BASE + 0x502d0, 0x2a80003b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x17c000bf); + MDP_OUTP(MDP_BASE + 0x502d4, 0x2a000039); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x188000c2); + MDP_OUTP(MDP_BASE + 0x502d8, 0x29400036); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x19c000c4); + MDP_OUTP(MDP_BASE + 0x502dc, 0x28800032); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac000c5); + MDP_OUTP(MDP_BASE + 0x502e0, 0x2800002f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc000c7); + MDP_OUTP(MDP_BASE + 0x502e4, 0x2740002c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc000c8); + MDP_OUTP(MDP_BASE + 0x502e8, 0x26c00029); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc000c9); + MDP_OUTP(MDP_BASE + 0x502ec, 0x26000027); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec000cc); + MDP_OUTP(MDP_BASE + 0x502f0, 0x25000024); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x200000cc); + MDP_OUTP(MDP_BASE + 0x502f4, 0x24800021); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x210000cd); + MDP_OUTP(MDP_BASE + 0x502f8, 0x23800020); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x220000ce); + MDP_OUTP(MDP_BASE + 0x502fc, 0x2300001d); +} + +static void mdp_load_bc_downscale_table_y_point4TOpoint6(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x740008c); + MDP_OUTP(MDP_BASE + 0x50300, 0x33800088); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x800008e); + MDP_OUTP(MDP_BASE + 0x50304, 0x33400084); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x8400092); + MDP_OUTP(MDP_BASE + 0x50308, 0x33000080); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9000094); + MDP_OUTP(MDP_BASE + 0x5030c, 0x3300007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9c00098); + MDP_OUTP(MDP_BASE + 0x50310, 0x32400077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xa40009b); + MDP_OUTP(MDP_BASE + 0x50314, 0x32000073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xb00009d); + MDP_OUTP(MDP_BASE + 0x50318, 0x31c0006f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xbc000a0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x3140006b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc8000a2); + MDP_OUTP(MDP_BASE + 0x50320, 0x31000067); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xd8000a5); + MDP_OUTP(MDP_BASE + 0x50324, 0x30800062); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xe4000a8); + MDP_OUTP(MDP_BASE + 0x50328, 0x2fc0005f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xec000aa); + MDP_OUTP(MDP_BASE + 0x5032c, 0x2fc0005b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8000ad); + MDP_OUTP(MDP_BASE + 0x50330, 0x2f400057); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x108000b0); + MDP_OUTP(MDP_BASE + 0x50334, 0x2e400054); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x114000b2); + MDP_OUTP(MDP_BASE + 0x50338, 0x2e000050); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x124000b4); + MDP_OUTP(MDP_BASE + 0x5033c, 0x2d80004c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x130000b6); + MDP_OUTP(MDP_BASE + 0x50340, 0x2d000049); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x140000b8); + MDP_OUTP(MDP_BASE + 0x50344, 0x2c800045); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x150000b9); + MDP_OUTP(MDP_BASE + 0x50348, 0x2c000042); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x15c000bd); + MDP_OUTP(MDP_BASE + 0x5034c, 0x2b40003e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x16c000bf); + MDP_OUTP(MDP_BASE + 0x50350, 0x2a80003b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x17c000bf); + MDP_OUTP(MDP_BASE + 0x50354, 0x2a000039); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x188000c2); + MDP_OUTP(MDP_BASE + 0x50358, 0x29400036); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x19c000c4); + MDP_OUTP(MDP_BASE + 0x5035c, 0x28800032); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac000c5); + MDP_OUTP(MDP_BASE + 0x50360, 0x2800002f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc000c7); + MDP_OUTP(MDP_BASE + 0x50364, 0x2740002c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc000c8); + MDP_OUTP(MDP_BASE + 0x50368, 0x26c00029); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc000c9); + MDP_OUTP(MDP_BASE + 0x5036c, 0x26000027); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec000cc); + MDP_OUTP(MDP_BASE + 0x50370, 0x25000024); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x200000cc); + MDP_OUTP(MDP_BASE + 0x50374, 0x24800021); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x210000cd); + MDP_OUTP(MDP_BASE + 0x50378, 0x23800020); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x220000ce); + MDP_OUTP(MDP_BASE + 0x5037c, 0x2300001d); +} + +static void mdp_load_bc_downscale_table_x_point6TOpoint8(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000070); + MDP_OUTP(MDP_BASE + 0x50280, 0x4bc00068); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000078); + MDP_OUTP(MDP_BASE + 0x50284, 0x4bc00060); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000080); + MDP_OUTP(MDP_BASE + 0x50288, 0x4b800059); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000089); + MDP_OUTP(MDP_BASE + 0x5028c, 0x4b000052); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe400091); + MDP_OUTP(MDP_BASE + 0x50290, 0x4a80004b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40009a); + MDP_OUTP(MDP_BASE + 0x50294, 0x4a000044); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe8000a3); + MDP_OUTP(MDP_BASE + 0x50298, 0x4940003d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec000ac); + MDP_OUTP(MDP_BASE + 0x5029c, 0x48400037); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff0000b4); + MDP_OUTP(MDP_BASE + 0x502a0, 0x47800031); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff8000bd); + MDP_OUTP(MDP_BASE + 0x502a4, 0x4640002b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc5); + MDP_OUTP(MDP_BASE + 0x502a8, 0x45000026); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x8000ce); + MDP_OUTP(MDP_BASE + 0x502ac, 0x43800021); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x10000d6); + MDP_OUTP(MDP_BASE + 0x502b0, 0x4240001c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x18000df); + MDP_OUTP(MDP_BASE + 0x502b4, 0x40800018); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x24000e6); + MDP_OUTP(MDP_BASE + 0x502b8, 0x3f000014); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x30000ee); + MDP_OUTP(MDP_BASE + 0x502bc, 0x3d400010); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x40000f5); + MDP_OUTP(MDP_BASE + 0x502c0, 0x3b80000c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x50000fc); + MDP_OUTP(MDP_BASE + 0x502c4, 0x39800009); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x6000102); + MDP_OUTP(MDP_BASE + 0x502c8, 0x37c00006); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x7000109); + MDP_OUTP(MDP_BASE + 0x502cc, 0x35800004); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x840010e); + MDP_OUTP(MDP_BASE + 0x502d0, 0x33800002); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9800114); + MDP_OUTP(MDP_BASE + 0x502d4, 0x31400000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xac00119); + MDP_OUTP(MDP_BASE + 0x502d8, 0x2f4003fe); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc40011e); + MDP_OUTP(MDP_BASE + 0x502dc, 0x2d0003fc); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xdc00121); + MDP_OUTP(MDP_BASE + 0x502e0, 0x2b0003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf400125); + MDP_OUTP(MDP_BASE + 0x502e4, 0x28c003fa); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x11000128); + MDP_OUTP(MDP_BASE + 0x502e8, 0x268003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x12c0012a); + MDP_OUTP(MDP_BASE + 0x502ec, 0x244003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1480012c); + MDP_OUTP(MDP_BASE + 0x502f0, 0x224003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1640012e); + MDP_OUTP(MDP_BASE + 0x502f4, 0x200003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1800012f); + MDP_OUTP(MDP_BASE + 0x502f8, 0x1e0003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1a00012f); + MDP_OUTP(MDP_BASE + 0x502fc, 0x1c0003f8); +} + +static void mdp_load_bc_downscale_table_y_point6TOpoint8(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000070); + MDP_OUTP(MDP_BASE + 0x50300, 0x4bc00068); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000078); + MDP_OUTP(MDP_BASE + 0x50304, 0x4bc00060); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000080); + MDP_OUTP(MDP_BASE + 0x50308, 0x4b800059); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000089); + MDP_OUTP(MDP_BASE + 0x5030c, 0x4b000052); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe400091); + MDP_OUTP(MDP_BASE + 0x50310, 0x4a80004b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40009a); + MDP_OUTP(MDP_BASE + 0x50314, 0x4a000044); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe8000a3); + MDP_OUTP(MDP_BASE + 0x50318, 0x4940003d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec000ac); + MDP_OUTP(MDP_BASE + 0x5031c, 0x48400037); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff0000b4); + MDP_OUTP(MDP_BASE + 0x50320, 0x47800031); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff8000bd); + MDP_OUTP(MDP_BASE + 0x50324, 0x4640002b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc5); + MDP_OUTP(MDP_BASE + 0x50328, 0x45000026); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x8000ce); + MDP_OUTP(MDP_BASE + 0x5032c, 0x43800021); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x10000d6); + MDP_OUTP(MDP_BASE + 0x50330, 0x4240001c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x18000df); + MDP_OUTP(MDP_BASE + 0x50334, 0x40800018); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x24000e6); + MDP_OUTP(MDP_BASE + 0x50338, 0x3f000014); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x30000ee); + MDP_OUTP(MDP_BASE + 0x5033c, 0x3d400010); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x40000f5); + MDP_OUTP(MDP_BASE + 0x50340, 0x3b80000c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x50000fc); + MDP_OUTP(MDP_BASE + 0x50344, 0x39800009); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x6000102); + MDP_OUTP(MDP_BASE + 0x50348, 0x37c00006); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x7000109); + MDP_OUTP(MDP_BASE + 0x5034c, 0x35800004); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x840010e); + MDP_OUTP(MDP_BASE + 0x50350, 0x33800002); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9800114); + MDP_OUTP(MDP_BASE + 0x50354, 0x31400000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xac00119); + MDP_OUTP(MDP_BASE + 0x50358, 0x2f4003fe); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc40011e); + MDP_OUTP(MDP_BASE + 0x5035c, 0x2d0003fc); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xdc00121); + MDP_OUTP(MDP_BASE + 0x50360, 0x2b0003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf400125); + MDP_OUTP(MDP_BASE + 0x50364, 0x28c003fa); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x11000128); + MDP_OUTP(MDP_BASE + 0x50368, 0x268003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x12c0012a); + MDP_OUTP(MDP_BASE + 0x5036c, 0x244003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1480012c); + MDP_OUTP(MDP_BASE + 0x50370, 0x224003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1640012e); + MDP_OUTP(MDP_BASE + 0x50374, 0x200003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1800012f); + MDP_OUTP(MDP_BASE + 0x50378, 0x1e0003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1a00012f); + MDP_OUTP(MDP_BASE + 0x5037c, 0x1c0003f8); +} + +static void mdp_load_bc_downscale_table_x_point8TO1(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff80000d); + MDP_OUTP(MDP_BASE + 0x50284, 0x7ec003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec0001c); + MDP_OUTP(MDP_BASE + 0x50288, 0x7d4003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40002b); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7b8003ed); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfd80003c); + MDP_OUTP(MDP_BASE + 0x50290, 0x794003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc0004d); + MDP_OUTP(MDP_BASE + 0x50294, 0x76c003e4); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfc40005f); + MDP_OUTP(MDP_BASE + 0x50298, 0x73c003e0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb800071); + MDP_OUTP(MDP_BASE + 0x5029c, 0x708003de); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfac00085); + MDP_OUTP(MDP_BASE + 0x502a0, 0x6d0003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa000098); + MDP_OUTP(MDP_BASE + 0x502a4, 0x698003d9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf98000ac); + MDP_OUTP(MDP_BASE + 0x502a8, 0x654003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8c000c1); + MDP_OUTP(MDP_BASE + 0x502ac, 0x610003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf84000d5); + MDP_OUTP(MDP_BASE + 0x502b0, 0x5c8003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf7c000e9); + MDP_OUTP(MDP_BASE + 0x502b4, 0x580003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf74000fd); + MDP_OUTP(MDP_BASE + 0x502b8, 0x534003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c00112); + MDP_OUTP(MDP_BASE + 0x502bc, 0x4e8003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6800126); + MDP_OUTP(MDP_BASE + 0x502c0, 0x494003da); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600013a); + MDP_OUTP(MDP_BASE + 0x502c4, 0x448003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600014d); + MDP_OUTP(MDP_BASE + 0x502c8, 0x3f4003dd); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00160); + MDP_OUTP(MDP_BASE + 0x502cc, 0x3a4003df); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00172); + MDP_OUTP(MDP_BASE + 0x502d0, 0x354003e1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00184); + MDP_OUTP(MDP_BASE + 0x502d4, 0x304003e3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6000195); + MDP_OUTP(MDP_BASE + 0x502d8, 0x2b0003e6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf64001a6); + MDP_OUTP(MDP_BASE + 0x502dc, 0x260003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c001b4); + MDP_OUTP(MDP_BASE + 0x502e0, 0x214003eb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf78001c2); + MDP_OUTP(MDP_BASE + 0x502e4, 0x1c4003ee); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf80001cf); + MDP_OUTP(MDP_BASE + 0x502e8, 0x17c003f1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf90001db); + MDP_OUTP(MDP_BASE + 0x502ec, 0x134003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa0001e5); + MDP_OUTP(MDP_BASE + 0x502f0, 0xf0003f6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb4001ee); + MDP_OUTP(MDP_BASE + 0x502f4, 0xac003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc001f5); + MDP_OUTP(MDP_BASE + 0x502f8, 0x70003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe4001fb); + MDP_OUTP(MDP_BASE + 0x502fc, 0x34003fe); +} + +static void mdp_load_bc_downscale_table_y_point8TO1(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff80000d); + MDP_OUTP(MDP_BASE + 0x50304, 0x7ec003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec0001c); + MDP_OUTP(MDP_BASE + 0x50308, 0x7d4003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40002b); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7b8003ed); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfd80003c); + MDP_OUTP(MDP_BASE + 0x50310, 0x794003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc0004d); + MDP_OUTP(MDP_BASE + 0x50314, 0x76c003e4); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfc40005f); + MDP_OUTP(MDP_BASE + 0x50318, 0x73c003e0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb800071); + MDP_OUTP(MDP_BASE + 0x5031c, 0x708003de); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfac00085); + MDP_OUTP(MDP_BASE + 0x50320, 0x6d0003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa000098); + MDP_OUTP(MDP_BASE + 0x50324, 0x698003d9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf98000ac); + MDP_OUTP(MDP_BASE + 0x50328, 0x654003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8c000c1); + MDP_OUTP(MDP_BASE + 0x5032c, 0x610003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf84000d5); + MDP_OUTP(MDP_BASE + 0x50330, 0x5c8003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf7c000e9); + MDP_OUTP(MDP_BASE + 0x50334, 0x580003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf74000fd); + MDP_OUTP(MDP_BASE + 0x50338, 0x534003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c00112); + MDP_OUTP(MDP_BASE + 0x5033c, 0x4e8003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6800126); + MDP_OUTP(MDP_BASE + 0x50340, 0x494003da); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600013a); + MDP_OUTP(MDP_BASE + 0x50344, 0x448003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600014d); + MDP_OUTP(MDP_BASE + 0x50348, 0x3f4003dd); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00160); + MDP_OUTP(MDP_BASE + 0x5034c, 0x3a4003df); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00172); + MDP_OUTP(MDP_BASE + 0x50350, 0x354003e1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00184); + MDP_OUTP(MDP_BASE + 0x50354, 0x304003e3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6000195); + MDP_OUTP(MDP_BASE + 0x50358, 0x2b0003e6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf64001a6); + MDP_OUTP(MDP_BASE + 0x5035c, 0x260003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c001b4); + MDP_OUTP(MDP_BASE + 0x50360, 0x214003eb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf78001c2); + MDP_OUTP(MDP_BASE + 0x50364, 0x1c4003ee); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf80001cf); + MDP_OUTP(MDP_BASE + 0x50368, 0x17c003f1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf90001db); + MDP_OUTP(MDP_BASE + 0x5036c, 0x134003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa0001e5); + MDP_OUTP(MDP_BASE + 0x50370, 0xf0003f6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb4001ee); + MDP_OUTP(MDP_BASE + 0x50374, 0xac003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc001f5); + MDP_OUTP(MDP_BASE + 0x50378, 0x70003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe4001fb); + MDP_OUTP(MDP_BASE + 0x5037c, 0x34003fe); +} + +static int mdp_get_edge_cond(MDPIBUF *iBuf, uint32 *dup, uint32 *dup2) +{ + uint32 reg; + uint32 dst_roi_width; /* Dimensions of DST ROI. */ + uint32 dst_roi_height; /* Used to calculate scaling ratios. */ + + /* + * positions of the luma pixel(relative to the image ) required for + * scaling the ROI + */ + int32 luma_interp_point_left = 0; /* left-most luma pixel needed */ + int32 luma_interp_point_right = 0; /* right-most luma pixel needed */ + int32 luma_interp_point_top = 0; /* top-most luma pixel needed */ + int32 luma_interp_point_bottom = 0; /* bottom-most luma pixel needed */ + + /* + * positions of the chroma pixel(relative to the image ) required for + * interpolating a chroma value at all required luma positions + */ + /* left-most chroma pixel needed */ + int32 chroma_interp_point_left = 0; + /* right-most chroma pixel needed */ + int32 chroma_interp_point_right = 0; + /* top-most chroma pixel needed */ + int32 chroma_interp_point_top = 0; + /* bottom-most chroma pixel needed */ + int32 chroma_interp_point_bottom = 0; + + /* + * a rectangular region within the chroma plane of the "image". + * Chroma pixels falling inside of this rectangle belongs to the ROI + */ + int32 chroma_bound_left = 0; + int32 chroma_bound_right = 0; + int32 chroma_bound_top = 0; + int32 chroma_bound_bottom = 0; + + /* + * number of chroma pixels to replicate on the left, right, + * top and bottom edge of the ROI. + */ + int32 chroma_repeat_left = 0; + int32 chroma_repeat_right = 0; + int32 chroma_repeat_top = 0; + int32 chroma_repeat_bottom = 0; + + /* + * number of luma pixels to replicate on the left, right, + * top and bottom edge of the ROI. + */ + int32 luma_repeat_left = 0; + int32 luma_repeat_right = 0; + int32 luma_repeat_top = 0; + int32 luma_repeat_bottom = 0; + + boolean chroma_edge_enable; + + uint32 _is_scale_enabled = 0; + uint32 _is_yuv_offsite_vertical = 0; + + /* fg edge duplicate */ + reg = 0x0; + + if (iBuf->mdpImg.mdpOp & MDPOP_ASCALE) { /* if scaling enabled */ + + _is_scale_enabled = 1; + + /* + * if rotation mode involves a 90 deg rotation, flip + * dst_roi_width with dst_roi_height. + * Scaling ratios is based on source ROI dimensions, and + * dst ROI dimensions before rotation. + */ + if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) { + dst_roi_width = iBuf->roi.dst_height; + dst_roi_height = iBuf->roi.dst_width; + } else { + dst_roi_width = iBuf->roi.dst_width; + dst_roi_height = iBuf->roi.dst_height; + } + + /* + * Find out the luma pixels needed for scaling in the + * x direction (LEFT and RIGHT). Locations of pixels are + * relative to the ROI. Upper-left corner of ROI corresponds + * to coordinates (0,0). Also set the number of luma pixel + * to repeat. + */ + if (iBuf->roi.width > 3 * dst_roi_width) { + /* scale factor < 1/3 */ + luma_interp_point_left = 0; + luma_interp_point_right = (iBuf->roi.width - 1); + luma_repeat_left = 0; + luma_repeat_right = 0; + } else if (iBuf->roi.width == 3 * dst_roi_width) { + /* scale factor == 1/3 */ + luma_interp_point_left = 0; + luma_interp_point_right = (iBuf->roi.width - 1) + 1; + luma_repeat_left = 0; + luma_repeat_right = 1; + } else if ((iBuf->roi.width > dst_roi_width) && + (iBuf->roi.width < 3 * dst_roi_width)) { + /* 1/3 < scale factor < 1 */ + luma_interp_point_left = -1; + luma_interp_point_right = (iBuf->roi.width - 1) + 1; + luma_repeat_left = 1; + luma_repeat_right = 1; + } + + else if (iBuf->roi.width == dst_roi_width) { + /* scale factor == 1 */ + luma_interp_point_left = -1; + luma_interp_point_right = (iBuf->roi.width - 1) + 2; + luma_repeat_left = 1; + luma_repeat_right = 2; + } else { /* (iBuf->roi.width < dst_roi_width) */ + /* scale factor > 1 */ + luma_interp_point_left = -2; + luma_interp_point_right = (iBuf->roi.width - 1) + 2; + luma_repeat_left = 2; + luma_repeat_right = 2; + } + + /* + * Find out the number of pixels needed for scaling in the + * y direction (TOP and BOTTOM). Locations of pixels are + * relative to the ROI. Upper-left corner of ROI corresponds + * to coordinates (0,0). Also set the number of luma pixel + * to repeat. + */ + if (iBuf->roi.height > 3 * dst_roi_height) { + /* scale factor < 1/3 */ + luma_interp_point_top = 0; + luma_interp_point_bottom = (iBuf->roi.height - 1); + luma_repeat_top = 0; + luma_repeat_bottom = 0; + } else if (iBuf->roi.height == 3 * dst_roi_height) { + /* scale factor == 1/3 */ + luma_interp_point_top = 0; + luma_interp_point_bottom = (iBuf->roi.height - 1) + 1; + luma_repeat_top = 0; + luma_repeat_bottom = 1; + } else if ((iBuf->roi.height > dst_roi_height) && + (iBuf->roi.height < 3 * dst_roi_height)) { + /* 1/3 < scale factor < 1 */ + luma_interp_point_top = -1; + luma_interp_point_bottom = (iBuf->roi.height - 1) + 1; + luma_repeat_top = 1; + luma_repeat_bottom = 1; + } else if (iBuf->roi.height == dst_roi_height) { + /* scale factor == 1 */ + luma_interp_point_top = -1; + luma_interp_point_bottom = (iBuf->roi.height - 1) + 2; + luma_repeat_top = 1; + luma_repeat_bottom = 2; + } else { /* (iBuf->roi.height < dst_roi_height) */ + /* scale factor > 1 */ + luma_interp_point_top = -2; + luma_interp_point_bottom = (iBuf->roi.height - 1) + 2; + luma_repeat_top = 2; + luma_repeat_bottom = 2; + } + } /* if (iBuf->scale.scale_flag) */ + else { /* scaling disabled */ + /* + * Since no scaling needed, Tile Fetch does not require any + * more luma pixel than what the ROI contains. + */ + luma_interp_point_left = (int32) 0; + luma_interp_point_right = (int32) (iBuf->roi.width - 1); + luma_interp_point_top = (int32) 0; + luma_interp_point_bottom = (int32) (iBuf->roi.height - 1); + + luma_repeat_left = 0; + luma_repeat_right = 0; + luma_repeat_top = 0; + luma_repeat_bottom = 0; + } + + /* After adding the ROI offsets, we have locations of + * luma_interp_points relative to the image. + */ + luma_interp_point_left += (int32) (iBuf->roi.x); + luma_interp_point_right += (int32) (iBuf->roi.x); + luma_interp_point_top += (int32) (iBuf->roi.y); + luma_interp_point_bottom += (int32) (iBuf->roi.y); + + /* + * After adding the ROI offsets, we have locations of + * chroma_interp_points relative to the image. + */ + chroma_interp_point_left = luma_interp_point_left; + chroma_interp_point_right = luma_interp_point_right; + chroma_interp_point_top = luma_interp_point_top; + chroma_interp_point_bottom = luma_interp_point_bottom; + + chroma_edge_enable = TRUE; + /* find out which chroma pixels are needed for chroma upsampling. */ + switch (iBuf->mdpImg.imgType) { + /* + * cosite in horizontal axis + * fully sampled in vertical axis + */ + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + /* floor( luma_interp_point_left / 2 ); */ + chroma_interp_point_left = luma_interp_point_left >> 1; + /* floor( ( luma_interp_point_right + 1 ) / 2 ); */ + chroma_interp_point_right = (luma_interp_point_right + 1) >> 1; + + chroma_interp_point_top = luma_interp_point_top; + chroma_interp_point_bottom = luma_interp_point_bottom; + break; + + /* + * cosite in horizontal axis + * offsite in vertical axis + */ + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + /* floor( luma_interp_point_left / 2) */ + chroma_interp_point_left = luma_interp_point_left >> 1; + + /* floor( ( luma_interp_point_right + 1 )/ 2 ) */ + chroma_interp_point_right = (luma_interp_point_right + 1) >> 1; + + /* floor( (luma_interp_point_top - 1 ) / 2 ) */ + chroma_interp_point_top = (luma_interp_point_top - 1) >> 1; + + /* floor( ( luma_interp_point_bottom + 1 ) / 2 ) */ + chroma_interp_point_bottom = + (luma_interp_point_bottom + 1) >> 1; + + _is_yuv_offsite_vertical = 1; + break; + + default: + chroma_edge_enable = FALSE; + chroma_interp_point_left = luma_interp_point_left; + chroma_interp_point_right = luma_interp_point_right; + chroma_interp_point_top = luma_interp_point_top; + chroma_interp_point_bottom = luma_interp_point_bottom; + + break; + } + + /* only if the image type is in YUV domain, we calculate chroma edge */ + if (chroma_edge_enable) { + /* Defines which chroma pixels belongs to the roi */ + switch (iBuf->mdpImg.imgType) { + /* + * Cosite in horizontal direction, and fully sampled + * in vertical direction. + */ + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + /* + * width of chroma ROI is 1/2 of size of luma ROI + * height of chroma ROI same as size of luma ROI + */ + chroma_bound_left = iBuf->roi.x / 2; + + /* there are half as many chroma pixel as luma pixels */ + chroma_bound_right = + (iBuf->roi.width + iBuf->roi.x - 1) / 2; + chroma_bound_top = iBuf->roi.y; + chroma_bound_bottom = + (iBuf->roi.height + iBuf->roi.y - 1); + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + /* + * cosite in horizontal dir, and offsite in vertical dir + * width of chroma ROI is 1/2 of size of luma ROI + * height of chroma ROI is 1/2 of size of luma ROI + */ + + chroma_bound_left = iBuf->roi.x / 2; + chroma_bound_right = + (iBuf->roi.width + iBuf->roi.x - 1) / 2; + chroma_bound_top = iBuf->roi.y / 2; + chroma_bound_bottom = + (iBuf->roi.height + iBuf->roi.y - 1) / 2; + break; + + default: + /* + * If no valid chroma sub-sampling format specified, + * assume 4:4:4 ( i.e. fully sampled). Set ROI + * boundaries for chroma same as ROI boundaries for + * luma. + */ + chroma_bound_left = iBuf->roi.x; + chroma_bound_right = iBuf->roi.width + iBuf->roi.x - 1; + chroma_bound_top = iBuf->roi.y; + chroma_bound_bottom = + (iBuf->roi.height + iBuf->roi.y - 1); + break; + } + + /* + * Knowing which chroma pixels are needed, and which chroma + * pixels belong to the ROI (i.e. available for fetching ), + * calculate how many chroma pixels Tile Fetch needs to + * duplicate. If any required chroma pixels falls outside + * of the ROI, Tile Fetch must obtain them by replicating + * pixels. + */ + if (chroma_bound_left > chroma_interp_point_left) + chroma_repeat_left = + chroma_bound_left - chroma_interp_point_left; + else + chroma_repeat_left = 0; + + if (chroma_interp_point_right > chroma_bound_right) + chroma_repeat_right = + chroma_interp_point_right - chroma_bound_right; + else + chroma_repeat_right = 0; + + if (chroma_bound_top > chroma_interp_point_top) + chroma_repeat_top = + chroma_bound_top - chroma_interp_point_top; + else + chroma_repeat_top = 0; + + if (chroma_interp_point_bottom > chroma_bound_bottom) + chroma_repeat_bottom = + chroma_interp_point_bottom - chroma_bound_bottom; + else + chroma_repeat_bottom = 0; + + if (_is_scale_enabled && (iBuf->roi.height == 1) + && _is_yuv_offsite_vertical) { + chroma_repeat_bottom = 3; + chroma_repeat_top = 0; + } + } + /* make sure chroma repeats are non-negative */ + if ((chroma_repeat_left < 0) || (chroma_repeat_right < 0) || + (chroma_repeat_top < 0) || (chroma_repeat_bottom < 0)) + return -1; + + /* make sure chroma repeats are no larger than 3 pixels */ + if ((chroma_repeat_left > 3) || (chroma_repeat_right > 3) || + (chroma_repeat_top > 3) || (chroma_repeat_bottom > 3)) + return -1; + + /* make sure luma repeats are non-negative */ + if ((luma_repeat_left < 0) || (luma_repeat_right < 0) || + (luma_repeat_top < 0) || (luma_repeat_bottom < 0)) + return -1; + + /* make sure luma repeats are no larger than 3 pixels */ + if ((luma_repeat_left > 3) || (luma_repeat_right > 3) || + (luma_repeat_top > 3) || (luma_repeat_bottom > 3)) + return -1; + + /* write chroma_repeat_left to register */ + reg |= (chroma_repeat_left & 3) << MDP_LEFT_CHROMA; + + /* write chroma_repeat_right to register */ + reg |= (chroma_repeat_right & 3) << MDP_RIGHT_CHROMA; + + /* write chroma_repeat_top to register */ + reg |= (chroma_repeat_top & 3) << MDP_TOP_CHROMA; + + /* write chroma_repeat_bottom to register */ + reg |= (chroma_repeat_bottom & 3) << MDP_BOTTOM_CHROMA; + + /* write luma_repeat_left to register */ + reg |= (luma_repeat_left & 3) << MDP_LEFT_LUMA; + + /* write luma_repeat_right to register */ + reg |= (luma_repeat_right & 3) << MDP_RIGHT_LUMA; + + /* write luma_repeat_top to register */ + reg |= (luma_repeat_top & 3) << MDP_TOP_LUMA; + + /* write luma_repeat_bottom to register */ + reg |= (luma_repeat_bottom & 3) << MDP_BOTTOM_LUMA; + + /* done with reg */ + *dup = reg; + + /* bg edge duplicate */ + reg = 0x0; + + switch (iBuf->ibuf_type) { + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + /* + * Edge condition for MDP_Y_CRCB/CBCR_H2V2 cosite only. + * For 420 cosite, 1 chroma replicated on all sides except + * left, so reg 101b8 should be 0x0209. For 420 offsite, + * 1 chroma replicated all sides. + */ + if (iBuf->roi.lcd_y == 0) { + reg |= BIT(MDP_TOP_CHROMA); + } + + if ((iBuf->roi.lcd_y + iBuf->roi.dst_height) == + iBuf->ibuf_height) { + reg |= BIT(MDP_BOTTOM_CHROMA); + } + + if (((iBuf->roi.lcd_x + iBuf->roi.dst_width) == + iBuf->ibuf_width) && ((iBuf->roi.dst_width % 2) == 0)) { + reg |= BIT(MDP_RIGHT_CHROMA); + } + + break; + + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + if (((iBuf->roi.lcd_x + iBuf->roi.dst_width) == + iBuf->ibuf_width) && ((iBuf->roi.dst_width % 2) == 0)) { + reg |= BIT(MDP_RIGHT_CHROMA); + } + break; + default: + break; + } + + *dup2 = reg; + + return 0; +} + +#define ADJUST_IP /* for 1/3 scale factor fix */ + +static int mdp_calc_scale_params( +/* ROI origin coordinate for the dimension */ + uint32 org, +/* src ROI dimension */ + uint32 dim_in, +/* scaled ROI dimension*/ + uint32 dim_out, +/* is this ROI width dimension? */ + boolean is_W, +/* initial phase location address */ + int32 *phase_init_ptr, +/* phase increment location address */ + uint32 *phase_step_ptr, +/* ROI start over-fetch location address */ + uint32 *num_repl_beg_ptr, +/* ROI end over-fetch location address */ + uint32 *num_repl_end_ptr) +{ + boolean rpa_on = FALSE; + int init_phase = 0; + uint32 beg_of = 0; + uint32 end_of = 0; + uint64 numer = 0; + uint64 denom = 0; + /*uint64 inverter = 1; */ + int64 point5 = 1; + int64 one = 1; + int64 k1, k2, k3, k4; /* linear equation coefficients */ + uint64 int_mask; + uint64 fract_mask; + uint64 Os; + int64 Osprime; + int64 Od; + int64 Odprime; + int64 Oreq; + uint64 Es; + uint64 Ed; + uint64 Ereq; +#ifdef ADJUST_IP + int64 IP64; + int64 delta; +#endif + uint32 mult; + + /* + * The phase accumulator should really be rational for all cases in a + * general purpose polyphase scaler for a tiled architecture with + * non-zero * origin capability because there is no way to represent + * certain scale factors in fixed point regardless of precision. + * The error incurred in attempting to use fixed point is most + * eggregious for SF where 1/SF is an integral multiple of 1/3. + * + * However, since the MDP2 has already been committed to HW, we + * only use the rational phase accumulator (RPA) when 1/SF is an + * integral multiple of 1/3. This will help minimize regressions in + * matching the HW to the C-Sim. + */ + /* + * Set the RPA flag for this dimension. + * + * In order for 1/SF (dim_in/dim_out) to be an integral multiple of + * 1/3, dim_out must be an integral multiple of 3. + */ + if (!(dim_out % 3)) { + mult = dim_out / 3; + rpa_on = (!(dim_in % mult)); + } + + numer = dim_out; + denom = dim_in; + + /* + * convert to U30.34 before division + * + * The K vectors carry 4 extra bits of precision + * and are rounded. + * + * We initially go 5 bits over then round by adding + * 1 and right shifting by 1 + * so final result is U31.33 + */ + numer <<= PQF_PLUS_5; + + /* now calculate the scale factor (aka k3) */ + k3 = ((mdp_do_div(numer, denom) + 1) >> 1); + + /* check scale factor for legal range [0.25 - 4.0] */ + if (((k3 >> 4) < (1LL << PQF_MINUS_2)) || + ((k3 >> 4) > (1LL << PQF_PLUS_2))) { + return -1; + } + + /* calculate inverse scale factor (aka k1) for phase init */ + numer = dim_in; + denom = dim_out; + numer <<= PQF_PLUS_5; + k1 = ((mdp_do_div(numer, denom) + 1) >> 1); + + /* + * calculate initial phase and ROI overfetch + */ + /* convert point5 & one to S39.24 (will always be positive) */ + point5 <<= (PQF_PLUS_4 - 1); + one <<= PQF_PLUS_4; + k2 = ((k1 - one) >> 1); + init_phase = (int)(k2 >> 4); + k4 = ((k3 - one) >> 1); + if (k3 == one) { + /* the simple case; SF = 1.0 */ + beg_of = 1; + end_of = 2; + } else { + /* calculate the masks */ + fract_mask = one - 1; + int_mask = ~fract_mask; + + if (!rpa_on) { + /* + * FIXED POINT IMPLEMENTATION + */ + if (!org) { + /* A fairly simple case; ROI origin = 0 */ + if (k1 < one) { + /* upscaling */ + beg_of = end_of = 2; + } + /* 0.33 <= SF < 1.0 */ + else if (k1 < (3LL << PQF_PLUS_4)) + beg_of = end_of = 1; + /* 0.33 == SF */ + else if (k1 == (3LL << PQF_PLUS_4)) { + beg_of = 0; + end_of = 1; + } + /* 0.25 <= SF < 0.33 */ + else + beg_of = end_of = 0; + } else { + /* + * The complicated case; ROI origin != 0 + * init_phase needs to be adjusted + * OF is also position dependent + */ + + /* map (org - .5) into destination space */ + Os = ((uint64) org << 1) - 1; + Od = ((k3 * Os) >> 1) + k4; + + /* take the ceiling */ + Odprime = (Od & int_mask); + if (Odprime != Od) + Odprime += one; + + /* now map that back to source space */ + Osprime = (k1 * (Odprime >> PQF_PLUS_4)) + k2; + + /* then floor & decrement to calculate the required + starting coordinate */ + Oreq = (Osprime & int_mask) - one; + + /* calculate end coord in destination space then map to + source space */ + Ed = Odprime + + ((uint64) dim_out << PQF_PLUS_4) - one; + Es = (k1 * (Ed >> PQF_PLUS_4)) + k2; + + /* now floor & increment by 2 to calculate the required + ending coordinate */ + Ereq = (Es & int_mask) + (one << 1); + + /* calculate initial phase */ +#ifdef ADJUST_IP + + IP64 = Osprime - Oreq; + delta = ((int64) (org) << PQF_PLUS_4) - Oreq; + IP64 -= delta; + + /* limit to valid range before the left shift */ + delta = (IP64 & (1LL << 63)) ? 4 : -4; + delta <<= PQF_PLUS_4; + while (abs((int)(IP64 >> PQF_PLUS_4)) > 4) + IP64 += delta; + + /* right shift to account for extra bits of precision */ + init_phase = (int)(IP64 >> 4); + +#else /* ADJUST_IP */ + + /* just calculate the real initial phase */ + init_phase = (int)((Osprime - Oreq) >> 4); + +#endif /* ADJUST_IP */ + + /* calculate the overfetch */ + beg_of = org - (uint32) (Oreq >> PQF_PLUS_4); + end_of = + (uint32) (Ereq >> PQF_PLUS_4) - (org + + dim_in - + 1); + } + } else { + /* + * RPA IMPLEMENTATION + * + * init_phase needs to be calculated in all RPA_on cases + * because it's a numerator, not a fixed point value. + */ + + /* map (org - .5) into destination space */ + Os = ((uint64) org << PQF_PLUS_4) - point5; + Od = mdp_do_div((dim_out * (Os + point5)), + dim_in) - point5; + + /* take the ceiling */ + Odprime = (Od & int_mask); + if (Odprime != Od) + Odprime += one; + + /* now map that back to source space */ + Osprime = + mdp_do_div((dim_in * (Odprime + point5)), + dim_out) - point5; + + /* then floor & decrement to calculate the required + starting coordinate */ + Oreq = (Osprime & int_mask) - one; + + /* calculate end coord in destination space then map to + source space */ + Ed = Odprime + ((uint64) dim_out << PQF_PLUS_4) - one; + Es = mdp_do_div((dim_in * (Ed + point5)), + dim_out) - point5; + + /* now floor & increment by 2 to calculate the required + ending coordinate */ + Ereq = (Es & int_mask) + (one << 1); + + /* calculate initial phase */ + +#ifdef ADJUST_IP + + IP64 = Osprime - Oreq; + delta = ((int64) (org) << PQF_PLUS_4) - Oreq; + IP64 -= delta; + + /* limit to valid range before the left shift */ + delta = (IP64 & (1LL << 63)) ? 4 : -4; + delta <<= PQF_PLUS_4; + while (abs((int)(IP64 >> PQF_PLUS_4)) > 4) + IP64 += delta; + + /* right shift to account for extra bits of precision */ + init_phase = (int)(IP64 >> 4); + +#else /* ADJUST_IP */ + + /* just calculate the real initial phase */ + init_phase = (int)((Osprime - Oreq) >> 4); + +#endif /* ADJUST_IP */ + + /* calculate the overfetch */ + beg_of = org - (uint32) (Oreq >> PQF_PLUS_4); + end_of = + (uint32) (Ereq >> PQF_PLUS_4) - (org + dim_in - 1); + } + } + + /* return the scale parameters */ + *phase_init_ptr = init_phase; + *phase_step_ptr = (uint32) (k1 >> 4); + *num_repl_beg_ptr = beg_of; + *num_repl_end_ptr = end_of; + + return 0; +} + +static uint8 *mdp_adjust_rot_addr(MDPIBUF *iBuf, uint8 *addr, uint32 uv) +{ + uint32 dest_ystride = iBuf->ibuf_width * iBuf->bpp; + uint32 h_slice = 1; + + if (uv && ((iBuf->ibuf_type == MDP_Y_CBCR_H2V2) || + (iBuf->ibuf_type == MDP_Y_CRCB_H2V2))) + h_slice = 2; + + if (MDP_CHKBIT(iBuf->mdpImg.mdpOp, MDPOP_ROT90) ^ + MDP_CHKBIT(iBuf->mdpImg.mdpOp, MDPOP_LR)) { + addr = + addr + (iBuf->roi.dst_width - + MIN(16, iBuf->roi.dst_width)) * iBuf->bpp; + } + if (MDP_CHKBIT(iBuf->mdpImg.mdpOp, MDPOP_UD)) { + addr = + addr + ((iBuf->roi.dst_height - + MIN(16, iBuf->roi.dst_height))/h_slice) * dest_ystride; + } + + return addr; +} + +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; + boolean use_pr; + uint32 phasex_step = 0; + uint32 phasey_step = 0; + int32 phasex_init = 0; + int32 phasey_init = 0; + uint32 lines_dup = 0; + uint32 lines_dup_bg = 0; + uint32 dummy; + uint32 mdp_blur = 0; + + 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; + } + + mdp_blur = iBuf->mdpImg.mdpOp & MDPOP_BLUR; + + if ((dst_roi_width_scale != iBuf->roi.width) || + (dst_roi_height_scale != iBuf->roi.height) || + mdp_blur) { + *pppop_reg_ptr |= + (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON); + + /* let's use SHIM logic to calculate the partial ROI scaling */ +#if 0 + phasex_step = + (uint32) mdp_do_div(0x20000000 * iBuf->roi.width, + dst_roi_width_scale); + phasey_step = + (uint32) mdp_do_div(0x20000000 * iBuf->roi.height, + dst_roi_height_scale); + +/* + phasex_step= ((long long) iBuf->roi.width * 0x20000000)/dst_roi_width_scale; + phasey_step= ((long long)iBuf->roi.height * 0x20000000)/dst_roi_height_scale; +*/ + + phasex_init = + (((long long)phasex_step - 0x20000000) >> 1); + phasey_init = + (((long long)phasey_step - 0x20000000) >> 1); + +#else + mdp_calc_scale_params(iBuf->roi.x, iBuf->roi.width, + dst_roi_width_scale, 1, + &phasex_init, &phasex_step, + &dummy, &dummy); + mdp_calc_scale_params(iBuf->roi.y, iBuf->roi.height, + dst_roi_height_scale, 0, + &phasey_init, &phasey_step, + &dummy, &dummy); +#endif + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x013c, + phasex_init); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0140, + phasey_init); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0144, + phasex_step); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0148, + phasey_step); + + use_pr = (inputRGB) && (outputRGB); + + if ((dst_roi_width_scale > iBuf->roi.width) || + (dst_roi_height_scale > iBuf->roi.height)) { + if ((use_pr) + && (mdp_curr_up_scale_xy != + MDP_PR_SCALE_UP)) { + mdp_load_pr_upscale_table(); + mdp_curr_up_scale_xy = MDP_PR_SCALE_UP; + } else if ((!use_pr) + && (mdp_curr_up_scale_xy != + MDP_BC_SCALE_UP)) { + mdp_load_bc_upscale_table(); + mdp_curr_up_scale_xy = MDP_BC_SCALE_UP; + } + } + + if (mdp_blur) { + load_scale_table(mdp_gaussian_blur_table, + ARRAY_SIZE(mdp_gaussian_blur_table)); + mdp_curr_down_scale_x = MDP_SCALE_BLUR; + mdp_curr_down_scale_y = MDP_SCALE_BLUR; + } + + /* 0.2 < x <= 1 scaling factor */ + if ((dst_roi_width_scale <= iBuf->roi.width) && + !mdp_blur) { + if (((dst_roi_width_scale * 10) / + iBuf->roi.width) > 8) { + if ((use_pr) + && (mdp_curr_down_scale_x != + MDP_PR_SCALE_POINT8_1)) { + mdp_load_pr_downscale_table_x_point8TO1 + (); + mdp_curr_down_scale_x = + MDP_PR_SCALE_POINT8_1; + } else if ((!use_pr) + && (mdp_curr_down_scale_x != + MDP_BC_SCALE_POINT8_1)) { + mdp_load_bc_downscale_table_x_point8TO1 + (); + mdp_curr_down_scale_x = + MDP_BC_SCALE_POINT8_1; + } + } else + if (((dst_roi_width_scale * 10) / + iBuf->roi.width) > 6) { + if ((use_pr) + && (mdp_curr_down_scale_x != + MDP_PR_SCALE_POINT6_POINT8)) { + mdp_load_pr_downscale_table_x_point6TOpoint8 + (); + mdp_curr_down_scale_x = + MDP_PR_SCALE_POINT6_POINT8; + } else if ((!use_pr) + && (mdp_curr_down_scale_x != + MDP_BC_SCALE_POINT6_POINT8)) + { + mdp_load_bc_downscale_table_x_point6TOpoint8 + (); + mdp_curr_down_scale_x = + MDP_BC_SCALE_POINT6_POINT8; + } + } else + if (((dst_roi_width_scale * 10) / + iBuf->roi.width) > 4) { + if ((use_pr) + && (mdp_curr_down_scale_x != + MDP_PR_SCALE_POINT4_POINT6)) { + mdp_load_pr_downscale_table_x_point4TOpoint6 + (); + mdp_curr_down_scale_x = + MDP_PR_SCALE_POINT4_POINT6; + } else if ((!use_pr) + && (mdp_curr_down_scale_x != + MDP_BC_SCALE_POINT4_POINT6)) + { + mdp_load_bc_downscale_table_x_point4TOpoint6 + (); + mdp_curr_down_scale_x = + MDP_BC_SCALE_POINT4_POINT6; + } + } else { + if ((use_pr) + && (mdp_curr_down_scale_x != + MDP_PR_SCALE_POINT2_POINT4)) { + mdp_load_pr_downscale_table_x_point2TOpoint4 + (); + mdp_curr_down_scale_x = + MDP_PR_SCALE_POINT2_POINT4; + } else if ((!use_pr) + && (mdp_curr_down_scale_x != + MDP_BC_SCALE_POINT2_POINT4)) + { + mdp_load_bc_downscale_table_x_point2TOpoint4 + (); + mdp_curr_down_scale_x = + MDP_BC_SCALE_POINT2_POINT4; + } + } + } + /* 0.2 < y <= 1 scaling factor */ + if ((dst_roi_height_scale <= iBuf->roi.height) && + !mdp_blur) { + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 8) { + if ((use_pr) + && (mdp_curr_down_scale_y != + MDP_PR_SCALE_POINT8_1)) { + mdp_load_pr_downscale_table_y_point8TO1 + (); + mdp_curr_down_scale_y = + MDP_PR_SCALE_POINT8_1; + } else if ((!use_pr) + && (mdp_curr_down_scale_y != + MDP_BC_SCALE_POINT8_1)) { + mdp_load_bc_downscale_table_y_point8TO1 + (); + mdp_curr_down_scale_y = + MDP_BC_SCALE_POINT8_1; + } + } else + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 6) { + if ((use_pr) + && (mdp_curr_down_scale_y != + MDP_PR_SCALE_POINT6_POINT8)) { + mdp_load_pr_downscale_table_y_point6TOpoint8 + (); + mdp_curr_down_scale_y = + MDP_PR_SCALE_POINT6_POINT8; + } else if ((!use_pr) + && (mdp_curr_down_scale_y != + MDP_BC_SCALE_POINT6_POINT8)) + { + mdp_load_bc_downscale_table_y_point6TOpoint8 + (); + mdp_curr_down_scale_y = + MDP_BC_SCALE_POINT6_POINT8; + } + } else + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 4) { + if ((use_pr) + && (mdp_curr_down_scale_y != + MDP_PR_SCALE_POINT4_POINT6)) { + mdp_load_pr_downscale_table_y_point4TOpoint6 + (); + mdp_curr_down_scale_y = + MDP_PR_SCALE_POINT4_POINT6; + } else if ((!use_pr) + && (mdp_curr_down_scale_y != + MDP_BC_SCALE_POINT4_POINT6)) + { + mdp_load_bc_downscale_table_y_point4TOpoint6 + (); + mdp_curr_down_scale_y = + MDP_BC_SCALE_POINT4_POINT6; + } + } else { + if ((use_pr) + && (mdp_curr_down_scale_y != + MDP_PR_SCALE_POINT2_POINT4)) { + mdp_load_pr_downscale_table_y_point2TOpoint4 + (); + mdp_curr_down_scale_y = + MDP_PR_SCALE_POINT2_POINT4; + } else if ((!use_pr) + && (mdp_curr_down_scale_y != + MDP_BC_SCALE_POINT2_POINT4)) + { + mdp_load_bc_downscale_table_y_point2TOpoint4 + (); + mdp_curr_down_scale_y = + MDP_BC_SCALE_POINT2_POINT4; + } + } + } + } else { + iBuf->mdpImg.mdpOp &= ~(MDPOP_ASCALE); + } + } + /* setting edge condition here after scaling check */ + if (mdp_get_edge_cond(iBuf, &lines_dup, &lines_dup_bg)) + printk(KERN_ERR "msm_fb: mdp_get_edge_cond() error!\n"); + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01b8, lines_dup); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01bc, lines_dup_bg); +} + +void mdp_init_scale_table(void) +{ + mdp_curr_up_scale_xy = MDP_INIT_SCALE; + mdp_curr_down_scale_x = MDP_INIT_SCALE; + mdp_curr_down_scale_y = MDP_INIT_SCALE; +} + +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) +{ + *src0 += (x + y * width) * bpp; + + /* if it's dest/bg buffer, we need to adjust it for rotation */ + if (layer != 0) + *src0 = mdp_adjust_rot_addr(iBuf, *src0, 0); + + if (*src1) { + /* + * MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now + * we need to shift x direction same as y dir for offsite + */ + *src1 += + ((x / h_slice) * h_slice + + ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp; + + /* if it's dest/bg buffer, we need to adjust it for rotation */ + if (layer != 0) + *src1 = mdp_adjust_rot_addr(iBuf, *src1, 1); + } +} + +void mdp_set_blend_attr(MDPIBUF *iBuf, + uint32 *alpha, + uint32 *tpVal, + uint32 perPixelAlpha, uint32 *pppop_reg_ptr) +{ + 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 | + PPP_BLEND_CALPHA_TRNASP; + + *alpha = iBuf->mdpImg.alpha; + *tpVal = iBuf->mdpImg.tpVal; + } else { + if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_SRCPIXEL_TRANSP; + *tpVal = iBuf->mdpImg.tpVal; + } else if (iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_ALPHA_BLEND_NORMAL | + PPP_OP_BLEND_CONSTANT_ALPHA; + *alpha = iBuf->mdpImg.alpha; + } + } + } +} diff --git a/drivers/staging/msm/mdp_ppp_v31.c b/drivers/staging/msm/mdp_ppp_v31.c new file mode 100644 index 00000000000..76495dbe4e6 --- /dev/null +++ b/drivers/staging/msm/mdp_ppp_v31.c @@ -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; + } +} diff --git a/drivers/staging/msm/mdp_vsync.c b/drivers/staging/msm/mdp_vsync.c new file mode 100644 index 00000000000..bbd45604435 --- /dev/null +++ b/drivers/staging/msm/mdp_vsync.c @@ -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; +} diff --git a/drivers/staging/msm/memory.c b/drivers/staging/msm/memory.c new file mode 100644 index 00000000000..cc80fdf17d6 --- /dev/null +++ b/drivers/staging/msm/memory.c @@ -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); +} diff --git a/drivers/staging/msm/memory_ll.h b/drivers/staging/msm/memory_ll.h new file mode 100644 index 00000000000..18a239a89a7 --- /dev/null +++ b/drivers/staging/msm/memory_ll.h @@ -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" diff --git a/drivers/staging/msm/msm_fb.c b/drivers/staging/msm/msm_fb.c new file mode 100644 index 00000000000..af5620e4eee --- /dev/null +++ b/drivers/staging/msm/msm_fb.c @@ -0,0 +1,2354 @@ +/* + * + * Core MSM framebuffer driver. + * + * Copyright (C) 2007 Google Incorporated + * Copyright (c) 2008-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/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 <mach/board.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/leds.h> +#include <asm/dma-mapping.h> + + +#define MSM_FB_C +#include "msm_fb.h" +#include "mddihosti.h" +#include "tvenc.h" +#include "mdp.h" +#include "mdp4.h" + +#ifdef CONFIG_FB_MSM_LOGO +#define INIT_IMAGE_FILE "/logo.rle" +extern int load_565rle_image(char *filename); +#endif + + +#define pgprot_noncached(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED) +#define pgprot_writecombine(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE) +#define pgprot_device(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_DEV_NONSHARED) +#define pgprot_writethroughcache(prot) \ + __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_WRITETHROUGH) +#define pgprot_writebackcache(prot) \ + __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_WRITEBACK) +#define pgprot_writebackwacache(prot) \ + __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_WRITEALLOC) + +static unsigned char *fbram; +static unsigned char *fbram_phys; +static int fbram_size; + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +int vsync_mode = 1; + +#define MAX_FBI_LIST 32 +static struct fb_info *fbi_list[MAX_FBI_LIST]; +static int fbi_list_index; + +static struct msm_fb_data_type *mfd_list[MAX_FBI_LIST]; +static int mfd_list_index; + +static u32 msm_fb_pseudo_palette[16] = { + 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff +}; + +u32 msm_fb_debug_enabled; +/* Setting msm_fb_msg_level to 8 prints out ALL messages */ +u32 msm_fb_msg_level = 7; + +/* Setting mddi_msg_level to 8 prints out ALL messages */ +u32 mddi_msg_level = 5; + +extern int32 mdp_block_power_cnt[MDP_MAX_BLOCK]; +extern unsigned long mdp_timer_duration; + +static int msm_fb_register(struct msm_fb_data_type *mfd); +static int msm_fb_open(struct fb_info *info, int user); +static int msm_fb_release(struct fb_info *info, int user); +static int msm_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd); +int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd); +static int msm_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int msm_fb_set_par(struct fb_info *info); +static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, + boolean op_enable); +static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd); +static int msm_fb_resume_sub(struct msm_fb_data_type *mfd); +static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg); +static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma); + +#ifdef MSM_FB_ENABLE_DBGFS + +#define MSM_FB_MAX_DBGFS 1024 +#define MAX_BACKLIGHT_BRIGHTNESS 255 + +int msm_fb_debugfs_file_index; +struct dentry *msm_fb_debugfs_root; +struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS]; + +struct dentry *msm_fb_get_debugfs_root(void) +{ + if (msm_fb_debugfs_root == NULL) + msm_fb_debugfs_root = debugfs_create_dir("msm_fb", NULL); + + return msm_fb_debugfs_root; +} + +void msm_fb_debugfs_file_create(struct dentry *root, const char *name, + u32 *var) +{ + if (msm_fb_debugfs_file_index >= MSM_FB_MAX_DBGFS) + return; + + msm_fb_debugfs_file[msm_fb_debugfs_file_index++] = + debugfs_create_u32(name, S_IRUGO | S_IWUSR, root, var); +} +#endif + +int msm_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (!mfd->cursor_update) + return -ENODEV; + + return mfd->cursor_update(info, cursor); +} + +static int msm_fb_resource_initialized; + +#ifndef CONFIG_FB_BACKLIGHT +static int lcd_backlight_registered; + +static void msm_fb_set_bl_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent); + int bl_lvl; + + if (value > MAX_BACKLIGHT_BRIGHTNESS) + value = MAX_BACKLIGHT_BRIGHTNESS; + + /* This maps android backlight level 0 to 255 into + driver backlight level 0 to bl_max with rounding */ + bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS) + /(2 * MAX_BACKLIGHT_BRIGHTNESS); + + if (!bl_lvl && value) + bl_lvl = 1; + + msm_fb_set_backlight(mfd, bl_lvl, 1); +} + +static struct led_classdev backlight_led = { + .name = "lcd-backlight", + .brightness = MAX_BACKLIGHT_BRIGHTNESS, + .brightness_set = msm_fb_set_bl_brightness, +}; +#endif + +static struct msm_fb_platform_data *msm_fb_pdata; + +int msm_fb_detect_client(const char *name) +{ + int ret = -EPERM; +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + u32 id; +#endif + + if (msm_fb_pdata && msm_fb_pdata->detect_client) { + ret = msm_fb_pdata->detect_client(name); + + /* if it's non mddi panel, we need to pre-scan + mddi client to see if we can disable mddi host */ + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + if (!ret && msm_fb_pdata->mddi_prescan) + id = mddi_get_client_id(); +#endif + } + + return ret; +} + +static int msm_fb_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + int rc; + + MSM_FB_DEBUG("msm_fb_probe\n"); + + if ((pdev->id == 0) && (pdev->num_resources > 0)) { + msm_fb_pdata = pdev->dev.platform_data; + fbram_size = + pdev->resource[0].end - pdev->resource[0].start + 1; + fbram_phys = (char *)pdev->resource[0].start; + fbram = ioremap((unsigned long)fbram_phys, fbram_size); + + if (!fbram) { + printk(KERN_ERR "fbram ioremap failed!\n"); + return -ENOMEM; + } + MSM_FB_INFO("msm_fb_probe: phy_Addr = 0x%x virt = 0x%x\n", + (int)fbram_phys, (int)fbram); + + msm_fb_resource_initialized = 1; + return 0; + } + + if (!msm_fb_resource_initialized) + return -EPERM; + + mfd = (struct msm_fb_data_type *)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; + + mfd->panel_info.frame_count = 0; + mfd->bl_level = mfd->panel_info.bl_max; + + if (mfd->panel_info.type == LCDC_PANEL) + mfd->allow_set_offset = + msm_fb_pdata->allow_set_offset != NULL ? + msm_fb_pdata->allow_set_offset() : 0; + else + mfd->allow_set_offset = 0; + + rc = msm_fb_register(mfd); + if (rc) + return rc; + +#ifdef CONFIG_FB_BACKLIGHT + msm_fb_config_backlight(mfd); +#else + /* android supports only one lcd-backlight/lcd for now */ + if (!lcd_backlight_registered) { + if (led_classdev_register(&pdev->dev, &backlight_led)) + printk(KERN_ERR "led_classdev_register failed\n"); + else + lcd_backlight_registered = 1; + } +#endif + + pdev_list[pdev_list_cnt++] = pdev; + return 0; +} + +static int msm_fb_remove(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + MSM_FB_DEBUG("msm_fb_remove\n"); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (msm_fb_suspend_sub(mfd)) + printk(KERN_ERR "msm_fb_remove: can't stop the device %d\n", mfd->index); + + if (mfd->channel_irq != 0) + free_irq(mfd->channel_irq, (void *)mfd); + + if (mfd->vsync_width_boundary) + vfree(mfd->vsync_width_boundary); + + if (mfd->vsync_resync_timer.function) + del_timer(&mfd->vsync_resync_timer); + + if (mfd->refresh_timer.function) + del_timer(&mfd->refresh_timer); + + if (mfd->dma_hrtimer.function) + hrtimer_cancel(&mfd->dma_hrtimer); + + /* remove /dev/fb* */ + unregister_framebuffer(mfd->fbi); + +#ifdef CONFIG_FB_BACKLIGHT + /* remove /sys/class/backlight */ + backlight_device_unregister(mfd->fbi->bl_dev); +#else + if (lcd_backlight_registered) { + lcd_backlight_registered = 0; + led_classdev_unregister(&backlight_led); + } +#endif + +#ifdef MSM_FB_ENABLE_DBGFS + if (mfd->sub_dir) + debugfs_remove(mfd->sub_dir); +#endif + + return 0; +} + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct msm_fb_data_type *mfd; + int ret = 0; + + MSM_FB_DEBUG("msm_fb_suspend\n"); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + acquire_console_sem(); + fb_set_suspend(mfd->fbi, 1); + + ret = msm_fb_suspend_sub(mfd); + if (ret != 0) { + printk(KERN_ERR "msm_fb: failed to suspend! %d\n", ret); + fb_set_suspend(mfd->fbi, 0); + } else { + pdev->dev.power.power_state = state; + } + + release_console_sem(); + return ret; +} +#else +#define msm_fb_suspend NULL +#endif + +static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd) +{ + int ret = 0; + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + /* + * suspend this channel + */ + mfd->suspend.sw_refreshing_enable = mfd->sw_refreshing_enable; + mfd->suspend.op_enable = mfd->op_enable; + mfd->suspend.panel_power_on = mfd->panel_power_on; + + if (mfd->op_enable) { + ret = + msm_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi, + mfd->suspend.op_enable); + if (ret) { + MSM_FB_INFO + ("msm_fb_suspend: can't turn off display!\n"); + return ret; + } + mfd->op_enable = FALSE; + } + /* + * try to power down + */ + mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + /* + * detach display channel irq if there's any + * or wait until vsync-resync completes + */ + if ((mfd->dest == DISPLAY_LCD)) { + if (mfd->panel_info.lcd.vsync_enable) { + if (mfd->panel_info.lcd.hw_vsync_mode) { + if (mfd->channel_irq != 0) + disable_irq(mfd->channel_irq); + } else { + volatile boolean vh_pending; + do { + vh_pending = mfd->vsync_handler_pending; + } while (vh_pending); + } + } + } + + return 0; +} + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int msm_fb_resume(struct platform_device *pdev) +{ + /* This resume function is called when interrupt is enabled. + */ + int ret = 0; + struct msm_fb_data_type *mfd; + + MSM_FB_DEBUG("msm_fb_resume\n"); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + acquire_console_sem(); + ret = msm_fb_resume_sub(mfd); + pdev->dev.power.power_state = PMSG_ON; + fb_set_suspend(mfd->fbi, 1); + release_console_sem(); + + return ret; +} +#else +#define msm_fb_resume NULL +#endif + +static int msm_fb_resume_sub(struct msm_fb_data_type *mfd) +{ + int ret = 0; + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + /* attach display channel irq if there's any */ + if (mfd->channel_irq != 0) + enable_irq(mfd->channel_irq); + + /* resume state var recover */ + mfd->sw_refreshing_enable = mfd->suspend.sw_refreshing_enable; + mfd->op_enable = mfd->suspend.op_enable; + + if (mfd->suspend.panel_power_on) { + ret = + msm_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi, + mfd->op_enable); + if (ret) + MSM_FB_INFO("msm_fb_resume: can't turn on display!\n"); + } + + return ret; +} + +static struct platform_driver msm_fb_driver = { + .probe = msm_fb_probe, + .remove = msm_fb_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = msm_fb_suspend, + .resume = msm_fb_resume, +#endif + .shutdown = NULL, + .driver = { + /* Driver name must match the device name added in platform.c. */ + .name = "msm_fb", + }, +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void msmfb_early_suspend(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + early_suspend); + msm_fb_suspend_sub(mfd); +} + +static void msmfb_early_resume(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + early_suspend); + msm_fb_resume_sub(mfd); +} +#endif + +void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl, u32 save) +{ + struct msm_fb_panel_data *pdata; + + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + if ((pdata) && (pdata->set_backlight)) { + down(&mfd->sem); + if ((bkl_lvl != mfd->bl_level) || (!save)) { + u32 old_lvl; + + old_lvl = mfd->bl_level; + mfd->bl_level = bkl_lvl; + pdata->set_backlight(mfd); + + if (!save) + mfd->bl_level = old_lvl; + } + up(&mfd->sem); + } +} + +static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, + boolean op_enable) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msm_fb_panel_data *pdata = NULL; + int ret = 0; + + if (!op_enable) + return -EPERM; + + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + if ((!pdata) || (!pdata->on) || (!pdata->off)) { + printk(KERN_ERR "msm_fb_blank_sub: no panel operation detected!\n"); + return -ENODEV; + } + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + if (!mfd->panel_power_on) { + mdelay(100); + ret = pdata->on(mfd->pdev); + if (ret == 0) { + mfd->panel_power_on = TRUE; + + msm_fb_set_backlight(mfd, + mfd->bl_level, 0); + +/* ToDo: possible conflict with android which doesn't expect sw refresher */ +/* + if (!mfd->hw_refresh) + { + if ((ret = msm_fb_resume_sw_refresher(mfd)) != 0) + { + MSM_FB_INFO("msm_fb_blank_sub: msm_fb_resume_sw_refresher failed = %d!\n",ret); + } + } +*/ + } + } + break; + + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_NORMAL: + case FB_BLANK_POWERDOWN: + default: + if (mfd->panel_power_on) { + int curr_pwr_state; + + mfd->op_enable = FALSE; + curr_pwr_state = mfd->panel_power_on; + mfd->panel_power_on = FALSE; + + mdelay(100); + ret = pdata->off(mfd->pdev); + if (ret) + mfd->panel_power_on = curr_pwr_state; + + msm_fb_set_backlight(mfd, 0, 0); + mfd->op_enable = TRUE; + } + break; + } + + return ret; +} + +static void msm_fb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + cfb_fillrect(info, rect); + if (!mfd->hw_refresh && (info->var.yoffset == 0) && + !mfd->sw_currently_refreshing) { + struct fb_var_screeninfo var; + + var = info->var; + var.reserved[0] = 0x54445055; + var.reserved[1] = (rect->dy << 16) | (rect->dx); + var.reserved[2] = ((rect->dy + rect->height) << 16) | + (rect->dx + rect->width); + + msm_fb_pan_display(&var, info); + } +} + +static void msm_fb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + cfb_copyarea(info, area); + if (!mfd->hw_refresh && (info->var.yoffset == 0) && + !mfd->sw_currently_refreshing) { + struct fb_var_screeninfo var; + + var = info->var; + var.reserved[0] = 0x54445055; + var.reserved[1] = (area->dy << 16) | (area->dx); + var.reserved[2] = ((area->dy + area->height) << 16) | + (area->dx + area->width); + + msm_fb_pan_display(&var, info); + } +} + +static void msm_fb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + cfb_imageblit(info, image); + if (!mfd->hw_refresh && (info->var.yoffset == 0) && + !mfd->sw_currently_refreshing) { + struct fb_var_screeninfo var; + + var = info->var; + var.reserved[0] = 0x54445055; + var.reserved[1] = (image->dy << 16) | (image->dx); + var.reserved[2] = ((image->dy + image->height) << 16) | + (image->dx + image->width); + + msm_fb_pan_display(&var, info); + } +} + +static int msm_fb_blank(int blank_mode, struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + return msm_fb_blank_sub(blank_mode, info, mfd->op_enable); +} + +static int msm_fb_set_lut(struct fb_cmap *cmap, struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (!mfd->lut_update) + return -ENODEV; + + mfd->lut_update(info, cmap); + return 0; +} + +/* + * Custom Framebuffer mmap() function for MSM driver. + * Differs from standard mmap() function by allowing for customized + * page-protection. + */ +static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma) +{ + /* Get frame buffer memory range. */ + unsigned long start = info->fix.smem_start; + u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); + unsigned long off = vma->vm_pgoff << PAGE_SHIFT; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + if (off >= len) { + /* memory mapped io */ + off -= len; + if (info->var.accel_flags) { + mutex_unlock(&info->lock); + return -EINVAL; + } + start = info->fix.mmio_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); + } + + /* Set VM flags. */ + start &= PAGE_MASK; + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + off += start; + vma->vm_pgoff = off >> PAGE_SHIFT; + /* This is an IO map - tell maydump to skip this VMA */ + vma->vm_flags |= VM_IO | VM_RESERVED; + + /* Set VM page protection */ + if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + else if (mfd->mdp_fb_page_protection == + MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE) + vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot); + else if (mfd->mdp_fb_page_protection == + MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE) + vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot); + else if (mfd->mdp_fb_page_protection == + MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE) + vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot); + else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + /* Remap the frame buffer I/O range */ + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + +static struct fb_ops msm_fb_ops = { + .owner = THIS_MODULE, + .fb_open = msm_fb_open, + .fb_release = msm_fb_release, + .fb_read = NULL, + .fb_write = NULL, + .fb_cursor = NULL, + .fb_check_var = msm_fb_check_var, /* vinfo check */ + .fb_set_par = msm_fb_set_par, /* set the video mode according to info->var */ + .fb_setcolreg = NULL, /* set color register */ + .fb_blank = msm_fb_blank, /* blank display */ + .fb_pan_display = msm_fb_pan_display, /* pan display */ + .fb_fillrect = msm_fb_fillrect, /* Draws a rectangle */ + .fb_copyarea = msm_fb_copyarea, /* Copy data from area to another */ + .fb_imageblit = msm_fb_imageblit, /* Draws a image to the display */ + .fb_rotate = NULL, + .fb_sync = NULL, /* wait for blit idle, optional */ + .fb_ioctl = msm_fb_ioctl, /* perform fb specific ioctl (optional) */ + .fb_mmap = msm_fb_mmap, +}; + +static int msm_fb_register(struct msm_fb_data_type *mfd) +{ + int ret = -ENODEV; + int bpp; + struct msm_panel_info *panel_info = &mfd->panel_info; + struct fb_info *fbi = mfd->fbi; + struct fb_fix_screeninfo *fix; + struct fb_var_screeninfo *var; + int *id; + int fbram_offset; + + /* + * fb info initialization + */ + fix = &fbi->fix; + var = &fbi->var; + + fix->type_aux = 0; /* if type == FB_TYPE_INTERLEAVED_PLANES */ + fix->visual = FB_VISUAL_TRUECOLOR; /* True Color */ + fix->ywrapstep = 0; /* No support */ + fix->mmio_start = 0; /* No MMIO Address */ + fix->mmio_len = 0; /* No MMIO Address */ + fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */ + + var->xoffset = 0, /* Offset from virtual to visible */ + var->yoffset = 0, /* resolution */ + var->grayscale = 0, /* No graylevels */ + var->nonstd = 0, /* standard pixel format */ + var->activate = FB_ACTIVATE_VBL, /* activate it at vsync */ + var->height = -1, /* height of picture in mm */ + var->width = -1, /* width of picture in mm */ + var->accel_flags = 0, /* acceleration flags */ + var->sync = 0, /* see FB_SYNC_* */ + var->rotate = 0, /* angle we rotate counter clockwise */ + mfd->op_enable = FALSE; + + switch (mfd->fb_imgType) { + case MDP_RGB_565: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 11; + var->blue.length = 5; + var->green.length = 6; + var->red.length = 5; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + bpp = 2; + break; + + case MDP_RGB_888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 8; + var->red.offset = 16; + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + bpp = 3; + break; + + case MDP_ARGB_8888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 8; + var->red.offset = 16; + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 24; + var->transp.length = 8; + bpp = 3; + break; + + case MDP_YCRYCB_H2V1: + /* ToDo: need to check TV-Out YUV422i framebuffer format */ + /* we might need to create new type define */ + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->xpanstep = 2; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + + /* how about R/G/B offset? */ + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 11; + var->blue.length = 5; + var->green.length = 6; + var->red.length = 5; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + bpp = 2; + break; + + default: + MSM_FB_ERR("msm_fb_init: fb %d unkown image type!\n", + mfd->index); + return ret; + } + + /* The adreno GPU hardware requires that the pitch be aligned to + 32 pixels for color buffers, so for the cases where the GPU + is writing directly to fb0, the framebuffer pitch + also needs to be 32 pixel aligned */ + + if (mfd->index == 0) + fix->line_length = ALIGN(panel_info->xres * bpp, 32); + else + fix->line_length = panel_info->xres * bpp; + + fix->smem_len = fix->line_length * panel_info->yres * mfd->fb_page; + + mfd->var_xres = panel_info->xres; + mfd->var_yres = panel_info->yres; + + var->pixclock = mfd->panel_info.clk_rate; + mfd->var_pixclock = var->pixclock; + + var->xres = panel_info->xres; + var->yres = panel_info->yres; + var->xres_virtual = panel_info->xres; + var->yres_virtual = panel_info->yres * mfd->fb_page; + var->bits_per_pixel = bpp * 8, /* FrameBuffer color depth */ + /* + * id field for fb app + */ + id = (int *)&mfd->panel; + +#if defined(CONFIG_FB_MSM_MDP22) + snprintf(fix->id, sizeof(fix->id), "msmfb22_%x", (__u32) *id); +#elif defined(CONFIG_FB_MSM_MDP30) + snprintf(fix->id, sizeof(fix->id), "msmfb30_%x", (__u32) *id); +#elif defined(CONFIG_FB_MSM_MDP31) + snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id); +#elif defined(CONFIG_FB_MSM_MDP40) + snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id); +#else + error CONFIG_FB_MSM_MDP undefined ! +#endif + fbi->fbops = &msm_fb_ops; + fbi->flags = FBINFO_FLAG_DEFAULT; + fbi->pseudo_palette = msm_fb_pseudo_palette; + + mfd->ref_cnt = 0; + mfd->sw_currently_refreshing = FALSE; + mfd->sw_refreshing_enable = TRUE; + mfd->panel_power_on = FALSE; + + mfd->pan_waiting = FALSE; + init_completion(&mfd->pan_comp); + init_completion(&mfd->refresher_comp); + init_MUTEX(&mfd->sem); + + fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram; + fbram += fbram_offset; + fbram_phys += fbram_offset; + fbram_size -= fbram_offset; + + if (fbram_size < fix->smem_len) { + printk(KERN_ERR "error: no more framebuffer memory!\n"); + return -ENOMEM; + } + + fbi->screen_base = fbram; + fbi->fix.smem_start = (unsigned long)fbram_phys; + + memset(fbi->screen_base, 0x0, fix->smem_len); + + mfd->op_enable = TRUE; + mfd->panel_power_on = FALSE; + + /* cursor memory allocation */ + if (mfd->cursor_update) { + mfd->cursor_buf = dma_alloc_coherent(NULL, + MDP_CURSOR_SIZE, + (dma_addr_t *) &mfd->cursor_buf_phys, + GFP_KERNEL); + if (!mfd->cursor_buf) + mfd->cursor_update = 0; + } + + if (mfd->lut_update) { + ret = fb_alloc_cmap(&fbi->cmap, 256, 0); + if (ret) + printk(KERN_ERR "%s: fb_alloc_cmap() failed!\n", + __func__); + } + + if (register_framebuffer(fbi) < 0) { + if (mfd->lut_update) + fb_dealloc_cmap(&fbi->cmap); + + if (mfd->cursor_buf) + dma_free_coherent(NULL, + MDP_CURSOR_SIZE, + mfd->cursor_buf, + (dma_addr_t) mfd->cursor_buf_phys); + + mfd->op_enable = FALSE; + return -EPERM; + } + + fbram += fix->smem_len; + fbram_phys += fix->smem_len; + fbram_size -= fix->smem_len; + + MSM_FB_INFO + ("FrameBuffer[%d] %dx%d size=%d bytes is registered successfully!\n", + mfd->index, fbi->var.xres, fbi->var.yres, fbi->fix.smem_len); + +#ifdef CONFIG_FB_MSM_LOGO + if (!load_565rle_image(INIT_IMAGE_FILE)) ; /* Flip buffer */ +#endif + ret = 0; + +#ifdef CONFIG_HAS_EARLYSUSPEND + mfd->early_suspend.suspend = msmfb_early_suspend; + mfd->early_suspend.resume = msmfb_early_resume; + mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2; + register_early_suspend(&mfd->early_suspend); +#endif + +#ifdef MSM_FB_ENABLE_DBGFS + { + struct dentry *root; + struct dentry *sub_dir; + char sub_name[2]; + + root = msm_fb_get_debugfs_root(); + if (root != NULL) { + sub_name[0] = (char)(mfd->index + 0x30); + sub_name[1] = '\0'; + sub_dir = debugfs_create_dir(sub_name, root); + } else { + sub_dir = NULL; + } + + mfd->sub_dir = sub_dir; + + if (sub_dir) { + msm_fb_debugfs_file_create(sub_dir, "op_enable", + (u32 *) &mfd->op_enable); + msm_fb_debugfs_file_create(sub_dir, "panel_power_on", + (u32 *) &mfd-> + panel_power_on); + msm_fb_debugfs_file_create(sub_dir, "ref_cnt", + (u32 *) &mfd->ref_cnt); + msm_fb_debugfs_file_create(sub_dir, "fb_imgType", + (u32 *) &mfd->fb_imgType); + msm_fb_debugfs_file_create(sub_dir, + "sw_currently_refreshing", + (u32 *) &mfd-> + sw_currently_refreshing); + msm_fb_debugfs_file_create(sub_dir, + "sw_refreshing_enable", + (u32 *) &mfd-> + sw_refreshing_enable); + + msm_fb_debugfs_file_create(sub_dir, "xres", + (u32 *) &mfd->panel_info. + xres); + msm_fb_debugfs_file_create(sub_dir, "yres", + (u32 *) &mfd->panel_info. + yres); + msm_fb_debugfs_file_create(sub_dir, "bpp", + (u32 *) &mfd->panel_info. + bpp); + msm_fb_debugfs_file_create(sub_dir, "type", + (u32 *) &mfd->panel_info. + type); + msm_fb_debugfs_file_create(sub_dir, "wait_cycle", + (u32 *) &mfd->panel_info. + wait_cycle); + msm_fb_debugfs_file_create(sub_dir, "pdest", + (u32 *) &mfd->panel_info. + pdest); + msm_fb_debugfs_file_create(sub_dir, "backbuff", + (u32 *) &mfd->panel_info. + fb_num); + msm_fb_debugfs_file_create(sub_dir, "clk_rate", + (u32 *) &mfd->panel_info. + clk_rate); + msm_fb_debugfs_file_create(sub_dir, "frame_count", + (u32 *) &mfd->panel_info. + frame_count); + + + switch (mfd->dest) { + case DISPLAY_LCD: + msm_fb_debugfs_file_create(sub_dir, + "vsync_enable", + (u32 *)&mfd->panel_info.lcd.vsync_enable); + msm_fb_debugfs_file_create(sub_dir, + "refx100", + (u32 *) &mfd->panel_info.lcd. refx100); + msm_fb_debugfs_file_create(sub_dir, + "v_back_porch", + (u32 *) &mfd->panel_info.lcd.v_back_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_front_porch", + (u32 *) &mfd->panel_info.lcd.v_front_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_pulse_width", + (u32 *) &mfd->panel_info.lcd.v_pulse_width); + msm_fb_debugfs_file_create(sub_dir, + "hw_vsync_mode", + (u32 *) &mfd->panel_info.lcd.hw_vsync_mode); + msm_fb_debugfs_file_create(sub_dir, + "vsync_notifier_period", (u32 *) + &mfd->panel_info.lcd.vsync_notifier_period); + break; + + case DISPLAY_LCDC: + msm_fb_debugfs_file_create(sub_dir, + "h_back_porch", + (u32 *) &mfd->panel_info.lcdc.h_back_porch); + msm_fb_debugfs_file_create(sub_dir, + "h_front_porch", + (u32 *) &mfd->panel_info.lcdc.h_front_porch); + msm_fb_debugfs_file_create(sub_dir, + "h_pulse_width", + (u32 *) &mfd->panel_info.lcdc.h_pulse_width); + msm_fb_debugfs_file_create(sub_dir, + "v_back_porch", + (u32 *) &mfd->panel_info.lcdc.v_back_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_front_porch", + (u32 *) &mfd->panel_info.lcdc.v_front_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_pulse_width", + (u32 *) &mfd->panel_info.lcdc.v_pulse_width); + msm_fb_debugfs_file_create(sub_dir, + "border_clr", + (u32 *) &mfd->panel_info.lcdc.border_clr); + msm_fb_debugfs_file_create(sub_dir, + "underflow_clr", + (u32 *) &mfd->panel_info.lcdc.underflow_clr); + msm_fb_debugfs_file_create(sub_dir, + "hsync_skew", + (u32 *) &mfd->panel_info.lcdc.hsync_skew); + break; + + default: + break; + } + } + } +#endif /* MSM_FB_ENABLE_DBGFS */ + + return ret; +} + +static int msm_fb_open(struct fb_info *info, int user) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (!mfd->ref_cnt) { + mdp_set_dma_pan_info(info, NULL, TRUE); + + if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) { + printk(KERN_ERR "msm_fb_open: can't turn on display!\n"); + return -1; + } + } + + mfd->ref_cnt++; + return 0; +} + +static int msm_fb_release(struct fb_info *info, int user) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + int ret = 0; + + if (!mfd->ref_cnt) { + MSM_FB_INFO("msm_fb_release: try to close unopened fb %d!\n", + mfd->index); + return -EINVAL; + } + + mfd->ref_cnt--; + + if (!mfd->ref_cnt) { + if ((ret = + msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, + mfd->op_enable)) != 0) { + printk(KERN_ERR "msm_fb_release: can't turn off display!\n"); + return ret; + } + } + + return ret; +} + +DECLARE_MUTEX(msm_fb_pan_sem); + +static int msm_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct mdp_dirty_region dirty; + struct mdp_dirty_region *dirtyPtr = NULL; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if ((!mfd->op_enable) || (!mfd->panel_power_on)) + return -EPERM; + + if (var->xoffset > (info->var.xres_virtual - info->var.xres)) + return -EINVAL; + + if (var->yoffset > (info->var.yres_virtual - info->var.yres)) + return -EINVAL; + + if (info->fix.xpanstep) + info->var.xoffset = + (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep; + + if (info->fix.ypanstep) + info->var.yoffset = + (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep; + + /* "UPDT" */ + if (var->reserved[0] == 0x54445055) { + dirty.xoffset = var->reserved[1] & 0xffff; + dirty.yoffset = (var->reserved[1] >> 16) & 0xffff; + + if ((var->reserved[2] & 0xffff) <= dirty.xoffset) + return -EINVAL; + if (((var->reserved[2] >> 16) & 0xffff) <= dirty.yoffset) + return -EINVAL; + + dirty.width = (var->reserved[2] & 0xffff) - dirty.xoffset; + dirty.height = + ((var->reserved[2] >> 16) & 0xffff) - dirty.yoffset; + info->var.yoffset = var->yoffset; + + if (dirty.xoffset < 0) + return -EINVAL; + + if (dirty.yoffset < 0) + return -EINVAL; + + if ((dirty.xoffset + dirty.width) > info->var.xres) + return -EINVAL; + + if ((dirty.yoffset + dirty.height) > info->var.yres) + return -EINVAL; + + if ((dirty.width <= 0) || (dirty.height <= 0)) + return -EINVAL; + + dirtyPtr = &dirty; + } + + /* Flip */ + /* A constant value is used to indicate that we should change the DMA + output buffer instead of just panning */ + + if (var->reserved[0] == 0x466c6970) { + unsigned long length, address; + struct file *p_src_file; + struct mdp_img imgdata; + int bpp; + + if (mfd->allow_set_offset) { + imgdata.memory_id = var->reserved[1]; + imgdata.priv = var->reserved[2]; + + /* If there is no memory ID then we want to reset back + to the original fb visibility */ + if (var->reserved[1]) { + if (var->reserved[4] == MDP_BLIT_SRC_GEM) { + panic("waaaaaaaaaaaaaah"); + if ( /*get_gem_img(&imgdata, + (unsigned long *) &address, + &length)*/ -1 < 0) { + return -1; + } + } else { + /*get_img(&imgdata, info, &address, + &length, &p_src_file);*/ + panic("waaaaaah"); + } + mfd->ibuf.visible_swapped = TRUE; + } else { + /* Flip back to the original address + adjusted for xoffset and yoffset */ + + bpp = info->var.bits_per_pixel / 8; + address = (unsigned long) info->fix.smem_start; + address += info->var.xoffset * bpp + + info->var.yoffset * info->fix.line_length; + + mfd->ibuf.visible_swapped = FALSE; + } + + mdp_set_offset_info(info, address, + (var->activate == FB_ACTIVATE_VBL)); + + mfd->dma_fnc(mfd); + return 0; + } else + return -EINVAL; + } + + down(&msm_fb_pan_sem); + mdp_set_dma_pan_info(info, dirtyPtr, + (var->activate == FB_ACTIVATE_VBL)); + mdp_dma_pan_update(info); + up(&msm_fb_pan_sem); + + ++mfd->panel_info.frame_count; + return 0; +} + +static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (var->rotate != FB_ROTATE_UR) + return -EINVAL; + if (var->grayscale != info->var.grayscale) + return -EINVAL; + + switch (var->bits_per_pixel) { + case 16: + if ((var->green.offset != 5) || + !((var->blue.offset == 11) + || (var->blue.offset == 0)) || + !((var->red.offset == 11) + || (var->red.offset == 0)) || + (var->blue.length != 5) || + (var->green.length != 6) || + (var->red.length != 5) || + (var->blue.msb_right != 0) || + (var->green.msb_right != 0) || + (var->red.msb_right != 0) || + (var->transp.offset != 0) || + (var->transp.length != 0)) + return -EINVAL; + break; + + case 24: + if ((var->blue.offset != 0) || + (var->green.offset != 8) || + (var->red.offset != 16) || + (var->blue.length != 8) || + (var->green.length != 8) || + (var->red.length != 8) || + (var->blue.msb_right != 0) || + (var->green.msb_right != 0) || + (var->red.msb_right != 0) || + !(((var->transp.offset == 0) && + (var->transp.length == 0)) || + ((var->transp.offset == 24) && + (var->transp.length == 8)))) + return -EINVAL; + break; + + default: + return -EINVAL; + } + + if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0)) + return -EINVAL; + + if (info->fix.smem_len < + (var->xres_virtual*var->yres_virtual*(var->bits_per_pixel/8))) + return -EINVAL; + + if ((var->xres == 0) || (var->yres == 0)) + return -EINVAL; + + if ((var->xres > mfd->panel_info.xres) || + (var->yres > mfd->panel_info.yres)) + return -EINVAL; + + if (var->xoffset > (var->xres_virtual - var->xres)) + return -EINVAL; + + if (var->yoffset > (var->yres_virtual - var->yres)) + return -EINVAL; + + return 0; +} + +static int msm_fb_set_par(struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct fb_var_screeninfo *var = &info->var; + int old_imgType; + int blank = 0; + + old_imgType = mfd->fb_imgType; + switch (var->bits_per_pixel) { + case 16: + if (var->red.offset == 0) + mfd->fb_imgType = MDP_BGR_565; + else + mfd->fb_imgType = MDP_RGB_565; + break; + + case 24: + if ((var->transp.offset == 0) && (var->transp.length == 0)) + mfd->fb_imgType = MDP_RGB_888; + else if ((var->transp.offset == 24) && + (var->transp.length == 8)) { + mfd->fb_imgType = MDP_ARGB_8888; + info->var.bits_per_pixel = 32; + } + break; + + default: + return -EINVAL; + } + + if ((mfd->var_pixclock != var->pixclock) || + (mfd->hw_refresh && ((mfd->fb_imgType != old_imgType) || + (mfd->var_pixclock != var->pixclock) || + (mfd->var_xres != var->xres) || + (mfd->var_yres != var->yres)))) { + mfd->var_xres = var->xres; + mfd->var_yres = var->yres; + mfd->var_pixclock = var->pixclock; + blank = 1; + } + + if (blank) { + msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable); + msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable); + } + + return 0; +} + +static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd) +{ + if (mfd->hw_refresh) + return -EPERM; + + if (mfd->sw_currently_refreshing) { + down(&mfd->sem); + mfd->sw_currently_refreshing = FALSE; + up(&mfd->sem); + + /* wait until the refresher finishes the last job */ + wait_for_completion_killable(&mfd->refresher_comp); + } + + return 0; +} + +int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd) +{ + boolean do_refresh; + + if (mfd->hw_refresh) + return -EPERM; + + down(&mfd->sem); + if ((!mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) { + do_refresh = TRUE; + mfd->sw_currently_refreshing = TRUE; + } else { + do_refresh = FALSE; + } + up(&mfd->sem); + + if (do_refresh) + mdp_refresh_screen((unsigned long)mfd); + + return 0; +} + +void mdp_ppp_put_img(struct file *p_src_file, struct file *p_dst_file) +{ +#ifdef CONFIG_ANDROID_PMEM + if (p_src_file) + put_pmem_file(p_src_file); + if (p_dst_file) + put_pmem_file(p_dst_file); +#endif +} + +int mdp_blit(struct fb_info *info, struct mdp_blit_req *req) +{ + int ret; + struct file *p_src_file = 0, *p_dst_file = 0; + if (unlikely(req->src_rect.h == 0 || req->src_rect.w == 0)) { + printk(KERN_ERR "mpd_ppp: src img of zero size!\n"); + return -EINVAL; + } + if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0)) + return 0; + + ret = mdp_ppp_blit(info, req, &p_src_file, &p_dst_file); + mdp_ppp_put_img(p_src_file, p_dst_file); + return ret; +} + +typedef void (*msm_dma_barrier_function_pointer) (void *, size_t); + +static inline void msm_fb_dma_barrier_for_rect(struct fb_info *info, + struct mdp_img *img, struct mdp_rect *rect, + msm_dma_barrier_function_pointer dma_barrier_fp + ) +{ + /* + * Compute the start and end addresses of the rectangles. + * NOTE: As currently implemented, the data between + * the end of one row and the start of the next is + * included in the address range rather than + * doing multiple calls for each row. + */ + + char * const pmem_start = info->screen_base; +/* int bytes_per_pixel = mdp_get_bytes_per_pixel(img->format); + unsigned long start = (unsigned long)pmem_start + img->offset + + (img->width * rect->y + rect->x) * bytes_per_pixel; + size_t size = ((rect->h - 1) * img->width + rect->w) * bytes_per_pixel; + (*dma_barrier_fp) ((void *) start, size); +*/ + panic("waaaaah"); +} + +static inline void msm_dma_nc_pre(void) +{ + dmb(); +} +static inline void msm_dma_wt_pre(void) +{ + dmb(); +} +static inline void msm_dma_todevice_wb_pre(void *start, size_t size) +{ + #warning this +// dma_cache_pre_ops(start, size, DMA_TO_DEVICE); +} + +static inline void msm_dma_fromdevice_wb_pre(void *start, size_t size) +{ + #warning this +// dma_cache_pre_ops(start, size, DMA_FROM_DEVICE); +} + +static inline void msm_dma_nc_post(void) +{ + dmb(); +} + +static inline void msm_dma_fromdevice_wt_post(void *start, size_t size) +{ + #warning this +// dma_cache_post_ops(start, size, DMA_FROM_DEVICE); +} + +static inline void msm_dma_todevice_wb_post(void *start, size_t size) +{ + #warning this +// dma_cache_post_ops(start, size, DMA_TO_DEVICE); +} + +static inline void msm_dma_fromdevice_wb_post(void *start, size_t size) +{ + #warning this +// dma_cache_post_ops(start, size, DMA_FROM_DEVICE); +} + +/* + * Do the write barriers required to guarantee data is committed to RAM + * (from CPU cache or internal buffers) before a DMA operation starts. + * NOTE: As currently implemented, the data between + * the end of one row and the start of the next is + * included in the address range rather than + * doing multiple calls for each row. +*/ +static void msm_fb_ensure_memory_coherency_before_dma(struct fb_info *info, + struct mdp_blit_req *req_list, + int req_list_count) +{ +#ifdef CONFIG_ARCH_QSD8X50 + int i; + + /* + * Normally, do the requested barriers for each address + * range that corresponds to a rectangle. + * + * But if at least one write barrier is requested for data + * going to or from the device but no address range is + * needed for that barrier, then do the barrier, but do it + * only once, no matter how many requests there are. + */ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + switch (mfd->mdp_fb_page_protection) { + default: + case MDP_FB_PAGE_PROTECTION_NONCACHED: + case MDP_FB_PAGE_PROTECTION_WRITECOMBINE: + /* + * The following barrier is only done at most once, + * since further calls would be redundant. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags + & MDP_NO_DMA_BARRIER_START)) { + msm_dma_nc_pre(); + break; + } + } + break; + + case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE: + /* + * The following barrier is only done at most once, + * since further calls would be redundant. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags + & MDP_NO_DMA_BARRIER_START)) { + msm_dma_wt_pre(); + break; + } + } + break; + + case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE: + case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE: + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & + MDP_NO_DMA_BARRIER_START)) { + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].src), + &(req_list[i].src_rect), + msm_dma_todevice_wb_pre + ); + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].dst), + &(req_list[i].dst_rect), + msm_dma_todevice_wb_pre + ); + } + } + break; + } +#else + dmb(); +#endif +} + + +/* + * Do the write barriers required to guarantee data will be re-read from RAM by + * the CPU after a DMA operation ends. + * NOTE: As currently implemented, the data between + * the end of one row and the start of the next is + * included in the address range rather than + * doing multiple calls for each row. +*/ +static void msm_fb_ensure_memory_coherency_after_dma(struct fb_info *info, + struct mdp_blit_req *req_list, + int req_list_count) +{ +#ifdef CONFIG_ARCH_QSD8X50 + int i; + + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + switch (mfd->mdp_fb_page_protection) { + default: + case MDP_FB_PAGE_PROTECTION_NONCACHED: + case MDP_FB_PAGE_PROTECTION_WRITECOMBINE: + /* + * The following barrier is only done at most once, + * since further calls would be redundant. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags + & MDP_NO_DMA_BARRIER_END)) { + msm_dma_nc_post(); + break; + } + } + break; + + case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE: + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & + MDP_NO_DMA_BARRIER_END)) { + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].dst), + &(req_list[i].dst_rect), + msm_dma_fromdevice_wt_post + ); + } + } + break; + case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE: + case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE: + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & + MDP_NO_DMA_BARRIER_END)) { + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].dst), + &(req_list[i].dst_rect), + msm_dma_fromdevice_wb_post + ); + } + } + break; + } +#else + dmb(); +#endif +} + +#ifdef CONFIG_MDP_PPP_ASYNC_OP +void msm_fb_ensure_mem_coherency_after_dma(struct fb_info *info, + struct mdp_blit_req *req_list, int req_list_count) +{ + BUG_ON(!info); + + /* + * Ensure that CPU cache and other internal CPU state is + * updated to reflect any change in memory modified by MDP blit + * DMA. + */ + msm_fb_ensure_memory_coherency_after_dma(info, + req_list, req_list_count); +} + +static int msmfb_async_blit(struct fb_info *info, void __user *p) +{ + /* + * CAUTION: The names of the struct types intentionally *DON'T* match + * the names of the variables declared -- they appear to be swapped. + * Read the code carefully and you should see that the variable names + * make sense. + */ + const int MAX_LIST_WINDOW = 16; + struct mdp_blit_req req_list[MAX_LIST_WINDOW]; + struct mdp_blit_req_list req_list_header; + + int count, i, req_list_count; + + /* Get the count size for the total BLIT request. */ + if (copy_from_user(&req_list_header, p, sizeof(req_list_header))) + return -EFAULT; + p += sizeof(req_list_header); + count = req_list_header.count; + while (count > 0) { + /* + * Access the requests through a narrow window to decrease copy + * overhead and make larger requests accessible to the + * coherency management code. + * NOTE: The window size is intended to be larger than the + * typical request size, but not require more than 2 + * kbytes of stack storage. + */ + req_list_count = count; + if (req_list_count > MAX_LIST_WINDOW) + req_list_count = MAX_LIST_WINDOW; + if (copy_from_user(&req_list, p, + sizeof(struct mdp_blit_req)*req_list_count)) + return -EFAULT; + + /* + * Ensure that any data CPU may have previously written to + * internal state (but not yet committed to memory) is + * guaranteed to be committed to memory now. + */ + msm_fb_ensure_memory_coherency_before_dma(info, + req_list, req_list_count); + + /* + * Do the blit DMA, if required -- returning early only if + * there is a failure. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & MDP_NO_BLIT)) { + int ret = 0; + struct mdp_ppp_djob *job = NULL; + + if (unlikely(req_list[i].src_rect.h == 0 || + req_list[i].src_rect.w == 0)) { + MSM_FB_ERR("mpd_ppp: " + "src img of zero size!\n"); + return -EINVAL; + } + + if (unlikely(req_list[i].dst_rect.h == 0 || + req_list[i].dst_rect.w == 0)) + continue; + + /* create a new display job */ + job = mdp_ppp_new_djob(); + if (unlikely(!job)) + return -ENOMEM; + + job->info = info; + memcpy(&job->req, &req_list[i], + sizeof(struct mdp_blit_req)); + + /* Do the actual blit. */ + ret = mdp_ppp_blit(info, &job->req, + &job->p_src_file, &job->p_dst_file); + + /* + * Note that early returns don't guarantee + * memory coherency. + */ + if (ret || mdp_ppp_get_ret_code()) { + mdp_ppp_clear_curr_djob(); + return ret; + } + } + } + + /* Go to next window of requests. */ + count -= req_list_count; + p += sizeof(struct mdp_blit_req)*req_list_count; + } + return 0; +} +#else + +/* + * NOTE: The userspace issues blit operations in a sequence, the sequence + * start with a operation marked START and ends in an operation marked + * END. It is guranteed by the userspace that all the blit operations + * between START and END are only within the regions of areas designated + * by the START and END operations and that the userspace doesnt modify + * those areas. Hence it would be enough to perform barrier/cache operations + * only on the START and END operations. + */ +static int msmfb_blit(struct fb_info *info, void __user *p) +{ + /* + * CAUTION: The names of the struct types intentionally *DON'T* match + * the names of the variables declared -- they appear to be swapped. + * Read the code carefully and you should see that the variable names + * make sense. + */ + const int MAX_LIST_WINDOW = 16; + struct mdp_blit_req req_list[MAX_LIST_WINDOW]; + struct mdp_blit_req_list req_list_header; + + int count, i, req_list_count; + + /* Get the count size for the total BLIT request. */ + if (copy_from_user(&req_list_header, p, sizeof(req_list_header))) + return -EFAULT; + p += sizeof(req_list_header); + count = req_list_header.count; + while (count > 0) { + /* + * Access the requests through a narrow window to decrease copy + * overhead and make larger requests accessible to the + * coherency management code. + * NOTE: The window size is intended to be larger than the + * typical request size, but not require more than 2 + * kbytes of stack storage. + */ + req_list_count = count; + if (req_list_count > MAX_LIST_WINDOW) + req_list_count = MAX_LIST_WINDOW; + if (copy_from_user(&req_list, p, + sizeof(struct mdp_blit_req)*req_list_count)) + return -EFAULT; + + /* + * Ensure that any data CPU may have previously written to + * internal state (but not yet committed to memory) is + * guaranteed to be committed to memory now. + */ + msm_fb_ensure_memory_coherency_before_dma(info, + req_list, req_list_count); + + /* + * Do the blit DMA, if required -- returning early only if + * there is a failure. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & MDP_NO_BLIT)) { + /* Do the actual blit. */ + int ret = mdp_blit(info, &(req_list[i])); + + /* + * Note that early returns don't guarantee + * memory coherency. + */ + if (ret) + return ret; + } + } + + /* + * Ensure that CPU cache and other internal CPU state is + * updated to reflect any change in memory modified by MDP blit + * DMA. + */ + msm_fb_ensure_memory_coherency_after_dma(info, + req_list, + req_list_count); + + /* Go to next window of requests. */ + count -= req_list_count; + p += sizeof(struct mdp_blit_req)*req_list_count; + } + return 0; +} +#endif + +#ifdef CONFIG_FB_MSM_OVERLAY +static int msmfb_overlay_get(struct fb_info *info, void __user *p) +{ + struct mdp_overlay req; + int ret; + + if (copy_from_user(&req, p, sizeof(req))) + return -EFAULT; + + ret = mdp4_overlay_get(info, &req); + if (ret) { + printk(KERN_ERR "%s: ioctl failed \n", + __func__); + return ret; + } + if (copy_to_user(p, &req, sizeof(req))) { + printk(KERN_ERR "%s: copy2user failed \n", + __func__); + return -EFAULT; + } + + return 0; +} + +static int msmfb_overlay_set(struct fb_info *info, void __user *p) +{ + struct mdp_overlay req; + int ret; + + if (copy_from_user(&req, p, sizeof(req))) + return -EFAULT; + + ret = mdp4_overlay_set(info, &req); + if (ret) { + printk(KERN_ERR "%s:ioctl failed \n", + __func__); + return ret; + } + + if (copy_to_user(p, &req, sizeof(req))) { + printk(KERN_ERR "%s: copy2user failed \n", + __func__); + return -EFAULT; + } + + return 0; +} + +static int msmfb_overlay_unset(struct fb_info *info, unsigned long *argp) +{ + int ret, ndx; + + ret = copy_from_user(&ndx, argp, sizeof(ndx)); + if (ret) { + printk(KERN_ERR "%s:msmfb_overlay_unset ioctl failed \n", + __func__); + return ret; + } + + return mdp4_overlay_unset(info, ndx); +} + +static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp) +{ + int ret; + struct msmfb_overlay_data req; + struct file *p_src_file = 0; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + printk(KERN_ERR "%s:msmfb_overlay_play ioctl failed \n", + __func__); + return ret; + } + + ret = mdp4_overlay_play(info, &req, &p_src_file); + + if (p_src_file) + put_pmem_file(p_src_file); + + return ret; +} + +#endif + +DECLARE_MUTEX(msm_fb_ioctl_ppp_sem); +DEFINE_MUTEX(msm_fb_ioctl_lut_sem); +DEFINE_MUTEX(msm_fb_ioctl_hist_sem); + +/* Set color conversion matrix from user space */ + +#ifndef CONFIG_FB_MSM_MDP40 +static void msmfb_set_color_conv(struct mdp_ccs *p) +{ + int i; + + if (p->direction == MDP_CCS_RGB2YUV) { + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* RGB->YUV primary forward matrix */ + for (i = 0; i < MDP_CCS_SIZE; i++) + writel(p->ccs[i], MDP_CSC_PFMVn(i)); + + #ifdef CONFIG_FB_MSM_MDP31 + for (i = 0; i < MDP_BV_SIZE; i++) + writel(p->bv[i], MDP_CSC_POST_BV2n(i)); + #endif + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } else { + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* YUV->RGB primary reverse matrix */ + for (i = 0; i < MDP_CCS_SIZE; i++) + writel(p->ccs[i], MDP_CSC_PRMVn(i)); + for (i = 0; i < MDP_BV_SIZE; i++) + writel(p->bv[i], MDP_CSC_PRE_BV1n(i)); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } +} +#endif + + +static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + void __user *argp = (void __user *)arg; + struct fb_cursor cursor; + struct fb_cmap cmap; + struct mdp_histogram hist; +#ifndef CONFIG_FB_MSM_MDP40 + struct mdp_ccs ccs_matrix; +#endif + struct mdp_page_protection fb_page_protection; + int ret = 0; + + if (!mfd->op_enable) + return -EPERM; + + switch (cmd) { +#ifdef CONFIG_FB_MSM_OVERLAY + case MSMFB_OVERLAY_GET: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_get(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_SET: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_set(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_UNSET: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_unset(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_PLAY: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_play(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; +#endif + case MSMFB_BLIT: + down(&msm_fb_ioctl_ppp_sem); +#ifdef CONFIG_MDP_PPP_ASYNC_OP + ret = msmfb_async_blit(info, argp); + mdp_ppp_wait(); /* Wait for all blits to be finished. */ +#else + ret = msmfb_blit(info, argp); +#endif + up(&msm_fb_ioctl_ppp_sem); + + break; + + /* Ioctl for setting ccs matrix from user space */ + case MSMFB_SET_CCS_MATRIX: +#ifndef CONFIG_FB_MSM_MDP40 + ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix)); + if (ret) { + printk(KERN_ERR + "%s:MSMFB_SET_CCS_MATRIX ioctl failed \n", + __func__); + return ret; + } + + down(&msm_fb_ioctl_ppp_sem); + if (ccs_matrix.direction == MDP_CCS_RGB2YUV) + mdp_ccs_rgb2yuv = ccs_matrix; + else + mdp_ccs_yuv2rgb = ccs_matrix; + + msmfb_set_color_conv(&ccs_matrix) ; + up(&msm_fb_ioctl_ppp_sem); +#else + ret = -EINVAL; +#endif + + break; + + /* Ioctl for getting ccs matrix to user space */ + case MSMFB_GET_CCS_MATRIX: +#ifndef CONFIG_FB_MSM_MDP40 + ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix)) ; + if (ret) { + printk(KERN_ERR + "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n", + __func__); + return ret; + } + + down(&msm_fb_ioctl_ppp_sem); + if (ccs_matrix.direction == MDP_CCS_RGB2YUV) + ccs_matrix = mdp_ccs_rgb2yuv; + else + ccs_matrix = mdp_ccs_yuv2rgb; + + ret = copy_to_user(argp, &ccs_matrix, sizeof(ccs_matrix)); + + if (ret) { + printk(KERN_ERR + "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n", + __func__); + return ret ; + } + up(&msm_fb_ioctl_ppp_sem); +#else + ret = -EINVAL; +#endif + + break; + +#ifdef CONFIG_MDP_PPP_ASYNC_OP + case MSMFB_ASYNC_BLIT: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_async_blit(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + + case MSMFB_BLIT_FLUSH: + down(&msm_fb_ioctl_ppp_sem); + mdp_ppp_wait(); + up(&msm_fb_ioctl_ppp_sem); + break; +#endif + + case MSMFB_GRP_DISP: +#ifdef CONFIG_FB_MSM_MDP22 + { + unsigned long grp_id; + + ret = copy_from_user(&grp_id, argp, sizeof(grp_id)); + if (ret) + return ret; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + writel(grp_id, MDP_FULL_BYPASS_WORD43); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, + FALSE); + break; + } +#else + return -EFAULT; +#endif + case MSMFB_SUSPEND_SW_REFRESHER: + if (!mfd->panel_power_on) + return -EPERM; + + mfd->sw_refreshing_enable = FALSE; + ret = msm_fb_stop_sw_refresher(mfd); + break; + + case MSMFB_RESUME_SW_REFRESHER: + if (!mfd->panel_power_on) + return -EPERM; + + mfd->sw_refreshing_enable = TRUE; + ret = msm_fb_resume_sw_refresher(mfd); + break; + + case MSMFB_CURSOR: + ret = copy_from_user(&cursor, argp, sizeof(cursor)); + if (ret) + return ret; + + ret = msm_fb_cursor(info, &cursor); + break; + + case MSMFB_SET_LUT: + ret = copy_from_user(&cmap, argp, sizeof(cmap)); + if (ret) + return ret; + + mutex_lock(&msm_fb_ioctl_lut_sem); + ret = msm_fb_set_lut(&cmap, info); + mutex_unlock(&msm_fb_ioctl_lut_sem); + break; + + case MSMFB_HISTOGRAM: + if (!mfd->do_histogram) + return -ENODEV; + + ret = copy_from_user(&hist, argp, sizeof(hist)); + if (ret) + return ret; + + mutex_lock(&msm_fb_ioctl_hist_sem); + ret = mfd->do_histogram(info, &hist); + mutex_unlock(&msm_fb_ioctl_hist_sem); + break; + + case MSMFB_GET_PAGE_PROTECTION: + fb_page_protection.page_protection + = mfd->mdp_fb_page_protection; + ret = copy_to_user(argp, &fb_page_protection, + sizeof(fb_page_protection)); + if (ret) + return ret; + break; + + case MSMFB_SET_PAGE_PROTECTION: +#ifdef CONFIG_ARCH_QSD8X50 + ret = copy_from_user(&fb_page_protection, argp, + sizeof(fb_page_protection)); + if (ret) + return ret; + + /* Validate the proposed page protection settings. */ + switch (fb_page_protection.page_protection) { + case MDP_FB_PAGE_PROTECTION_NONCACHED: + case MDP_FB_PAGE_PROTECTION_WRITECOMBINE: + case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE: + /* Write-back cache (read allocate) */ + case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE: + /* Write-back cache (write allocate) */ + case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE: + mfd->mdp_fb_page_protection = + fb_page_protection.page_protection; + break; + default: + ret = -EINVAL; + break; + } +#else + /* + * Don't allow caching until 7k DMA cache operations are + * available. + */ + ret = -EINVAL; +#endif + break; + + default: + MSM_FB_INFO("MDP: unknown ioctl (cmd=%d) received!\n", cmd); + ret = -EINVAL; + break; + } + + return ret; +} + +static int msm_fb_register_driver(void) +{ + return platform_driver_register(&msm_fb_driver); +} + +void msm_fb_add_device(struct platform_device *pdev) +{ + struct msm_fb_panel_data *pdata; + struct platform_device *this_dev = NULL; + struct fb_info *fbi; + struct msm_fb_data_type *mfd = NULL; + u32 type, id, fb_num; + + if (!pdev) + return; + id = pdev->id; + + pdata = pdev->dev.platform_data; + if (!pdata) + return; + type = pdata->panel_info.type; + fb_num = pdata->panel_info.fb_num; + + if (fb_num <= 0) + return; + + if (fbi_list_index >= MAX_FBI_LIST) { + printk(KERN_ERR "msm_fb: no more framebuffer info list!\n"); + return; + } + /* + * alloc panel device data + */ + this_dev = msm_fb_device_alloc(pdata, type, id); + + if (!this_dev) { + printk(KERN_ERR + "%s: msm_fb_device_alloc failed!\n", __func__); + return; + } + + /* + * alloc framebuffer info + par data + */ + fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL); + if (fbi == NULL) { + platform_device_put(this_dev); + printk(KERN_ERR "msm_fb: can't alloca framebuffer info data!\n"); + return; + } + + mfd = (struct msm_fb_data_type *)fbi->par; + mfd->key = MFD_KEY; + mfd->fbi = fbi; + mfd->panel.type = type; + mfd->panel.id = id; + mfd->fb_page = fb_num; + mfd->index = fbi_list_index; + mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE; + + /* link to the latest pdev */ + mfd->pdev = this_dev; + + mfd_list[mfd_list_index++] = mfd; + fbi_list[fbi_list_index++] = fbi; + + /* + * set driver data + */ + platform_set_drvdata(this_dev, mfd); + + if (platform_device_add(this_dev)) { + printk(KERN_ERR "msm_fb: platform_device_add failed!\n"); + platform_device_put(this_dev); + framebuffer_release(fbi); + fbi_list_index--; + return; + } +} +EXPORT_SYMBOL(msm_fb_add_device); + +int __init msm_fb_init(void) +{ + int rc = -ENODEV; + + if (msm_fb_register_driver()) + return rc; + +#ifdef MSM_FB_ENABLE_DBGFS + { + struct dentry *root; + + if ((root = msm_fb_get_debugfs_root()) != NULL) { + msm_fb_debugfs_file_create(root, + "msm_fb_msg_printing_level", + (u32 *) &msm_fb_msg_level); + msm_fb_debugfs_file_create(root, + "mddi_msg_printing_level", + (u32 *) &mddi_msg_level); + msm_fb_debugfs_file_create(root, "msm_fb_debug_enabled", + (u32 *) &msm_fb_debug_enabled); + } + } +#endif + + return 0; +} + +module_init(msm_fb_init); diff --git a/drivers/staging/msm/msm_fb.h b/drivers/staging/msm/msm_fb.h new file mode 100644 index 00000000000..f9391380047 --- /dev/null +++ b/drivers/staging/msm/msm_fb.h @@ -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 */ diff --git a/drivers/staging/msm/msm_fb_bl.c b/drivers/staging/msm/msm_fb_bl.c new file mode 100644 index 00000000000..033fc9486e0 --- /dev/null +++ b/drivers/staging/msm/msm_fb_bl.c @@ -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"); + } + } +} diff --git a/drivers/staging/msm/msm_fb_def.h b/drivers/staging/msm/msm_fb_def.h new file mode 100644 index 00000000000..6de44093742 --- /dev/null +++ b/drivers/staging/msm/msm_fb_def.h @@ -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 */ diff --git a/drivers/staging/msm/msm_fb_panel.c b/drivers/staging/msm/msm_fb_panel.c new file mode 100644 index 00000000000..b17a239a1bc --- /dev/null +++ b/drivers/staging/msm/msm_fb_panel.c @@ -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; +} diff --git a/drivers/staging/msm/msm_fb_panel.h b/drivers/staging/msm/msm_fb_panel.h new file mode 100644 index 00000000000..ab458310c3a --- /dev/null +++ b/drivers/staging/msm/msm_fb_panel.h @@ -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 */ diff --git a/drivers/staging/msm/msm_mdp.h b/drivers/staging/msm/msm_mdp.h new file mode 100644 index 00000000000..2d5323f5b62 --- /dev/null +++ b/drivers/staging/msm/msm_mdp.h @@ -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_*/ diff --git a/drivers/staging/msm/staging-devices.c b/drivers/staging/msm/staging-devices.c new file mode 100644 index 00000000000..0f8ec3e2601 --- /dev/null +++ b/drivers/staging/msm/staging-devices.c @@ -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); diff --git a/drivers/staging/msm/tv_ntsc.c b/drivers/staging/msm/tv_ntsc.c new file mode 100644 index 00000000000..5eb67611661 --- /dev/null +++ b/drivers/staging/msm/tv_ntsc.c @@ -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);
\ No newline at end of file diff --git a/drivers/staging/msm/tv_pal.c b/drivers/staging/msm/tv_pal.c new file mode 100644 index 00000000000..204da514660 --- /dev/null +++ b/drivers/staging/msm/tv_pal.c @@ -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); diff --git a/drivers/staging/msm/tvenc.c b/drivers/staging/msm/tvenc.c new file mode 100644 index 00000000000..f41c5ac22f2 --- /dev/null +++ b/drivers/staging/msm/tvenc.c @@ -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); diff --git a/drivers/staging/msm/tvenc.h b/drivers/staging/msm/tvenc.h new file mode 100644 index 00000000000..a682dbebcf7 --- /dev/null +++ b/drivers/staging/msm/tvenc.h @@ -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 */ |